• 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 #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 }