Skip to content

Commit b68b0d1

Browse files
Remove AttributeList from Device Layer (project-chip#41546)
* Remove AttributeList from Device Layer It was only used in a single place and probably didn't belong in the device layer in the first place. Use a Span instead for DeviceInforProvider::SetUserLabelList. Also simplify DeviceInforProvider::ClearUserLabelList(). * Add missing const to Span type * Move max size constants into the header and add more tests * Allow the global DeviceInfoProvider to be reset to null This is primarily useful for testing. Also remove the comment stating that callers should assume the provider is not null; it starts out as null, and the cluster code interacting with it already handles null gracefully. --------- Co-authored-by: Andrei Litvin <[email protected]>
1 parent 515eed1 commit b68b0d1

File tree

10 files changed

+114
-357
lines changed

10 files changed

+114
-357
lines changed

src/BUILD.gn

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ if (chip_build_tests) {
8484
"${chip_root}/src/crypto/tests",
8585
"${chip_root}/src/data-model-providers/codedriven/endpoint/tests",
8686
"${chip_root}/src/inet/tests",
87-
"${chip_root}/src/include/platform/tests",
8887
"${chip_root}/src/lib/address_resolve/tests",
8988
"${chip_root}/src/app/server-cluster/tests",
9089
"${chip_root}/src/lib/asn1/tests",

src/app/clusters/user-label-server/tests/TestUserLabelCluster.cpp

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <clusters/UserLabel/Enums.h>
2626
#include <clusters/UserLabel/Metadata.h>
2727
#include <clusters/UserLabel/Structs.h>
28+
#include <platform/DeviceInfoProvider.h>
2829

2930
namespace {
3031

@@ -35,21 +36,55 @@ using namespace chip::app::Clusters::UserLabel;
3536
using namespace chip::app::Clusters::UserLabel::Attributes;
3637
using namespace chip::Test;
3738

39+
// Mock DeviceInfoProvider for testing
40+
class MockDeviceInfoProvider : public DeviceLayer::DeviceInfoProvider
41+
{
42+
public:
43+
MockDeviceInfoProvider() = default;
44+
~MockDeviceInfoProvider() override = default;
45+
46+
FixedLabelIterator * IterateFixedLabel(EndpointId endpoint) override { return nullptr; }
47+
UserLabelIterator * IterateUserLabel(EndpointId endpoint) override { return nullptr; }
48+
SupportedCalendarTypesIterator * IterateSupportedCalendarTypes() override { return nullptr; }
49+
SupportedLocalesIterator * IterateSupportedLocales() override { return nullptr; }
50+
51+
protected:
52+
// Simple no-op implementations - we only need these to return success
53+
// so that the cluster's validation logic can be tested
54+
CHIP_ERROR SetUserLabelLength(EndpointId endpoint, size_t val) override { return CHIP_NO_ERROR; }
55+
CHIP_ERROR GetUserLabelLength(EndpointId endpoint, size_t & val) override
56+
{
57+
val = 0;
58+
return CHIP_NO_ERROR;
59+
}
60+
CHIP_ERROR SetUserLabelAt(EndpointId endpoint, size_t index, const UserLabelType & userLabel) override { return CHIP_NO_ERROR; }
61+
CHIP_ERROR DeleteUserLabelAt(EndpointId endpoint, size_t index) override { return CHIP_NO_ERROR; }
62+
};
63+
3864
struct TestUserLabelCluster : public ::testing::Test
3965
{
4066
static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); }
4167

4268
static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); }
4369

44-
void SetUp() override { ASSERT_EQ(userLabel.Startup(context), CHIP_NO_ERROR); }
70+
void SetUp() override
71+
{
72+
DeviceLayer::SetDeviceInfoProvider(&mDeviceInfoProvider);
73+
ASSERT_EQ(userLabel.Startup(context), CHIP_NO_ERROR);
74+
}
4575

46-
void TearDown() override { userLabel.Shutdown(); }
76+
void TearDown() override
77+
{
78+
userLabel.Shutdown();
79+
DeviceLayer::SetDeviceInfoProvider(nullptr);
80+
}
4781

4882
TestUserLabelCluster() : context(testContext.Create()), userLabel(kRootEndpointId) {}
4983

5084
chip::Test::TestServerClusterContext testContext;
5185
ServerClusterContext context;
5286
UserLabelCluster userLabel;
87+
MockDeviceInfoProvider mDeviceInfoProvider;
5388
};
5489

5590
} // namespace
@@ -83,3 +118,56 @@ TEST_F(TestUserLabelCluster, ReadAttributeTest)
83118
ASSERT_GT(it.GetValue().label.size(), 0u);
84119
}
85120
}
121+
122+
TEST_F(TestUserLabelCluster, WriteValidLabelListTest)
123+
{
124+
ClusterTester tester(userLabel);
125+
Structs::LabelStruct::Type labels[] = {
126+
{ .label = "room"_span, .value = "bedroom 2"_span },
127+
{ .label = "orientation"_span, .value = "North"_span },
128+
};
129+
ASSERT_EQ(tester.WriteAttribute(LabelList::Id, DataModel::List(labels)), CHIP_NO_ERROR);
130+
}
131+
132+
TEST_F(TestUserLabelCluster, WriteLabelWithLabelTooLongTest)
133+
{
134+
ClusterTester tester(userLabel);
135+
constexpr auto tooLongLabel = "this_label_is_way_too_long"_span;
136+
static_assert(tooLongLabel.size() > UserLabelCluster::kMaxLabelSize);
137+
Structs::LabelStruct::Type labels[] = {
138+
{ .label = tooLongLabel, .value = "value"_span },
139+
};
140+
ASSERT_EQ(tester.WriteAttribute(LabelList::Id, DataModel::List(labels)), CHIP_IM_GLOBAL_STATUS(ConstraintError));
141+
}
142+
143+
TEST_F(TestUserLabelCluster, WriteLabelWithValueTooLongTest)
144+
{
145+
ClusterTester tester(userLabel);
146+
constexpr auto tooLongValue = "this_value_is_way_too_long"_span;
147+
static_assert(tooLongValue.size() > UserLabelCluster::kMaxValueSize);
148+
Structs::LabelStruct::Type labels[] = {
149+
{ .label = "room"_span, .value = tooLongValue },
150+
};
151+
ASSERT_EQ(tester.WriteAttribute(LabelList::Id, DataModel::List(labels)), CHIP_IM_GLOBAL_STATUS(ConstraintError));
152+
}
153+
154+
TEST_F(TestUserLabelCluster, WriteEmptyLabelsTest)
155+
{
156+
ClusterTester tester(userLabel);
157+
Structs::LabelStruct::Type labels[] = {
158+
{ .label = ""_span, .value = ""_span }, // empty label and value are allowed per spec
159+
};
160+
ASSERT_EQ(tester.WriteAttribute(LabelList::Id, DataModel::List(labels)), CHIP_NO_ERROR);
161+
}
162+
163+
TEST_F(TestUserLabelCluster, WriteMaxSizeLabelListTest)
164+
{
165+
ClusterTester tester(userLabel);
166+
std::array<Structs::LabelStruct::Type, chip::DeviceLayer::kMaxUserLabelListLength> labels;
167+
for (size_t i = 0; i < labels.size(); i++)
168+
{
169+
labels[i].label = "label"_span;
170+
labels[i].value = "value"_span;
171+
}
172+
ASSERT_EQ(tester.WriteAttribute(LabelList::Id, DataModel::List(labels.data(), labels.size())), CHIP_NO_ERROR);
173+
}

src/app/clusters/user-label-server/user-label-cluster.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <app/server/Server.h>
2020
#include <clusters/UserLabel/Metadata.h>
2121

22+
#include <array>
23+
2224
namespace chip::app::Clusters {
2325

2426
using namespace UserLabel;
@@ -66,24 +68,8 @@ CHIP_ERROR ReadLabelList(EndpointId endpoint, AttributeValueEncoder & encoder)
6668
/// Matches constraints on a LabelStruct.
6769
bool IsValidLabelEntry(const Structs::LabelStruct::Type & entry)
6870
{
69-
constexpr size_t kMaxLabelSize = 16;
70-
constexpr size_t kMaxValueSize = 16;
71-
7271
// NOTE: spec default for label and value is empty, so empty is accepted here
73-
return (entry.label.size() <= kMaxLabelSize) && (entry.value.size() <= kMaxValueSize);
74-
}
75-
76-
bool IsValidLabelEntryList(const LabelList::TypeInfo::DecodableType & list)
77-
{
78-
auto iter = list.begin();
79-
while (iter.Next())
80-
{
81-
if (!IsValidLabelEntry(iter.GetValue()))
82-
{
83-
return false;
84-
}
85-
}
86-
return true;
72+
return (entry.label.size() <= UserLabelCluster::kMaxLabelSize) && (entry.value.size() <= UserLabelCluster::kMaxValueSize);
8773
}
8874

8975
CHIP_ERROR WriteLabelList(const ConcreteDataAttributePath & path, AttributeValueDecoder & decoder)
@@ -96,20 +82,22 @@ CHIP_ERROR WriteLabelList(const ConcreteDataAttributePath & path, AttributeValue
9682

9783
if (!path.IsListItemOperation())
9884
{
99-
DeviceLayer::AttributeList<Structs::LabelStruct::Type, DeviceLayer::kMaxUserLabelListLength> labelList;
85+
size_t numLabels = 0;
86+
std::array<Structs::LabelStruct::Type, DeviceLayer::kMaxUserLabelListLength> labels;
10087
LabelList::TypeInfo::DecodableType decodablelist;
10188

10289
ReturnErrorOnFailure(decoder.Decode(decodablelist));
103-
VerifyOrReturnError(IsValidLabelEntryList(decodablelist), CHIP_IM_GLOBAL_STATUS(ConstraintError));
104-
10590
auto iter = decodablelist.begin();
10691
while (iter.Next())
10792
{
108-
ReturnErrorOnFailure(labelList.add(iter.GetValue()));
93+
auto & label = iter.GetValue();
94+
VerifyOrReturnError(IsValidLabelEntry(label), CHIP_IM_GLOBAL_STATUS(ConstraintError));
95+
VerifyOrReturnError(numLabels < labels.size(), CHIP_ERROR_NO_MEMORY);
96+
labels[numLabels++] = label;
10997
}
11098
ReturnErrorOnFailure(iter.GetStatus());
11199

112-
return provider->SetUserLabelList(endpoint, labelList);
100+
return provider->SetUserLabelList(endpoint, Span(labels.data(), numLabels));
113101
}
114102

115103
if (path.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)

src/app/clusters/user-label-server/user-label-cluster.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class UserLabelCluster : public DefaultServerCluster, public chip::FabricTable::
3737
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,
3838
AttributeValueDecoder & decoder) override;
3939
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
40+
41+
// Constraints for label entries
42+
static constexpr size_t kMaxLabelSize = 16;
43+
static constexpr size_t kMaxValueSize = 16;
4044
};
4145

4246
} // namespace chip::app::Clusters

src/include/platform/AttributeList.h

Lines changed: 0 additions & 142 deletions
This file was deleted.

src/include/platform/DeviceInfoProvider.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <app/util/basic-types.h>
2525
#include <lib/core/CHIPError.h>
2626
#include <lib/core/CHIPPersistentStorageDelegate.h>
27-
#include <platform/AttributeList.h>
27+
#include <lib/support/Span.h>
2828

2929
namespace chip {
3030
namespace DeviceLayer {
@@ -101,7 +101,7 @@ class DeviceInfoProvider
101101
* @return CHIP_NO_ERROR on success.
102102
* @return CHIP_ERROR if an error occurs.
103103
*/
104-
CHIP_ERROR SetUserLabelList(EndpointId endpoint, const AttributeList<UserLabelType, kMaxUserLabelListLength> & labelList);
104+
CHIP_ERROR SetUserLabelList(EndpointId endpoint, Span<const UserLabelType> labelList);
105105

106106
/**
107107
* @brief Clears the user label list for a specified endpoint.
@@ -206,7 +206,7 @@ class DeviceInfoProvider
206206
*
207207
* Callers have to externally synchronize usage of this function.
208208
*
209-
* @return The global Device Info Provider. Assume never null.
209+
* @return The global Device Info Provider.
210210
*/
211211
DeviceInfoProvider * GetDeviceInfoProvider();
212212

@@ -215,8 +215,6 @@ DeviceInfoProvider * GetDeviceInfoProvider();
215215
*
216216
* Callers have to externally synchronize usage of this function.
217217
*
218-
* If the `provider` is nullptr, no change is done.
219-
*
220218
* @param[in] provider the Device Info Provider
221219
*/
222220
void SetDeviceInfoProvider(DeviceInfoProvider * provider);

src/include/platform/PlatformManager.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
#pragma once
2525

26-
#include <platform/AttributeList.h>
2726
#include <platform/CHIPDeviceConfig.h>
2827
#include <platform/CHIPDeviceEvent.h>
2928
#include <system/PlatformEventSupport.h>

0 commit comments

Comments
 (0)