component/esp-matter: unit tests for get_val and get_val_type apis

This commit is contained in:
Shubham Patil
2025-11-27 16:04:46 +05:30
parent 864b07f505
commit 08f53683ea
3 changed files with 813 additions and 0 deletions
@@ -0,0 +1,6 @@
list(APPEND srcs_list "attribute_get_val.cpp")
list(APPEND srcs_list "attribute_get_val_type.cpp")
idf_component_register(SRCS ${srcs_list}
INCLUDE_DIRS "."
REQUIRES unity esp_matter)
@@ -0,0 +1,397 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <unity.h>
#include <esp_matter.h>
#include <esp_matter_core.h>
#include <nvs_flash.h>
using namespace esp_matter;
using namespace chip::app::Clusters;
static node_t *test_node = nullptr;
static endpoint_t *root_endpoint = nullptr;
static endpoint_t *test_endpoint = nullptr;
static uint16_t test_endpoint_id = 0;
static uint16_t root_endpoint_id = 0;
// Configurable test values for ESP Matter managed attributes
static uint8_t test_current_level = 42;
static bool test_on_off = true;
static uint16_t test_identify_time = 10;
static uint8_t test_identify_type = 2;
static uint8_t test_color_mode = 1;
static uint16_t test_color_temp = 250;
void setup_for_get_val()
{
static bool setup_done = false;
if (setup_done) {
return;
}
esp_err_t err = nvs_flash_init();
TEST_ASSERT_EQUAL(ESP_OK, err);
node::config_t node_config;
test_node = node::create(&node_config, nullptr, nullptr);
TEST_ASSERT_NOT_NULL(test_node);
root_endpoint = endpoint::get(test_node, 0);
TEST_ASSERT_NOT_NULL(root_endpoint);
root_endpoint_id = endpoint::get_id(root_endpoint);
TEST_ASSERT_EQUAL(0, root_endpoint_id);
// basically we would need some dataset that we should use for the test
// for now we are using the extended_color_light::config_t
endpoint::extended_color_light::config_t light_config;
light_config.on_off.on_off = test_on_off;
light_config.level_control.current_level = nullable<uint8_t>(test_current_level);
light_config.identify.identify_time = test_identify_time;
light_config.identify.identify_type = test_identify_type;
light_config.color_control.color_mode = test_color_mode;
test_endpoint = endpoint::extended_color_light::create(test_node, &light_config, ENDPOINT_FLAG_NONE, nullptr);
TEST_ASSERT_NOT_NULL(test_endpoint);
test_endpoint_id = endpoint::get_id(test_endpoint);
err = esp_matter::start(nullptr);
TEST_ASSERT_EQUAL(ESP_OK, err);
setup_done = true;
}
void teardown_for_get_val()
{
// TODO: Add proper cleanup once the Matter stack supports a clean shutdown sequence
return;
}
TEST_CASE("get_val invalid inputs", "[get_val][invalid]")
{
setup_for_get_val();
esp_err_t err = attribute::get_val(nullptr, nullptr);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
esp_matter_attr_val_t val;
err = attribute::get_val(nullptr, &val);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
attribute_t *attr = attribute::get(test_endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id);
TEST_ASSERT_NOT_NULL(attr);
err = attribute::get_val(attr, nullptr);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
/// with ids as input
err = attribute::get_val(chip::kInvalidEndpointId, chip::kInvalidClusterId, chip::kInvalidAttributeId, nullptr);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
err = attribute::get_val(chip::kInvalidEndpointId, chip::kInvalidClusterId, chip::kInvalidAttributeId, &val);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
teardown_for_get_val();
}
// Arrays - not supported for get_val
TEST_CASE("get_val array not supported", "[get_val][esp_matter_managed][invalid][array]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(test_endpoint_id, Descriptor::Id, Descriptor::Attributes::ServerList::Id, &val);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, err);
err = attribute::get_val(test_endpoint_id, Descriptor::Id, Descriptor::Attributes::DeviceTypeList::Id, &val);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, err);
teardown_for_get_val();
}
// Primitive Types - ESP Matter Managed
TEST_CASE("get_val bool - OnOff", "[get_val][esp_matter_managed][bool]")
{
setup_for_get_val();
attribute_t *attr = attribute::get(test_endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_attr_val_t setable_val = esp_matter_bool(true);
esp_err_t err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
esp_matter_attr_val_t true_val;
err = attribute::get_val(attr, &true_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, true_val.type);
TEST_ASSERT_EQUAL(true, true_val.val.b);
setable_val = esp_matter_bool(false);
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
esp_matter_attr_val_t false_val;
err = attribute::get_val(attr, &false_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, false_val.type);
TEST_ASSERT_EQUAL(false, false_val.val.b);
teardown_for_get_val();
}
TEST_CASE("get_val uint8 - ColorMode", "[get_val][esp_matter_managed][uint8]")
{
setup_for_get_val();
attribute_t *attr = attribute::get(test_endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorMode::Id);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_attr_val_t setable_val = esp_matter_enum8(0);
esp_err_t err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
esp_matter_attr_val_t retrieved_val;
err = attribute::get_val(attr, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM8, retrieved_val.type);
TEST_ASSERT_EQUAL(0, retrieved_val.val.u8);
setable_val = esp_matter_enum8(1);
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
err = attribute::get_val(attr, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM8, retrieved_val.type);
TEST_ASSERT_EQUAL(1, retrieved_val.val.u8);
setable_val = esp_matter_enum8(2);
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
err = attribute::get_val(attr, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM8, retrieved_val.type);
TEST_ASSERT_EQUAL(2, retrieved_val.val.u8);
// Invalid enum value (ColorMode valid range is 0-2)
setable_val = esp_matter_enum8(3);
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
teardown_for_get_val();
}
TEST_CASE("get_val uint16 - ColorTemperatureMireds", "[get_val][esp_matter_managed][uint16]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(test_endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorTemperatureMireds::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, val.type);
TEST_ASSERT_EQUAL(test_color_temp, val.val.u16);
teardown_for_get_val();
}
TEST_CASE("get_val uint32 - Feature map", "[get_val][esp_matter_managed][uint32]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(test_endpoint_id, OnOff::Id, Globals::Attributes::FeatureMap::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP32, val.type);
TEST_ASSERT_EQUAL(1, val.val.u32);
teardown_for_get_val();
}
// Nullable Types - ESP Matter Managed
TEST_CASE("get_val nullable uint8 - CurrentLevel", "[get_val][esp_matter_managed][nullable][uint8]")
{
setup_for_get_val();
attribute_t *attr = attribute::get(test_endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_attr_val_t setable_val = esp_matter_nullable_uint8(test_current_level);
esp_err_t err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
esp_matter_attr_val_t retrieved_val;
err = attribute::get_val(test_endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_NULLABLE_UINT8, retrieved_val.type);
nullable<uint8_t> data(retrieved_val.val.u8);
TEST_ASSERT_FALSE(data.is_null());
TEST_ASSERT_EQUAL(test_current_level, data.value());
setable_val = esp_matter_nullable_uint8(nullable<uint8_t>());
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
err = attribute::get_val(test_endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_NULLABLE_UINT8, retrieved_val.type);
nullable<uint8_t> null_data(retrieved_val.val.u8);
TEST_ASSERT_TRUE(null_data.is_null());
teardown_for_get_val();
}
TEST_CASE("get_val nullable uint16 - StartUpColorTemperatureMireds", "[get_val][esp_matter_managed][nullable][uint16]")
{
setup_for_get_val();
attribute_t *attr = attribute::get(test_endpoint_id, ColorControl::Id, ColorControl::Attributes::StartUpColorTemperatureMireds::Id);
TEST_ASSERT_NOT_NULL(attr);
// this is nvs type value, so it may screw up our tests if ran without clearing the nvs
// hence, always set and verify the value
esp_matter_attr_val_t setable_val = esp_matter_nullable_uint16(test_color_temp);
esp_err_t err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_TRUE(err == ESP_OK || err == ESP_ERR_NOT_FINISHED);
esp_matter_attr_val_t retrieved_val;
err = attribute::get_val(attr, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_NULLABLE_UINT16, retrieved_val.type);
nullable<uint16_t> data(retrieved_val.val.u16);
TEST_ASSERT_FALSE(data.is_null());
TEST_ASSERT_EQUAL(test_color_temp, data.value());
setable_val = esp_matter_nullable_uint16(nullable<uint16_t>());
err = attribute::set_val(attr, &setable_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
err = attribute::get_val(attr, &retrieved_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_NULLABLE_UINT16, retrieved_val.type);
nullable<uint16_t> data2(retrieved_val.val.u16);
TEST_ASSERT_TRUE(data2.is_null());
teardown_for_get_val();
}
// ====================================================================================
// get_val() -> Internally Managed Attributes (by ConnectedHomeIP)
// ====================================================================================
// Arrays - not supported for get_val
TEST_CASE("get_val array not supported", "[get_val][internal_managed][invalid][array]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(test_endpoint_id, Descriptor::Id, Descriptor::Attributes::ServerList::Id, &val);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, err);
err = attribute::get_val(test_endpoint_id, Descriptor::Id, Descriptor::Attributes::DeviceTypeList::Id, &val);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, err);
err = attribute::get_val(root_endpoint_id, Descriptor::Id, Descriptor::Attributes::PartsList::Id, &val);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, err);
teardown_for_get_val();
}
// Primitive Types - Internally Managed
TEST_CASE("get_val uint16", "[get_val][internal_managed][uint16]")
{
setup_for_get_val();
esp_matter_attr_val_t vendor_id_val;
esp_err_t err = attribute::get_val(root_endpoint_id, BasicInformation::Id, BasicInformation::Attributes::VendorID::Id, &vendor_id_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, vendor_id_val.type);
TEST_ASSERT_EQUAL(CONFIG_DEVICE_VENDOR_ID, vendor_id_val.val.u16);
esp_matter_attr_val_t product_id_val;
err = attribute::get_val(root_endpoint_id, BasicInformation::Id, BasicInformation::Attributes::ProductID::Id, &product_id_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, product_id_val.type);
TEST_ASSERT_EQUAL(CONFIG_DEVICE_PRODUCT_ID, product_id_val.val.u16);
teardown_for_get_val();
}
TEST_CASE("get_val uint32 - SoftwareVersion", "[get_val][internal_managed][uint32]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(root_endpoint_id, BasicInformation::Id, BasicInformation::Attributes::SoftwareVersion::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT32, val.type);
TEST_ASSERT_EQUAL(1, val.val.u32);
teardown_for_get_val();
}
TEST_CASE("get_val uint8 - MaxNetworks", "[get_val][internal_managed][uint8]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(root_endpoint_id, NetworkCommissioning::Id, NetworkCommissioning::Attributes::MaxNetworks::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, val.type);
TEST_ASSERT_EQUAL(1, val.val.u8);
teardown_for_get_val();
}
TEST_CASE("get_val bool - SupportsConcurrentConnection", "[get_val][internal_managed][bool]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(root_endpoint_id, GeneralCommissioning::Id, GeneralCommissioning::Attributes::SupportsConcurrentConnection::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, val.type);
TEST_ASSERT_EQUAL(true, val.val.b);
teardown_for_get_val();
}
// Strings - Internally Managed
TEST_CASE("get_val char_string", "[get_val][internal_managed][char_string]")
{
setup_for_get_val();
esp_matter_attr_val_t vendor_name_val;
esp_err_t err = attribute::get_val(root_endpoint_id, BasicInformation::Id, BasicInformation::Attributes::VendorName::Id, &vendor_name_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_CHAR_STRING, vendor_name_val.type);
TEST_ASSERT_NOT_NULL(vendor_name_val.val.a.b);
TEST_ASSERT_GREATER_THAN(0, vendor_name_val.val.a.s);
TEST_ASSERT_EQUAL_STRING("TEST_VENDOR", vendor_name_val.val.a.b);
free(vendor_name_val.val.a.b);
esp_matter_attr_val_t product_name_val;
err = attribute::get_val(root_endpoint_id, BasicInformation::Id, BasicInformation::Attributes::ProductName::Id, &product_name_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_CHAR_STRING, product_name_val.type);
TEST_ASSERT_NOT_NULL(product_name_val.val.a.b);
TEST_ASSERT_GREATER_THAN(0, product_name_val.val.a.s);
TEST_ASSERT_EQUAL_STRING("TEST_PRODUCT", product_name_val.val.a.b);
free(product_name_val.val.a.b);
teardown_for_get_val();
}
// Nullable Types - Internally Managed
TEST_CASE("get_val nullable int32 - LastConnectErrorValue", "[get_val][internal_managed][nullable][int32]")
{
setup_for_get_val();
esp_matter_attr_val_t val;
esp_err_t err = attribute::get_val(root_endpoint_id, NetworkCommissioning::Id, NetworkCommissioning::Attributes::LastConnectErrorValue::Id, &val);
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_NULLABLE_INT32, val.type);
nullable<int32_t> nullable_val(val.val.i32);
TEST_ASSERT_EQUAL(true, nullable_val.is_null());
teardown_for_get_val();
}
@@ -0,0 +1,410 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <unity.h>
#include <esp_matter.h>
#include <esp_matter_core.h>
#include <esp_matter_data_model.h>
#include <nvs_flash.h>
using namespace esp_matter;
// Test data model
static node_t *test_node = nullptr;
static endpoint_t *test_endpoint = nullptr;
static cluster_t *test_cluster = nullptr;
static uint16_t test_endpoint_id = 1;
static uint32_t test_cluster_id = 0xFFF1; // Custom test cluster
static bool node_created = false;
void setup_for_get_val_type()
{
if (!node_created) {
esp_err_t err = nvs_flash_init();
TEST_ASSERT_EQUAL(ESP_OK, err);
node::config_t node_config;
test_node = node::create(&node_config, nullptr, nullptr);
TEST_ASSERT_NOT_NULL(test_node);
test_endpoint = endpoint::create(test_node, ENDPOINT_FLAG_NONE, nullptr);
TEST_ASSERT_NOT_NULL(test_endpoint);
test_endpoint_id = endpoint::get_id(test_endpoint);
node_created = true;
}
// Fresh cluster per test case
test_cluster = cluster::create(test_endpoint, test_cluster_id, CLUSTER_FLAG_SERVER);
TEST_ASSERT_NOT_NULL(test_cluster);
}
void teardown_for_get_val_type()
{
// Only destroy the cluster, not the endpoint — endpoint is reused across test cases
// since node/endpoint creation involves starting the Matter stack which cannot be cleanly restarted.
if (test_cluster) {
cluster::destroy(test_cluster);
test_cluster = nullptr;
}
}
TEST_CASE("invalid inputs to get_val_type", "[get_val_type][invalid]")
{
setup_for_get_val_type();
esp_matter_val_type_t type = attribute::get_val_type((attribute_t *)nullptr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INVALID, type);
type = attribute::get_val_type(0xFFFF, 0x0006, 0x0000);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INVALID, type);
type = attribute::get_val_type(1, 0xFFFFFFFF, 0x0000);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INVALID, type);
type = attribute::get_val_type(1, 0x0006, 0xFFFFFFFF);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INVALID, type);
teardown_for_get_val_type();
}
// Test all primitive types from attribute_utils.h
TEST_CASE("get_val_type for all primitive types", "[get_val_type][all_types]")
{
setup_for_get_val_type();
uint32_t attr_id = 1; // Start attribute IDs from 1
// Test 1: Boolean
{
esp_matter_attr_val_t val = esp_matter_bool(true);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, type);
// Test with IDs
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, type);
}
// Test 2: Integer (32-bit signed)
{
esp_matter_attr_val_t val = esp_matter_int(42);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INTEGER, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INTEGER, type);
}
// Test 3: Float
{
esp_matter_attr_val_t val = esp_matter_float(3.14f);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_FLOAT, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_FLOAT, type);
}
// Test 4: INT8
{
esp_matter_attr_val_t val = esp_matter_int8(-128);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT8, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT8, type);
}
// Test 5: UINT8
{
esp_matter_attr_val_t val = esp_matter_uint8(255);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, type);
}
// Test 6: INT16
{
esp_matter_attr_val_t val = esp_matter_int16(-32768);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT16, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT16, type);
}
// Test 7: UINT16
{
esp_matter_attr_val_t val = esp_matter_uint16(65535);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, type);
}
// Test 8: INT32
{
esp_matter_attr_val_t val = esp_matter_int32(-2147483648);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT32, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT32, type);
}
// Test 9: UINT32
{
esp_matter_attr_val_t val = esp_matter_uint32(0xFFFFFFFF);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT32, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT32, type);
}
// Test 10: INT64
{
esp_matter_attr_val_t val = esp_matter_int64(-9223372036854775807LL);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT64, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT64, type);
}
// Test 11: UINT64
{
esp_matter_attr_val_t val = esp_matter_uint64(0xFFFFFFFFFFFFFFFFULL);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT64, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT64, type);
}
// Test 12: ENUM8
{
esp_matter_attr_val_t val = esp_matter_enum8(5);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM8, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM8, type);
}
// Test 13: ENUM16
{
esp_matter_attr_val_t val = esp_matter_enum16(1000);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM16, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ENUM16, type);
}
// Test 14: BITMAP8
{
esp_matter_attr_val_t val = esp_matter_bitmap8(0xAB);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP8, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP8, type);
}
// Test 15: BITMAP16
{
esp_matter_attr_val_t val = esp_matter_bitmap16(0xABCD);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP16, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP16, type);
}
// Test 16: BITMAP32
{
esp_matter_attr_val_t val = esp_matter_bitmap32(0xABCD1234);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP32, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BITMAP32, type);
}
// Test 17: CHAR_STRING
{
char test_str[] = "TestString";
esp_matter_attr_val_t val = esp_matter_char_str(test_str, strlen(test_str));
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_CHAR_STRING, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_CHAR_STRING, type);
}
// Test 18: OCTET_STRING
{
uint8_t test_octets[] = {0x01, 0x02, 0x03, 0x04};
esp_matter_attr_val_t val = esp_matter_octet_str(test_octets, sizeof(test_octets));
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_OCTET_STRING, type);
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id - 1);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_OCTET_STRING, type);
}
// Test 19: ARRAY
{
// apparently our internal impl wants this to be malloced,
// otherwise at the time of destruction, we will try to free a stack allocated buffer
uint8_t *test_array = (uint8_t *)malloc(3 * sizeof(uint8_t));
TEST_ASSERT_NOT_NULL(test_array);
test_array[0] = 1; test_array[1] = 2; test_array[2] = 3;
esp_matter_attr_val_t val = esp_matter_array(test_array, 3 * sizeof(uint8_t), 3);
attribute_t *attr = attribute::create(test_cluster, attr_id++, ATTRIBUTE_FLAG_NONE, val);
TEST_ASSERT_NOT_NULL(attr);
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_ARRAY, type);
// no need to free test_array here, it will be freed when the attribute is destroyed
}
teardown_for_get_val_type();
}
// Test that type persists after value updates
TEST_CASE("get_val_type persists after attribute update", "[get_val_type][persistence]")
{
setup_for_get_val_type();
uint32_t attr_id = 100;
// Create a UINT8 attribute
esp_matter_attr_val_t initial_val = esp_matter_uint8(10);
attribute_t *attr = attribute::create(test_cluster, attr_id, ATTRIBUTE_FLAG_NONE, initial_val);
TEST_ASSERT_NOT_NULL(attr);
// Verify initial type
esp_matter_val_type_t type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, type);
// Update value
esp_matter_attr_val_t new_val = esp_matter_uint8(200);
esp_err_t err = attribute::set_val(attr, &new_val);
TEST_ASSERT_EQUAL(ESP_OK, err);
// Type should remain the same
type = attribute::get_val_type(attr);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, type);
// Verify with IDs as well
type = attribute::get_val_type(test_endpoint_id, test_cluster_id, attr_id);
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, type);
teardown_for_get_val_type();
}
// Test multiple attributes in same cluster
TEST_CASE("get_val_type for multiple attributes in same cluster", "[get_val_type][multiple]")
{
setup_for_get_val_type();
// Create attributes with different types
esp_matter_attr_val_t bool_val = esp_matter_bool(false);
attribute_t *bool_attr = attribute::create(test_cluster, 1, ATTRIBUTE_FLAG_NONE, bool_val);
TEST_ASSERT_NOT_NULL(bool_attr);
esp_matter_attr_val_t uint8_val = esp_matter_uint8(42);
attribute_t *uint8_attr = attribute::create(test_cluster, 2, ATTRIBUTE_FLAG_NONE, uint8_val);
TEST_ASSERT_NOT_NULL(uint8_attr);
esp_matter_attr_val_t uint16_val = esp_matter_uint16(1234);
attribute_t *uint16_attr = attribute::create(test_cluster, 3, ATTRIBUTE_FLAG_NONE, uint16_val);
TEST_ASSERT_NOT_NULL(uint16_attr);
esp_matter_attr_val_t int32_val = esp_matter_int32(-9999);
attribute_t *int32_attr = attribute::create(test_cluster, 4, ATTRIBUTE_FLAG_NONE, int32_val);
TEST_ASSERT_NOT_NULL(int32_attr);
// Verify all types via attribute handle
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN, attribute::get_val_type(bool_attr));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8, attribute::get_val_type(uint8_attr));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16, attribute::get_val_type(uint16_attr));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT32, attribute::get_val_type(int32_attr));
// Verify all types via IDs
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_BOOLEAN,
attribute::get_val_type(test_endpoint_id, test_cluster_id, 1));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT8,
attribute::get_val_type(test_endpoint_id, test_cluster_id, 2));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_UINT16,
attribute::get_val_type(test_endpoint_id, test_cluster_id, 3));
TEST_ASSERT_EQUAL(ESP_MATTER_VAL_TYPE_INT32,
attribute::get_val_type(test_endpoint_id, test_cluster_id, 4));
teardown_for_get_val_type();
}