Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix null handling for enum types. #13091

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions src/app/tests/TestNumericAttributeTraits.cpp
Original file line number Diff line number Diff line change
@@ -38,6 +38,156 @@ using namespace chip::app;

namespace {

void Test_UINT8(nlTestSuite * apSuite, void * apContext)
{
// Unsigned 8-bit Integer : 1 byte, endianness does not matter.
using IntType = NumericAttributeTraits<uint8_t>;
using StorageType = typename IntType::StorageType;
using WorkingType = typename IntType::WorkingType;

StorageType sValue;
WorkingType wValue;
StorageType sNullValue;
WorkingType wNullValue;
const StorageType storageTestData = 17;
const WorkingType workingTestUnsignedNullValue = 0xFF;

// 1) Verify the size of the types
NL_TEST_ASSERT(apSuite, sizeof(sValue) == 1);
NL_TEST_ASSERT(apSuite, sizeof(wValue) >= 1);

// Initialize the Storage Value with the test-buffer
memcpy(&sValue, &storageTestData, sizeof(sValue));

// Convert the Storage Type to Working Type and
wValue = IntType::StorageToWorking(sValue);

// 2) Verify that the correct storage format has been used
NL_TEST_ASSERT(apSuite, wValue == 17);

StorageType sNewValue;

// Convert back to Storage Value
IntType::WorkingToStorage(wValue, sNewValue);

// 3) Verify that the bytes are located as intended
NL_TEST_ASSERT(apSuite, memcmp(&storageTestData, &sNewValue, sizeof(sNewValue)) == 0);

// Set Storage value to Null
IntType::SetNull(sNullValue);
wNullValue = IntType::StorageToWorking(sNullValue);
NL_TEST_ASSERT(apSuite, wNullValue == workingTestUnsignedNullValue);
NL_TEST_ASSERT(apSuite, (IntType::IsNullValue(sNullValue) == true));

// Verify that null values can fit into not nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(false, sNullValue) == true));

// Verify that null values can't fit into nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(true, sNullValue) == false));
}

void Test_SINT8(nlTestSuite * apSuite, void * apContext)
{
// Signed 8-bit Integer : 1 byte, endianness does not matter.
using IntType = NumericAttributeTraits<int8_t>;
using StorageType = typename IntType::StorageType;
using WorkingType = typename IntType::WorkingType;

StorageType sValue;
WorkingType wValue;
StorageType sNullValue;
WorkingType wNullValue;
const StorageType storageTestData = 17;
const WorkingType workingTestUnsignedNullValue = -128; // 0x80

// 1) Verify the size of the types
NL_TEST_ASSERT(apSuite, sizeof(sValue) == 1);
NL_TEST_ASSERT(apSuite, sizeof(wValue) >= 1);

// Initialize the Storage Value with the test-buffer
memcpy(&sValue, &storageTestData, sizeof(sValue));

// Convert the Storage Type to Working Type and
wValue = IntType::StorageToWorking(sValue);

// 2) Verify that the correct storage format has been used
NL_TEST_ASSERT(apSuite, wValue == 17);

StorageType sNewValue;

// Convert back to Storage Value
IntType::WorkingToStorage(wValue, sNewValue);

// 3) Verify that the bytes are located as intended
NL_TEST_ASSERT(apSuite, memcmp(&storageTestData, &sNewValue, sizeof(sNewValue)) == 0);

// Set Storage value to Null
IntType::SetNull(sNullValue);
wNullValue = IntType::StorageToWorking(sNullValue);
NL_TEST_ASSERT(apSuite, wNullValue == workingTestUnsignedNullValue);
NL_TEST_ASSERT(apSuite, (IntType::IsNullValue(sNullValue) == true));

// Verify that null values can fit into not nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(false, sNullValue) == true));

// Verify that null values can't fit into nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(true, sNullValue) == false));
}

enum class SimpleEnum : uint8_t
{
kZero = 0,
kOne = 1,
};

void Test_SimpleEnum(nlTestSuite * apSuite, void * apContext)
{
// Unsigned 8-bit Integer : 1 byte, endianness does not matter.
using IntType = NumericAttributeTraits<SimpleEnum>;
using StorageType = typename IntType::StorageType;
using WorkingType = typename IntType::WorkingType;

StorageType sValue;
WorkingType wValue;
StorageType sNullValue;
WorkingType wNullValue;
const StorageType storageTestData = SimpleEnum::kOne;
const WorkingType workingTestUnsignedNullValue = static_cast<SimpleEnum>(0xFF);

// 1) Verify the size of the types
NL_TEST_ASSERT(apSuite, sizeof(sValue) == 1);
NL_TEST_ASSERT(apSuite, sizeof(wValue) >= 1);

// Initialize the Storage Value with the test-buffer
memcpy(&sValue, &storageTestData, sizeof(sValue));

// Convert the Storage Type to Working Type and
wValue = IntType::StorageToWorking(sValue);

// 2) Verify that the correct storage format has been used
NL_TEST_ASSERT(apSuite, wValue == SimpleEnum::kOne);

StorageType sNewValue;

// Convert back to Storage Value
IntType::WorkingToStorage(wValue, sNewValue);

// 3) Verify that the bytes are located as intended
NL_TEST_ASSERT(apSuite, memcmp(&storageTestData, &sNewValue, sizeof(sNewValue)) == 0);

// Set Storage value to Null
IntType::SetNull(sNullValue);
wNullValue = IntType::StorageToWorking(sNullValue);
NL_TEST_ASSERT(apSuite, wNullValue == workingTestUnsignedNullValue);
NL_TEST_ASSERT(apSuite, (IntType::IsNullValue(sNullValue) == true));

// Verify that null values can fit into not nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(false, sNullValue) == true));

// Verify that null values can't fit into nullable
NL_TEST_ASSERT(apSuite, (IntType::CanRepresentValue(true, sNullValue) == false));
}

////////////////////////////////////////////////////////////
// ______ __ __ _______ ______ ________ //
// / \ / | / | / \ / |/ | //
@@ -1009,6 +1159,10 @@ static int TestTeardown(void * inContext)
// clang-format off
const nlTest sTests[] =
{
NL_TEST_DEF("Test_UINT8", Test_UINT8),
NL_TEST_DEF("Test_SINT8", Test_SINT8),
NL_TEST_DEF("Test_SimpleEnum", Test_SimpleEnum),

NL_TEST_DEF("Test_UINT24_LE",Test_UINT24_LE),
NL_TEST_DEF("Test_SINT24_LE",Test_SINT24_LE),
NL_TEST_DEF("Test_UINT24_BE",Test_UINT24_BE),
124 changes: 124 additions & 0 deletions src/app/tests/suites/TestCluster.yaml
Original file line number Diff line number Diff line change
@@ -1745,6 +1745,18 @@ tests:

# Tests for nullable UInt8 attribute

- label: "Write attribute NULLABLE_INT8U Min Value"
command: "writeAttribute"
attribute: "nullable_int8u"
arguments:
value: 0

- label: "Read attribute NULLABLE_INT8U Min Value"
command: "readAttribute"
attribute: "nullable_int8u"
response:
value: 0

- label: "Write attribute NULLABLE_INT8U Max Value"
command: "writeAttribute"
attribute: "nullable_int8u"
@@ -1821,6 +1833,18 @@ tests:

# Tests for nullable UInt16 attribute

- label: "Write attribute NULLABLE_INT16U Min Value"
command: "writeAttribute"
attribute: "nullable_int16u"
arguments:
value: 0

- label: "Read attribute NULLABLE_INT16U Min Value"
command: "readAttribute"
attribute: "nullable_int16u"
response:
value: 0

- label: "Write attribute NULLABLE_INT16U Max Value"
command: "writeAttribute"
attribute: "nullable_int16u"
@@ -1897,6 +1921,18 @@ tests:

# Tests for nullable UInt32 attribute

- label: "Write attribute NULLABLE_INT32U Min Value"
command: "writeAttribute"
attribute: "nullable_int32u"
arguments:
value: 0

- label: "Read attribute NULLABLE_INT32U Min Value"
command: "readAttribute"
attribute: "nullable_int32u"
response:
value: 0

- label: "Write attribute NULLABLE_INT32U Max Value"
command: "writeAttribute"
attribute: "nullable_int32u"
@@ -1973,6 +2009,18 @@ tests:

# Tests for nullable UInt64 attribute

- label: "Write attribute NULLABLE_INT64U Min Value"
command: "writeAttribute"
attribute: "nullable_int64u"
arguments:
value: 0

- label: "Read attribute NULLABLE_INT64U Min Value"
command: "readAttribute"
attribute: "nullable_int64u"
response:
value: 0

- label: "Write attribute NULLABLE_INT64U Max Value"
command: "writeAttribute"
attribute: "nullable_int64u"
@@ -2480,6 +2528,18 @@ tests:

# Tests for Enum8 attribute

- label: "Write attribute NULLABLE_ENUM8 Min Value"
command: "writeAttribute"
attribute: "nullable_enum8"
arguments:
value: 0

- label: "Read attribute NULLABLE_ENUM8 Min Value"
command: "readAttribute"
attribute: "nullable_enum8"
response:
value: 0

- label: "Write attribute NULLABLE_ENUM8 Max Value"
command: "writeAttribute"
attribute: "nullable_enum8"
@@ -2520,6 +2580,18 @@ tests:

# Tests for Enum16 attribute

- label: "Write attribute NULLABLE_ENUM16 Min Value"
command: "writeAttribute"
attribute: "nullable_enum16"
arguments:
value: 0

- label: "Read attribute NULLABLE_ENUM16 Min Value"
command: "readAttribute"
attribute: "nullable_enum16"
response:
value: 0

- label: "Write attribute NULLABLE_ENUM16 Max Value"
command: "writeAttribute"
attribute: "nullable_enum16"
@@ -2558,6 +2630,58 @@ tests:
response:
value: null

# Tests for named enum attribute

- label: "Write attribute NULLABLE_SIMPLE_ENUM Min Value"
command: "writeAttribute"
attribute: "nullable_enum_attr"
arguments:
value: 0

- label: "Read attribute NULLABLE_SIMPLE_ENUM Min Value"
command: "readAttribute"
attribute: "nullable_enum_attr"
response:
value: 0

- label: "Write attribute NULLABLE_SIMPLE_ENUM Max Value"
command: "writeAttribute"
attribute: "nullable_enum_attr"
arguments:
value: 254

- label: "Read attribute NULLABLE_SIMPLE_ENUM Max Value"
command: "readAttribute"
attribute: "nullable_enum_attr"
response:
value: 254

- label: "Write attribute NULLABLE_SIMPLE_ENUM Invalid Value"
command: "writeAttribute"
attribute: "nullable_enum_attr"
arguments:
value: 255
response:
error: CONSTRAINT_ERROR

- label: "Read attribute NULLABLE_SIMPLE_ENUM unchanged Value"
command: "readAttribute"
attribute: "nullable_enum_attr"
response:
value: 254

- label: "Write attribute NULLABLE_SIMPLE_ENUM null Value"
command: "writeAttribute"
attribute: "nullable_enum_attr"
arguments:
value: null

- label: "Read attribute NULLABLE_SIMPLE_ENUM null Value"
command: "readAttribute"
attribute: "nullable_enum_attr"
response:
value: null

# Tests for Octet String attribute

- label: "Read attribute NULLABLE_OCTET_STRING Default Value"
3 changes: 2 additions & 1 deletion src/app/util/attribute-storage-null-handling.h
Original file line number Diff line number Diff line change
@@ -74,7 +74,8 @@ struct NumericAttributeTraits
template <typename U = T, typename std::enable_if_t<std::is_enum<U>::value, int> = 0>
static constexpr StorageType GetNullValue()
{
return GetNullValue<std::underlying_type_t<T>>();
static_assert(!std::is_signed<std::underlying_type_t<T>>::value, "Enums must be unsigned");
return static_cast<StorageType>(std::numeric_limits<std::underlying_type_t<T>>::max());
}

public:
1,107 changes: 788 additions & 319 deletions src/darwin/Framework/CHIPTests/CHIPClustersTests.m

Large diffs are not rendered by default.

4,729 changes: 2,692 additions & 2,037 deletions zzz_generated/chip-tool/zap-generated/test/Commands.h

Large diffs are not rendered by default.