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