Commit 87bac0eee2eccd545a2ad5e9d382c4d222ef2fac

Authored by Jojo-1000
Committed by Jan
1 parent 77890282

Fix Hue::requestUsername exception on API error, update test.

hueplusplus/Hue.cpp
... ... @@ -179,33 +179,26 @@ std::string Hue::requestUsername()
179 179 {
180 180 lastCheck = std::chrono::steady_clock::now();
181 181 answer = http_handler->POSTJson("/api", request, ip, port);
182   -
183   - try
  182 + nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username");
  183 + if (jsonUser != nullptr)
184 184 {
185   - nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username");
186   - if (jsonUser != nullptr)
187   - {
188   - // [{"success":{"username": "<username>"}}]
189   - username = jsonUser;
190   - // Update commands with new username and ip
191   - commands = HueCommandAPI(ip, port, username, http_handler);
192   - std::cout << "Success! Link button was pressed!\n";
193   - std::cout << "Username is \"" << username << "\"\n";
194   - break;
195   - }
  185 + // [{"success":{"username": "<username>"}}]
  186 + username = jsonUser;
  187 + // Update commands with new username and ip
  188 + commands = HueCommandAPI(ip, port, username, http_handler);
  189 + std::cout << "Success! Link button was pressed!\n";
  190 + std::cout << "Username is \"" << username << "\"\n";
  191 + break;
196 192 }
197   - catch (const HueAPIResponseException& e)
  193 + else if (answer.size() > 0 && answer[0].count("error"))
198 194 {
199   - // 101: Link button not pressed
200   - if (e.GetErrorNumber() == 101)
  195 + // All errors except 101: Link button not pressed
  196 + if (utils::safeGetMember(answer, 0, "error", "type") != 101)
201 197 {
202   - std::cout << "Link button not pressed!\n";
203   - }
204   - else
205   - {
206   - throw;
  198 + throw HueAPIResponseException::Create(CURRENT_FILE_INFO, answer[0]);
207 199 }
208 200 }
  201 +
209 202 std::this_thread::sleep_until(lastCheck + std::chrono::seconds(1));
210 203 }
211 204 }
... ...
hueplusplus/HueCommandAPI.cpp
... ... @@ -112,10 +112,7 @@ nlohmann::json HueCommandAPI::HandleError(FileInfo fileInfo, const nlohmann::jso
112 112 {
113 113 if (response.count("error") != 0)
114 114 {
115   - int errorCode = response["type"];
116   - std::string address = response["address"];
117   - std::string description = response["description"];
118   - throw HueAPIResponseException(std::move(fileInfo), errorCode, std::move(address), std::move(description));
  115 + throw HueAPIResponseException::Create(std::move(fileInfo), response);
119 116 }
120 117 return response;
121 118 }
... ...
hueplusplus/HueException.cpp
... ... @@ -69,6 +69,15 @@ const std::string&amp; HueAPIResponseException::GetDescription() const noexcept
69 69 return description;
70 70 }
71 71  
  72 +HueAPIResponseException HueAPIResponseException::Create(FileInfo fileInfo, const nlohmann::json& response)
  73 +{
  74 + const nlohmann::json error = response["error"];
  75 + int errorCode = error["type"];
  76 + std::string address = error["address"];
  77 + std::string description = error["description"];
  78 + return HueAPIResponseException(std::move(fileInfo), errorCode, std::move(address), std::move(description));
  79 +}
  80 +
72 81 std::string HueAPIResponseException::GetMessage(int error, const std::string& addr, const std::string& description)
73 82 {
74 83 std::string result = std::to_string(error);
... ...
hueplusplus/include/HueException.h
... ... @@ -26,6 +26,8 @@
26 26 #include <exception>
27 27 #include <string>
28 28  
  29 +#include "json/json.hpp"
  30 +
29 31 //! \brief Contains information about error location, use CURRENT_FILE_INFO to create
30 32 struct FileInfo
31 33 {
... ... @@ -96,6 +98,12 @@ public:
96 98 //! \brief Error description
97 99 const std::string& GetDescription() const noexcept;
98 100  
  101 + //! \brief Creates exception from API response.
  102 + //! \param fileInfo Location of the cause
  103 + //! \param response Hue API response. Must contain a member "error" with "type", "address" and "description".
  104 + //! \returns HueAPIResponseException with info from the response.
  105 + static HueAPIResponseException Create(FileInfo fileInfo, const nlohmann::json& response);
  106 +
99 107 private:
100 108 //! \brief Creates exception message containing the given information
101 109 static std::string GetMessage(int error, const std::string& addr, const std::string& description);
... ...
hueplusplus/test/test_Hue.cpp
... ... @@ -57,7 +57,7 @@ protected:
57 57 .Times(AtLeast(1))
58 58 .WillRepeatedly(Return(getBridgeXml()));
59 59 }
60   - ~HueFinderTest() {};
  60 + ~HueFinderTest(){};
61 61 };
62 62  
63 63 TEST_F(HueFinderTest, FindBridges)
... ... @@ -86,35 +86,25 @@ TEST_F(HueFinderTest, FindBridges)
86 86 TEST_F(HueFinderTest, GetBridge)
87 87 {
88 88 using namespace ::testing;
89   - nlohmann::json request;
90   - request["devicetype"] = "HuePlusPlus#User";
  89 + nlohmann::json request{{"devicetype", "HuePlusPlus#User"}};
91 90  
92   - nlohmann::json user_ret_uns;
93   - user_ret_uns = nlohmann::json::array();
94   - user_ret_uns[0] = nlohmann::json::object();
95   - user_ret_uns[0]["error"] = nlohmann::json::object();
96   - user_ret_uns[0]["error"]["type"] = 101;
97   - user_ret_uns[0]["error"]["address"] = "";
98   - user_ret_uns[0]["error"]["description"] = "link button not pressed";
  91 + nlohmann::json errorResponse
  92 + = {{{"error", {{"type", 101}, {"address", ""}, {"description", "link button not pressed"}}}}};
99 93  
100 94 EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
101 95 .Times(AtLeast(1))
102   - .WillRepeatedly(Return(user_ret_uns));
  96 + .WillRepeatedly(Return(errorResponse));
103 97  
104 98 HueFinder finder(handler);
105 99 std::vector<HueFinder::HueIdentification> bridges = finder.FindBridges();
106 100  
107 101 ASSERT_THROW(finder.GetBridge(bridges[0]), HueException);
108 102  
109   - nlohmann::json user_ret_suc;
110   - user_ret_suc = nlohmann::json::array();
111   - user_ret_suc[0] = nlohmann::json::object();
112   - user_ret_suc[0]["success"] = nlohmann::json::object();
113   - user_ret_suc[0]["success"]["username"] = getBridgeUsername();
  103 + nlohmann::json successResponse = {{{"success", {{"username", getBridgeUsername()}}}}};
114 104  
115 105 EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
116 106 .Times(1)
117   - .WillOnce(Return(user_ret_suc));
  107 + .WillOnce(Return(successResponse));
118 108  
119 109 finder = HueFinder(handler);
120 110 bridges = finder.FindBridges();
... ... @@ -126,8 +116,7 @@ TEST_F(HueFinderTest, GetBridge)
126 116 EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
127 117  
128 118 // Verify that username is correctly set in api requests
129   - nlohmann::json hue_bridge_state;
130   - hue_bridge_state["lights"] = {};
  119 + nlohmann::json hue_bridge_state{{"lights", {}}};
131 120 EXPECT_CALL(
132 121 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
133 122 .Times(1)
... ... @@ -176,51 +165,59 @@ TEST(Hue, requestUsername)
176 165 {
177 166 using namespace ::testing;
178 167 std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
179   - nlohmann::json request;
180   - request["devicetype"] = "HuePlusPlus#User";
  168 + nlohmann::json request{{"devicetype", "HuePlusPlus#User"}};
181 169  
182   - nlohmann::json user_ret_uns;
183   - user_ret_uns = nlohmann::json::array();
184   - user_ret_uns[0] = nlohmann::json::object();
185   - user_ret_uns[0]["error"] = nlohmann::json::object();
186   - user_ret_uns[0]["error"]["type"] = 101;
187   - user_ret_uns[0]["error"]["address"] = "";
188   - user_ret_uns[0]["error"]["description"] = "link button not pressed";
  170 + {
  171 + nlohmann::json errorResponse
  172 + = {{{"error", {{"type", 101}, {"address", ""}, {"description", "link button not pressed"}}}}};
189 173  
190   - EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
191   - .Times(AtLeast(1))
192   - .WillRepeatedly(Return(user_ret_uns));
  174 + EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
  175 + .Times(AtLeast(1))
  176 + .WillRepeatedly(Return(errorResponse));
193 177  
194   - Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler);
  178 + Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler);
195 179  
196   - test_bridge.requestUsername();
197   - EXPECT_EQ(test_bridge.getUsername(), "") << "Bridge username not matching";
  180 + std::string username = test_bridge.requestUsername();
  181 + EXPECT_EQ(username, "") << "Returned username not matching";
  182 + EXPECT_EQ(test_bridge.getUsername(), "") << "Bridge username not matching";
  183 + }
198 184  
199   - nlohmann::json user_ret_suc;
200   - user_ret_suc = nlohmann::json::array();
201   - user_ret_suc[0] = nlohmann::json::object();
202   - user_ret_suc[0]["success"] = nlohmann::json::object();
203   - user_ret_suc[0]["success"]["username"] = getBridgeUsername();
204   - EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
205   - .Times(1)
206   - .WillRepeatedly(Return(user_ret_suc));
  185 + {
  186 + // Other error code causes exception
  187 + int otherError = 1;
  188 + nlohmann::json exceptionResponse
  189 + = {{{"error", {{"type", otherError}, {"address", ""}, {"description", "some error"}}}}};
  190 + Hue testBridge(getBridgeIp(), getBridgePort(), "", handler);
207 191  
208   - test_bridge = Hue(getBridgeIp(), getBridgePort(), "", handler);
  192 + EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
  193 + .WillOnce(Return(exceptionResponse));
209 194  
210   - test_bridge.requestUsername();
  195 + EXPECT_THROW(testBridge.requestUsername(), HueAPIResponseException);
  196 + }
211 197  
212   - EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
213   - EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
  198 + {
  199 + nlohmann::json successResponse = {{{"success", {{"username", getBridgeUsername()}}}}};
  200 + EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
  201 + .Times(1)
  202 + .WillRepeatedly(Return(successResponse));
214 203  
215   - // Verify that username is correctly set in api requests
216   - nlohmann::json hue_bridge_state;
217   - hue_bridge_state["lights"] = {};
218   - EXPECT_CALL(
219   - *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
220   - .Times(1)
221   - .WillOnce(Return(hue_bridge_state));
  204 + Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler);
222 205  
223   - test_bridge.getAllLights();
  206 + std::string username = test_bridge.requestUsername();
  207 +
  208 + EXPECT_EQ(username, test_bridge.getUsername()) << "Returned username not matching";
  209 + EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
  210 + EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
  211 +
  212 + // Verify that username is correctly set in api requests
  213 + nlohmann::json hue_bridge_state{{"lights", {}}};
  214 + EXPECT_CALL(
  215 + *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  216 + .Times(1)
  217 + .WillOnce(Return(hue_bridge_state));
  218 +
  219 + test_bridge.getAllLights();
  220 + }
224 221 }
225 222  
226 223 TEST(Hue, setIP)
... ...