1 /*
2  * Copyright (c) 2021 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 #include "basic_tdd_test.h"
16 #include <cstring>
17 #include <sys/prctl.h>
18 #include "async_task_manager.h"
19 #include "common/graphic_startup.h"
20 #include "common/task_manager.h"
21 #include "component_utils.h"
22 #include "core/render_manager.h"
23 #include "descriptor_utils.h"
24 #include "dock/screen_device_proxy.h"
25 #include "event_injector.h"
26 #include "js_app_context.h"
27 #include "js_app_environment.h"
28 #include "module_manager.h"
29 #include "root_view.h"
30 
31 namespace OHOS {
32 namespace ACELite {
BasicTddTest()33 BasicTddTest::BasicTddTest() : rootComponent_(nullptr) {}
~BasicTddTest()34 BasicTddTest::~BasicTddTest() {}
35 
36 ScreenDevice *BasicTddTest::display_ = nullptr;
37 Window *BasicTddTest::window_ = nullptr;
38 pthread_t BasicTddTest::tickThread_ = -1;
39 bool BasicTddTest::isTickTaskRunning_ = false;
40 
41 // 10ms a tick
42 constexpr uint16_t TICK = 10000;
43 constexpr uint32_t SWIPE_TIME = 100;
44 
45 constexpr uint8_t NUMBER_TWO = 2;
46 
SetUpTestCase(void)47 void BasicTddTest::SetUpTestCase(void)
48 {
49     GraphicStartUp::Init();
50     isTickTaskRunning_ = true;
51 
52     display_ = new ScreenDevice();
53     ScreenDeviceProxy::GetInstance()->SetDevice(display_);
54     ScreenDeviceProxy::GetInstance()->SetScreenSize(HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);
55 
56     WindowConfig config = {};
57     uint16_t width = GetHorizontalResolution();
58     uint16_t height = GetVerticalResolution();
59     config.rect.SetRect(0, 0, width - 1, height - 1);
60     window_ = Window::CreateWindow(config);
61     RootView *rootView = RootView::GetInstance();
62     rootView->SetPosition(0, 0);
63     rootView->SetWidth(width);
64     rootView->SetHeight(height);
65     window_->BindRootView(rootView);
66     TaskManager::GetInstance()->Remove(&RenderManager::GetInstance());
67     if (pthread_create(&tickThread_, nullptr, TickHandler, nullptr) == 0) {
68         pthread_detach(tickThread_);
69         HILOG_DEBUG(HILOG_MODULE_ACE, "[BasicTddTest::SetUpTestCase]: Success to fork tick thread.");
70     } else {
71         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::SetUpTestCase]: Failed to fork tick thread.");
72     }
73 }
74 
TearDownTestCase(void)75 void BasicTddTest::TearDownTestCase(void)
76 {
77     isTickTaskRunning_ = false;
78     if (window_ != nullptr) {
79         Window::DestroyWindow(window_);
80         window_ = nullptr;
81     }
82     if (display_ != nullptr) {
83         delete display_;
84         display_ = nullptr;
85     }
86 }
87 
SetUp()88 void BasicTddTest::SetUp()
89 {
90     JsAppContext *appContext = JsAppContext::GetInstance();
91     const int32_t apiVersion = 6;
92     appContext->SetCompatibleApi(apiVersion);
93     appContext->SetTargetApi(apiVersion);
94     JsAppEnvironment::GetInstance()->InitJsFramework();
95     EventInjector *injector = EventInjector::GetInstance();
96     if (!injector->IsEventInjectorRegistered(EventDataType::POINT_TYPE)) {
97         injector->RegisterEventInjector(EventDataType::POINT_TYPE);
98     }
99     injector->SetWindowId(window_->GetWindowId());
100     AsyncTaskManager::GetInstance().SetFront(true);
101 }
102 
TearDown()103 void BasicTddTest::TearDown()
104 {
105     ModuleManager::GetInstance()->CleanUpModule();
106     JsAppEnvironment::GetInstance()->Cleanup();
107 
108     EventInjector *injector = EventInjector::GetInstance();
109     if (injector->IsEventInjectorRegistered(EventDataType::POINT_TYPE)) {
110         injector->UnregisterEventInjector(EventDataType::POINT_TYPE);
111     }
112     AsyncTaskManager::GetInstance().SetFront(false);
113 }
114 
RunJS(const char * bundle,const uint32_t size) const115 JSValue BasicTddTest::RunJS(const char *bundle, const uint32_t size) const
116 {
117     return jerry_eval(reinterpret_cast<const jerry_char_t *>(bundle), size, JERRY_PARSE_NO_OPTS);
118 }
119 
CreatePage(const char * bundle,const uint32_t size)120 JSValue BasicTddTest::CreatePage(const char *bundle, const uint32_t size)
121 {
122     JSValue page = RunJS(bundle, size);
123     if (JSError::Is(page)) {
124         return JSUndefined::Create();
125     }
126     JSGlobal::Set("$root", page);
127     CallLifecycle(page, "onInit");
128     JSValue rootEl = JSObject::Call(page, "$render");
129     if (JSUndefined::Is(rootEl) || JSError::Is(rootEl)) {
130         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to render page.");
131         JSRelease(rootEl);
132         JSRelease(page);
133         return JSUndefined::Create();
134     }
135     CallLifecycle(page, "onReady");
136     rootComponent_ = ComponentUtils::GetComponentFromBindingObject(rootEl);
137     if (rootComponent_ == nullptr) {
138         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to get root component.");
139         JSRelease(rootEl);
140         JSRelease(page);
141         return JSUndefined::Create();
142     }
143     uint16_t horizontalResolution = GetHorizontalResolution();
144     uint16_t verticalResolution = GetVerticalResolution();
145     ConstrainedParameter rootViewParam(horizontalResolution, verticalResolution);
146     Component::BuildViewTree(rootComponent_, nullptr, rootViewParam);
147     rootComponent_->OnViewAttached();
148     UIView *view = rootComponent_->GetComponentRootView();
149     if (view == nullptr) {
150         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to get page root view.");
151         JSRelease(rootEl);
152         JSRelease(page);
153         return JSUndefined::Create();
154     }
155     RootView *rootView = RootView::GetInstance();
156     rootView->Add(view);
157     rootView->Invalidate();
158     CallLifecycle(page, "onShow");
159     return page;
160 }
161 
DestroyPage(JSValue page)162 void BasicTddTest::DestroyPage(JSValue page)
163 {
164     RootView *rootView = RootView::GetInstance();
165     rootView->RemoveAll();
166     rootView->Invalidate();
167     CallLifecycle(page, "onHide");
168     CallLifecycle(page, "onDestroy");
169     ComponentUtils::ReleaseComponents(rootComponent_);
170     rootComponent_ = nullptr;
171     JsAppContext::GetInstance()->ReleaseStyles();
172     JSGlobal::Del("$root");
173     JSRelease(page);
174 }
175 
GetViewByRef(JSValue page,const char * ref) const176 UIView *BasicTddTest::GetViewByRef(JSValue page, const char *ref) const
177 {
178     JSValue refs = JSObject::Get(page, "$refs");
179     if (JSUndefined::Is(refs)) {
180         JSRelease(refs);
181         return nullptr;
182     }
183     JSValue dom = JSObject::Get(refs, ref);
184     if (JSUndefined::Is(dom)) {
185         JSRelease(refs);
186         JSRelease(dom);
187         return nullptr;
188     }
189     UIView *view = ComponentUtils::GetViewFromBindingObject(dom);
190     JSRelease(refs);
191     JSRelease(dom);
192     return view;
193 }
194 
ClickByRef(JSValue page,const char * ref,uint8_t sleepTicks) const195 void BasicTddTest::ClickByRef(JSValue page, const char *ref, uint8_t sleepTicks) const
196 {
197     return Click(GetViewByRef(page, ref), sleepTicks);
198 }
199 
LongPressByRef(JSValue page,const char * ref,uint8_t sleepTicks) const200 void BasicTddTest::LongPressByRef(JSValue page, const char *ref, uint8_t sleepTicks) const
201 {
202     return LongPress(GetViewByRef(page, ref), sleepTicks);
203 }
204 
Click(const UIView * view,uint8_t sleepTicks) const205 void BasicTddTest::Click(const UIView *view, uint8_t sleepTicks) const
206 {
207     if (view == nullptr) {
208         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::Click]: Failed to click because view is nullptr");
209         return;
210     }
211     Rect rect = view->GetOrigRect();
212     int16_t x = rect.GetLeft() + rect.GetWidth() / NUMBER_TWO;
213     int16_t y = rect.GetTop() + rect.GetHeight() / NUMBER_TWO;
214     return Click(x, y, sleepTicks);
215 }
216 
LongPress(const UIView * view,uint8_t sleepTicks) const217 void BasicTddTest::LongPress(const UIView *view, uint8_t sleepTicks) const
218 {
219     if (view == nullptr) {
220         HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::LongPress]: Failed to long press because view is nullptr");
221         return;
222     }
223     Rect rect = view->GetOrigRect();
224     int16_t x = rect.GetLeft() + rect.GetWidth() / NUMBER_TWO;
225     int16_t y = rect.GetTop() + rect.GetHeight() / NUMBER_TWO;
226     return LongPress(x, y, sleepTicks);
227 }
228 
Click(int16_t x,int16_t y,uint8_t sleepTicks) const229 void BasicTddTest::Click(int16_t x, int16_t y, uint8_t sleepTicks) const
230 {
231     Point point = {x, y};
232     EventInjector *injector = EventInjector::GetInstance();
233     if (injector->SetClickEvent(point)) {
234         HILOG_DEBUG(HILOG_MODULE_ACE,
235                     "[BasicTddTest::Click]: Success to inject CLICK event on (%{public}d, %{public}d)\n", x, y);
236     } else {
237         HILOG_ERROR(HILOG_MODULE_ACE,
238                     "[BasicTddTest::Click]: Failed to inject CLICK event on (%{public}d, %{public}d)\n", x, y);
239     }
240     // Waiting for tick breath.
241     usleep(sleepTicks * TICK);
242 }
243 
LongPress(int16_t x,int16_t y,uint8_t sleepTicks) const244 void BasicTddTest::LongPress(int16_t x, int16_t y, uint8_t sleepTicks) const
245 {
246     Point point = {x, y};
247     EventInjector *injector = EventInjector::GetInstance();
248     if (injector->SetLongPressEvent(point)) {
249         HILOG_DEBUG(HILOG_MODULE_ACE,
250                     "[BasicTddTest::LongPress]: Success to inject LONGPRESS event on (%{public}d, %{public}d)\n", x, y);
251     } else {
252         HILOG_ERROR(HILOG_MODULE_ACE,
253                     "[BasicTddTest::LongPress]: Failed to inject LONGPRESS event on (%{public}d, %{public}d)\n", x, y);
254     }
255     // Waiting for tick breath.
256     usleep(sleepTicks * TICK);
257 }
258 
Swipe(int16_t startX,int16_t startY,int16_t endX,int16_t endY,uint8_t sleepTicks) const259 void BasicTddTest::Swipe(int16_t startX, int16_t startY, int16_t endX, int16_t endY, uint8_t sleepTicks) const
260 {
261     Point startPoint = {startX, startY};
262     Point endPoint = {endX, endY};
263     EventInjector *injector = EventInjector::GetInstance();
264     if (injector->SetDragEvent(startPoint, endPoint, SWIPE_TIME)) {
265         HILOG_DEBUG(HILOG_MODULE_ACE,
266                     "[BasicTddTest::Swipe]: Success to inject SWIPE event from (%{public}d, %{public}d) to "
267                     "(%{public}d, %{public}d)\n",
268                     startX, startY, endX, endY);
269     } else {
270         HILOG_ERROR(
271             HILOG_MODULE_ACE,
272             "[BasicTddTest::Swipe]: Failed to inject SWIPE from (%{public}d, %{public}d) to (%{public}d, %{public}d)\n",
273             startX, startY, endX, endY);
274     }
275 
276     // Waiting for tick breath.
277     usleep(sleepTicks * TICK);
278 }
279 
GetChildrenSize(const UIViewGroup & grop) const280 uint8_t BasicTddTest::GetChildrenSize(const UIViewGroup &grop) const
281 {
282     UIView *child = grop.GetChildrenHead();
283     uint8_t size = 0;
284     while (child != nullptr) {
285         ++size;
286         child = child->GetNextSibling();
287     }
288     return size;
289 }
290 
TickHandler(void * args)291 void *BasicTddTest::TickHandler(void *args)
292 {
293     (void)args;
294     prctl(PR_SET_NAME, "TickTask");
295     while (isTickTaskRunning_) {
296         // Periodically call TaskHandler(). It could be done in a timer interrupt or an OS task too.
297         TaskManager::GetInstance()->TaskHandler();
298         // Just to let the system breathe
299         usleep(TICK);
300     }
301     return nullptr;
302 }
303 
CallLifecycle(JSValue page,const char * lifecycle) const304 void BasicTddTest::CallLifecycle(JSValue page, const char *lifecycle) const
305 {
306     JSValue func = JSObject::Get(page, lifecycle);
307     if (JSFunction::Is(func)) {
308         JSRelease(JSFunction::Call(func, page, nullptr, 0));
309     }
310     JSRelease(func);
311 }
312 } // namespace ACELite
313 } // namespace OHOS
314