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