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 "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("zl");
438 server.Call(call1, reply1);
439 ASSERT_EQ(USAGE_ERROR, reply1.exception_.code_);
440 ASSERT_TRUE(reply1.exception_.message_.find("Illegal argument count") != string::npos);
441 // call with argument of wrong type
442 auto call2 = ApiCallInfo {.apiId_ = "By.type", .callerObjRef_ = string(REF_SEED_BY)};
443 auto reply2 = ApiReplyInfo();
444 call2.paramList_.emplace_back(1);
445 server.Call(call2, reply2);
446 ASSERT_EQ(USAGE_ERROR, reply2.exception_.code_);
447 ASSERT_TRUE(reply2.exception_.message_.find("Expect string") != string::npos);
448 // call with argument defaulted (bool=true)
449 auto call3 = ApiCallInfo {.apiId_ = "By.enabled", .callerObjRef_ = string(REF_SEED_BY)};
450 auto reply3 = ApiReplyInfo();
451 call3.paramList_.emplace_back(true); // no defaulted
452 server.Call(call3, reply3);
453 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
454
455 auto call4 = ApiCallInfo {.apiId_ = "By.enabled", .callerObjRef_ = string(REF_SEED_BY)};
456 auto reply4 = ApiReplyInfo(); // defaulted
457 server.Call(call4, reply4);
458 ASSERT_EQ(NO_ERROR, reply4.exception_.code_);
459 // call with bad object ref
460 auto call5 = ApiCallInfo {.apiId_ = "By.isAfter", .callerObjRef_ = string(REF_SEED_BY)};
461 call5.paramList_.emplace_back("By#100");
462 auto reply5 = ApiReplyInfo();
463 server.Call(call5, reply5);
464 ASSERT_EQ(INTERNAL_ERROR, reply5.exception_.code_); // bad-object is internal_error
465 ASSERT_TRUE(reply5.exception_.message_.find("Bad object ref") != string::npos);
466 // call with json param with wrong property
467 auto call6 = ApiCallInfo {.apiId_ = "UiDriver.create"};
468 auto reply6 = ApiReplyInfo();
469 server.Call(call6, reply6);
470 auto call7 = ApiCallInfo {.apiId_ = "UiDriver.findWindow", .callerObjRef_ = reply6.resultValue_.get<string>()};
471 auto arg = json();
472 arg["badProp"] = "wyz";
473 call7.paramList_.emplace_back(arg);
474 auto reply7 = ApiReplyInfo();
475 server.Call(call7, reply7);
476 ASSERT_EQ(USAGE_ERROR, reply7.exception_.code_);
477 ASSERT_TRUE(reply7.exception_.message_.find("Illegal property") != string::npos);
478 }
479
TEST_F(FrontendApiHandlerTest,parameterPreChecks3)480 TEST_F(FrontendApiHandlerTest, parameterPreChecks3)
481 {
482 const auto& server = FrontendApiServer::Get();
483 auto call0 = ApiCallInfo {.apiId_ = "UiDriver.create"};
484 auto reply0 = ApiReplyInfo();
485 server.Call(call0, reply0);
486
487 auto call1 = ApiCallInfo {.apiId_ = "UiDriver.delayMs", .callerObjRef_ = reply0.resultValue_.get<string>()};
488 call1.paramList_.emplace_back(-100);
489 auto reply1 = ApiReplyInfo();
490 server.Call(call1, reply1);
491 ASSERT_TRUE(reply1.exception_.message_.find("Expect integer which cannot be less than 0") != string::npos);
492 }
493
TEST_F(FrontendApiHandlerTest,pointerMatrixparameterPreChecks)494 TEST_F(FrontendApiHandlerTest, pointerMatrixparameterPreChecks)
495 {
496 const auto& server = FrontendApiServer::Get();
497 // call with argument llegal fingers
498 auto call0 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
499 auto reply0 = ApiReplyInfo();
500 call0.paramList_.emplace_back(11);
501 call0.paramList_.emplace_back(3);
502 server.Call(call0, reply0);
503 ASSERT_EQ(ERR_INVALID_INPUT, reply0.exception_.code_);
504 ASSERT_TRUE(reply0.exception_.message_.find("Number of illegal fingers") != string::npos);
505 // call with argument illegal steps
506 auto call2 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
507 auto reply2 = ApiReplyInfo();
508 call2.paramList_.emplace_back(2);
509 call2.paramList_.emplace_back(1001);
510 server.Call(call2, reply2);
511 ASSERT_EQ(ERR_INVALID_INPUT, reply2.exception_.code_);
512 ASSERT_TRUE(reply2.exception_.message_.find("Number of illegal steps") != string::npos);
513 // call with argument illegal steps
514 auto call4 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
515 auto reply4 = ApiReplyInfo();
516 call4.paramList_.emplace_back(5);
517 call4.paramList_.emplace_back(0);
518 server.Call(call4, reply4);
519 ASSERT_EQ(ERR_INVALID_INPUT, reply4.exception_.code_);
520 ASSERT_TRUE(reply4.exception_.message_.find("Number of illegal steps") != string::npos);
521 // call with argument illegal fingers
522 auto call5 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
523 auto reply5 = ApiReplyInfo();
524 call5.paramList_.emplace_back(0);
525 call5.paramList_.emplace_back(5);
526 server.Call(call5, reply5);
527 ASSERT_EQ(ERR_INVALID_INPUT, reply5.exception_.code_);
528 ASSERT_TRUE(reply5.exception_.message_.find("Number of illegal fingers") != string::npos);
529 // call with argument illegal fingers
530 auto call6 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
531 auto reply6 = ApiReplyInfo();
532 call6.paramList_.emplace_back(0);
533 call6.paramList_.emplace_back(5);
534 server.Call(call6, reply6);
535 ASSERT_EQ(ERR_INVALID_INPUT, reply6.exception_.code_);
536 ASSERT_TRUE(reply6.exception_.message_.find("Number of illegal fingers") != string::npos);
537 }
538
TEST_F(FrontendApiHandlerTest,pointerMatrixparameterPreChecksOne)539 TEST_F(FrontendApiHandlerTest, pointerMatrixparameterPreChecksOne)
540 {
541 const auto& server = FrontendApiServer::Get();
542 // call with argument illegal steps
543 auto call7 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
544 auto reply7 = ApiReplyInfo();
545 call7.paramList_.emplace_back(5);
546 call7.paramList_.emplace_back(0);
547 server.Call(call7, reply7);
548 ASSERT_EQ(ERR_INVALID_INPUT, reply7.exception_.code_);
549 ASSERT_TRUE(reply7.exception_.message_.find("Number of illegal steps") != string::npos);
550 // call with argument illegal fingers
551 auto call10 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
552 auto reply10 = ApiReplyInfo();
553 call10.paramList_.emplace_back(6);
554 call10.paramList_.emplace_back(10);
555 server.Call(call10, reply10);
556 ASSERT_EQ(NO_ERROR, reply10.exception_.code_);
557 auto call11 = ApiCallInfo {.apiId_ = "PointerMatrix.setPoint", .callerObjRef_ = reply10.resultValue_.get<string>()};
558 call11.paramList_.emplace_back(6);
559 call11.paramList_.emplace_back(1);
560 auto arg1 = json();
561 arg1["x"] = 9;
562 arg1["y"] = 10;
563 call11.paramList_.emplace_back(arg1);
564 auto reply11 = ApiReplyInfo();
565 server.Call(call11, reply11);
566 ASSERT_EQ(ERR_INVALID_INPUT, reply11.exception_.code_);
567 ASSERT_TRUE(reply11.exception_.message_.find("Number of illegal fingers") != string::npos);
568 // call with argument illegal steps
569 auto call12 = ApiCallInfo {.apiId_ = "PointerMatrix.create"};
570 auto reply12 = ApiReplyInfo();
571 call12.paramList_.emplace_back(6);
572 call12.paramList_.emplace_back(10);
573 server.Call(call12, reply12);
574 ASSERT_EQ(NO_ERROR, reply12.exception_.code_);
575 auto call13 = ApiCallInfo {.apiId_ = "PointerMatrix.setPoint", .callerObjRef_ = reply12.resultValue_.get<string>()};
576 call13.paramList_.emplace_back(5);
577 call13.paramList_.emplace_back(11);
578 auto arg2 = json();
579 arg2["x"] = 9;
580 arg2["y"] = 10;
581 call13.paramList_.emplace_back(arg2);
582 auto reply13 = ApiReplyInfo();
583 server.Call(call13, reply13);
584 ASSERT_EQ(ERR_INVALID_INPUT, reply13.exception_.code_);
585 ASSERT_TRUE(reply13.exception_.message_.find("Number of illegal steps") != string::npos);
586 }
587
TEST_F(FrontendApiHandlerTest,injectMultiPointerActionparameterPreChecks)588 TEST_F(FrontendApiHandlerTest, injectMultiPointerActionparameterPreChecks)
589 {
590 const auto& server = FrontendApiServer::Get();
591 auto call2 = ApiCallInfo {.apiId_ = "UiDriver.create"};
592 auto reply2 = ApiReplyInfo();
593 server.Call(call2, reply2);
594 auto call3 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply2.resultValue_.get<string>()};
595 auto from = json();
596 from["x"] = 30;
597 from["y"] = 40;
598 auto to = json();
599 to["x"] = 300;
600 to["y"] = 400;
601 call3.paramList_.emplace_back(from);
602 call3.paramList_.emplace_back(to);
603 call3.paramList_.emplace_back(0);
604 call3.paramList_.emplace_back(4000);
605 auto reply3 = ApiReplyInfo();
606 server.Call(call3, reply3);
607 ASSERT_EQ(USAGE_ERROR, reply3.exception_.code_);
608 ASSERT_TRUE(reply3.exception_.message_.find("The stepLen is out of range") != string::npos);
609
610 auto call4 = ApiCallInfo {.apiId_ = "UiDriver.create"};
611 auto reply4 = ApiReplyInfo();
612 server.Call(call4, reply4);
613 auto call5 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply4.resultValue_.get<string>()};
614 call5.paramList_.emplace_back(from);
615 call5.paramList_.emplace_back(to);
616 call5.paramList_.emplace_back(451);
617 call5.paramList_.emplace_back(4000);
618 auto reply5 = ApiReplyInfo();
619 server.Call(call5, reply5);
620 ASSERT_EQ(USAGE_ERROR, reply5.exception_.code_);
621 ASSERT_TRUE(reply5.exception_.message_.find("The stepLen is out of range") != string::npos);
622
623 auto call6 = ApiCallInfo {.apiId_ = "UiDriver.create"};
624 auto reply6 = ApiReplyInfo();
625 server.Call(call6, reply6);
626 auto call7 = ApiCallInfo {.apiId_ = "UiDriver.fling", .callerObjRef_ = reply6.resultValue_.get<string>()};
627 auto from3 = json();
628 from3["x"] = "";
629 from3["y"] = "";
630 call7.paramList_.emplace_back(from3);
631 call7.paramList_.emplace_back(to);
632 call7.paramList_.emplace_back(500);
633 call7.paramList_.emplace_back(4000);
634 auto reply7 = ApiReplyInfo();
635 server.Call(call7, reply7);
636 ASSERT_EQ(USAGE_ERROR, reply7.exception_.code_);
637 }
638
TEST_F(FrontendApiHandlerTest,callback)639 TEST_F(FrontendApiHandlerTest, callback)
640 {
641 auto& server = FrontendApiServer::Get();
642 server.SetCallbackHandler(nullptr);
643 ApiCallInfo call { .apiId_ = "wyz" };
644 ApiReplyInfo reply {};
645 server.Callback(call, reply);
646 ASSERT_EQ(ERR_INTERNAL, reply.exception_.code_); // no callback handler
647
648 auto handler = [](const ApiCallInfo& in, ApiReplyInfo& out) {
649 out.resultValue_ = in.apiId_ + "Amm";
650 };
651 server.SetCallbackHandler(handler);
652 reply.exception_ = ApiCallErr(NO_ERROR);
653 server.Callback(call, reply);
654 ASSERT_EQ(NO_ERROR, reply.exception_.code_);
655 ASSERT_EQ("wyzAmm", reply.resultValue_.get<string>());
656 }
657
TEST_F(FrontendApiHandlerTest,onEventCallback)658 TEST_F(FrontendApiHandlerTest, onEventCallback)
659 {
660 auto& server = FrontendApiServer::Get();
661 auto call1 = ApiCallInfo {.apiId_ = "Driver.create"};
662 auto reply1 = ApiReplyInfo();
663 server.Call(call1, reply1);
664
665 auto call2 = ApiCallInfo {.apiId_ = "Driver.createUIEventObserver",
666 .callerObjRef_ = reply1.resultValue_.get<string>()};
667 auto reply2 = ApiReplyInfo();
668 server.Call(call2, reply2);
669 ASSERT_EQ(NO_ERROR, reply2.exception_.code_);
670 ASSERT_EQ(nlohmann::detail::value_t::string, reply2.resultValue_.type());
671 const auto ref2 = reply2.resultValue_.get<string>();
672 ASSERT_TRUE(ref2.find("UIEventObserver#") != string::npos);
673
674 string result = "capture event: ";
675 auto jsCallback = [&result](const ApiCallInfo& in, ApiReplyInfo& out) {
676 auto &elementInfo = in.paramList_.at(INDEX_ZERO);
677 result = result + string(elementInfo["type"]) + ",";
678 };
679 server.SetCallbackHandler(jsCallback);
680 auto jsCbId = to_string(reinterpret_cast<uintptr_t>(&jsCallback));
681 auto call3 = ApiCallInfo {.apiId_ = "UIEventObserver.once",
682 .callerObjRef_ = reply2.resultValue_.get<string>()};
683 call3.paramList_.push_back("toastShow");
684 call3.paramList_.push_back(jsCbId);
685 auto reply3 = ApiReplyInfo();
686 server.Call(call3, reply3);
687 ASSERT_EQ(NO_ERROR, reply3.exception_.code_);
688 auto monitor = DummyEventMonitor::GetInstance();
689 ASSERT_EQ(1, monitor.GetListenerCount());
690 monitor.OnEvent("toastShow");
691 ASSERT_EQ("capture event: toastShow,", result);
692
693 auto call4 = ApiCallInfo {.apiId_ = "UIEventObserver.once",
694 .callerObjRef_ = reply2.resultValue_.get<string>()};
695 call4.paramList_.push_back("dialogShow");
696 call4.paramList_.push_back(jsCbId);
697 auto reply4 = ApiReplyInfo();
698 server.Call(call4, reply4);
699 ASSERT_EQ(NO_ERROR, reply4.exception_.code_);
700 monitor.OnEvent("dialogShow");
701 ASSERT_EQ("capture event: toastShow,dialogShow,", result);
702 // Works once
703 monitor.OnEvent("toastShow");
704 ASSERT_EQ("capture event: toastShow,dialogShow,", result);
705 }