/* * * Copyright (c) 2023 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 #include #include #include #include #include using namespace chip; using namespace chip::DeviceLayer; using namespace chip::app::Clusters::TimeSynchronization; using chip::TimeSyncDataProvider; using TrustedTimeSource = app::Clusters::TimeSynchronization::Structs::TrustedTimeSourceStruct::Type; using TimeZoneList = Span; using TimeZone = app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type; using DSTOffsetList = app::DataModel::List; using DSTOffset = app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type; namespace { class TestTimeSyncDataProvider : public ::testing::Test { public: static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } }; TEST_F(TestTimeSyncDataProvider, TestTrustedTimeSourceStoreLoad) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); TrustedTimeSource tts = { chip::FabricIndex(1), chip::NodeId(20), chip::EndpointId(0) }; EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.StoreTrustedTimeSource(tts)); TrustedTimeSource retrievedTrustedTimeSource; EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.LoadTrustedTimeSource(retrievedTrustedTimeSource)); EXPECT_EQ(retrievedTrustedTimeSource.fabricIndex, chip::FabricIndex(1)); EXPECT_EQ(retrievedTrustedTimeSource.nodeID, chip::NodeId(20)); EXPECT_EQ(retrievedTrustedTimeSource.endpoint, chip::EndpointId(0)); } TEST_F(TestTimeSyncDataProvider, TestTrustedTimeSourceEmpty) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); TrustedTimeSource tts; EXPECT_EQ(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, timeSyncDataProv.LoadTrustedTimeSource(tts)); } TEST_F(TestTimeSyncDataProvider, TestDefaultNTPStoreLoad) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); char ntp[10] = "localhost"; chip::CharSpan defaultNTP(ntp); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.StoreDefaultNtp(defaultNTP)); char buf[5]; chip::MutableCharSpan getDefaultNtp(buf); EXPECT_EQ(CHIP_ERROR_BUFFER_TOO_SMALL, timeSyncDataProv.LoadDefaultNtp(getDefaultNtp)); EXPECT_EQ(getDefaultNtp.size(), 5u); char buf1[20]; chip::MutableCharSpan getDefaultNtp1(buf1); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.LoadDefaultNtp(getDefaultNtp1)); EXPECT_EQ(getDefaultNtp1.size(), 10u); } TEST_F(TestTimeSyncDataProvider, TestDefaultNTPEmpty) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); chip::MutableCharSpan defaultNTP; EXPECT_EQ(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, timeSyncDataProv.LoadDefaultNtp(defaultNTP)); } TEST_F(TestTimeSyncDataProvider, TestTimeZoneStoreLoad) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); const auto makeTimeZone = [](int32_t offset = 0, uint64_t validAt = 0, char * name = nullptr) { TimeSyncDataProvider::TimeZoneStore tzS; tzS.timeZone.offset = offset; tzS.timeZone.validAt = validAt; if (name != nullptr) { Platform::CopyString(tzS.name, name); tzS.timeZone.name.SetValue(chip::CharSpan::fromCharString(tzS.name)); } return tzS; }; char tzShort[] = "LA"; char tzLong[] = "MunichOnTheLongRiverOfIsarInNiceSummerWeatherWithAugustinerBeer"; char tzBerlin[] = "Berlin"; TimeSyncDataProvider::TimeZoneStore tzS[3] = { makeTimeZone(1, 1, tzShort), makeTimeZone(2, 2, tzLong), makeTimeZone(3, 3, tzBerlin) }; TimeZoneList tzL(tzS); EXPECT_EQ(tzL.size(), 3u); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.StoreTimeZone(tzL)); TimeSyncDataProvider::TimeZoneStore emptyTzS[3] = { makeTimeZone(), makeTimeZone(), makeTimeZone() }; tzL = TimeZoneList(emptyTzS); TimeSyncDataProvider::TimeZoneObj tzObj{ tzL, 3 }; EXPECT_EQ(tzL.size(), 3u); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.LoadTimeZone(tzObj)); EXPECT_EQ(tzObj.validSize, 3u); EXPECT_FALSE(tzL.empty()); if (!tzL.empty()) { auto & tz = tzL[0].timeZone; EXPECT_EQ(tz.offset, 1); EXPECT_EQ(tz.validAt, 1u); EXPECT_TRUE(tz.name.HasValue()); EXPECT_EQ(tz.name.Value().size(), 2u); tzL = tzL.SubSpan(1); } if (!tzL.empty()) { auto & tz = tzL[0].timeZone; EXPECT_EQ(tz.offset, 2); EXPECT_EQ(tz.validAt, 2u); EXPECT_TRUE(tz.name.HasValue()); EXPECT_EQ(tz.name.Value().size(), 63u); tzL = tzL.SubSpan(1); } if (!tzL.empty()) { auto & tz = tzL[0].timeZone; EXPECT_EQ(tz.offset, 3); EXPECT_EQ(tz.validAt, 3u); EXPECT_TRUE(tz.name.HasValue()); EXPECT_EQ(tz.name.Value().size(), 6u); tzL = tzL.SubSpan(1); } EXPECT_TRUE(tzL.empty()); } TEST_F(TestTimeSyncDataProvider, TestTimeZoneEmpty) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); TimeSyncDataProvider::TimeZoneObj timeZoneObj; EXPECT_EQ(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, timeSyncDataProv.LoadTimeZone(timeZoneObj)); EXPECT_FALSE(timeZoneObj.timeZoneList.begin()); EXPECT_EQ(timeZoneObj.validSize, 0u); } TEST_F(TestTimeSyncDataProvider, TestDSTOffset) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); const auto makeDSTOffset = [](int32_t offset = 0, uint64_t validStarting = 0, uint64_t validUntil = 0) { DSTOffset dst; dst.offset = offset; dst.validStarting = validStarting; if (validUntil) dst.validUntil.SetNonNull(validUntil); return dst; }; DSTOffset dstS[3] = { makeDSTOffset(1, 1, 2), makeDSTOffset(2, 2, 3), makeDSTOffset(3, 3) }; DSTOffsetList dstL(dstS); TimeSyncDataProvider::DSTOffsetObj dstObj{ dstL, 3 }; EXPECT_EQ(dstObj.validSize, 3u); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.StoreDSTOffset(dstL)); DSTOffset emtpyDstS[3] = { makeDSTOffset(), makeDSTOffset(), makeDSTOffset() }; dstObj.dstOffsetList = DSTOffsetList(emtpyDstS); dstObj.validSize = 0; EXPECT_EQ(dstObj.dstOffsetList.size(), 3u); EXPECT_EQ(CHIP_NO_ERROR, timeSyncDataProv.LoadDSTOffset(dstObj)); EXPECT_EQ(dstObj.validSize, 3u); EXPECT_FALSE(dstObj.dstOffsetList.empty()); if (!dstObj.dstOffsetList.empty()) { auto & dst = dstObj.dstOffsetList.data()[0]; EXPECT_EQ(dst.offset, 1); EXPECT_EQ(dst.validStarting, 1u); EXPECT_FALSE(dst.validUntil.IsNull()); EXPECT_EQ(dst.validUntil.Value(), 2u); dstObj.dstOffsetList = dstObj.dstOffsetList.SubSpan(1); } if (!dstObj.dstOffsetList.empty()) { auto & dst = dstObj.dstOffsetList.data()[0]; EXPECT_EQ(dst.offset, 2); EXPECT_EQ(dst.validStarting, 2u); EXPECT_FALSE(dst.validUntil.IsNull()); EXPECT_EQ(dst.validUntil.Value(), 3u); dstObj.dstOffsetList = dstObj.dstOffsetList.SubSpan(1); } if (!dstObj.dstOffsetList.empty()) { auto & dst = dstObj.dstOffsetList.data()[0]; EXPECT_EQ(dst.offset, 3); EXPECT_EQ(dst.validStarting, 3u); EXPECT_TRUE(dst.validUntil.IsNull()); dstObj.dstOffsetList = dstObj.dstOffsetList.SubSpan(1); } EXPECT_TRUE(dstObj.dstOffsetList.empty()); } TEST_F(TestTimeSyncDataProvider, TestDSTOffsetEmpty) { TestPersistentStorageDelegate persistentStorage; TimeSyncDataProvider timeSyncDataProv; timeSyncDataProv.Init(persistentStorage); TimeSyncDataProvider::DSTOffsetObj dstObj; EXPECT_EQ(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, timeSyncDataProv.LoadDSTOffset(dstObj)); EXPECT_TRUE(dstObj.dstOffsetList.empty()); EXPECT_EQ(dstObj.validSize, 0u); } } // namespace