| #include <array> | 
 | #include "propertywatchimpl.hpp" | 
 | #include "propertywatchtest.hpp" | 
 |  | 
 | using namespace std::string_literals; | 
 | using namespace phosphor::dbus::monitoring; | 
 |  | 
 | const std::array<std::string, 4> paths = | 
 | { | 
 |     "/xyz/openbmc_project/testing/inst1"s, | 
 |     "/xyz/openbmc_project/testing/inst2"s, | 
 |     "/xyz/openbmc_project/testing/inst3"s, | 
 |     "/xyz/openbmc_project/testing/inst4"s, | 
 | }; | 
 |  | 
 | const std::array<std::string, 2> interfaces = | 
 | { | 
 |     "xyz.openbmc_project.Iface1"s, | 
 |     "xyz.openbmc_project.Iface2"s, | 
 | }; | 
 |  | 
 | const std::array<std::string, 2> properties = | 
 | { | 
 |     "Value1"s, | 
 |     "Value2"s, | 
 | }; | 
 |  | 
 | const std::string meta; | 
 |  | 
 | std::array<any_ns::any, 8> storage = { }; | 
 |  | 
 | const PropertyIndex watchIndex = | 
 | { | 
 |     { | 
 |         { | 
 |             PropertyIndex::key_type{paths[0], interfaces[0], properties[0]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[0]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[0], interfaces[1], properties[1]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[1]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[1], interfaces[0], properties[0]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[2]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[1], interfaces[1], properties[1]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[3]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[2], interfaces[0], properties[0]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[4]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[2], interfaces[1], properties[1]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[5]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[3], interfaces[0], properties[0]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[6]} | 
 |         }, | 
 |         { | 
 |             PropertyIndex::key_type{paths[3], interfaces[1], properties[1]}, | 
 |             PropertyIndex::mapped_type{meta, meta, storage[7]} | 
 |         }, | 
 |     }, | 
 | }; | 
 |  | 
 | template <typename T> struct ExpectedValues {}; | 
 | template <> struct ExpectedValues<uint8_t> | 
 | { | 
 |     static auto& get(size_t i) | 
 |     { | 
 |         static const std::array<uint8_t, 8> values = | 
 |         { | 
 |             {0, 1, 2, 3, 4, 5, 6, 7}, | 
 |         }; | 
 |         return values[i]; | 
 |     } | 
 | }; | 
 |  | 
 | template <> struct ExpectedValues<uint16_t> | 
 | { | 
 |     static auto& get(size_t i) | 
 |     { | 
 |         static const std::array<uint16_t, 8> values = | 
 |         { | 
 |             {88, 77, 66, 55, 44, 33, 22, 11}, | 
 |         }; | 
 |         return values[i]; | 
 |     } | 
 | }; | 
 |  | 
 | template <> struct ExpectedValues<uint32_t> | 
 | { | 
 |     static auto& get(size_t i) | 
 |     { | 
 |         static const std::array<uint32_t, 8> values = | 
 |         { | 
 |             {0xffffffff, 1, 3, 0, 5, 7, 9, 0xffffffff}, | 
 |         }; | 
 |         return values[i]; | 
 |     } | 
 | }; | 
 |  | 
 | template <> struct ExpectedValues<uint64_t> | 
 | { | 
 |     static auto& get(size_t i) | 
 |     { | 
 |         static const std::array<uint64_t, 8> values = | 
 |         { | 
 |             {0xffffffffffffffff, 3, 7, 12234, 0, 3, 9, 0xffffffff}, | 
 |         }; | 
 |         return values[i]; | 
 |     } | 
 | }; | 
 |  | 
 | template <> struct ExpectedValues<std::string> | 
 | { | 
 |     static auto& get(size_t i) | 
 |     { | 
 |         static const std::array<std::string, 8> values = | 
 |         { | 
 |             {""s, "foo"s, "bar"s, "baz"s, "hello"s, "string", "\x2\x3", "\\"}, | 
 |         }; | 
 |         return values[i]; | 
 |     } | 
 | }; | 
 |  | 
 | template <typename T> | 
 | void testStart() | 
 | { | 
 |     using ::testing::Return; | 
 |     using ::testing::_; | 
 |  | 
 |     MockDBusInterface dbus; | 
 |     MockDBusInterface::instance(dbus); | 
 |  | 
 |     const std::vector<std::string> expectedMapperInterfaces; | 
 |     PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex); | 
 |  | 
 |     auto ndx = static_cast<size_t>(0); | 
 |     for (const auto& o : convert(watchIndex)) | 
 |     { | 
 |         const auto& path = o.first.get(); | 
 |         const auto& interfaces = o.second; | 
 |         std::vector<std::string> mapperResponse; | 
 |         std::transform( | 
 |             interfaces.begin(), | 
 |             interfaces.end(), | 
 |             std::back_inserter(mapperResponse), | 
 |         // *INDENT-OFF* | 
 |             [](const auto & item) | 
 |             { | 
 |                 return item.first; | 
 |             }); | 
 |         // *INDENT-ON* | 
 |         EXPECT_CALL( | 
 |             dbus, | 
 |             mapperGetObject( | 
 |                 MAPPER_BUSNAME, | 
 |                 MAPPER_PATH, | 
 |                 MAPPER_INTERFACE, | 
 |                 "GetObject", | 
 |                 path, | 
 |                 expectedMapperInterfaces)) | 
 |         .WillOnce(Return(GetObject({{"", mapperResponse}}))); | 
 |         EXPECT_CALL( | 
 |             dbus, | 
 |             fwdAddMatch( | 
 |                 sdbusplus::bus::match::rules::member("InterfacesAdded") + | 
 |                 sdbusplus::bus::match::rules::path(path) + | 
 |                 sdbusplus::bus::match::rules::interface( | 
 |                     "org.freedesktop.DBus.ObjectManager"), | 
 |                 _)); | 
 |         for (const auto& i : interfaces) | 
 |         { | 
 |             const auto& interface = i.first.get(); | 
 |             const auto& properties = i.second; | 
 |             EXPECT_CALL( | 
 |                 dbus, | 
 |                 fwdAddMatch( | 
 |                     sdbusplus::bus::match::rules::member("PropertiesChanged") + | 
 |                     sdbusplus::bus::match::rules::path(path) + | 
 |                     sdbusplus::bus::match::rules::argN(0, interface) + | 
 |                     sdbusplus::bus::match::rules::interface( | 
 |                         "org.freedesktop.DBus.Properties"), | 
 |                     _)); | 
 |  | 
 |             PropertiesChanged<T> serviceResponse; | 
 |             for (const auto& p : properties) | 
 |             { | 
 |                 serviceResponse[p] = ExpectedValues<T>::get(ndx); | 
 |                 ++ndx; | 
 |             } | 
 |             Expect<T>::getProperties(dbus, path, interface) | 
 |             .WillOnce(Return(serviceResponse)); | 
 |         } | 
 |     } | 
 |  | 
 |     watch.start(); | 
 |  | 
 |     ndx = 0; | 
 |     for (auto s : storage) | 
 |     { | 
 |         ASSERT_EQ(s.empty(), false); | 
 |         ASSERT_EQ(any_ns::any_cast<T>(s), ExpectedValues<T>::get(ndx)); | 
 |         ++ndx; | 
 |     } | 
 |  | 
 |     // Make sure start logic only runs the first time. | 
 |     watch.start(); | 
 | } | 
 |  | 
 | TEST(PropertyWatchTest, TestStart) | 
 | { | 
 |     testStart<uint8_t>(); | 
 |     testStart<uint16_t>(); | 
 |     testStart<uint32_t>(); | 
 |     testStart<uint64_t>(); | 
 |     testStart<std::string>(); | 
 | } | 
 |  | 
 | MockDBusInterface* MockDBusInterface::ptr = nullptr; |