Skip to content

Commit 397dc02

Browse files
restyled-commitsLyudmilaKostanyan
authored andcommitted
Restyled by clang-format
1 parent 2ad2ac9 commit 397dc02

File tree

3 files changed

+265
-256
lines changed

3 files changed

+265
-256
lines changed

src/app/clusters/groupcast/tests/TestGroupcastCluster.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ TEST_F(TestGroupcastCluster, TestJoinGroupCommand)
117117

118118
chip::app::Testing::MockCommandHandler cmdHandler;
119119
chip::Test::ClusterTester tester(cluster);
120-
auto result = tester.Invoke<Commands::JoinGroup::Type::ResponseType,
121-
Commands::JoinGroup::Type>(Commands::JoinGroup::Id, cmdData);
120+
auto result =
121+
tester.Invoke<Commands::JoinGroup::Type::ResponseType, Commands::JoinGroup::Type>(Commands::JoinGroup::Id, cmdData);
122122
ASSERT_TRUE(result.status.has_value());
123-
EXPECT_EQ(result.status.value().GetStatusCode().GetStatus(), // NOLINT(bugprone-unchecked-optional-access)
124-
Protocols::InteractionModel::Status::Failure); // Currently expect Failure as JoinGroup command returns
125-
// CHIP_ERROR_NOT_IMPLEMENTED
123+
EXPECT_EQ(result.status.value().GetStatusCode().GetStatus(), // NOLINT(bugprone-unchecked-optional-access)
124+
Protocols::InteractionModel::Status::Failure); // Currently expect Failure as JoinGroup command returns
125+
// CHIP_ERROR_NOT_IMPLEMENTED
126126
}
127127
} // namespace

src/app/clusters/testing/ClusterTester.h

Lines changed: 159 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -41,176 +41,182 @@
4141
namespace chip {
4242
namespace Test {
4343

44-
// Helper class for testing clusters.
45-
//
46-
// This class ensures that data read by attribute is referencing valid memory for all
47-
// read requests until the ClusterTester object goes out of scope. (for the case where the underlying read references a list or
48-
// string that points to TLV data).
49-
//
50-
// Read/Write of all attribute types should work, but make sure to use ::Type for encoding
51-
// and ::DecodableType for decoding structure types.
52-
//
53-
// Example of usage:
54-
//
55-
// ExampleCluster cluster(someEndpointId);
56-
//
57-
// // Possibly steps to setup the cluster
58-
//
59-
// ClusterTester tester(cluster);
60-
// app::Clusters::ExampleCluster::Attributes::FeatureMap::TypeInfo::DecodableType features;
61-
// ASSERT_EQ(tester.ReadAttribute(FeatureMap::Id, features), CHIP_NO_ERROR);
62-
//
63-
// app::Clusters::ExampleCluster::Attributes::ExampleListAttribute::TypeInfo::DecodableType list;
64-
// ASSERT_EQ(tester.ReadAttribute(LabelList::Id, list), CHIP_NO_ERROR);
65-
// auto it = list.begin();
66-
// while (it.Next())
67-
// {
68-
// ASSERT_GT(it.GetValue().label.size(), 0u);
69-
// }
70-
//
71-
class ClusterTester {
72-
public:
73-
ClusterTester(app::ServerClusterInterface & cluster)
74-
: mCluster(cluster)
75-
{
76-
}
44+
// Helper class for testing clusters.
45+
//
46+
// This class ensures that data read by attribute is referencing valid memory for all
47+
// read requests until the ClusterTester object goes out of scope. (for the case where the underlying read references a list or
48+
// string that points to TLV data).
49+
//
50+
// Read/Write of all attribute types should work, but make sure to use ::Type for encoding
51+
// and ::DecodableType for decoding structure types.
52+
//
53+
// Example of usage:
54+
//
55+
// ExampleCluster cluster(someEndpointId);
56+
//
57+
// // Possibly steps to setup the cluster
58+
//
59+
// ClusterTester tester(cluster);
60+
// app::Clusters::ExampleCluster::Attributes::FeatureMap::TypeInfo::DecodableType features;
61+
// ASSERT_EQ(tester.ReadAttribute(FeatureMap::Id, features), CHIP_NO_ERROR);
62+
//
63+
// app::Clusters::ExampleCluster::Attributes::ExampleListAttribute::TypeInfo::DecodableType list;
64+
// ASSERT_EQ(tester.ReadAttribute(LabelList::Id, list), CHIP_NO_ERROR);
65+
// auto it = list.begin();
66+
// while (it.Next())
67+
// {
68+
// ASSERT_GT(it.GetValue().label.size(), 0u);
69+
// }
70+
//
71+
class ClusterTester
72+
{
73+
public:
74+
ClusterTester(app::ServerClusterInterface & cluster) : mCluster(cluster) {}
75+
76+
app::ServerClusterContext & GetServerClusterContext() { return mTestServerClusterContext.Get(); }
77+
78+
// Read attribute into `out` parameter.
79+
// The `out` parameter must be of the correct type for the attribute being read.
80+
// Use `app::Clusters::<ClusterName>::Attributes::<AttributeName>::TypeInfo::DecodableType` for the `out` parameter to be spec
81+
// compliant (see the comment of the class for usage example).
82+
// Will construct the attribute path using the first path returned by `GetPaths()` on the cluster.
83+
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
84+
template <typename T>
85+
app::DataModel::ActionReturnStatus ReadAttribute(AttributeId attr_id, T & out)
86+
{
87+
VerifyOrReturnError(VerifyClusterPathsValid(), CHIP_ERROR_INCORRECT_STATE);
88+
auto path = mCluster.GetPaths()[0];
89+
90+
// Store the read operation in a vector<std::unique_ptr<...>> to ensure its lifetime
91+
// using std::unique_ptr because ReadOperation is non-copyable and non-movable
92+
// vector reallocation is not an issue since we store unique_ptrs
93+
std::unique_ptr<app::Testing::ReadOperation> readOperation =
94+
std::make_unique<app::Testing::ReadOperation>(path.mEndpointId, path.mClusterId, attr_id);
95+
96+
mReadOperations.push_back(std::move(readOperation));
97+
app::Testing::ReadOperation & readOperationRef = *mReadOperations.back().get();
98+
99+
std::unique_ptr<app::AttributeValueEncoder> encoder = readOperationRef.StartEncoding();
100+
app::DataModel::ActionReturnStatus status = mCluster.ReadAttribute(readOperationRef.GetRequest(), *encoder);
101+
VerifyOrReturnError(status.IsSuccess(), status);
102+
ReturnErrorOnFailure(readOperationRef.FinishEncoding());
103+
104+
std::vector<app::Testing::DecodedAttributeData> attributeData;
105+
ReturnErrorOnFailure(readOperationRef.GetEncodedIBs().Decode(attributeData));
106+
VerifyOrReturnError(attributeData.size() == 1u, CHIP_ERROR_INCORRECT_STATE);
107+
108+
return app::DataModel::Decode(attributeData[0].dataReader, out);
109+
}
110+
111+
// Write attribute from `value` parameter.
112+
// The `value` parameter must be of the correct type for the attribute being written.
113+
// Use `app::Clusters::<ClusterName>::Attributes::<AttributeName>::TypeInfo::Type` for the `value` parameter to be spec
114+
// compliant (see the comment of the class for usage example).
115+
// Will construct the attribute path using the first path returned by `GetPaths()` on the cluster.
116+
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
117+
template <typename T>
118+
app::DataModel::ActionReturnStatus WriteAttribute(AttributeId attr_id, const T & value)
119+
{
120+
VerifyOrReturnError(VerifyClusterPathsValid(), CHIP_ERROR_INCORRECT_STATE);
121+
auto path = mCluster.GetPaths()[0];
122+
123+
app::Testing::WriteOperation writeOperation(path.mEndpointId, path.mClusterId, attr_id);
124+
125+
app::AttributeValueDecoder decoder = writeOperation.DecoderFor(value);
126+
return mCluster.WriteAttribute(writeOperation.GetRequest(), decoder);
127+
}
128+
129+
// Result structure for Invoke operations, containing both status and decoded response.
130+
template <typename ResponseType>
131+
struct InvokeResult
132+
{
133+
std::optional<app::DataModel::ActionReturnStatus> status;
134+
std::optional<ResponseType> response;
135+
136+
// Returns true if the command was successful and response is available
137+
bool IsSuccess() const { return status.has_value() && status->IsSuccess() && response.has_value(); }
138+
};
77139

78-
app::ServerClusterContext & GetServerClusterContext() { return mTestServerClusterContext.Get(); }
140+
// Invoke a command and return the decoded result.
141+
// The `RequestType`, `ResponseType` type-parameters must be of the correct type for the command being invoked.
142+
// Use `app::Clusters::<ClusterName>::Commands::<CommandName>::Type` for the `RequestType` type-parameter to be spec compliant
143+
// Use `app::Clusters::<ClusterName>::Commands::<CommandName>::Type::ResponseType` for the `ResponseType` type-parameter to be
144+
// spec compliant Will construct the command path using the first path returned by `GetPaths()` on the cluster.
145+
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
146+
template <typename ResponseType, typename RequestType>
147+
[[nodiscard]] InvokeResult<ResponseType> Invoke(chip::CommandId commandId, const RequestType & request)
148+
{
149+
InvokeResult<ResponseType> result;
79150

80-
// Read attribute into `out` parameter.
81-
// The `out` parameter must be of the correct type for the attribute being read.
82-
// Use `app::Clusters::<ClusterName>::Attributes::<AttributeName>::TypeInfo::DecodableType` for the `out` parameter to be spec
83-
// compliant (see the comment of the class for usage example).
84-
// Will construct the attribute path using the first path returned by `GetPaths()` on the cluster.
85-
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
86-
template <typename T>
87-
app::DataModel::ActionReturnStatus ReadAttribute(AttributeId attr_id, T & out)
88-
{
89-
VerifyOrReturnError(VerifyClusterPathsValid(), CHIP_ERROR_INCORRECT_STATE);
90-
auto path = mCluster.GetPaths()[0];
151+
const auto & paths = mCluster.GetPaths();
152+
VerifyOrReturnValue(paths.size() == 1u, result);
91153

92-
// Store the read operation in a vector<std::unique_ptr<...>> to ensure its lifetime
93-
// using std::unique_ptr because ReadOperation is non-copyable and non-movable
94-
// vector reallocation is not an issue since we store unique_ptrs
95-
std::unique_ptr<app::Testing::ReadOperation> readOperation = std::make_unique<app::Testing::ReadOperation>(path.mEndpointId, path.mClusterId, attr_id);
154+
mHandler.ClearResponses();
155+
mHandler.ClearStatuses();
96156

97-
mReadOperations.push_back(std::move(readOperation));
98-
app::Testing::ReadOperation & readOperationRef = *mReadOperations.back().get();
157+
const app::DataModel::InvokeRequest invokeRequest = { .path = { paths[0].mEndpointId, paths[0].mClusterId, commandId } };
99158

100-
std::unique_ptr<app::AttributeValueEncoder> encoder = readOperationRef.StartEncoding();
101-
app::DataModel::ActionReturnStatus status = mCluster.ReadAttribute(readOperationRef.GetRequest(), *encoder);
102-
VerifyOrReturnError(status.IsSuccess(), status);
103-
ReturnErrorOnFailure(readOperationRef.FinishEncoding());
159+
TLV::TLVWriter writer;
160+
writer.Init(mTlvBuffer);
104161

105-
std::vector<app::Testing::DecodedAttributeData> attributeData;
106-
ReturnErrorOnFailure(readOperationRef.GetEncodedIBs().Decode(attributeData));
107-
VerifyOrReturnError(attributeData.size() == 1u, CHIP_ERROR_INCORRECT_STATE);
162+
TLV::TLVReader reader;
108163

109-
return app::DataModel::Decode(attributeData[0].dataReader, out);
110-
}
164+
VerifyOrReturnValue(request.Encode(writer, TLV::AnonymousTag()) == CHIP_NO_ERROR, result);
165+
VerifyOrReturnValue(writer.Finalize() == CHIP_NO_ERROR, result);
111166

112-
// Write attribute from `value` parameter.
113-
// The `value` parameter must be of the correct type for the attribute being written.
114-
// Use `app::Clusters::<ClusterName>::Attributes::<AttributeName>::TypeInfo::Type` for the `value` parameter to be spec
115-
// compliant (see the comment of the class for usage example).
116-
// Will construct the attribute path using the first path returned by `GetPaths()` on the cluster.
117-
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
118-
template <typename T>
119-
app::DataModel::ActionReturnStatus WriteAttribute(AttributeId attr_id, const T & value)
120-
{
121-
VerifyOrReturnError(VerifyClusterPathsValid(), CHIP_ERROR_INCORRECT_STATE);
122-
auto path = mCluster.GetPaths()[0];
167+
reader.Init(mTlvBuffer, writer.GetLengthWritten());
168+
VerifyOrReturnValue(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()) == CHIP_NO_ERROR, result);
123169

124-
app::Testing::WriteOperation writeOperation(path.mEndpointId, path.mClusterId, attr_id);
170+
result.status = mCluster.InvokeCommand(invokeRequest, reader, &mHandler);
125171

126-
app::AttributeValueDecoder decoder = writeOperation.DecoderFor(value);
127-
return mCluster.WriteAttribute(writeOperation.GetRequest(), decoder);
128-
}
129-
130-
// Result structure for Invoke operations, containing both status and decoded response.
131-
template <typename ResponseType>
132-
struct InvokeResult {
133-
std::optional<app::DataModel::ActionReturnStatus> status;
134-
std::optional<ResponseType> response;
135-
136-
// Returns true if the command was successful and response is available
137-
bool IsSuccess() const { return status.has_value() && status->IsSuccess() && response.has_value(); }
138-
};
139-
140-
// Invoke a command and return the decoded result.
141-
// The `RequestType`, `ResponseType` type-parameters must be of the correct type for the command being invoked.
142-
// Use `app::Clusters::<ClusterName>::Commands::<CommandName>::Type` for the `RequestType` type-parameter to be spec compliant
143-
// Use `app::Clusters::<ClusterName>::Commands::<CommandName>::Type::ResponseType` for the `ResponseType` type-parameter to be
144-
// spec compliant Will construct the command path using the first path returned by `GetPaths()` on the cluster.
145-
// @returns `CHIP_ERROR_INCORRECT_STATE` if `GetPaths()` doesn't return a list with one path.
146-
template <typename ResponseType, typename RequestType>
147-
[[nodiscard]] InvokeResult<ResponseType> Invoke(chip::CommandId commandId, const RequestType & request)
172+
// If command was successful and there's a response, decode it (skip for NullObjectType)
173+
if constexpr (!std::is_same_v<ResponseType, app::DataModel::NullObjectType>)
148174
{
149-
InvokeResult<ResponseType> result;
150-
151-
const auto & paths = mCluster.GetPaths();
152-
VerifyOrReturnValue(paths.size() == 1u, result);
153-
154-
mHandler.ClearResponses();
155-
mHandler.ClearStatuses();
156-
157-
const app::DataModel::InvokeRequest invokeRequest = { .path = { paths[0].mEndpointId, paths[0].mClusterId, commandId } };
158-
159-
TLV::TLVWriter writer;
160-
writer.Init(mTlvBuffer);
161-
162-
TLV::TLVReader reader;
163-
164-
VerifyOrReturnValue(request.Encode(writer, TLV::AnonymousTag()) == CHIP_NO_ERROR, result);
165-
VerifyOrReturnValue(writer.Finalize() == CHIP_NO_ERROR, result);
166-
167-
reader.Init(mTlvBuffer, writer.GetLengthWritten());
168-
VerifyOrReturnValue(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()) == CHIP_NO_ERROR, result);
169-
170-
result.status = mCluster.InvokeCommand(invokeRequest, reader, &mHandler);
171-
172-
// If command was successful and there's a response, decode it (skip for NullObjectType)
173-
if constexpr (!std::is_same_v<ResponseType, app::DataModel::NullObjectType>) {
174-
if (result.status.has_value() && result.status->IsSuccess() && mHandler.HasResponse()) {
175-
ResponseType decodedResponse;
176-
CHIP_ERROR decodeError = mHandler.DecodeResponse(decodedResponse);
177-
if (decodeError == CHIP_NO_ERROR) {
178-
result.response = std::move(decodedResponse);
179-
} else {
180-
// Decode failed; reflect error in status and log
181-
result.status = app::DataModel::ActionReturnStatus(decodeError);
182-
ChipLogError(Test, "DecodeResponse failed: %s", decodeError.AsString());
183-
}
175+
if (result.status.has_value() && result.status->IsSuccess() && mHandler.HasResponse())
176+
{
177+
ResponseType decodedResponse;
178+
CHIP_ERROR decodeError = mHandler.DecodeResponse(decodedResponse);
179+
if (decodeError == CHIP_NO_ERROR)
180+
{
181+
result.response = std::move(decodedResponse);
182+
}
183+
else
184+
{
185+
// Decode failed; reflect error in status and log
186+
result.status = app::DataModel::ActionReturnStatus(decodeError);
187+
ChipLogError(Test, "DecodeResponse failed: %s", decodeError.AsString());
184188
}
185189
}
186-
187-
return result;
188190
}
189191

190-
private:
191-
bool VerifyClusterPathsValid()
192+
return result;
193+
}
194+
195+
private:
196+
bool VerifyClusterPathsValid()
197+
{
198+
auto paths = mCluster.GetPaths();
199+
if (paths.size() != 1)
192200
{
193-
auto paths = mCluster.GetPaths();
194-
if (paths.size() != 1) {
195-
ChipLogError(Test, "cluster.GetPaths() did not return exactly one path");
196-
return false;
197-
}
198-
return true;
201+
ChipLogError(Test, "cluster.GetPaths() did not return exactly one path");
202+
return false;
199203
}
200-
201-
TestServerClusterContext mTestServerClusterContext {};
202-
app::ServerClusterInterface & mCluster;
203-
204-
// Buffer size for TLV encoding/decoding of command payloads.
205-
// 256 bytes was chosen as a conservative upper bound for typical command payloads in tests.
206-
// All command payloads used in tests must fit within this buffer; tests with larger payloads will fail.
207-
// If protocol or test requirements change, this value may need to be increased.
208-
static constexpr size_t kTlvBufferSize = 256;
209-
210-
app::Testing::MockCommandHandler mHandler;
211-
uint8_t mTlvBuffer[kTlvBufferSize];
212-
std::vector<std::unique_ptr<app::Testing::ReadOperation>> mReadOperations;
213-
};
204+
return true;
205+
}
206+
207+
TestServerClusterContext mTestServerClusterContext{};
208+
app::ServerClusterInterface & mCluster;
209+
210+
// Buffer size for TLV encoding/decoding of command payloads.
211+
// 256 bytes was chosen as a conservative upper bound for typical command payloads in tests.
212+
// All command payloads used in tests must fit within this buffer; tests with larger payloads will fail.
213+
// If protocol or test requirements change, this value may need to be increased.
214+
static constexpr size_t kTlvBufferSize = 256;
215+
216+
app::Testing::MockCommandHandler mHandler;
217+
uint8_t mTlvBuffer[kTlvBufferSize];
218+
std::vector<std::unique_ptr<app::Testing::ReadOperation>> mReadOperations;
219+
};
214220

215221
} // namespace Test
216222
} // namespace chip

0 commit comments

Comments
 (0)