@@ -41,6 +41,21 @@ static chip::app::CircularEventBuffer gCircularEventBuffer[3];
4141
4242constexpr EndpointId kTestEndpointId = 1 ;
4343
44+ const Structs::MeasurementAccuracyRangeStruct::Type kTestAccuracyRanges [] = {
45+ { .rangeMin = 0 ,
46+ .rangeMax = 1'000'000'000'000'000 , // 1 million Mwh
47+ .percentMax = MakeOptional (static_cast <chip::Percent100ths>(500 )),
48+ .percentMin = MakeOptional (static_cast <chip::Percent100ths>(50 )) }
49+ };
50+
51+ const Structs::MeasurementAccuracyStruct::Type kTestAccuracy = {
52+ .measurementType = MeasurementTypeEnum::kElectricalEnergy ,
53+ .measured = true ,
54+ .minMeasuredValue = 0 ,
55+ .maxMeasuredValue = 1'000'000'000'000'000 ,
56+ .accuracyRanges = DataModel::List<const Structs::MeasurementAccuracyRangeStruct::Type>(kTestAccuracyRanges )
57+ };
58+
4459struct TestElectricalEnergyMeasurementClusterBackwardsCompatibility : public ::testing::Test
4560{
4661 static void SetUpTestSuite () { ASSERT_EQ (chip::Platform::MemoryInit (), CHIP_NO_ERROR ); }
@@ -95,7 +110,7 @@ TEST_F(TestElectricalEnergyMeasurementClusterBackwardsCompatibility, TestAttrAcc
95110 EXPECT_FALSE (minimalAttrAccess.HasFeature (Feature::kExportedEnergy ));
96111 EXPECT_FALSE (minimalAttrAccess.HasFeature (Feature::kCumulativeEnergy ));
97112 EXPECT_FALSE (minimalAttrAccess.HasFeature (Feature::kPeriodicEnergy ));
98- minimalAttrAccess.Shutdown (ClusterShutdownType:: kClusterShutdown );
113+ minimalAttrAccess.Shutdown ();
99114
100115 // Test optional attribute checking methods
101116 EXPECT_TRUE (attrAccess.SupportsOptAttr (OptionalAttributes::kOptionalAttributeCumulativeEnergyReset ));
@@ -104,10 +119,10 @@ TEST_F(TestElectricalEnergyMeasurementClusterBackwardsCompatibility, TestAttrAcc
104119 ElectricalEnergyMeasurementAttrAccess noOptAttrAccess (features, noOptionalAttrs, kTestEndpointId + 2 );
105120 EXPECT_EQ (noOptAttrAccess.Init (), CHIP_NO_ERROR );
106121 EXPECT_FALSE (noOptAttrAccess.SupportsOptAttr (OptionalAttributes::kOptionalAttributeCumulativeEnergyReset ));
107- noOptAttrAccess.Shutdown (ClusterShutdownType:: kClusterShutdown );
122+ noOptAttrAccess.Shutdown ();
108123
109124 // Test shutdown
110- attrAccess.Shutdown (ClusterShutdownType:: kClusterShutdown );
125+ attrAccess.Shutdown ();
111126
112127 // Verify cluster is unregistered from the registry
113128 EXPECT_EQ (FindElectricalEnergyMeasurementClusterOnEndpoint (kTestEndpointId ), nullptr );
@@ -130,22 +145,68 @@ TEST_F(TestElectricalEnergyMeasurementClusterBackwardsCompatibility, TestCodegen
130145 // Initialize the cluster with test context for event logging
131146 EXPECT_EQ (cluster->Startup (mContext .Get ()), CHIP_NO_ERROR );
132147
133- // Test SetMeasurementAccuracy
148+ // Test SetMeasurementAccuracy and verify accuracyRanges survives source data destruction
149+ {
150+ Structs::MeasurementAccuracyRangeStruct::Type testMeasurementAccuracyRanges[] = {
151+ { .rangeMin = 0 ,
152+ .rangeMax = 1'000'000'000'000'000 , // 1 million Mwh
153+ .percentMax = MakeOptional (static_cast <chip::Percent100ths>(500 )),
154+ .percentMin = MakeOptional (static_cast <chip::Percent100ths>(50 )) }
155+ };
156+
157+ Structs::MeasurementAccuracyStruct::Type accuracy;
158+ accuracy.measurementType = MeasurementTypeEnum::kApparentEnergy ;
159+ accuracy.measured = true ;
160+ accuracy.minMeasuredValue = 0 ;
161+ accuracy.maxMeasuredValue = 1000000 ;
162+ accuracy.accuracyRanges = DataModel::List<const Structs::MeasurementAccuracyRangeStruct::Type>(
163+ testMeasurementAccuracyRanges, MATTER_ARRAY_SIZE (testMeasurementAccuracyRanges));
164+
165+ EXPECT_EQ (SetMeasurementAccuracy (kTestEndpointId , accuracy), CHIP_NO_ERROR );
166+
167+ // Overwrite source data; if the cluster only holds a Span, reads will return these values instead
168+ testMeasurementAccuracyRanges[0 ].rangeMin = 999 ;
169+ testMeasurementAccuracyRanges[0 ].rangeMax = 999 ;
170+ testMeasurementAccuracyRanges[0 ].percentMax = MakeOptional (static_cast <chip::Percent100ths>(999 ));
171+ testMeasurementAccuracyRanges[0 ].percentMin = MakeOptional (static_cast <chip::Percent100ths>(999 ));
172+ }
173+
174+ // Verify that the MeasurementAccuracyStruct is preserved past the scope of the previous test
175+ Structs::MeasurementAccuracyStruct::Type readAccuracy;
176+ cluster->GetMeasurementAccuracy (readAccuracy);
177+ EXPECT_EQ (readAccuracy.measurementType , MeasurementTypeEnum::kApparentEnergy );
178+ EXPECT_TRUE (readAccuracy.measured );
179+ EXPECT_EQ (readAccuracy.minMeasuredValue , 0 );
180+ EXPECT_EQ (readAccuracy.maxMeasuredValue , 1000000 );
181+ EXPECT_EQ (readAccuracy.accuracyRanges .size (), 1u );
182+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMin , 0 );
183+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMax , 1'000'000'000'000'000 );
184+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMax .Value (), 500 );
185+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMin .Value (), 50 );
186+
187+ // Test SetMeasurementAccuracy and verify empty accuracyRanges doesn't modify the existing accuracyRanges
134188 {
135189 Structs::MeasurementAccuracyStruct::Type accuracy;
136190 accuracy.measurementType = MeasurementTypeEnum::kApparentEnergy ;
137191 accuracy.measured = true ;
138192 accuracy.minMeasuredValue = 0 ;
139193 accuracy.maxMeasuredValue = 1000000 ;
140- accuracy.accuracyRanges = DataModel::List<Structs::MeasurementAccuracyRangeStruct::Type>();
141194
142195 EXPECT_EQ (SetMeasurementAccuracy (kTestEndpointId , accuracy), CHIP_NO_ERROR );
143196
144197 // Verify the value was set
145198 Structs::MeasurementAccuracyStruct::Type readAccuracy;
146199 cluster->GetMeasurementAccuracy (readAccuracy);
200+ // Verify that the MeasurementAccuracyStruct is not erased by the empty accuracyRanges
147201 EXPECT_EQ (readAccuracy.measurementType , MeasurementTypeEnum::kApparentEnergy );
148202 EXPECT_TRUE (readAccuracy.measured );
203+ EXPECT_EQ (readAccuracy.minMeasuredValue , 0 );
204+ EXPECT_EQ (readAccuracy.maxMeasuredValue , 1000000 );
205+ EXPECT_EQ (readAccuracy.accuracyRanges .size (), 1u );
206+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMin , 0 );
207+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMax , 1'000'000'000'000'000 );
208+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMax .Value (), 500 );
209+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMin .Value (), 50 );
149210 }
150211
151212 // Test SetCumulativeReset
@@ -272,7 +333,36 @@ TEST_F(TestElectricalEnergyMeasurementClusterBackwardsCompatibility, TestCodegen
272333 }
273334
274335 // Cleanup
275- attrAccess.Shutdown (ClusterShutdownType::kClusterShutdown );
336+ attrAccess.Shutdown ();
337+ }
338+
339+ TEST_F (TestElectricalEnergyMeasurementClusterBackwardsCompatibility, TestConstructorWithAccuracy)
340+ {
341+ BitMask<Feature> features (Feature::kImportedEnergy , Feature::kCumulativeEnergy );
342+ BitMask<OptionalAttributes> noOptionalAttrs;
343+
344+ ElectricalEnergyMeasurementCluster cluster (ElectricalEnergyMeasurementCluster::Config{
345+ .endpointId = kTestEndpointId + 10 ,
346+ .featureFlags = features,
347+ .optionalAttributes = noOptionalAttrs,
348+ .accuracyStruct = kTestAccuracy ,
349+ });
350+
351+ Structs::MeasurementAccuracyStruct::Type readAccuracy;
352+ cluster.GetMeasurementAccuracy (readAccuracy);
353+
354+ EXPECT_EQ (readAccuracy.measurementType , MeasurementTypeEnum::kElectricalEnergy );
355+ EXPECT_TRUE (readAccuracy.measured );
356+ EXPECT_EQ (readAccuracy.minMeasuredValue , 0 );
357+ EXPECT_EQ (readAccuracy.maxMeasuredValue , 1'000'000'000'000'000 );
358+ ASSERT_EQ (readAccuracy.accuracyRanges .size (), 1u );
359+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMin , 0 );
360+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].rangeMax , 1'000'000'000'000'000 );
361+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMax .Value (), 500 );
362+ EXPECT_EQ (readAccuracy.accuracyRanges [0 ].percentMin .Value (), 50 );
363+
364+ // Verify zero-copy: the ranges Span should point directly at the static data
365+ EXPECT_EQ (readAccuracy.accuracyRanges .data (), kTestAccuracyRanges );
276366}
277367
278368} // namespace
0 commit comments