• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }