/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "basic_tdd_test.h" #include #include #include "async_task_manager.h" #include "common/graphic_startup.h" #include "common/task_manager.h" #include "component_utils.h" #include "core/render_manager.h" #include "descriptor_utils.h" #include "dock/screen_device_proxy.h" #include "event_injector.h" #include "js_app_context.h" #include "js_app_environment.h" #include "module_manager.h" #include "root_view.h" namespace OHOS { namespace ACELite { BasicTddTest::BasicTddTest() : rootComponent_(nullptr) {} BasicTddTest::~BasicTddTest() {} ScreenDevice *BasicTddTest::display_ = nullptr; Window *BasicTddTest::window_ = nullptr; pthread_t BasicTddTest::tickThread_ = -1; bool BasicTddTest::isTickTaskRunning_ = false; // 10ms a tick constexpr uint16_t TICK = 10000; constexpr uint32_t SWIPE_TIME = 100; constexpr uint8_t NUMBER_TWO = 2; void BasicTddTest::SetUpTestCase(void) { GraphicStartUp::Init(); isTickTaskRunning_ = true; display_ = new ScreenDevice(); ScreenDeviceProxy::GetInstance()->SetDevice(display_); ScreenDeviceProxy::GetInstance()->SetScreenSize(HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION); WindowConfig config = {}; uint16_t width = GetHorizontalResolution(); uint16_t height = GetVerticalResolution(); config.rect.SetRect(0, 0, width - 1, height - 1); window_ = Window::CreateWindow(config); RootView *rootView = RootView::GetInstance(); rootView->SetPosition(0, 0); rootView->SetWidth(width); rootView->SetHeight(height); window_->BindRootView(rootView); TaskManager::GetInstance()->Remove(&RenderManager::GetInstance()); if (pthread_create(&tickThread_, nullptr, TickHandler, nullptr) == 0) { pthread_detach(tickThread_); HILOG_DEBUG(HILOG_MODULE_ACE, "[BasicTddTest::SetUpTestCase]: Success to fork tick thread."); } else { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::SetUpTestCase]: Failed to fork tick thread."); } } void BasicTddTest::TearDownTestCase(void) { isTickTaskRunning_ = false; if (window_ != nullptr) { Window::DestroyWindow(window_); window_ = nullptr; } if (display_ != nullptr) { delete display_; display_ = nullptr; } } void BasicTddTest::SetUp() { JsAppContext *appContext = JsAppContext::GetInstance(); const int32_t apiVersion = 6; appContext->SetCompatibleApi(apiVersion); appContext->SetTargetApi(apiVersion); JsAppEnvironment::GetInstance()->InitJsFramework(); EventInjector *injector = EventInjector::GetInstance(); if (!injector->IsEventInjectorRegistered(EventDataType::POINT_TYPE)) { injector->RegisterEventInjector(EventDataType::POINT_TYPE); } injector->SetWindowId(window_->GetWindowId()); AsyncTaskManager::GetInstance().SetFront(true); } void BasicTddTest::TearDown() { ModuleManager::GetInstance()->CleanUpModule(); JsAppEnvironment::GetInstance()->Cleanup(); EventInjector *injector = EventInjector::GetInstance(); if (injector->IsEventInjectorRegistered(EventDataType::POINT_TYPE)) { injector->UnregisterEventInjector(EventDataType::POINT_TYPE); } AsyncTaskManager::GetInstance().SetFront(false); } JSValue BasicTddTest::RunJS(const char *bundle, const uint32_t size) const { return jerry_eval(reinterpret_cast(bundle), size, JERRY_PARSE_NO_OPTS); } JSValue BasicTddTest::CreatePage(const char *bundle, const uint32_t size) { JSValue page = RunJS(bundle, size); if (JSError::Is(page)) { return JSUndefined::Create(); } JSGlobal::Set("$root", page); CallLifecycle(page, "onInit"); JSValue rootEl = JSObject::Call(page, "$render"); if (JSUndefined::Is(rootEl) || JSError::Is(rootEl)) { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to render page."); JSRelease(rootEl); JSRelease(page); return JSUndefined::Create(); } CallLifecycle(page, "onReady"); rootComponent_ = ComponentUtils::GetComponentFromBindingObject(rootEl); if (rootComponent_ == nullptr) { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to get root component."); JSRelease(rootEl); JSRelease(page); return JSUndefined::Create(); } uint16_t horizontalResolution = GetHorizontalResolution(); uint16_t verticalResolution = GetVerticalResolution(); ConstrainedParameter rootViewParam(horizontalResolution, verticalResolution); Component::BuildViewTree(rootComponent_, nullptr, rootViewParam); rootComponent_->OnViewAttached(); UIView *view = rootComponent_->GetComponentRootView(); if (view == nullptr) { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::CreatePage]: Failed to get page root view."); JSRelease(rootEl); JSRelease(page); return JSUndefined::Create(); } RootView *rootView = RootView::GetInstance(); rootView->Add(view); rootView->Invalidate(); CallLifecycle(page, "onShow"); return page; } void BasicTddTest::DestroyPage(JSValue page) { RootView *rootView = RootView::GetInstance(); rootView->RemoveAll(); rootView->Invalidate(); CallLifecycle(page, "onHide"); CallLifecycle(page, "onDestroy"); ComponentUtils::ReleaseComponents(rootComponent_); rootComponent_ = nullptr; JsAppContext::GetInstance()->ReleaseStyles(); JSGlobal::Del("$root"); JSRelease(page); } UIView *BasicTddTest::GetViewByRef(JSValue page, const char *ref) const { JSValue refs = JSObject::Get(page, "$refs"); if (JSUndefined::Is(refs)) { JSRelease(refs); return nullptr; } JSValue dom = JSObject::Get(refs, ref); if (JSUndefined::Is(dom)) { JSRelease(refs); JSRelease(dom); return nullptr; } UIView *view = ComponentUtils::GetViewFromBindingObject(dom); JSRelease(refs); JSRelease(dom); return view; } void BasicTddTest::ClickByRef(JSValue page, const char *ref, uint8_t sleepTicks) const { return Click(GetViewByRef(page, ref), sleepTicks); } void BasicTddTest::LongPressByRef(JSValue page, const char *ref, uint8_t sleepTicks) const { return LongPress(GetViewByRef(page, ref), sleepTicks); } void BasicTddTest::Click(const UIView *view, uint8_t sleepTicks) const { if (view == nullptr) { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::Click]: Failed to click because view is nullptr"); return; } Rect rect = view->GetOrigRect(); int16_t x = rect.GetLeft() + rect.GetWidth() / NUMBER_TWO; int16_t y = rect.GetTop() + rect.GetHeight() / NUMBER_TWO; return Click(x, y, sleepTicks); } void BasicTddTest::LongPress(const UIView *view, uint8_t sleepTicks) const { if (view == nullptr) { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::LongPress]: Failed to long press because view is nullptr"); return; } Rect rect = view->GetOrigRect(); int16_t x = rect.GetLeft() + rect.GetWidth() / NUMBER_TWO; int16_t y = rect.GetTop() + rect.GetHeight() / NUMBER_TWO; return LongPress(x, y, sleepTicks); } void BasicTddTest::Click(int16_t x, int16_t y, uint8_t sleepTicks) const { Point point = {x, y}; EventInjector *injector = EventInjector::GetInstance(); if (injector->SetClickEvent(point)) { HILOG_DEBUG(HILOG_MODULE_ACE, "[BasicTddTest::Click]: Success to inject CLICK event on (%{public}d, %{public}d)\n", x, y); } else { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::Click]: Failed to inject CLICK event on (%{public}d, %{public}d)\n", x, y); } // Waiting for tick breath. usleep(sleepTicks * TICK); } void BasicTddTest::LongPress(int16_t x, int16_t y, uint8_t sleepTicks) const { Point point = {x, y}; EventInjector *injector = EventInjector::GetInstance(); if (injector->SetLongPressEvent(point)) { HILOG_DEBUG(HILOG_MODULE_ACE, "[BasicTddTest::LongPress]: Success to inject LONGPRESS event on (%{public}d, %{public}d)\n", x, y); } else { HILOG_ERROR(HILOG_MODULE_ACE, "[BasicTddTest::LongPress]: Failed to inject LONGPRESS event on (%{public}d, %{public}d)\n", x, y); } // Waiting for tick breath. usleep(sleepTicks * TICK); } void BasicTddTest::Swipe(int16_t startX, int16_t startY, int16_t endX, int16_t endY, uint8_t sleepTicks) const { Point startPoint = {startX, startY}; Point endPoint = {endX, endY}; EventInjector *injector = EventInjector::GetInstance(); if (injector->SetDragEvent(startPoint, endPoint, SWIPE_TIME)) { HILOG_DEBUG(HILOG_MODULE_ACE, "[BasicTddTest::Swipe]: Success to inject SWIPE event from (%{public}d, %{public}d) to " "(%{public}d, %{public}d)\n", startX, startY, endX, endY); } else { HILOG_ERROR( HILOG_MODULE_ACE, "[BasicTddTest::Swipe]: Failed to inject SWIPE from (%{public}d, %{public}d) to (%{public}d, %{public}d)\n", startX, startY, endX, endY); } // Waiting for tick breath. usleep(sleepTicks * TICK); } uint8_t BasicTddTest::GetChildrenSize(const UIViewGroup &grop) const { UIView *child = grop.GetChildrenHead(); uint8_t size = 0; while (child != nullptr) { ++size; child = child->GetNextSibling(); } return size; } void *BasicTddTest::TickHandler(void *args) { (void)args; prctl(PR_SET_NAME, "TickTask"); while (isTickTaskRunning_) { // Periodically call TaskHandler(). It could be done in a timer interrupt or an OS task too. TaskManager::GetInstance()->TaskHandler(); // Just to let the system breathe usleep(TICK); } return nullptr; } void BasicTddTest::CallLifecycle(JSValue page, const char *lifecycle) const { JSValue func = JSObject::Get(page, lifecycle); if (JSFunction::Is(func)) { JSRelease(JSFunction::Call(func, page, nullptr, 0)); } JSRelease(func); } } // namespace ACELite } // namespace OHOS