blob: 31def9f749642f75779f6e96c3de4997a7862133 [file] [log] [blame]
/**
*
* Copyright (c) 2025 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <lib/core/StringBuilderAdapters.h>
#include <pw_unit_test/framework.h>
#include <app/clusters/closure-control-server/closure-control-cluster-delegate.h>
#include <app/clusters/closure-control-server/closure-control-cluster-logic.h>
#include <app/clusters/closure-control-server/closure-control-cluster-objects.h>
#include <lib/support/CHIPMem.h>
#include <platform/CHIPDeviceLayer.h>
#include <system/SystemClock.h>
#include <system/SystemTimer.h>
#include <unordered_set>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters::ClosureControl;
using namespace chip::app::Clusters;
using namespace chip::System::Clock::Literals;
using Status = chip::Protocols::InteractionModel::Status;
namespace chip {
namespace System {
// TODO: This might be worthwhile to generalize and put into the system layer, but it too will need unit tests.
// This was taken from the Valve control cluster rework - what we do there should be done here as well.
class TimerAndMockClock : public Clock::Internal::MockClock, public Layer
{
public:
// System Layer overrides
CHIP_ERROR Init() override { return CHIP_NO_ERROR; }
void Shutdown() override { Clear(); }
void Clear()
{
mTimerList.Clear();
mTimerNodes.ReleaseAll();
}
bool IsInitialized() const override { return true; }
CHIP_ERROR StartTimer(Clock::Timeout aDelay, TimerCompleteCallback aComplete, void * aAppState) override
{
Clock::Timestamp awakenTime = GetMonotonicMilliseconds64() + std::chrono::duration_cast<Clock::Milliseconds64>(aDelay);
TimerList::Node * node = mTimerNodes.Create(*this, awakenTime, aComplete, aAppState);
mTimerList.Add(node);
return CHIP_NO_ERROR;
}
void CancelTimer(TimerCompleteCallback aComplete, void * aAppState) override
{
TimerList::Node * cancelled = mTimerList.Remove(aComplete, aAppState);
if (cancelled != nullptr)
{
mTimerNodes.Release(cancelled);
}
}
CHIP_ERROR ExtendTimerTo(Clock::Timeout aDelay, TimerCompleteCallback aComplete, void * aAppState) override
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override
{
return mTimerList.GetRemainingTime(onComplete, appState) != Clock::Timeout(0);
}
Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override
{
return mTimerList.GetRemainingTime(onComplete, appState);
}
CHIP_ERROR ScheduleWork(TimerCompleteCallback aComplete, void * aAppState) override { return CHIP_ERROR_NOT_IMPLEMENTED; }
// Clock overrides
void SetMonotonic(Clock::Milliseconds64 timestamp)
{
MockClock::SetMonotonic(timestamp);
// Find all the timers that fired at this time or before and invoke the callbacks
TimerList::Node * node;
while ((node = mTimerList.Earliest()) != nullptr && node->AwakenTime() <= timestamp)
{
mTimerList.PopEarliest();
// Invoke auto-releases
mTimerNodes.Invoke(node);
}
}
void AdvanceMonotonic(Clock::Milliseconds64 increment) { SetMonotonic(GetMonotonicMilliseconds64() + increment); }
private:
TimerPool<> mTimerNodes;
TimerList mTimerList;
};
} // namespace System
} // namespace chip
namespace {
// These are globals because SetUpTestSuite is static which requires static variables
System::TimerAndMockClock gSystemLayerAndClock = System::TimerAndMockClock();
System::Clock::ClockBase * gSavedClock = nullptr;
// Simple mock implementation of DelegateBase
class MockDelegate : public DelegateBase
{
public:
virtual ~MockDelegate() = default;
Status HandleStopCommand() override { return Status::Success; }
Status HandleMoveToCommand(const Optional<chip::app::Clusters::ClosureControl::TargetPositionEnum> & tag,
const Optional<bool> & latch, const Optional<Globals::ThreeLevelAutoEnum> & speed) override
{
return Status::Success;
}
Status HandleCalibrateCommand() override { return Status::Success; }
CHIP_ERROR GetCurrentErrorAtIndex(size_t index, ClosureErrorEnum & closureError) override { return CHIP_NO_ERROR; }
bool IsManualLatchingNeeded() override { return false; }
bool IsReadyToMove() override { return true; }
ElapsedS GetCalibrationCountdownTime() override { return 30; }
ElapsedS GetMovingCountdownTime() override { return 20; }
ElapsedS GetWaitingForMotionCountdownTime() override { return 10; }
private:
std::unordered_set<ClosureErrorEnum> currentErrors;
};
// Simple mock implementation of MatterContext
class MockMatterContext : public MatterContext
{
public:
MockMatterContext() : MatterContext(kInvalidEndpointId) {}
void MarkDirty(AttributeId attributeId) override
{
hasBeenMarkedDirty = true;
mReportedAttributeId = attributeId;
}
bool HasBeenMarkedDirty() const { return hasBeenMarkedDirty; }
void ResetDirtyFlag() { hasBeenMarkedDirty = false; }
bool MatchesReportedAttributeId(AttributeId attributeId) const { return attributeId == mReportedAttributeId; }
void ResetReportedAttributeId() { mReportedAttributeId = kInvalidAttributeId; }
private:
bool hasBeenMarkedDirty = false;
AttributeId mReportedAttributeId = kInvalidAttributeId;
};
class TestClosureControlClusterLogic : public ::testing::Test
{
public:
static void SetUpTestSuite()
{
ASSERT_EQ(Platform::MemoryInit(), CHIP_NO_ERROR);
gSavedClock = &System::SystemClock();
System::Clock::Internal::SetSystemClockForTesting(&gSystemLayerAndClock);
DeviceLayer::SetSystemLayerForTesting(&gSystemLayerAndClock);
}
static void TearDownTestSuite()
{
gSystemLayerAndClock.Shutdown();
DeviceLayer::SetSystemLayerForTesting(nullptr);
System::Clock::Internal::SetSystemClockForTesting(gSavedClock);
Platform::MemoryShutdown();
}
void SetUp() override
{
mockDelegate = MockDelegate();
mockContext = MockMatterContext();
conformance = ClusterConformance();
logic = std::make_unique<ClusterLogic>(mockDelegate, mockContext);
}
void TearDown() override { logic.reset(); }
MockDelegate mockDelegate;
MockMatterContext mockContext;
ClusterConformance conformance;
ClusterInitParameters initParams;
std::unique_ptr<ClusterLogic> logic;
};
} // namespace
TEST_F(TestClosureControlClusterLogic, Init_ValidConformance)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
}
TEST_F(TestClosureControlClusterLogic, Init_InvalidConformance)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kSpeed).Set(Feature::kInstantaneous);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR);
}
TEST_F(TestClosureControlClusterLogic, ReadFeatureMap_Init)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
}
TEST_F(TestClosureControlClusterLogic, GetFeatureMap_WithoutInit)
{
conformance.FeatureMap().Set(Feature::kPositioning);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
BitFlags<Feature> featureMap;
EXPECT_EQ(logic->GetFeatureMap(featureMap), CHIP_ERROR_INCORRECT_STATE);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, GetFeatureMap_WithInit)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
BitFlags<Feature> featureMap;
EXPECT_EQ(logic->GetFeatureMap(featureMap), CHIP_NO_ERROR);
EXPECT_EQ(featureMap, conformance.FeatureMap());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, GetClusterRevision_WithoutInit)
{
conformance.FeatureMap().Set(Feature::kPositioning);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
Attributes::ClusterRevision::TypeInfo::Type clusterRevision;
EXPECT_EQ(logic->GetClusterRevision(clusterRevision), CHIP_ERROR_INCORRECT_STATE);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, GetClusterRevision_WithInit)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
uint16_t kExpectedClusterRevision = 1u;
Attributes::ClusterRevision::TypeInfo::Type clusterRevision;
EXPECT_EQ(logic->GetClusterRevision(clusterRevision), CHIP_NO_ERROR);
EXPECT_EQ(clusterRevision, kExpectedClusterRevision);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_Stopped)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kStopped), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kStopped);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), 0u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_Moving)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kMoving);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_GT(countdownTime.Value(), 0u);
EXPECT_LE(countdownTime.Value(), 30u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_WaitingForMotion)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kWaitingForMotion), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kWaitingForMotion);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_GT(countdownTime.Value(), 0u);
EXPECT_LE(countdownTime.Value(), 30u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_Error)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kError), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kError);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), 0u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_SetupRequired)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kSetupRequired), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kSetupRequired);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), 0u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_CalibratingValid)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kCalibrating), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kCalibrating);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_GT(countdownTime.Value(), 0u);
EXPECT_LE(countdownTime.Value(), 30u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_CalibratingInvalid)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kCalibrating), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kStopped);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(countdownTime.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_ProtectedValid)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kProtection);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kProtected), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kProtected);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), 0u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_ProtectedInvalid)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kProtected), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kStopped);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(countdownTime.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_DisengagedValid)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kManuallyOperable);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kDisengaged), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kDisengaged);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), 0u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetMainState_DisengagedInvalid)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kDisengaged), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kStopped);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(countdownTime.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_UnknownEnumValue)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kUnknownEnumValue), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kStopped);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(countdownTime.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_WithoutInit)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kStopped), CHIP_ERROR_INCORRECT_STATE);
MainStateEnum readValue = MainStateEnum::kMoving; // Other enum to validate no changes to the read value
EXPECT_EQ(logic->GetMainState(readValue), CHIP_ERROR_INCORRECT_STATE);
EXPECT_EQ(readValue, MainStateEnum::kMoving);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetMainState_NoChanges)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kError), CHIP_NO_ERROR);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
mockContext.ResetDirtyFlag();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kError), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kError);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, GetSetMainState_ValidChange)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
MainStateEnum readValue = MainStateEnum::kUnknownEnumValue;
EXPECT_EQ(logic->GetMainState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue, MainStateEnum::kMoving);
DataModel::Nullable<ElapsedS> countdownTime = DataModel::NullNullable;
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_GT(countdownTime.Value(), 0u);
EXPECT_LE(countdownTime.Value(), 30u);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
}
TEST_F(TestClosureControlClusterLogic, SetCountdownTimeFromDelegate_Invalid)
{
conformance.FeatureMap().Set(Feature::kPositioning);
DataModel::Nullable<ElapsedS> countdownTime;
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(countdownTime), CHIP_ERROR_INCORRECT_STATE);
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_ERROR_INCORRECT_STATE);
EXPECT_TRUE(countdownTime.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetCountdownTimeFromDelegate_ValidChange)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(DataModel::NullNullable), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Change from null
DataModel::Nullable<ElapsedS> countdownTime = DataModel::MakeNullable<ElapsedS>(0);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<ElapsedS> readValue;
EXPECT_EQ(logic->GetCountdownTime(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue.Value(), 0u);
// change from 0
countdownTime.SetNonNull(1);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->GetCountdownTime(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue.Value(), 1u);
// validate Increase
countdownTime.SetNonNull(2);
EXPECT_EQ(logic->SetCountdownTimeFromDelegate(countdownTime), CHIP_NO_ERROR);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::CountdownTime::Id));
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->GetCountdownTime(readValue), CHIP_NO_ERROR);
EXPECT_EQ(readValue.Value(), 2u);
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidPositioningOnly)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(GenericOverallCurrentState(
Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyOpened)), NullOptional, NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kFullyOpened);
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_InvalidSpeedPositioningOnly)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyOpened)), NullOptional,
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_InvalidLatchPositioningOnly)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(GenericOverallCurrentState(
Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyOpened)), Optional(true), NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidPositioningAndMotionLatching)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(GenericOverallCurrentState(
Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true), NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kPartiallyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), true);
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_InvalidSpeedPositioningAndMotionLatching)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidPositioningAndSpeed)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyClosed)), NullOptional,
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kFullyClosed);
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kLow);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_InvalidLatchPositioningAndSpeed)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyClosed)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidAllFeatures)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kHigh)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kFullyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), true);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kHigh);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidNullToNull)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set the attribute to null
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState;
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_ValidValueThenNull)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set a valid value
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(GenericOverallCurrentState(
Optional(DataModel::MakeNullable(CurrentPositionEnum::kFullyOpened)), NullOptional, NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kFullyOpened);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Reset the value
overallCurrentState.SetNull();
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_TRUE(readValue.IsNull());
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_AllFeaturesChangePositioning)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
// Change position
overallCurrentState.Value().position.Value().SetNonNull(CurrentPositionEnum::kFullyOpened);
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kFullyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), true);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kLow);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_AllFeaturesChangeLatching)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
// Change latching
overallCurrentState.Value().latch.Value().SetNonNull(false);
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kPartiallyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), false);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kLow);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_AllFeaturesChangeSpeed)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
// Change speed
overallCurrentState.Value().speed.SetValue(Globals::ThreeLevelAutoEnum::kHigh);
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kPartiallyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), true);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kHigh);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
EXPECT_TRUE(mockContext.MatchesReportedAttributeId(Attributes::OverallCurrentState::Id));
}
TEST_F(TestClosureControlClusterLogic, SetOverallState_AllFeaturesNoChange)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
// Set the same value again
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
DataModel::Nullable<GenericOverallCurrentState> readValue;
EXPECT_EQ(logic->GetOverallCurrentState(readValue), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value().Value(), CurrentPositionEnum::kPartiallyOpened);
EXPECT_EQ(readValue.Value().latch.Value().Value(), true);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kLow);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, CalibrateCommand_NoCalibrationFeature)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleCalibrate(), Status::UnsupportedCommand);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, CalibrateCommand_InCalibrationMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kCalibrating), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleCalibrate(), Status::Success);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, CalibrateCommand_InNonCompatibleMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleCalibrate(), Status::InvalidInState);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
EXPECT_EQ(logic->SetMainState(MainStateEnum::kWaitingForMotion), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleCalibrate(), Status::InvalidInState);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, Calibrate)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
EXPECT_EQ(logic->SetMainState(MainStateEnum::kStopped), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleCalibrate(), Status::Success);
MainStateEnum state;
DataModel::Nullable<ElapsedS> countdownTime;
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(countdownTime), CHIP_NO_ERROR);
EXPECT_EQ(state, MainStateEnum::kCalibrating);
EXPECT_FALSE(countdownTime.IsNull());
EXPECT_EQ(countdownTime.Value(), static_cast<ElapsedS>(30));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, StopCommand_InstatenousFeature)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kInstantaneous);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleStop(), Status::UnsupportedCommand);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, StopCommand_InCalibrationMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kCalibrating), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
MainStateEnum state;
EXPECT_EQ(logic->HandleStop(), Status::Success);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(state, MainStateEnum::kStopped);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, StopCommand_InMovingMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
MainStateEnum state;
EXPECT_EQ(logic->HandleStop(), Status::Success);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(state, MainStateEnum::kStopped);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, StopCommand_InWaitingForMotionMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kCalibration);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kMoving), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
MainStateEnum state;
EXPECT_EQ(logic->HandleStop(), Status::Success);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(state, MainStateEnum::kStopped);
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, StopCommand_InNonCompatibleMainState)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kManuallyOperable);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kDisengaged), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleStop(), Status::Success);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
EXPECT_EQ(logic->SetMainState(MainStateEnum::kError), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleStop(), Status::Success);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_NoArguments)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(NullOptional, NullOptional, NullOptional), Status::InvalidCommand);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_InvalidState)
{
conformance.FeatureMap()
.Set(Feature::kPositioning)
.Set(Feature::kMotionLatching)
.Set(Feature::kSpeed)
.Set(Feature::kManuallyOperable);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
EXPECT_EQ(logic->SetMainState(MainStateEnum::kError), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::InvalidInState);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
EXPECT_EQ(logic->SetMainState(MainStateEnum::kDisengaged), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::InvalidInState);
EXPECT_FALSE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_AllFeatures)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value(), TargetPositionEnum::kMoveToFullyOpen);
EXPECT_EQ(readValue.Value().latch.Value(), false);
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kHigh);
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_OnlyPositioningFeature)
{
conformance.FeatureMap().Set(Feature::kPositioning);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(GenericOverallCurrentState(
Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), NullOptional, NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value(), TargetPositionEnum::kMoveToFullyOpen);
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_OnlyMotionLatchingFeature)
{
conformance.FeatureMap().Set(Feature::kMotionLatching);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(NullOptional, Optional(true), NullOptional));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_FALSE(readValue.Value().position.HasValue());
EXPECT_EQ(readValue.Value().latch.Value(), false);
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_PositioningAndSpeedFeature)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), NullOptional,
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), Optional<bool>(false),
Optional<Globals::ThreeLevelAutoEnum>(Globals::ThreeLevelAutoEnum::kHigh)),
Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value(), TargetPositionEnum::kMoveToFullyOpen);
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kHigh);
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_OnlyPosiitonField)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(Optional<TargetPositionEnum>(TargetPositionEnum::kMoveToFullyOpen), NullOptional, NullOptional),
Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_EQ(readValue.Value().position.Value(), TargetPositionEnum::kMoveToFullyOpen);
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_OnlyLatchField)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(NullOptional, Optional(true), NullOptional), Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_FALSE(readValue.Value().position.HasValue());
EXPECT_EQ(readValue.Value().latch.Value(), true);
EXPECT_FALSE(readValue.Value().speed.HasValue());
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}
TEST_F(TestClosureControlClusterLogic, MoveToCommand_OnlySpeedField)
{
conformance.FeatureMap().Set(Feature::kPositioning).Set(Feature::kMotionLatching).Set(Feature::kSpeed);
EXPECT_EQ(logic->Init(conformance, initParams), CHIP_NO_ERROR);
// Set initial state
DataModel::Nullable<GenericOverallCurrentState> overallCurrentState(
GenericOverallCurrentState(Optional(DataModel::MakeNullable(CurrentPositionEnum::kPartiallyOpened)), Optional(true),
Optional(Globals::ThreeLevelAutoEnum::kLow)));
EXPECT_EQ(logic->SetOverallCurrentState(overallCurrentState), CHIP_NO_ERROR);
mockContext.ResetDirtyFlag();
mockContext.ResetReportedAttributeId();
EXPECT_EQ(logic->HandleMoveTo(NullOptional, NullOptional, Optional(Globals::ThreeLevelAutoEnum::kLow)), Status::Success);
DataModel::Nullable<GenericOverallTargetState> readValue;
MainStateEnum state;
DataModel::Nullable<ElapsedS> coundowntime;
EXPECT_EQ(logic->GetOverallTargetState(readValue), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetMainState(state), CHIP_NO_ERROR);
EXPECT_EQ(logic->GetCountdownTime(coundowntime), CHIP_NO_ERROR);
EXPECT_FALSE(readValue.IsNull());
EXPECT_FALSE(readValue.Value().position.HasValue());
EXPECT_FALSE(readValue.Value().latch.HasValue());
EXPECT_EQ(readValue.Value().speed.Value(), Globals::ThreeLevelAutoEnum::kLow);
EXPECT_EQ(state, MainStateEnum::kMoving);
EXPECT_FALSE(coundowntime.IsNull());
EXPECT_EQ(coundowntime.Value(), static_cast<ElapsedS>(20));
EXPECT_TRUE(mockContext.HasBeenMarkedDirty());
}