1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <utility>
17
18 #include "gtest/gtest.h"
19 // For testing private method
20 #include "nlohmann/json.hpp"
21 #define private public
22 #include "frontend_api_handler.h"
23 #undef private
24 #include "dummy_controller.h"
25 #include "widget_selector.h"
26 #include "ui_driver.h"
27
28 using namespace OHOS::uitest;
29 using namespace std;
30 using namespace nlohmann;
31
32 vector<shared_ptr<UiEventListener>> DummyEventMonitor::listeners_;
33
34 // test fixture
35 class FrontendApiHandlerTest : public testing::Test {
36 public:
37 ~FrontendApiHandlerTest() override = default;
38 protected:
SetUp()39 void SetUp() override
40 {
41 auto dummyController = make_unique<DummyController>();
42 dummyController->SetWorkable(true);
43 UiDriver::RegisterController(move(dummyController));
44 }
45
TearDown()46 void TearDown() override
47 {
48 // common-preprocessors works on all apiCall, delete after testing
49 FrontendApiServer::Get().RemoveCommonPreprocessor("dummyProcessor");
50 }
51 };
52
TEST_F(FrontendApiHandlerTest,basicJsonReadWrite)53 TEST_F(FrontendApiHandlerTest, basicJsonReadWrite)
54 {
55 auto container = json::array();
56 // write
57 container.emplace_back("wyz");
58 container.emplace_back(1);
59 container.emplace_back(0.1);
60 container.emplace_back(true);
61 container.emplace_back(nullptr);
62 // read
63 ASSERT_EQ(5, container.size());
64 ASSERT_EQ("wyz", container.at(INDEX_ZERO).get<string>());
65 ASSERT_EQ(1, container.at(INDEX_ONE).get<uint8_t>());
66 ASSERT_NEAR(0.1, container.at(INDEX_TWO).get<float>(), 1E-6);
67 ASSERT_EQ(true, container.at(INDEX_THREE).get<bool>());
68 ASSERT_EQ(nlohmann::detail::value_t::null, container.at(INDEX_FOUR).type());
69 }
70
GenerateUniqueId()71 static string GenerateUniqueId()
72 {
73 return to_string(GetCurrentMicroseconds());
74 }
75
TEST_F(FrontendApiHandlerTest,noInvocationHandler)76 TEST_F(FrontendApiHandlerTest, noInvocationHandler)
77 {
78 static auto apiId = GenerateUniqueId();
79 auto call = ApiCallInfo {.apiId_ = "wyz"};
80 auto reply = ApiReplyInfo();
81 FrontendApiServer::Get().Call(call, reply);
82 ASSERT_EQ(ERR_INTERNAL, reply.exception_.code_);
83 ASSERT_TRUE(reply.exception_.message_.find("No handler found") != string::npos);
84 }
85
TEST_F(FrontendApiHandlerTest,addRemoveHandler)86 TEST_F(FrontendApiHandlerTest, addRemoveHandler)
87 {
88 static auto apiId = GenerateUniqueId();
89 auto &server = FrontendApiServer::Get();
90 ASSERT_FALSE(server.HasHandlerFor(apiId));
91 auto handler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
92 // nop
93 };
94 server.AddHandler(apiId, handler);
95 ASSERT_TRUE(server.HasHandlerFor(apiId));
96
97 json caller;
98 auto call = ApiCallInfo {.apiId_ = apiId};
99 auto reply = ApiReplyInfo();
100 server.Call(call, reply);
101 ASSERT_EQ(NO_ERROR, reply.exception_.code_);
102
103 server.RemoveHandler(apiId);
104 ASSERT_FALSE(server.HasHandlerFor(apiId));
105 server.Call(call, reply);
106 ASSERT_EQ(ERR_INTERNAL, reply.exception_.code_) << "The handler should be unavailable after been removed";
107 }
108
TEST_F(FrontendApiHandlerTest,inOutDataTransfer)109 TEST_F(FrontendApiHandlerTest, inOutDataTransfer)
110 {
111 static auto apiId = GenerateUniqueId();
112 auto &server = FrontendApiServer::Get();
113 auto handler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
114 out.resultValue_ = in.paramList_.at(0).get<string>().length() + in.paramList_.at(1).get<uint8_t>();
115 };
116 server.AddHandler(apiId, handler);
117
118 auto call = ApiCallInfo {.apiId_ = apiId};
119 auto reply = ApiReplyInfo();
120 call.paramList_.emplace_back("wyz");
121 call.paramList_.emplace_back(10);
122 server.Call(call, reply);
123 ASSERT_EQ(NO_ERROR, reply.exception_.code_);
124 ASSERT_EQ(string("wyz").length() + 10, reply.resultValue_.get<uint8_t>());
125 }
126
TEST_F(FrontendApiHandlerTest,jsonExceptionDefance)127 TEST_F(FrontendApiHandlerTest, jsonExceptionDefance)
128 {
129 static auto apiId = GenerateUniqueId();
130 auto &server = FrontendApiServer::Get();
131 auto handler = [](const ApiCallInfo &in, ApiReplyInfo &out) {
132 out.resultValue_ = in.paramList_.at(100).get<uint8_t>();
133 };
134 server.AddHandler(apiId, handler);
135
136 auto call = ApiCallInfo {.apiId_ = apiId};
137 auto reply = ApiReplyInfo();
138 server.Call(call, reply);
139 // json exception should be caught and reported properly
140 ASSERT_EQ(ERR_INTERNAL, reply.exception_.code_);
141 ASSERT_TRUE(reply.exception_.message_.find("json.exception.out_of_range") != string::npos);
142 }
143
TEST_F(FrontendApiHandlerTest,apiErrorDeliver)144 TEST_F(FrontendApiHandlerTest, apiErrorDeliver)
145 {
146 static auto apiId = GenerateUniqueId();
147 auto &server = FrontendApiServer::Get();
148 auto handler = [](const ApiCallInfo &in, ApiReplyInfo &out) { out.exception_.code_ = USAGE_ERROR; };
149 server.AddHandler(apiId, handler);
150
151 auto call = ApiCallInfo {.apiId_ = apiId};
152 auto reply = ApiReplyInfo();
153 server.Call(call, reply);
154 // api error should be delivered out to caller
155 ASSERT_EQ(USAGE_ERROR, reply.exception_.code_);
156 }
157
TEST_F(FrontendApiHandlerTest,commonPreprocessor)158 TEST_F(FrontendApiHandlerTest, commonPreprocessor)
159 {
160 static auto apiId = GenerateUniqueId();
161 auto &server = FrontendApiServer::Get();
162 auto handlerCalled = false;
163 auto handler = [&handlerCalled](const ApiCallInfo &in, ApiReplyInfo &out) { handlerCalled = true; };
164 server.AddHandler(apiId, handler);
165
166 auto processor = [](const ApiCallInfo &in, ApiReplyInfo &out) {
167 if (in.paramList_.at(0).get<string>() == "oops") {
168 out.exception_.code_ = ERR_OPERATION_UNSUPPORTED;
169 }
170 };
171 server.AddCommonPreprocessor("dummyProcessor", processor);
172
173 auto call = ApiCallInfo {.apiId_ = apiId};
174 auto reply = ApiReplyInfo();
175 // handler should be called if preprocessing passed
176 call.paramList_.emplace_back("nice");
177 server.Call(call, reply);
178 ASSERT_EQ(NO_ERROR, reply.exception_.code_);
179 ASSERT_TRUE(handlerCalled);
180 // preprocessing failed, handler should not be called
181 call.paramList_.clear();
182 call.paramList_.emplace_back("oops");
183 handlerCalled = false;
184 server.Call(call, reply);
185 ASSERT_EQ(ERR_OPERATION_UNSUPPORTED, reply.exception_.code_);
186 ASSERT_FALSE(handlerCalled);
187 }
188
TEST_F(FrontendApiHandlerTest,checkAllHandlersRegisted)189 TEST_F(FrontendApiHandlerTest, checkAllHandlersRegisted)
190 {
191 auto &server = FrontendApiServer::Get();
192 // each frontend-api should have handler
193 for (const auto &classDef : FRONTEND_CLASS_DEFS) {
194 for (size_t idx = 0; idx < classDef->methodCount_; idx++) {
195 const auto &methodDef = classDef->methods_[idx];
196 if (methodDef.name_ == "UiWindow.isActived") {
197 continue;
198 }
199 const auto message = "No handler registered for '" + string(methodDef.name_) + "'";
200 ASSERT_TRUE(server.HasHandlerFor(methodDef.name_)) << message;
201 }
202 }
203 }
204
205 // API8 end to end call test
TEST_F(FrontendApiHandlerTest,callApiE2EOldAPi)206 TEST_F(FrontendApiHandlerTest, callApiE2EOldAPi)
207 {
208 const auto& server = FrontendApiServer::Get();
209 // create by1 with seed
210 auto call0 = ApiCallInfo {.apiId_ = "By.text", .callerObjRef_ = string(REF_SEED_BY)};
211 call0.paramList_.emplace_back("wyz");
212 auto reply0 = ApiReplyInfo();
213 server.Call(call0, reply0);
214 // check result
215 ASSERT_EQ(NO_ERROR, reply0.exception_.code_);
216 ASSERT_EQ(nlohmann::detail::value_t::string, reply0.resultValue_.type()); // should return backend-by-ref
217 const auto ref0 = reply0.resultValue_.get<string>();
218 ASSERT_TRUE(ref0.find("By#") != string::npos);
219
220 // go on creating combine by: isAfter (after ref0)
221 auto call1 = ApiCallInfo {.apiId_ = "By.isAfter", .callerObjRef_ = string(REF_SEED_BY)};
222 call1.paramList_.emplace_back(ref0);
223 auto reply1 = ApiReplyInfo();
224 server.Call(call1, reply1);
225 ASSERT_EQ(NO_ERROR, reply1.exception_.code_);
226 ASSERT_EQ(nlohmann::detail::value_t::string, reply1.resultValue_.type()); // should return backend-by-ref
227 const auto ref1 = reply1.resultValue_.get<string>();
228 ASSERT_TRUE(ref1.find("By#") != string::npos);
229 // should always return a new By
230 ASSERT_NE(ref0, ref1);
231
232 auto call2 = ApiCallInfo {.apiId_ = "UiDriver.create", .callerObjRef_ = string()};
233 auto reply2 = ApiReplyInfo();
234 server.Call(call2, reply2);
235 ASSERT_EQ(NO_ERROR, reply2.exception_.code_);
236 ASSERT_EQ(nlohmann::detail::value_t::string, reply2.resultValue_.type()); // should return backend-On-ref
237 const auto ref2 = reply2.resultValue_.get<string>();
238 ASSERT_TRUE(ref2.find("UiDriver#") != string::npos);
239
240 auto call3 = ApiCallInfo {.apiId_ = "By.id", .callerObjRef_ = string(REF_SEED_BY)};
241 call3.paramList_.emplace_back(1);
242 auto reply3 = ApiReplyInfo();
243 server.Call(call3, reply3);
244 // check result
245 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
246 ASSERT_EQ(nlohmann::detail::value_t::string, reply3.resultValue_.type()); // should return backend-by-ref
247 const auto ref3 = reply3.resultValue_.get<string>();
248 ASSERT_TRUE(ref3.find("By#") != string::npos);
249
250 auto call4 = ApiCallInfo {.apiId_ = "By.key", .callerObjRef_ = string(REF_SEED_BY)};
251 call4.paramList_.emplace_back("1");
252 auto reply4 = ApiReplyInfo();
253 server.Call(call4, reply4);
254 // check result
255 ASSERT_EQ(NO_ERROR, reply4.exception_.code_);
256 ASSERT_EQ(nlohmann::detail::value_t::string, reply4.resultValue_.type()); // should return backend-by-ref
257 const auto ref4 = reply4.resultValue_.get<string>();
258 ASSERT_TRUE(ref4.find("By#") != string::npos);
259 }
260
261 // API9+ end to end call test
TEST_F(FrontendApiHandlerTest,callApiE2E)262 TEST_F(FrontendApiHandlerTest, callApiE2E)
263 {
264 const auto& server = FrontendApiServer::Get();
265
266 // create by1 with seed
267 auto call0 = ApiCallInfo {.apiId_ = "On.text", .callerObjRef_ = string(REF_SEED_BY)};
268 call0.paramList_.emplace_back("wyz");
269 auto reply0 = ApiReplyInfo();
270 server.Call(call0, reply0);
271 // check result
272 ASSERT_EQ(NO_ERROR, reply0.exception_.code_);
273 ASSERT_EQ(nlohmann::detail::value_t::string, reply0.resultValue_.type()); // should return backend-On-ref
274 const auto ref0 = reply0.resultValue_.get<string>();
275 ASSERT_TRUE(ref0.find("On#") != string::npos);
276
277 // go on creating combine by: isAfter (after ref0)
278 auto call1 = ApiCallInfo {.apiId_ = "On.isAfter", .callerObjRef_ = string(REF_SEED_BY)};
279 call1.paramList_.emplace_back(ref0);
280 auto reply1 = ApiReplyInfo();
281 server.Call(call1, reply1);
282 // check result
283 ASSERT_EQ(NO_ERROR, reply1.exception_.code_);
284 ASSERT_EQ(nlohmann::detail::value_t::string, reply1.resultValue_.type()); // should return backend-On-ref
285 const auto ref1 = reply1.resultValue_.get<string>();
286 ASSERT_TRUE(ref1.find("On#") != string::npos);
287 ASSERT_NE(ref0, ref1);
288
289 // should always return a new By
290 auto call2 = ApiCallInfo {.apiId_ = "Driver.create", .callerObjRef_ = string()};
291 auto reply2 = ApiReplyInfo();
292 server.Call(call2, reply2);
293 ASSERT_EQ(NO_ERROR, reply2.exception_.code_);
294 ASSERT_EQ(nlohmann::detail::value_t::string, reply2.resultValue_.type()); // should return backend-On-ref
295 const auto ref2 = reply2.resultValue_.get<string>();
296 ASSERT_TRUE(ref2.find("Driver#") != string::npos);
297
298 auto call3 = ApiCallInfo {.apiId_ = "On.id", .callerObjRef_ = string(REF_SEED_BY)};
299 call3.paramList_.emplace_back("1");
300 auto reply3 = ApiReplyInfo();
301 server.Call(call3, reply3);
302 // check result
303 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
304 ASSERT_EQ(nlohmann::detail::value_t::string, reply3.resultValue_.type()); // should return backend-by-ref
305 const auto ref3 = reply3.resultValue_.get<string>();
306 ASSERT_TRUE(ref3.find("On#") != string::npos);
307 }
308
309 // FrontendAPiServer::ApiMapPre and ApiMapPost Test (Used for old api adaptation)
TEST_F(FrontendApiHandlerTest,apiMapTest)310 TEST_F(FrontendApiHandlerTest, apiMapTest) {
311 const auto& server = FrontendApiServer::Get();
312 auto call0 = ApiCallInfo {.apiId_ = "UiDriver.findComponent", .callerObjRef_ = "UiDriver#0"};
313 call0.paramList_.emplace_back("By#1");
314 string oldApiName = server.ApiMapPre(call0);
315 // Call_id and callerObjRef should be converted correctly.
316 // Object parameters and object return value should be converted.
317 ASSERT_EQ(call0.paramList_.at(0).get<string>(), "On#1");
318 ASSERT_EQ(call0.apiId_, "Driver.findComponent");
319 ASSERT_EQ(call0.callerObjRef_, "Driver#0");
320 ASSERT_EQ(oldApiName, "UiDriver.findComponent");
321 auto reply0 = ApiReplyInfo();
322 reply0.resultValue_ = "Component#1";
323 server.ApiMapPost(oldApiName, reply0);
324 ASSERT_EQ(reply0.resultValue_.get<string>(), "UiComponent#1");
325
326 oldApiName = "UiDriver.findComponents";
327 auto reply1 = ApiReplyInfo();
328 reply1.resultValue_ = nlohmann::json::array();
329 reply1.resultValue_.emplace_back("Component#0");
330 reply1.resultValue_.emplace_back("Component#1");
331 server.ApiMapPost(oldApiName, reply1);
332 // Object array return value should be converted;
333 ASSERT_EQ(reply1.resultValue_.at(0).get<string>(), "UiComponent#0");
334 ASSERT_EQ(reply1.resultValue_.at(1).get<string>(), "UiComponent#1");
335
336 auto call1 = ApiCallInfo {.apiId_ = "By.text", .callerObjRef_ = "By#seed"};
337 call1.paramList_.emplace_back("By#0");
338 oldApiName = server.ApiMapPre(call1);
339 // String parameters should NOT be converted;
340 ASSERT_EQ(call1.apiId_, "On.text");
341 ASSERT_EQ(call1.callerObjRef_, "On#seed");
342 ASSERT_EQ(call1.paramList_.at(0).get<string>(), "By#0");
343 ASSERT_EQ(oldApiName, "By.text");
344
345 auto call2 = ApiCallInfo {.apiId_ = "UiComponent.getText", .callerObjRef_ = "UiComponent#0"};
346 oldApiName = server.ApiMapPre(call2);
347 // String return value should NOT be converted.
348 ASSERT_EQ(call2.apiId_, "Component.getText");
349 ASSERT_EQ(call2.callerObjRef_, "Component#0");
350 ASSERT_EQ(oldApiName, "UiComponent.getText");
351 auto reply2 = ApiReplyInfo();
352 reply2.resultValue_ = "Component#0";
353 server.ApiMapPost(oldApiName, reply2);
354 ASSERT_EQ(reply2.resultValue_.get<string>(), "Component#0");
355
356 auto call3 = ApiCallInfo {.apiId_ = "Component.getText", .callerObjRef_ = "Component#0"};
357 oldApiName = server.ApiMapPre(call3);
358 // New API should NOT be converted.
359 ASSERT_EQ(call3.apiId_, "Component.getText");
360 ASSERT_EQ(call3.callerObjRef_, "Component#0");
361 ASSERT_EQ(oldApiName, "");
362
363 // Test special apiId_ mapping
364 ApiCallInfo calls[] = {
365 {.apiId_ = "By.id", .callerObjRef_ = "By#0"},
366 {.apiId_ = "By.key", .callerObjRef_ = "By#0"},
367 {.apiId_ = "UiComponent.getId", .callerObjRef_ = "UiComponent#0"},
368 {.apiId_ = "UiComponent.getKey", .callerObjRef_ = "UiComponent#0"}
369 };
370 string expectedResults[] = {
371 "On.accessibilityId",
372 "On.id",
373 "Component.getAccessibilityId",
374 "Component.getId"
375 };
376 for (size_t i = 0; i < sizeof(calls) / sizeof(ApiCallInfo); i++) {
377 server.ApiMapPre(calls[i]);
378 ASSERT_EQ(calls[i].apiId_, expectedResults[i]);
379 }
380 }
381
TEST_F(FrontendApiHandlerTest,parameterPreChecks1)382 TEST_F(FrontendApiHandlerTest, parameterPreChecks1)
383 {
384 const auto& server = FrontendApiServer::Get();
385 // set the optional parameter as undefined.
386 auto call0 = ApiCallInfo {.apiId_ = "On.text", .callerObjRef_ = string(REF_SEED_BY)};
387 call0.paramList_.emplace_back("wyz");
388 call0.paramList_.emplace_back(nullptr);
389 auto reply0 = ApiReplyInfo();
390 server.Call(call0, reply0);
391 ASSERT_EQ(NO_ERROR, reply0.exception_.code_);
392 // set the mandatory parameter as undefined.
393 auto call1 = ApiCallInfo {.apiId_ = "On.type", .callerObjRef_ = string(REF_SEED_BY)};
394 call1.paramList_.emplace_back(nullptr);
395 auto reply1 = ApiReplyInfo();
396 server.Call(call1, reply1);
397 ASSERT_EQ(ERR_INVALID_INPUT, reply1.exception_.code_);
398 ASSERT_TRUE(reply1.exception_.message_.find("failed: Expect string") != string::npos);
399 // set the mandatory parameter of FRONTEND_JSON_DEFS as undefined.
400 auto call3 = ApiCallInfo {.apiId_ = "Driver.create"};
401 auto reply3 = ApiReplyInfo();
402 server.Call(call3, reply3);
403 auto call4 = ApiCallInfo {.apiId_ = "Driver.click", .callerObjRef_ = reply3.resultValue_.get<string>()};
404 auto arg1 = json();
405 arg1["x"] = 1;
406 arg1["y"] = "null";
407 call4.paramList_.emplace_back(arg1);
408 auto reply4 = ApiReplyInfo();
409 server.Call(call4, reply4);
410 ASSERT_EQ(ERR_INVALID_INPUT, reply4.exception_.code_);
411 ASSERT_TRUE(reply1.exception_.message_.find("failed: Expect string") != string::npos);
412 // set the optional parameter of FRONTEND_JSON_DEFS as undefined.
413 auto call5 = ApiCallInfo {.apiId_ = "Driver.findWindow", .callerObjRef_ = reply3.resultValue_.get<string>()};
414 auto arg2 = json();
415 arg2["bundleName"] = "xyz";
416 arg2["title"] = "null";
417 call5.paramList_.emplace_back(arg2);
418 auto reply5 = ApiReplyInfo();
419 server.Call(call5, reply5);
420 // cheak parameter pass, but updateUi failed.
421 ASSERT_EQ("Get window nodes failed", reply5.exception_.message_);
422 }
423
TEST_F(FrontendApiHandlerTest,parameterPreChecks2)424 TEST_F(FrontendApiHandlerTest, parameterPreChecks2)
425 {
426 const auto& server = FrontendApiServer::Get();
427 // call with argument missing
428 auto call0 = ApiCallInfo {.apiId_ = "By.type", .callerObjRef_ = string(REF_SEED_BY)};
429 auto reply0 = ApiReplyInfo();
430 server.Call(call0, reply0);
431 ASSERT_EQ(USAGE_ERROR, reply0.exception_.code_);
432 ASSERT_TRUE(reply0.exception_.message_.find("Illegal argument count") != string::npos);
433 // call with argument redundant
434 auto call1 = ApiCallInfo {.apiId_ = "By.type", .callerObjRef_ = string(REF_SEED_BY)};
435 auto reply1 = ApiReplyInfo();
436 call1.paramList_.emplace_back("wyz");
437 call1.paramList_.emplace_back(1);
438 call1.paramList_.emplace_back(1);
439 server.Call(call1, reply1);
440 ASSERT_EQ(USAGE_ERROR, reply1.exception_.code_);
441 ASSERT_TRUE(reply1.exception_.message_.find("Illegal argument count") != string::npos);
442 // call with argument of wrong type
443 auto call2 = ApiCallInfo {.apiId_ = "By.type", .callerObjRef_ = string(REF_SEED_BY)};
444 auto reply2 = ApiReplyInfo();
445 call2.paramList_.emplace_back(1);
446 server.Call(call2, reply2);
447 ASSERT_EQ(USAGE_ERROR, reply2.exception_.code_);
448 ASSERT_TRUE(reply2.exception_.message_.find("Expect string") != string::npos);
449 // call with argument defaulted (bool=true)
450 auto call3 = ApiCallInfo {.apiId_ = "By.enabled", .callerObjRef_ = string(REF_SEED_BY)};
451 auto reply3 = ApiReplyInfo();
452 call3.paramList_.emplace_back(true); // no defaulted
453 server.Call(call3, reply3);
454 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
455
456 auto call4 = ApiCallInfo {.apiId_ = "By.enabled", .callerObjRef_ = string(REF_SEED_BY)};
457 auto reply4 = ApiReplyInfo(); // defaulted
458 server.Call(call4, reply4);
459 ASSERT_EQ(NO_ERROR, reply4.exception_.code_);
460 // call with bad object ref
461 auto call5 = ApiCallInfo {.apiId_ = "By.isAfter", .callerObjRef_ = string(REF_SEED_BY)};
462 call5.paramList_.emplace_back("By#100");
463 auto reply5 = ApiReplyInfo();
464 server.Call(call5, reply5);
465 ASSERT_EQ(INTERNAL_ERROR, reply5.exception_.code_); // bad-object is internal_error
466 ASSERT_TRUE(reply5.exception_.message_.find("Bad object ref") != string::npos);
467 // call with json param with wrong property
468 auto call6 = ApiCallInfo {.apiId_ = "UiDriver.create"};
469 auto reply6 = ApiReplyInfo();
470 server.Call(call6, reply6);
471 auto call7 = ApiCallInfo {.apiId_ = "UiDriver.findWindow", .callerObjRef_ = reply6.resultValue_.get<string>()};
472 auto arg = json();
473 arg["badProp"] = "wyz";
474 call7.paramList_.emplace_back(arg);
475 auto reply7 = ApiReplyInfo();
476 server.Call(call7, reply7);
477 ASSERT_EQ(USAGE_ERROR, reply7.exception_.code_);
478 ASSERT_TRUE(reply7.exception_.message_.find("Illegal property") != string::npos);
479 }
480
TEST_F(FrontendApiHandlerTest,parameterPreChecks3)481 TEST_F(FrontendApiHandlerTest, parameterPreChecks3)
482 {
483 const auto& server = FrontendApiServer::Get();
484 auto call0 = ApiCallInfo {.apiId_ = "UiDriver.create"};
485 auto reply0 = ApiReplyInfo();
486 server.Call(call0, reply0);
487
488 auto call1 = ApiCallInfo {.apiId_ = "UiDriver.delayMs", .callerObjRef_ = reply0.resultValue_.get<string>()};
489 call1.paramList_.emplace_back(-100);
490 auto reply1 = ApiReplyInfo();
491 server.Call(call1, reply1);
492 ASSERT_TRUE(reply1.exception_.message_.find("Expect integer which cannot be less than 0") != string::npos);
493 }
494
TEST_F(FrontendApiHandlerTest,parameterPreChecks4)495 TEST_F(FrontendApiHandlerTest, parameterPreChecks4)
496 {
497 const auto& server = FrontendApiServer::Get();
498 // call with argument missing
499 auto call0 = ApiCallInfo {.apiId_ = "On.id", .callerObjRef_ = string(REF_SEED_BY)};
500 auto reply0 = ApiReplyInfo();
501 server.Call(call0, reply0);
502 ASSERT_EQ(ERR_INVALID_INPUT, reply0.exception_.code_);
503 ASSERT_TRUE(reply0.exception_.message_.find("Illegal argument count") != string::npos);
504 // call with argument redundant
505 auto call1 = ApiCallInfo {.apiId_ = "On.id", .callerObjRef_ = string(REF_SEED_BY)};
506 auto reply1 = ApiReplyInfo();
507 call1.paramList_.emplace_back("wyz");
508 call1.paramList_.emplace_back(1);
509 call1.paramList_.emplace_back(1);
510 server.Call(call1, reply1);
511 ASSERT_EQ(ERR_INVALID_INPUT, reply1.exception_.code_);
512 ASSERT_TRUE(reply1.exception_.message_.find("Illegal argument count") != string::npos);
513 // call with argument of wrong type
514 auto call2 = ApiCallInfo {.apiId_ = "On.text", .callerObjRef_ = string(REF_SEED_BY)};
515 auto reply2 = ApiReplyInfo();
516 call2.paramList_.emplace_back(1);
517 server.Call(call2, reply2);
518 ASSERT_EQ(ERR_INVALID_INPUT, reply2.exception_.code_);
519 ASSERT_TRUE(reply2.exception_.message_.find("Expect string") != string::npos);
520 // call with argument of wrong type
521 auto call3 = ApiCallInfo {.apiId_ = "On.text", .callerObjRef_ = string(REF_SEED_BY)};
522 auto reply3 = ApiReplyInfo();
523 call3.paramList_.emplace_back("text");
524 call3.paramList_.emplace_back("REG_EXP");
525 server.Call(call3, reply3);
526 ASSERT_EQ(ERR_INVALID_INPUT, reply3.exception_.code_);
527 ASSERT_TRUE(reply3.exception_.message_.find("Expect integer") != string::npos);
528 }
529
TEST_F(FrontendApiHandlerTest,pointerMatrixparameterPreChecks)530 TEST_F(FrontendApiHandlerTest, pointerMatrixparameterPreChecks)
531 {
532 const auto& server = FrontendApiServer::Get();
533 // call with argument llegal fingers
534 auto call0 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
535 auto reply0 = ApiReplyInfo();
536 call0.paramList_.emplace_back(11);
537 call0.paramList_.emplace_back(3);
538 server.Call(call0, reply0);
539 ASSERT_EQ(ERR_INVALID_INPUT, reply0.exception_.code_);
540 ASSERT_TRUE(reply0.exception_.message_.find("Number of illegal fingers") != string::npos);
541 // call with argument illegal steps
542 auto call2 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
543 auto reply2 = ApiReplyInfo();
544 call2.paramList_.emplace_back(2);
545 call2.paramList_.emplace_back(1001);
546 server.Call(call2, reply2);
547 ASSERT_EQ(ERR_INVALID_INPUT, reply2.exception_.code_);
548 ASSERT_TRUE(reply2.exception_.message_.find("Number of illegal steps") != string::npos);
549 // call with argument illegal steps
550 auto call4 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
551 auto reply4 = ApiReplyInfo();
552 call4.paramList_.emplace_back(5);
553 call4.paramList_.emplace_back(0);
554 server.Call(call4, reply4);
555 ASSERT_EQ(ERR_INVALID_INPUT, reply4.exception_.code_);
556 ASSERT_TRUE(reply4.exception_.message_.find("Number of illegal steps") != string::npos);
557 // call with argument illegal fingers
558 auto call5 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
559 auto reply5 = ApiReplyInfo();
560 call5.paramList_.emplace_back(0);
561 call5.paramList_.emplace_back(5);
562 server.Call(call5, reply5);
563 ASSERT_EQ(ERR_INVALID_INPUT, reply5.exception_.code_);
564 ASSERT_TRUE(reply5.exception_.message_.find("Number of illegal fingers") != string::npos);
565 // call with argument illegal fingers
566 auto call6 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
567 auto reply6 = ApiReplyInfo();
568 call6.paramList_.emplace_back(0);
569 call6.paramList_.emplace_back(5);
570 server.Call(call6, reply6);
571 ASSERT_EQ(ERR_INVALID_INPUT, reply6.exception_.code_);
572 ASSERT_TRUE(reply6.exception_.message_.find("Number of illegal fingers") != string::npos);
573 }
574
TEST_F(FrontendApiHandlerTest,pointerMatrixparameterPreChecksOne)575 TEST_F(FrontendApiHandlerTest, pointerMatrixparameterPreChecksOne)
576 {
577 const auto& server = FrontendApiServer::Get();
578 // call with argument illegal steps
579 auto call7 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
580 auto reply7 = ApiReplyInfo();
581 call7.paramList_.emplace_back(5);
582 call7.paramList_.emplace_back(0);
583 server.Call(call7, reply7);
584 ASSERT_EQ(ERR_INVALID_INPUT, reply7.exception_.code_);
585 ASSERT_TRUE(reply7.exception_.message_.find("Number of illegal steps") != string::npos);
586 // call with argument illegal fingers
587 auto call10 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
588 auto reply10 = ApiReplyInfo();
589 call10.paramList_.emplace_back(6);
590 call10.paramList_.emplace_back(10);
591 server.Call(call10, reply10);
592 ASSERT_EQ(NO_ERROR, reply10.exception_.code_);
593 auto call11 = ApiCallInfo {.apiId_ = "PointerMatrix.setPoint", .callerObjRef_ = reply10.resultValue_.get<string>()};
594 call11.paramList_.emplace_back(6);
595 call11.paramList_.emplace_back(1);
596 auto arg1 = json();
597 arg1["x"] = 9;
598 arg1["y"] = 10;
599 call11.paramList_.emplace_back(arg1);
600 auto reply11 = ApiReplyInfo();
601 server.Call(call11, reply11);
602 ASSERT_EQ(ERR_INVALID_INPUT, reply11.exception_.code_);
603 ASSERT_TRUE(reply11.exception_.message_.find("Number of illegal fingers") != string::npos);
604 // call with argument illegal steps
605 auto call12 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
606 auto reply12 = ApiReplyInfo();
607 call12.paramList_.emplace_back(6);
608 call12.paramList_.emplace_back(10);
609 server.Call(call12, reply12);
610 ASSERT_EQ(NO_ERROR, reply12.exception_.code_);
611 auto call13 = ApiCallInfo {.apiId_ = "PointerMatrix.setPoint", .callerObjRef_ = reply12.resultValue_.get<string>()};
612 call13.paramList_.emplace_back(5);
613 call13.paramList_.emplace_back(11);
614 auto arg2 = json();
615 arg2["x"] = 9;
616 arg2["y"] = 10;
617 call13.paramList_.emplace_back(arg2);
618 auto reply13 = ApiReplyInfo();
619 server.Call(call13, reply13);
620 ASSERT_EQ(ERR_INVALID_INPUT, reply13.exception_.code_);
621 ASSERT_TRUE(reply13.exception_.message_.find("Number of illegal steps") != string::npos);
622 }
623
TEST_F(FrontendApiHandlerTest,injectMultiPointerActionparameterPreChecks)624 TEST_F(FrontendApiHandlerTest, injectMultiPointerActionparameterPreChecks)
625 {
626 const auto& server = FrontendApiServer::Get();
627 auto call2 = ApiCallInfo {.apiId_ = "UiDriver.create"};
628 auto reply2 = ApiReplyInfo();
629 server.Call(call2, reply2);
630 auto call3 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply2.resultValue_.get<string>()};
631 auto from = json();
632 from["x"] = 30;
633 from["y"] = 40;
634 auto to = json();
635 to["x"] = 300;
636 to["y"] = 400;
637 call3.paramList_.emplace_back(from);
638 call3.paramList_.emplace_back(to);
639 call3.paramList_.emplace_back(0);
640 call3.paramList_.emplace_back(4000);
641 auto reply3 = ApiReplyInfo();
642 server.Call(call3, reply3);
643 ASSERT_EQ(USAGE_ERROR, reply3.exception_.code_);
644 ASSERT_TRUE(reply3.exception_.message_.find("The stepLen is out of range") != string::npos);
645
646 auto call4 = ApiCallInfo {.apiId_ = "UiDriver.create"};
647 auto reply4 = ApiReplyInfo();
648 server.Call(call4, reply4);
649 auto call5 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply4.resultValue_.get<string>()};
650 call5.paramList_.emplace_back(from);
651 call5.paramList_.emplace_back(to);
652 call5.paramList_.emplace_back(451);
653 call5.paramList_.emplace_back(4000);
654 auto reply5 = ApiReplyInfo();
655 server.Call(call5, reply5);
656 ASSERT_EQ(USAGE_ERROR, reply5.exception_.code_);
657 ASSERT_TRUE(reply5.exception_.message_.find("The stepLen is out of range") != string::npos);
658
659 auto call6 = ApiCallInfo {.apiId_ = "UiDriver.create"};
660 auto reply6 = ApiReplyInfo();
661 server.Call(call6, reply6);
662 auto call7 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply6.resultValue_.get<string>()};
663 auto from3 = json();
664 from3["x"] = "";
665 from3["y"] = "";
666 call7.paramList_.emplace_back(from3);
667 call7.paramList_.emplace_back(to);
668 call7.paramList_.emplace_back(500);
669 call7.paramList_.emplace_back(4000);
670 auto reply7 = ApiReplyInfo();
671 server.Call(call7, reply7);
672 ASSERT_EQ(USAGE_ERROR, reply7.exception_.code_);
673 }
674
TEST_F(FrontendApiHandlerTest,callback)675 TEST_F(FrontendApiHandlerTest, callback)
676 {
677 auto& server = FrontendApiServer::Get();
678 server.SetCallbackHandler(nullptr);
679 ApiCallInfo call { .apiId_ = "wyz" };
680 ApiReplyInfo reply {};
681 server.Callback(call, reply);
682 ASSERT_EQ(ERR_INTERNAL, reply.exception_.code_); // no callback handler
683
684 auto handler = [](const ApiCallInfo& in, ApiReplyInfo& out) {
685 out.resultValue_ = in.apiId_ + "Amm";
686 };
687 server.SetCallbackHandler(handler);
688 reply.exception_ = ApiCallErr(NO_ERROR);
689 server.Callback(call, reply);
690 ASSERT_EQ(NO_ERROR, reply.exception_.code_);
691 ASSERT_EQ("wyzAmm", reply.resultValue_.get<string>());
692 }
693
TEST_F(FrontendApiHandlerTest,onEventCallback)694 TEST_F(FrontendApiHandlerTest, onEventCallback)
695 {
696 auto& server = FrontendApiServer::Get();
697 auto call1 = ApiCallInfo {.apiId_ = "Driver.create"};
698 auto reply1 = ApiReplyInfo();
699 server.Call(call1, reply1);
700
701 auto call2 = ApiCallInfo {.apiId_ = "Driver.createUIEventObserver",
702 .callerObjRef_ = reply1.resultValue_.get<string>()};
703 auto reply2 = ApiReplyInfo();
704 server.Call(call2, reply2);
705 ASSERT_EQ(NO_ERROR, reply2.exception_.code_);
706 ASSERT_EQ(nlohmann::detail::value_t::string, reply2.resultValue_.type());
707 const auto ref2 = reply2.resultValue_.get<string>();
708 ASSERT_TRUE(ref2.find("UIEventObserver#") != string::npos);
709
710 string result = "capture event: ";
711 auto jsCallback = [&result](const ApiCallInfo& in, ApiReplyInfo& out) {
712 auto &elementInfo = in.paramList_.at(INDEX_ZERO);
713 result = result + string(elementInfo["type"]) + ",";
714 };
715 server.SetCallbackHandler(jsCallback);
716 auto jsCbId = to_string(reinterpret_cast<uintptr_t>(&jsCallback));
717 auto call3 = ApiCallInfo {.apiId_ = "UIEventObserver.once",
718 .callerObjRef_ = reply2.resultValue_.get<string>()};
719 call3.paramList_.push_back("toastShow");
720 call3.paramList_.push_back(jsCbId);
721 auto reply3 = ApiReplyInfo();
722 server.Call(call3, reply3);
723 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
724 auto monitor = DummyEventMonitor::GetInstance();
725 ASSERT_EQ(1, monitor.GetListenerCount());
726 monitor.OnEvent("toastShow");
727 ASSERT_EQ("capture event: toastShow,", result);
728
729 auto call4 = ApiCallInfo {.apiId_ = "UIEventObserver.once",
730 .callerObjRef_ = reply2.resultValue_.get<string>()};
731 call4.paramList_.push_back("dialogShow");
732 call4.paramList_.push_back(jsCbId);
733 auto reply4 = ApiReplyInfo();
734 server.Call(call4, reply4);
735 ASSERT_EQ(NO_ERROR, reply4.exception_.code_);
736 monitor.OnEvent("dialogShow");
737 ASSERT_EQ("capture event: toastShow,dialogShow,", result);
738 // Works once
739 monitor.OnEvent("toastShow");
740 ASSERT_EQ("capture event: toastShow,dialogShow,", result);
741 }
742
TEST_F(FrontendApiHandlerTest,touchPadMultiFingerSwipeParameterPreChecks)743 TEST_F(FrontendApiHandlerTest, touchPadMultiFingerSwipeParameterPreChecks)
744 {
745 const auto& server = FrontendApiServer::Get();
746 auto call1 = ApiCallInfo {.apiId_ = "UiDriver.create"};
747 auto reply1 = ApiReplyInfo();
748 server.Call(call1, reply1);
749 auto call2 = ApiCallInfo {.apiId_ = "UiDriver.touchPadMultiFingerSwipe",
750 .callerObjRef_ = reply1.resultValue_.get<string>()};
751 call2.paramList_.emplace_back(2);
752 call2.paramList_.emplace_back(0);
753 auto reply2 = ApiReplyInfo();
754 server.Call(call2, reply2);
755 ASSERT_EQ(USAGE_ERROR, reply2.exception_.code_);
756 ASSERT_TRUE(reply2.exception_.message_.find("Number of illegal fingers") != string::npos);
757
758 auto call3 = ApiCallInfo {.apiId_ = "UiDriver.create"};
759 auto reply3 = ApiReplyInfo();
760 server.Call(call3, reply3);
761 auto call4 = ApiCallInfo {.apiId_ = "UiDriver.touchPadMultiFingerSwipe",
762 .callerObjRef_ = reply1.resultValue_.get<string>()};
763 call4.paramList_.emplace_back(5);
764 call4.paramList_.emplace_back(0);
765 auto reply4 = ApiReplyInfo();
766 server.Call(call4, reply4);
767 ASSERT_EQ(USAGE_ERROR, reply4.exception_.code_);
768 ASSERT_TRUE(reply4.exception_.message_.find("Number of illegal fingers") != string::npos);
769 }