Commit a90248d34c5ffdc2c1272b9207389e16c22b9b8e

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent bcac6298

Add tests for BaseDevice, Sensor and SensorList.

Fix some errors in these classes.
Make sensor constructors explicit.
include/hueplusplus/CLIPSensors.h
... ... @@ -45,14 +45,15 @@ public:
45 45 void setURL(const std::string& url);
46 46  
47 47 time::AbsoluteTime getLastUpdated() const;
  48 +
48 49 protected:
49   - BaseCLIP(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  50 + explicit BaseCLIP(Sensor sensor) : BaseDevice(std::move(sensor)) { }
50 51 };
51 52  
52 53 class CLIPSwitch : public BaseCLIP
53 54 {
54 55 public:
55   - CLIPSwitch(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  56 + explicit CLIPSwitch(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
56 57  
57 58 int getButtonEvent() const;
58 59 void setButtonEvent(int code);
... ... @@ -62,7 +63,7 @@ public:
62 63 class CLIPOpenClose : public BaseCLIP
63 64 {
64 65 public:
65   - CLIPOpenClose(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  66 + explicit CLIPOpenClose(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
66 67  
67 68 bool isOpen() const;
68 69 void setOpen(bool open);
... ... @@ -73,7 +74,7 @@ public:
73 74 class CLIPPresence : public BaseCLIP
74 75 {
75 76 public:
76   - CLIPPresence(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  77 + explicit CLIPPresence(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
77 78  
78 79 bool getPresence() const;
79 80 void setPresence(bool presence);
... ... @@ -84,7 +85,7 @@ public:
84 85 class CLIPTemperature : public BaseCLIP
85 86 {
86 87 public:
87   - CLIPTemperature(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  88 + explicit CLIPTemperature(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
88 89  
89 90 int getTemperature() const;
90 91 void setTemperature(int temperature);
... ... @@ -94,7 +95,7 @@ public:
94 95 class CLIPHumidity : public BaseCLIP
95 96 {
96 97 public:
97   - CLIPHumidity(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  98 + explicit CLIPHumidity(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
98 99  
99 100 int getHumidity() const;
100 101 void setHumidity(int humidity);
... ... @@ -104,7 +105,7 @@ public:
104 105 class CLIPLightLevel : public BaseCLIP
105 106 {
106 107 public:
107   - CLIPLightLevel(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  108 + explicit CLIPLightLevel(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
108 109  
109 110 int getDarkThreshold() const;
110 111 void setDarkThreshold(int threshold);
... ... @@ -122,7 +123,7 @@ public:
122 123 class CLIPGenericFlag : public BaseCLIP
123 124 {
124 125 public:
125   - CLIPGenericFlag(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  126 + explicit CLIPGenericFlag(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
126 127  
127 128 bool getFlag() const;
128 129 void setFlag(bool flag);
... ... @@ -132,7 +133,7 @@ public:
132 133 class CLIPGenericStatus : public BaseCLIP
133 134 {
134 135 public:
135   - CLIPGenericStatus(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  136 + explicit CLIPGenericStatus(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
136 137  
137 138 int getStatus() const;
138 139 void setStatus(int status);
... ...
include/hueplusplus/Sensor.h
... ... @@ -2,6 +2,7 @@
2 2 \file Sensor.h
3 3 Copyright Notice\n
4 4 Copyright (C) 2020 Stefan Herbrechtsmeier - developer\n
  5 + Copyright (C) 2020 Jan Rogall - developer\n
5 6  
6 7 This file is part of hueplusplus.
7 8  
... ... @@ -45,13 +46,15 @@ Alert alertFromString(const std::string& s);
45 46 //!
46 47 class Sensor : public BaseDevice
47 48 {
48   - friend class Bridge;
49   -
50 49 public:
51   - //! \brief std dtor
52   - ~Sensor() = default;
  50 + //! \brief Construct Sensor.
  51 + //! \param id Integer that specifies the id of this sensor
  52 + //! \param commands HueCommandAPI for communication with the bridge
  53 + //! \param refreshDuration Time between refreshing the cached state.
  54 + Sensor(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration);
53 55  
54   - bool hasSwupdate() const;
  56 + //!\name Config attributes
  57 + ///@{
55 58  
56 59 bool hasOn() const;
57 60 // Check whether sensor is on. Does not update when off
... ... @@ -70,34 +73,36 @@ public:
70 73 bool hasReachable() const;
71 74 bool isReachable() const;
72 75  
73   - time::AbsoluteTime getLastUpdated() const;
74   -
75 76 bool hasUserTest() const;
76 77 void setUserTest(bool enabled);
77 78  
78 79 bool hasURL() const;
79 80 std::string getURL() const;
80 81 void setURL(const std::string& url);
81   -
  82 +
82 83 std::vector<std::string> getPendingConfig() const;
83   -
  84 +
84 85 bool hasLEDIndication() const;
85 86 bool getLEDIndication() const;
86 87 void setLEDIndication(bool on);
87 88  
88   - nlohmann::json getState() const;
89   - void setStateAttribute(const std::string& key, const nlohmann::json& value);
90   -
91 89 nlohmann::json getConfig() const;
92 90 void setConfigAttribute(const std::string& key, const nlohmann::json& value);
93 91  
  92 + ///@}
  93 +
  94 + time::AbsoluteTime getLastUpdated() const;
  95 +
  96 + nlohmann::json getState() const;
  97 + void setStateAttribute(const std::string& key, const nlohmann::json& value);
  98 +
94 99 bool isCertified() const;
95 100 bool isPrimary() const;
96 101  
97 102 template <typename T>
98 103 T asSensorType() const &
99 104 {
100   - if (getType() != T::type_str)
  105 + if (getType() != T::typeStr)
101 106 {
102 107 throw HueException(FileInfo {__FILE__, __LINE__, __func__}, "Sensor type does not match: " + getType());
103 108 }
... ... @@ -112,14 +117,6 @@ public:
112 117 }
113 118 return T(std::move(*this));
114 119 }
115   -
116   -protected:
117   - //! \brief Protected ctor that is used by \ref Bridge class.
118   - //!
119   - //! \param id Integer that specifies the id of this sensor
120   - //! \param commands HueCommandAPI for communication with the bridge
121   - //! \param refreshDuration Time between refreshing the cached state.
122   - Sensor(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration);
123 120 };
124 121  
125 122 class CreateSensor
... ... @@ -142,7 +139,7 @@ namespace sensors
142 139 class DaylightSensor : public BaseDevice
143 140 {
144 141 public:
145   - DaylightSensor(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  142 + explicit DaylightSensor(Sensor sensor) : BaseDevice(std::move(sensor)) { }
146 143  
147 144 bool isOn() const;
148 145 void setOn(bool on);
... ...
include/hueplusplus/SensorList.h
... ... @@ -40,12 +40,15 @@ public:
40 40 template <typename T>
41 41 std::vector<T> getAllByType()
42 42 {
  43 + nlohmann::json state = this->stateCache.getValue();
43 44 std::vector<T> result;
44   - std::string type = T::typeStr;
45   - // TODO: Maybe only parse the sensors with correct type
46   - for (Sensor& s : getAll())
  45 + for (auto it = state.begin(); it != state.end(); ++it)
47 46 {
48   - result.push_back(s.asSensorType<T>());
  47 + // Only parse the sensors with the correct type
  48 + if (it->value("type", "") == T::typeStr)
  49 + {
  50 + result.push_back(get(maybeStoi(it.key())).asSensorType<T>());
  51 + }
49 52 }
50 53 return result;
51 54 }
... ...
include/hueplusplus/ZLLSensors.h
... ... @@ -31,7 +31,7 @@ namespace sensors
31 31 class ZGPSwitch : public BaseDevice
32 32 {
33 33 public:
34   - ZGPSwitch(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  34 + explicit ZGPSwitch(Sensor sensor) : BaseDevice(std::move(sensor)) { }
35 35  
36 36 bool isOn() const;
37 37 void setOn(bool on);
... ... @@ -48,7 +48,7 @@ public:
48 48 class ZLLSwitch : public BaseDevice
49 49 {
50 50 public:
51   - ZLLSwitch(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  51 + explicit ZLLSwitch(Sensor sensor) : BaseDevice(std::move(sensor)) { }
52 52  
53 53 bool isOn() const;
54 54 void setOn(bool on);
... ... @@ -87,7 +87,7 @@ public:
87 87 class ZLLPresence : public BaseDevice
88 88 {
89 89 public:
90   - ZLLPresence(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  90 + explicit ZLLPresence(Sensor sensor) : BaseDevice(std::move(sensor)) { }
91 91 bool isOn() const;
92 92 void setOn(bool on);
93 93  
... ... @@ -113,7 +113,7 @@ public:
113 113 class ZLLTemperature : public BaseDevice
114 114 {
115 115 public:
116   - ZLLTemperature(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  116 + explicit ZLLTemperature(Sensor sensor) : BaseDevice(std::move(sensor)) { }
117 117  
118 118 bool isOn() const;
119 119 void setOn(bool on);
... ... @@ -133,7 +133,7 @@ public:
133 133 class ZLLLightLevel : public BaseDevice
134 134 {
135 135 public:
136   - ZLLLightLevel(Sensor sensor) : BaseDevice(std::move(sensor)) { }
  136 + explicit ZLLLightLevel(Sensor sensor) : BaseDevice(std::move(sensor)) { }
137 137  
138 138 bool isOn() const;
139 139 void setOn(bool on);
... ...
src/Bridge.cpp
... ... @@ -36,6 +36,7 @@
36 36 #include "hueplusplus/UPnP.h"
37 37 #include "hueplusplus/Utils.h"
38 38  
  39 +
39 40 namespace hueplusplus
40 41 {
41 42 BridgeFinder::BridgeFinder(std::shared_ptr<const IHttpHandler> handler) : http_handler(std::move(handler)) { }
... ...
src/Sensor.cpp
... ... @@ -57,11 +57,6 @@ Alert alertFromString(const std::string&amp; s)
57 57 }
58 58 }
59 59  
60   -bool Sensor::hasSwupdate() const
61   -{
62   - return state.getValue().at("config").count("swupdate") != 0;
63   -}
64   -
65 60 bool Sensor::hasOn() const
66 61 {
67 62 return state.getValue().at("config").count("on") != 0;
... ... @@ -124,7 +119,7 @@ void Sensor::sendAlert(Alert type)
124 119 alertStr = "none";
125 120 break;
126 121 }
127   - sendPutRequest("/state", nlohmann::json {{"alert", alertStr}}, CURRENT_FILE_INFO);
  122 + sendPutRequest("/config", nlohmann::json {{"alert", alertStr}}, CURRENT_FILE_INFO);
128 123 }
129 124 bool Sensor::hasReachable() const
130 125 {
... ... @@ -205,7 +200,7 @@ nlohmann::json Sensor::getState() const
205 200 }
206 201 void Sensor::setStateAttribute(const std::string& key, const nlohmann::json& value)
207 202 {
208   - sendPutRequest("/state", nlohmann::json {{"key", value}}, CURRENT_FILE_INFO);
  203 + sendPutRequest("/state", nlohmann::json {{key, value}}, CURRENT_FILE_INFO);
209 204 }
210 205  
211 206 nlohmann::json Sensor::getConfig() const
... ... @@ -215,7 +210,7 @@ nlohmann::json Sensor::getConfig() const
215 210  
216 211 void Sensor::setConfigAttribute(const std::string& key, const nlohmann::json& value)
217 212 {
218   - sendPutRequest("/config", nlohmann::json {{"key", value}}, CURRENT_FILE_INFO);
  213 + sendPutRequest("/config", nlohmann::json {{key, value}}, CURRENT_FILE_INFO);
219 214 }
220 215  
221 216 bool Sensor::isCertified() const
... ...
test/CMakeLists.txt
... ... @@ -31,6 +31,7 @@ target_compile_features(gtest PUBLIC cxx_std_14)
31 31 # define all test sources
32 32 set(TEST_SOURCES
33 33 test_APICache.cpp
  34 + test_BaseDevice.cpp
34 35 test_BaseHttpHandler.cpp
35 36 test_Bridge.cpp
36 37 test_BridgeConfig.cpp
... ... @@ -46,6 +47,8 @@ set(TEST_SOURCES
46 47 test_ResourceList.cpp
47 48 test_Scene.cpp
48 49 test_Schedule.cpp
  50 + test_Sensor.cpp
  51 + test_SensorList.cpp
49 52 test_SimpleBrightnessStrategy.cpp
50 53 test_SimpleColorHueStrategy.cpp
51 54 test_SimpleColorTemperatureStrategy.cpp
... ...
test/test_BaseDevice.cpp 0 โ†’ 100644
  1 +/**
  2 + \file test_BaseDevice.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <gmock/gmock.h>
  23 +#include <gtest/gtest.h>
  24 +
  25 +#include "testhelper.h"
  26 +
  27 +#include "hueplusplus/BaseDevice.h"
  28 +#include "mocks/mock_HttpHandler.h"
  29 +
  30 +using namespace hueplusplus;
  31 +using namespace testing;
  32 +
  33 +class TestDevice : public BaseDevice
  34 +{
  35 +public:
  36 + TestDevice(int id, const HueCommandAPI& commands, const std::string& path,
  37 + std::chrono::steady_clock::duration refreshDuration)
  38 + : BaseDevice(id, commands, path, refreshDuration)
  39 + { }
  40 +};
  41 +
  42 +class BaseDeviceTest : public Test
  43 +{
  44 +protected:
  45 + std::shared_ptr<MockHttpHandler> handler;
  46 + HueCommandAPI commands;
  47 + nlohmann::json state;
  48 + std::string path = "/test/";
  49 +
  50 +protected:
  51 + BaseDeviceTest()
  52 + : handler(std::make_shared<MockHttpHandler>()),
  53 + commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
  54 + state({{"type", "testType"}, {"name", "Test name"}, {"swversion", "1.2.3.4"}, {"modelid", "TEST"},
  55 + {"manufacturername", "testManuf"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
  56 + {"productname", "Test type"}})
  57 + { }
  58 +
  59 + TestDevice getDevice(int id)
  60 + {
  61 + EXPECT_CALL(*handler,
  62 + GETJson("/api/" + getBridgeUsername() + path + std::to_string(id), _, getBridgeIp(), getBridgePort()))
  63 + .WillOnce(Return(state));
  64 + return TestDevice(id, commands, path, std::chrono::steady_clock::duration::max());
  65 + }
  66 +};
  67 +
  68 +TEST_F(BaseDeviceTest, getId)
  69 +{
  70 + const int id = 1;
  71 + EXPECT_EQ(id, getDevice(id).getId());
  72 +}
  73 +
  74 +TEST_F(BaseDeviceTest, getName)
  75 +{
  76 + EXPECT_EQ("Test name", getDevice(1).getName());
  77 +}
  78 +
  79 +TEST_F(BaseDeviceTest, getType)
  80 +{
  81 + EXPECT_EQ("testType", getDevice(1).getType());
  82 +}
  83 +
  84 +TEST_F(BaseDeviceTest, getModelId)
  85 +{
  86 + EXPECT_EQ("TEST", getDevice(1).getModelId());
  87 +}
  88 +
  89 +TEST_F(BaseDeviceTest, getUId)
  90 +{
  91 + EXPECT_EQ("00:00:00:00:00:00:00:00-00", getDevice(1).getUId());
  92 + state.erase("uniqueid");
  93 + EXPECT_EQ("", getDevice(1).getUId());
  94 +}
  95 +
  96 +TEST_F(BaseDeviceTest, getManufacturername)
  97 +{
  98 + EXPECT_EQ("testManuf", getDevice(1).getManufacturername());
  99 + state.erase("manufacturername");
  100 + EXPECT_EQ("", getDevice(1).getManufacturername());
  101 +}
  102 +
  103 +TEST_F(BaseDeviceTest, getProductname)
  104 +{
  105 + EXPECT_EQ("Test type", getDevice(1).getProductname());
  106 + state.erase("productname");
  107 + EXPECT_EQ("", getDevice(1).getProductname());
  108 +}
  109 +
  110 +TEST_F(BaseDeviceTest, getSwVersion)
  111 +{
  112 + EXPECT_EQ("1.2.3.4", getDevice(1).getSwVersion());
  113 +}
  114 +
  115 +TEST_F(BaseDeviceTest, setName)
  116 +{
  117 + const std::string name = "asdbsdakfl";
  118 + const nlohmann::json request = {{"name", name}};
  119 + const nlohmann::json response = { {{"success", {{"/lights/1/name", name}}}} };
  120 +
  121 + TestDevice device = getDevice(1);
  122 + EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + path + "1/name", request, getBridgeIp(), getBridgePort()))
  123 + .WillOnce(Return(response));
  124 + EXPECT_TRUE(device.setName(name));
  125 +}
0 126 \ No newline at end of file
... ...
test/test_Bridge.cpp
... ... @@ -35,13 +35,13 @@
35 35  
36 36 using namespace hueplusplus;
37 37  
38   -class HueFinderTest : public ::testing::Test
  38 +class BridgeFinderTest : public ::testing::Test
39 39 {
40 40 protected:
41 41 std::shared_ptr<MockHttpHandler> handler;
42 42  
43 43 protected:
44   - HueFinderTest() : handler(std::make_shared<MockHttpHandler>())
  44 + BridgeFinderTest() : handler(std::make_shared<MockHttpHandler>())
45 45 {
46 46 using namespace ::testing;
47 47  
... ... @@ -59,10 +59,10 @@ protected:
59 59 .Times(AtLeast(1))
60 60 .WillRepeatedly(Return(getBridgeXml()));
61 61 }
62   - ~HueFinderTest() {};
  62 + ~BridgeFinderTest() {};
63 63 };
64 64  
65   -TEST_F(HueFinderTest, FindBridges)
  65 +TEST_F(BridgeFinderTest, FindBridges)
66 66 {
67 67 BridgeFinder finder(handler);
68 68 std::vector<BridgeFinder::BridgeIdentification> bridges = finder.FindBridges();
... ... @@ -85,7 +85,7 @@ TEST_F(HueFinderTest, FindBridges)
85 85 EXPECT_TRUE(bridges.empty());
86 86 }
87 87  
88   -TEST_F(HueFinderTest, GetBridge)
  88 +TEST_F(BridgeFinderTest, GetBridge)
89 89 {
90 90 using namespace ::testing;
91 91 nlohmann::json request {{"devicetype", "HuePlusPlus#User"}};
... ... @@ -120,7 +120,7 @@ TEST_F(HueFinderTest, GetBridge)
120 120 Mock::VerifyAndClearExpectations(handler.get());
121 121 }
122 122  
123   -TEST_F(HueFinderTest, AddUsername)
  123 +TEST_F(BridgeFinderTest, AddUsername)
124 124 {
125 125 BridgeFinder finder(handler);
126 126 std::vector<BridgeFinder::BridgeIdentification> bridges = finder.FindBridges();
... ... @@ -133,7 +133,7 @@ TEST_F(HueFinderTest, AddUsername)
133 133 EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
134 134 }
135 135  
136   -TEST_F(HueFinderTest, GetAllUsernames)
  136 +TEST_F(BridgeFinderTest, GetAllUsernames)
137 137 {
138 138 BridgeFinder finder(handler);
139 139 std::vector<BridgeFinder::BridgeIdentification> bridges = finder.FindBridges();
... ...
test/test_Sensor.cpp 0 โ†’ 100644
  1 +/**
  2 + \file test_Sensor.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <hueplusplus/Sensor.h>
  23 +
  24 +#include <gtest/gtest.h>
  25 +
  26 +#include "testhelper.h"
  27 +
  28 +#include "mocks/mock_HttpHandler.h"
  29 +
  30 +using namespace hueplusplus;
  31 +using namespace testing;
  32 +
  33 +class SensorTest : public Test
  34 +{
  35 +protected:
  36 + std::shared_ptr<MockHttpHandler> handler;
  37 + HueCommandAPI commands;
  38 + nlohmann::json state;
  39 +
  40 +protected:
  41 + SensorTest()
  42 + : handler(std::make_shared<MockHttpHandler>()),
  43 + commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
  44 + state({{"type", "testSensor"}, {"name", "Test sensor"}, {"swversion", "1.2.3.4"}, {"modelid", "test"},
  45 + {"manufacturername", "testManuf"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
  46 + {"productname", "Test sensor"}, {"config", nlohmann::json::object()},
  47 + {"state", nlohmann::json::object()}})
  48 + { }
  49 +
  50 + Sensor getSensor(int id = 1)
  51 + {
  52 + EXPECT_CALL(*handler,
  53 + GETJson(
  54 + "/api/" + getBridgeUsername() + "/sensors/" + std::to_string(id), _, getBridgeIp(), getBridgePort()))
  55 + .WillOnce(Return(state));
  56 + return Sensor(id, commands, std::chrono::steady_clock::duration::max());
  57 + }
  58 +};
  59 +
  60 +TEST(Alert, alertFromString)
  61 +{
  62 + EXPECT_EQ(Alert::none, alertFromString("none"));
  63 + EXPECT_EQ(Alert::select, alertFromString("select"));
  64 + EXPECT_EQ(Alert::lselect, alertFromString("lselect"));
  65 + EXPECT_EQ(Alert::none, alertFromString("anything"));
  66 +}
  67 +
  68 +TEST(Alert, alertToString)
  69 +{
  70 + EXPECT_EQ("none", alertToString(Alert::none));
  71 + EXPECT_EQ("select", alertToString(Alert::select));
  72 + EXPECT_EQ("lselect", alertToString(Alert::lselect));
  73 +}
  74 +
  75 +TEST_F(SensorTest, On)
  76 +{
  77 + EXPECT_FALSE(getSensor().hasOn());
  78 + state["config"]["on"] = true;
  79 + EXPECT_TRUE(getSensor().hasOn());
  80 + EXPECT_TRUE(getSensor().isOn());
  81 +
  82 + EXPECT_CALL(*handler,
  83 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"on", false}}), getBridgeIp(),
  84 + getBridgePort()))
  85 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/on", false}}}}}));
  86 + getSensor().setOn(false);
  87 +}
  88 +
  89 +TEST_F(SensorTest, BatteryState)
  90 +{
  91 + EXPECT_FALSE(getSensor().hasBatteryState());
  92 + state["config"]["battery"] = 90;
  93 + EXPECT_TRUE(getSensor().hasBatteryState());
  94 + EXPECT_EQ(90, getSensor().getBatteryState());
  95 +
  96 + int percent = 10;
  97 + EXPECT_CALL(*handler,
  98 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"battery", percent}}),
  99 + getBridgeIp(), getBridgePort()))
  100 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/battery", percent}}}}}));
  101 + getSensor().setBatteryState(percent);
  102 +}
  103 +
  104 +TEST_F(SensorTest, Alert)
  105 +{
  106 + EXPECT_FALSE(getSensor().hasAlert());
  107 + state["config"]["alert"] = "none";
  108 + EXPECT_TRUE(getSensor().hasAlert());
  109 + EXPECT_EQ(Alert::none, getSensor().getLastAlert());
  110 +
  111 + std::string alert = "lselect";
  112 + EXPECT_CALL(*handler,
  113 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"alert", alert}}), getBridgeIp(),
  114 + getBridgePort()))
  115 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/alert", alert}}}}}));
  116 + getSensor().sendAlert(Alert::lselect);
  117 +}
  118 +
  119 +TEST_F(SensorTest, Reachable)
  120 +{
  121 + EXPECT_FALSE(getSensor().hasReachable());
  122 + state["config"]["reachable"] = false;
  123 + EXPECT_TRUE(getSensor().hasReachable());
  124 + EXPECT_FALSE(getSensor().isReachable());
  125 +}
  126 +
  127 +TEST_F(SensorTest, UserTest)
  128 +{
  129 + EXPECT_FALSE(getSensor().hasUserTest());
  130 + state["config"]["usertest"] = false;
  131 + EXPECT_TRUE(getSensor().hasUserTest());
  132 +
  133 + EXPECT_CALL(*handler,
  134 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"usertest", true}}),
  135 + getBridgeIp(), getBridgePort()))
  136 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/usertest", true}}}}}));
  137 + getSensor().setUserTest(true);
  138 +}
  139 +
  140 +TEST_F(SensorTest, URL)
  141 +{
  142 + EXPECT_FALSE(getSensor().hasURL());
  143 + const std::string url = "https://abc";
  144 + state["config"]["url"] = url;
  145 + EXPECT_TRUE(getSensor().hasURL());
  146 + EXPECT_EQ(url, getSensor().getURL());
  147 +
  148 + std::string newUrl = "https://cde";
  149 + EXPECT_CALL(*handler,
  150 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"url", newUrl}}), getBridgeIp(),
  151 + getBridgePort()))
  152 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/url", newUrl}}}}}));
  153 + getSensor().setURL(newUrl);
  154 +}
  155 +
  156 +TEST_F(SensorTest, getPendingConfig)
  157 +{
  158 + EXPECT_TRUE(getSensor().getPendingConfig().empty());
  159 + state["config"]["pending"] = nullptr;
  160 + EXPECT_TRUE(getSensor().getPendingConfig().empty());
  161 +
  162 + state["config"]["pending"] = {"abc", "cde", "def"};
  163 +
  164 + EXPECT_THAT(getSensor().getPendingConfig(), UnorderedElementsAre("abc", "cde", "def"));
  165 +}
  166 +
  167 +TEST_F(SensorTest, LEDIndication)
  168 +{
  169 + EXPECT_FALSE(getSensor().hasLEDIndication());
  170 + state["config"]["ledindication"] = true;
  171 + EXPECT_TRUE(getSensor().hasLEDIndication());
  172 + EXPECT_TRUE(getSensor().getLEDIndication());
  173 +
  174 + EXPECT_CALL(*handler,
  175 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"ledindication", false}}),
  176 + getBridgeIp(), getBridgePort()))
  177 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/ledindication", false}}}}}));
  178 + getSensor().setLEDIndication(false);
  179 +}
  180 +
  181 +TEST_F(SensorTest, getConfig)
  182 +{
  183 + EXPECT_EQ(state["config"], getSensor().getConfig());
  184 + state["config"]["attribute"] = false;
  185 + EXPECT_EQ(state["config"], getSensor().getConfig());
  186 +}
  187 +
  188 +TEST_F(SensorTest, setConfigAttribute)
  189 +{
  190 + const std::string key = "attribute";
  191 + const nlohmann::json value = "some value";
  192 + EXPECT_CALL(*handler,
  193 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{key, value}}), getBridgeIp(),
  194 + getBridgePort()))
  195 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/" + key, value}}}}}));
  196 + getSensor().setConfigAttribute(key, value);
  197 +}
  198 +
  199 +TEST_F(SensorTest, getLastUpdated)
  200 +{
  201 + time::AbsoluteTime none = getSensor().getLastUpdated();
  202 + EXPECT_EQ(std::chrono::seconds(0), none.getBaseTime().time_since_epoch());
  203 +
  204 + const std::string timestamp = "2020-05-02T12:00:01";
  205 + state["state"]["lastupdated"] = timestamp;
  206 + time::AbsoluteTime time = time::AbsoluteTime::parseUTC(timestamp);
  207 + EXPECT_EQ(time.getBaseTime(), getSensor().getLastUpdated().getBaseTime());
  208 +}
  209 +
  210 +TEST_F(SensorTest, getState)
  211 +{
  212 + nlohmann::json stateContent = {{"bla", "bla"}};
  213 + state["state"] = stateContent;
  214 + EXPECT_EQ(stateContent, getSensor().getState());
  215 +}
  216 +
  217 +TEST_F(SensorTest, setStateAttribute)
  218 +{
  219 + const std::string key = "attribute";
  220 + const nlohmann::json value = "some value";
  221 + EXPECT_CALL(*handler,
  222 + PUTJson("/api/" + getBridgeUsername() + "/sensors/1/state", nlohmann::json({{key, value}}), getBridgeIp(),
  223 + getBridgePort()))
  224 + .WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/state/" + key, value}}}}}));
  225 + getSensor().setStateAttribute(key, value);
  226 +}
  227 +
  228 +TEST_F(SensorTest, isCertified)
  229 +{
  230 + EXPECT_FALSE(getSensor().isCertified());
  231 + state["capabilities"]["certified"] = true;
  232 + EXPECT_TRUE(getSensor().isCertified());
  233 +}
  234 +
  235 +TEST_F(SensorTest, isPrimary)
  236 +{
  237 + EXPECT_FALSE(getSensor().isPrimary());
  238 + state["capabilities"]["primary"] = true;
  239 + EXPECT_TRUE(getSensor().isPrimary());
  240 +}
  241 +
  242 +TEST_F(SensorTest, asSensorType)
  243 +{
  244 + // Test both rvalue and const access
  245 + {
  246 + const Sensor s = getSensor();
  247 + EXPECT_THROW(s.asSensorType<sensors::DaylightSensor>(), HueException);
  248 + }
  249 + EXPECT_THROW(getSensor().asSensorType<sensors::DaylightSensor>(), HueException);
  250 +
  251 + state["type"] = sensors::DaylightSensor::typeStr;
  252 + sensors::DaylightSensor ds = getSensor().asSensorType<sensors::DaylightSensor>();
  253 + EXPECT_EQ(1, ds.getId());
  254 + const Sensor s = getSensor();
  255 + ds = s.asSensorType<sensors::DaylightSensor>();
  256 + EXPECT_EQ(s.getId(), ds.getId());
  257 +}
... ...
test/test_SensorList.cpp 0 โ†’ 100644
  1 +/**
  2 + \file test_SensorList.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <gtest/gtest.h>
  23 +
  24 +#include "testhelper.h"
  25 +
  26 +#include "hueplusplus/SensorList.h"
  27 +#include "mocks/mock_HttpHandler.h"
  28 +
  29 +using namespace hueplusplus;
  30 +using namespace testing;
  31 +
  32 +class BlaSensor
  33 +{
  34 +public:
  35 + BlaSensor(Sensor s) { }
  36 +
  37 + static constexpr const char* typeStr = "bla";
  38 +};
  39 +
  40 +TEST(SensorList, getAsType)
  41 +{
  42 + auto handler = std::make_shared<MockHttpHandler>();
  43 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  44 +
  45 + SensorList sensors {commands, "/sensors", std::chrono::steady_clock::duration::max()};
  46 +
  47 + const int id = 2;
  48 + const nlohmann::json response = {{std::to_string(id), {{"type", "Daylight"}}}};
  49 +
  50 + EXPECT_CALL(*handler,
  51 + GETJson("/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  52 + .WillOnce(Return(response));
  53 + EXPECT_CALL(*handler,
  54 + GETJson("/api/" + getBridgeUsername() + "/sensors/" + std::to_string(id), nlohmann::json::object(),
  55 + getBridgeIp(), getBridgePort()))
  56 + .Times(2)
  57 + .WillRepeatedly(Return(nlohmann::json {{"type", "Daylight"}}));
  58 +
  59 + sensors::DaylightSensor daylightSensor = sensors.getAsType<sensors::DaylightSensor>(id);
  60 + EXPECT_THROW(sensors.getAsType<BlaSensor>(2), HueException);
  61 +}
  62 +
  63 +TEST(SensorList, getAllByType)
  64 +{
  65 +
  66 + auto handler = std::make_shared<MockHttpHandler>();
  67 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  68 +
  69 + SensorList sensors {commands, "/sensors", std::chrono::steady_clock::duration::max()};
  70 +
  71 + // Empty
  72 + {
  73 + const nlohmann::json response = nlohmann::json::object();
  74 +
  75 + EXPECT_CALL(*handler,
  76 + GETJson(
  77 + "/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  78 + .WillOnce(Return(response));
  79 + EXPECT_TRUE(sensors.getAllByType<sensors::DaylightSensor>().empty());
  80 + }
  81 + // Not matching
  82 + {
  83 + const nlohmann::json response = {{"1", {{"type", "stuff"}}}};
  84 + EXPECT_CALL(*handler,
  85 + GETJson(
  86 + "/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  87 + .WillOnce(Return(response));
  88 + sensors.refresh();
  89 + EXPECT_TRUE(sensors.getAllByType<sensors::DaylightSensor>().empty());
  90 + }
  91 + // Some matching (daylight maybe not the best example, because there is always exactly one)
  92 + {
  93 + const nlohmann::json response = {{"1", {{"type", "stuff"}}}, {"2", {{"type", "Daylight"}}},
  94 + {"3", {{"type", "stuff"}}}, {"4", {{"type", "Daylight"}}}};
  95 + EXPECT_CALL(*handler,
  96 + GETJson(
  97 + "/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  98 + .WillOnce(Return(response));
  99 + EXPECT_CALL(*handler,
  100 + GETJson(
  101 + "/api/" + getBridgeUsername() + "/sensors/2", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  102 + .WillOnce(Return(response["2"]));
  103 + EXPECT_CALL(*handler,
  104 + GETJson(
  105 + "/api/" + getBridgeUsername() + "/sensors/4", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  106 + .WillOnce(Return(response["4"]));
  107 + sensors.refresh();
  108 + std::vector<sensors::DaylightSensor> result = sensors.getAllByType<sensors::DaylightSensor>();
  109 + EXPECT_THAT(result,
  110 + UnorderedElementsAre(Truly([](const auto& s) { return s.getId() == 2; }),
  111 + Truly([](const auto& s) { return s.getId() == 4; })));
  112 + }
  113 +}
... ...