diff --git a/services/ui/BUILD.gn b/services/ui/BUILD.gn index 7edf2c6843a5d2780cbc44900dabc6817d015ce7..f9b2d9ee3d07503e53cd329bb2de11077e4e63f4 100644 --- a/services/ui/BUILD.gn +++ b/services/ui/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Huawei Device Co., Ltd. +# Copyright (c) 2025 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 @@ -75,10 +75,10 @@ ohos_static_library("libui") { "updater_ui_facade.cpp", "updater_ui_tools.cpp", "view/component/box_progress_adapter.cpp", - "view/component/component_factory.cpp", "view/component/img_view_adapter.cpp", "view/component/label_btn_adapter.cpp", "view/component/text_label_adapter.cpp", + "view/component/component_register.cpp", "view/layout/auto_layout.cpp", "view/layout/layout_parser.cpp", "view/page/base_page.cpp", diff --git a/services/ui/updater_ui_traits.h b/services/ui/updater_ui_traits.h index 74de8dd4fa35734e47c2686876b3d3db5bbfe434..dd3c0cc5e1a4cef79f77832c30993c538d5a185c 100644 --- a/services/ui/updater_ui_traits.h +++ b/services/ui/updater_ui_traits.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -16,7 +16,10 @@ #ifndef UPDATER_UI_TRAITS_H #define UPDATER_UI_TRAITS_H -#include "component/component_factory.h" +#include "component/box_progress_adapter.h" +#include "component/img_view_adapter.h" +#include "component/text_label_adapter.h" +#include "component/label_btn_adapter.h" #include "json_visitor.h" #include "macros_updater.h" #include "traits_util.h" diff --git a/services/ui/view/component/box_progress_adapter.cpp b/services/ui/view/component/box_progress_adapter.cpp index 5a10461db94a6f57eef9a28dd359b0a2435ab04e..f341425b593d8e555b6ec3e6e0b7dd765efe2a7a 100644 --- a/services/ui/view/component/box_progress_adapter.cpp +++ b/services/ui/view/component/box_progress_adapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -24,7 +24,7 @@ namespace Updater { BoxProgressAdapter::BoxProgressAdapter(const UxViewInfo &info) { SetViewCommonInfo(info.commonInfo); - const UxBoxProgressInfo &spec = std::get(info.specificInfo); + const UxBoxProgressInfo &spec = AsSpecific(info.specificInfo); this->SetRange(progressWidth_ - 1, 0); this->SetValue(spec.defaultValue); diff --git a/services/ui/view/component/box_progress_adapter.h b/services/ui/view/component/box_progress_adapter.h index e080939eb63aebc9e224d343796049888e357857..4df19c7058213e5ac0ec17f86398d8db949d3983 100644 --- a/services/ui/view/component/box_progress_adapter.h +++ b/services/ui/view/component/box_progress_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -18,6 +18,7 @@ #include #include "component_common.h" +#include "component_factory.h" #include "components/ui_box_progress.h" #include "macros_updater.h" @@ -29,13 +30,13 @@ struct UxBoxProgressInfo { std::string endPoint; bool hasEp; }; -struct UxViewInfo; + class ImgViewAdapter; -class BoxProgressAdapter : public OHOS::UIBoxProgress, public ComponentCommon { +class BoxProgressAdapter : public OHOS::UIBoxProgress, public ComponentCommon { static constexpr uint32_t MAX_PROGRESS_VALUE = 100; DISALLOW_COPY_MOVE(BoxProgressAdapter); public: - using SpecificInfoType = UxBoxProgressInfo; + static constexpr auto COMPONENT_TYPE = "UIBoxProgress"; BoxProgressAdapter() = default; explicit BoxProgressAdapter(const UxViewInfo &info); diff --git a/services/ui/view/component/component_common.h b/services/ui/view/component/component_common.h index e2b2307e1c242c16dafa43f0b070dfac50b0e3db..5a48e767c6419429ecba1df382a1ab7a2ba670ea 100644 --- a/services/ui/view/component/component_common.h +++ b/services/ui/view/component/component_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -16,8 +16,11 @@ #ifndef COMPONENT_COMMON_H #define COMPONENT_COMMON_H +#include #include +#include #include "components/ui_view.h" +#include "json_visitor.h" namespace Updater { struct UxViewCommonInfo { @@ -30,42 +33,75 @@ struct UxViewCommonInfo { bool visible; }; -class ComponentInterface { -public: - virtual ~ComponentInterface() = default; - virtual const char *GetComponentType() = 0; - virtual OHOS::UIView *GetOhosView() = 0; +struct Serializable { + virtual ~Serializable() = default; + + virtual bool DeserializeFromJson(const JsonNode &componentNode, const JsonNode &defaultNode) = 0; + virtual const std::string &GetStructKey() const = 0; }; -// crtp util to ensure type conversion safety and make component code less repetitive -template -class ComponentCommon : public ComponentInterface { -public: - ~ComponentCommon() override = default; - const char *GetComponentType() override +struct UxViewSpecificInfo : public Serializable { + virtual const std::string &GetType() const = 0; + virtual bool IsValid() const = 0; +}; + +struct UxViewInfo { + UxViewCommonInfo commonInfo {}; + // Each derived view component has its own specific data item definitions. + std::unique_ptr specificInfo; +}; + +template +struct SpecificInfoWrapper : public UxViewSpecificInfo { + SpecificInfoWrapper() = default; + DISALLOW_COPY_MOVE(SpecificInfoWrapper); + + using TSpecificInfo = typename TComponent::SpecificInfoType; + + TSpecificInfo data; + + bool DeserializeFromJson(const JsonNode &componentNode, const JsonNode &defaultNode) override + { + return Visit(componentNode, defaultNode, data); + } + + const std::string &GetStructKey() const override { - static_assert(Component::COMPONENT_TYPE != nullptr, "you must not assign a nullptr to COMPONNET_TYPE"); - return Component::COMPONENT_TYPE; + static std::string key {Traits::STRUCT_KEY}; + return key; } - OHOS::UIView *GetOhosView() override + + const std::string &GetType() const override { - return static_cast(this); + static std::string type {TComponent::COMPONENT_TYPE}; + return type; } - void SetViewCommonInfo(const UxViewCommonInfo &common) + + bool IsValid() const override { - viewId_ = common.id; - auto child = static_cast(this); - child->SetPosition(common.x, common.y, common.w, common.h); - child->SetVisible(common.visible); - child->SetViewId(viewId_.c_str()); + return TComponent::IsValid(data); } -protected: - std::string viewId_ {}; -private: - friend Component; - ComponentCommon() = default; }; -} +class ComponentInterface { +public: + virtual ~ComponentInterface() = default; + virtual const char *GetComponentType() = 0; + virtual OHOS::UIView *GetOhosView() = 0; + virtual void SetViewCommonInfo(const UxViewCommonInfo &common) = 0; +}; + +template +struct IsUpdaterComponent { + inline static constexpr bool value = std::is_base_of_v; +}; + +template +using EnableIfIsUpdaterComponent = std::enable_if_t::value>; + +template +using EnableIfNotUpdaterComponent = std::enable_if_t::value>; + +} // namespace Updater -#endif \ No newline at end of file +#endif diff --git a/services/ui/view/component/component_factory.cpp b/services/ui/view/component/component_factory.cpp deleted file mode 100644 index 4f88b3016751939002a1615190352629b212c717..0000000000000000000000000000000000000000 --- a/services/ui/view/component/component_factory.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2022 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 "component_factory.h" - -namespace Updater { -/* - * T is component, T::SpecificInfoType is the specific info of this component. - * ex. T is ImgViewAdapter, then T::SpecificInfoType is UxImageInfo - * T is LabelBtnAdapter, then T::SpecificInfoType is UxLabelBtnInfo - * T is BoxProgressAdapter, then T::SpecificInfoType is UxBoxProgressInfo - * T is TextLabelAdapter, then T::SpecificInfoType is UxLabelInfo - */ -template -class CreateFunctor { -public: - auto operator()([[maybe_unused]] const typename T::SpecificInfoType &specific) const - -> std::function(const UxViewInfo &info)> - { - return [] (const UxViewInfo &info) { return std::make_unique(info); }; - } -}; - -template -class CheckFunctor { -public: - auto operator()(const typename T::SpecificInfoType &specific) const - -> std::function - { - return [&specific] ([[maybe_unused]] const UxViewInfo &info) { return T::IsValid(specific); }; - } -}; - -template typename Functor, typename ...Component> -class Visitor : Functor... { -public: - /* - * overloading only works within the same scope. - * so import overloaded operator() into this scope - * from base class - */ - using Functor::operator()...; - auto Visit(const UxViewInfo &info) const - { - return std::visit(*this, info.specificInfo)(info); - } -}; - -std::unique_ptr ComponentFactory::CreateUxComponent(const UxViewInfo &info) -{ - return Visitor {}.Visit(info); -} - -bool ComponentFactory::CheckUxComponent(const UxViewInfo &info) -{ - return Visitor {}.Visit(info); -} -} // namespace Updater diff --git a/services/ui/view/component/component_factory.h b/services/ui/view/component/component_factory.h index 9aea8db4b99c24dfe0c873167231528bb2de8640..762236524726479246e5127f78129bb6a2fa69fa 100644 --- a/services/ui/view/component/component_factory.h +++ b/services/ui/view/component/component_factory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -18,64 +18,174 @@ #include #include +#include #include #include +#include #include -#include "box_progress_adapter.h" -#include "component_common.h" -#include "img_view_adapter.h" -#include "label_btn_adapter.h" -#include "text_label_adapter.h" -#ifdef COMPONENT_EXT_INCLUDE -#include COMPONENT_EXT_INCLUDE -#endif -/* - * all supported component types listed here, you - * should add a template argument when add a new - * component type - */ -#ifndef COMPONENT_EXT_TYPE_LIST -#define COMPONENT_TYPE_LIST BoxProgressAdapter, ImgViewAdapter, TextLabelAdapter, LabelBtnAdapter -#else -#define COMPONENT_TYPE_LIST BoxProgressAdapter, ImgViewAdapter, TextLabelAdapter, LabelBtnAdapter \ - COMPONENT_EXT_TYPE_LIST -#endif +#include "component_common.h" +#include "log/log.h" namespace Updater { -template -struct SpecificInfo { - using Type = std::variant; -}; +// Generic factory for create UxView and UxInfo class ComponentFactory final { -public: - static std::unique_ptr CreateUxComponent(const UxViewInfo &info); - static bool CheckUxComponent(const UxViewInfo &info); -}; + using TViewPtr = std::unique_ptr; + using TViewCreator = std::function; + using TSpecificInfoCreator = std::function()>; + + ComponentFactory() = default; + DISALLOW_COPY_MOVE(ComponentFactory); -using SpecificInfoFunc = std::function::Type()>; + struct RegistryInfo { + std::string componentType; + TViewCreator createView; + TSpecificInfoCreator createInfo; -template -const auto &GetSpecificInfoMap() -{ - const static std::unordered_map specificInfoMap { - { Components::COMPONENT_TYPE, [] () { return typename Components::SpecificInfoType {}; }}... + RegistryInfo( + const std::string &componentTypeName, TViewCreator &&createViewFunc, TSpecificInfoCreator &&createInfoFunc) + : componentType(componentTypeName), createView(createViewFunc), createInfo(createInfoFunc) + {} }; - return specificInfoMap; -} -struct UxViewInfo { - UxViewCommonInfo commonInfo {}; - SpecificInfo::Type specificInfo {}; +public: + template + static bool Register(const std::string &componentType) + { + auto &factory = Instance(); + factory.RegisterImpl(componentType); + return true; + } + + static std::unique_ptr CreateView(const std::string &componentType, const UxViewInfo &info) + { + auto &factory = Instance(); + std::lock_guard lock(factory.mutex_); + + auto itr = factory.registry_.find(componentType); + if (itr == factory.registry_.end()) { + LOG(ERROR) << "CreateView failed, componentType: " << componentType; + return nullptr; + } + if (itr->second == nullptr) { + LOG(ERROR) << "CreateView failed, no factory, componentType:" << componentType; + return nullptr; + } + + return itr->second->createView(info); + } + + static std::unique_ptr CreateSpecificInfo(const std::string &componentType) + { + auto &factory = Instance(); + std::lock_guard lock(factory.mutex_); + + auto itr = factory.registry_.find(componentType); + if (itr == factory.registry_.end()) { + LOG(ERROR) << "CreateSpecificInfo failed, componentType: " << componentType; + return nullptr; + } + if (itr->second == nullptr) { + LOG(ERROR) << "CreateSpecificInfo failed, no factory, componentType: " << componentType; + return nullptr; + } + + return itr->second->createInfo(); + } + +private: + static ComponentFactory &Instance() + { + static ComponentFactory factory; + return factory; + } + + template + void RegisterImpl(const std::string &componentType) + { + std::lock_guard lock(mutex_); + if (registry_.count(componentType) > 0) { + LOG(WARNING) << "component register again: " << componentType; + return; + } + + auto item = std::make_unique( + componentType, + // Create concrete UxView component + [](const UxViewInfo &info) { return std::make_unique(info); }, + // Create concrete UxView's info + []() { return std::make_unique>(); }); + + registry_.emplace(componentType, std::move(item)); + LOG(INFO) << "component register: " << componentType; + } + +private: + std::mutex mutex_; + std::unordered_map> registry_; }; -namespace Detail { -template -inline constexpr bool CHECK_COMPONENT_LIST = (std::is_same_v || ...); -} +// crtp util to ensure type conversion safety and make component code less repetitive +template +class ComponentCommon : public ComponentInterface { +public: + using SpecificInfoType = TSpecificInfo; + + static bool RegisterHook() + { + return ComponentFactory::Register(TComponent::COMPONENT_TYPE); + } + + ~ComponentCommon() override = default; + const char *GetComponentType() override + { + static_assert(TComponent::COMPONENT_TYPE != nullptr, "you must not assign a nullptr to COMPONNET_TYPE"); + return TComponent::COMPONENT_TYPE; + } + OHOS::UIView *GetOhosView() override + { + return static_cast(this); + } + void SetViewCommonInfo(const UxViewCommonInfo &common) override + { + viewId_ = common.id; + auto child = static_cast(this); + child->SetPosition(common.x, common.y, common.w, common.h); + child->SetVisible(common.visible); + child->SetViewId(viewId_.c_str()); + } + +protected: + const TSpecificInfo &AsSpecific(const std::unique_ptr &specificPtr) + { + const static SpecificInfoWrapper empty {}; + + if (specificPtr == nullptr) { + LOG(ERROR) << TComponent::COMPONENT_TYPE << " specific convert failed, src is nullptr"; + return empty.data; + } + if (empty.GetType() != specificPtr->GetType()) { + LOG(ERROR) << TComponent::COMPONENT_TYPE << " specific convert failed, src COMPONENT_TYPE is " + << specificPtr->GetType(); + return empty.data; + } + if (empty.GetStructKey() != specificPtr->GetStructKey()) { + LOG(ERROR) << TComponent::COMPONENT_TYPE << " specific convert failed, src STRUCT_KEY is " + << specificPtr->GetStructKey(); + return empty.data; + } + + return static_cast *>(specificPtr.get())->data; + } + +protected: + std::string viewId_{}; + +private: + friend TComponent; + ComponentCommon() = default; +}; -template -inline constexpr bool IS_UPDATER_COMPONENT = Detail::CHECK_COMPONENT_LIST; -} // namespace Updater +} // namespace Updater #endif diff --git a/services/ui/view/component/component_register.cpp b/services/ui/view/component/component_register.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f71e599257867b8a884097d3a6b7cfd90d70fc97 --- /dev/null +++ b/services/ui/view/component/component_register.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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 "component_register.h" +#include "log/log.h" +#include "updater_init.h" +#include "updater_ui_traits.h" + +namespace Updater { +void RegisterComponents() +{ + LOG(INFO) << "Register Ux components"; + (void)BoxProgressAdapter::RegisterHook(); + (void)ImgViewAdapter::RegisterHook(); + (void)TextLabelAdapter::RegisterHook(); + (void)LabelBtnAdapter::RegisterHook(); + + UpdaterInit::GetInstance().InvokeEvent(UpdaterInitEvent::UPDATER_COMPONENT_REGISTER_EVENT); + LOG(INFO) << "Ux components ready"; +} + +} // namespace Updater diff --git a/services/ui/view/component/component_register.h b/services/ui/view/component/component_register.h new file mode 100644 index 0000000000000000000000000000000000000000..5f4a34e8ff734e4ced9b72e030a10ec0b560faea --- /dev/null +++ b/services/ui/view/component/component_register.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef UPDATER_UI_COMPONENT_REGISTER_H +#define UPDATER_UI_COMPONENT_REGISTER_H + +namespace Updater { + +void RegisterComponents(); + +} // namespace Updater +#endif diff --git a/services/ui/view/component/img_view_adapter.cpp b/services/ui/view/component/img_view_adapter.cpp index 8b1b61e0db55fe7041ddc42f59871c150ef4cd83..3798be20145735f84a11b180ce633c7ef51a11ce 100644 --- a/services/ui/view/component/img_view_adapter.cpp +++ b/services/ui/view/component/img_view_adapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -77,7 +77,7 @@ ImgViewAdapter::ImgViewAdapter() = default; ImgViewAdapter::ImgViewAdapter(const UxViewInfo &info) { - const UxImageInfo &spec = std::get(info.specificInfo); + const UxImageInfo &spec = AsSpecific(info.specificInfo); dir_ = spec.resPath; imgCnt_ = spec.imgCnt; interval_ = spec.updInterval; diff --git a/services/ui/view/component/img_view_adapter.h b/services/ui/view/component/img_view_adapter.h index e1476905dd606c6fd6e64aed0a7d290395c8691c..3b2656a8b45edf47beb9cbef3aaf493d8907c502 100644 --- a/services/ui/view/component/img_view_adapter.h +++ b/services/ui/view/component/img_view_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -19,6 +19,7 @@ #include #include "animator/animator_manager.h" #include "component_common.h" +#include "component_factory.h" #include "components/ui_image_view.h" #include "macros_updater.h" @@ -29,8 +30,8 @@ struct UxImageInfo { uint32_t imgCnt; uint32_t updInterval; }; -struct UxViewInfo; -class ImgViewAdapter : public OHOS::UIImageView, public ComponentCommon { + +class ImgViewAdapter : public OHOS::UIImageView, public ComponentCommon { DISALLOW_COPY_MOVE(ImgViewAdapter); class ImgAnimatorCallback; static constexpr uint32_t MAX_IMG_CNT = 300; @@ -38,7 +39,7 @@ class ImgViewAdapter : public OHOS::UIImageView, public ComponentCommon(info.specificInfo); + const UxLabelBtnInfo &spec = AsSpecific(info.specificInfo); SetViewCommonInfo(info.commonInfo); this->SetText(TranslateText(spec.text).c_str()); this->SetFont(DEFAULT_FONT_FILENAME, spec.fontSize); @@ -95,7 +95,7 @@ LabelBtnAdapter::LabelBtnAdapter(const UxViewInfo &info) bool LabelBtnAdapter::IsValid(const UxLabelBtnInfo &info) { if (info.fontSize > MAX_FONT_SIZE) { - LOG(ERROR) << "label viewinfo check failed, fontSize: " << info.fontSize; + LOG(ERROR) << "label viewinfo check failed, fontSize: " << static_cast(info.fontSize); return false; } diff --git a/services/ui/view/component/label_btn_adapter.h b/services/ui/view/component/label_btn_adapter.h index dae57c89b8726b30f3842e8f17047f0478e191ee..8b56156a5d793955bfbd200f10bd989c6666e130 100644 --- a/services/ui/view/component/label_btn_adapter.h +++ b/services/ui/view/component/label_btn_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -17,6 +17,7 @@ #include #include "component_common.h" +#include "component_factory.h" #include "components/ui_label_button.h" #include "macros_updater.h" @@ -30,13 +31,13 @@ struct UxLabelBtnInfo { std::string focusedBgColor; bool focusable; }; -struct UxViewInfo; -class LabelBtnAdapter : public OHOS::UILabelButton, public ComponentCommon { + +class LabelBtnAdapter : public OHOS::UILabelButton, public ComponentCommon { DISALLOW_COPY_MOVE(LabelBtnAdapter); struct LabelBtnOnFocusListener; static constexpr uint32_t MAX_FONT_SIZE = 200; public: - using SpecificInfoType = UxLabelBtnInfo; + static constexpr auto COMPONENT_TYPE = "UILabelButton"; LabelBtnAdapter(); explicit LabelBtnAdapter(const UxViewInfo &info); diff --git a/services/ui/view/component/text_label_adapter.cpp b/services/ui/view/component/text_label_adapter.cpp index 4f21ccadc27f58dd8248cfc666f1a45e9ec0b2ce..c0e0d2902807655b06bad40b1f1f4ea0680f27ce 100644 --- a/services/ui/view/component/text_label_adapter.cpp +++ b/services/ui/view/component/text_label_adapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -71,7 +71,7 @@ TextLabelAdapter::~TextLabelAdapter() = default; TextLabelAdapter::TextLabelAdapter(const UxViewInfo &info) { - const UxLabelInfo &spec = std::get(info.specificInfo); + const UxLabelInfo &spec = AsSpecific(info.specificInfo); SetViewCommonInfo(info.commonInfo); this->SetAlign(GetAlign(spec.align), OHOS::TEXT_ALIGNMENT_CENTER); this->SetText(TranslateText(spec.text).c_str()); @@ -102,7 +102,7 @@ TextLabelAdapter::TextLabelAdapter(const UxViewInfo &info) bool TextLabelAdapter::IsValid(const UxLabelInfo &info) { if (info.fontSize > MAX_FONT_SIZE) { - LOG(ERROR) << "label viewinfo check failed, fontSize: " << info.fontSize; + LOG(ERROR) << "label viewinfo check failed, fontSize: " << static_cast(info.fontSize); return false; } diff --git a/services/ui/view/component/text_label_adapter.h b/services/ui/view/component/text_label_adapter.h index 5c5ec9832a27c34189e4161f9120e6503ebc0fad..0b93e542e908ba8970f48ee72d1cb2bc21340be8 100644 --- a/services/ui/view/component/text_label_adapter.h +++ b/services/ui/view/component/text_label_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -16,6 +16,7 @@ #define UPDATER_UI_TEXT_LABEL_ADAPTER_H #include "component_common.h" +#include "component_factory.h" #include "components/ui_label.h" #include "json_visitor.h" #include "macros_updater.h" @@ -38,13 +39,13 @@ struct UxLabelInfo { bool touchable; std::string lineBreakMode; }; -struct UxViewInfo; -class TextLabelAdapter : public OHOS::UILabel, public ComponentCommon { + +class TextLabelAdapter : public OHOS::UILabel, public ComponentCommon { DISALLOW_COPY_MOVE(TextLabelAdapter); struct TextLabelOnFocusListener; static constexpr uint32_t MAX_FONT_SIZE = 200; public: - using SpecificInfoType = UxLabelInfo; + static constexpr auto COMPONENT_TYPE = "UILabel"; TextLabelAdapter(); explicit TextLabelAdapter(const UxViewInfo &info); diff --git a/services/ui/view/layout/layout_parser.cpp b/services/ui/view/layout/layout_parser.cpp index 9fef70194751555b00c69837ec56701fc665dfd9..4cda6b2c0e0c35e25b456da3ed9fbce0fad49d16 100644 --- a/services/ui/view/layout/layout_parser.cpp +++ b/services/ui/view/layout/layout_parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -14,12 +14,13 @@ */ #include "layout_parser.h" +#include "auto_layout.h" #include "component/component_factory.h" +#include "component/component_register.h" #include "components/ui_view.h" #include "json_visitor.h" #include "log/log.h" #include "view_api.h" -#include "auto_layout.h" namespace Updater { namespace { @@ -35,6 +36,7 @@ class LayoutParser::Impl { public: bool LoadLayout(const std::vector &layoutFiles, std::vector &vec) const { + RegisterComponents(); layout.Init(); std::vector().swap(vec); UxPageInfo pageInfo = {}; @@ -48,6 +50,8 @@ public: } return true; } + +private: bool LoadLayout(const std::string &filename, UxPageInfo &pageInfo) const { JsonNode node {std::filesystem::path {filename}}; @@ -66,7 +70,7 @@ public: return true; } -private: + bool ParseViewInfo(const JsonNode &root, std::vector &vec) const { UxViewInfo info {}; @@ -85,25 +89,25 @@ private: return false; } const JsonNode &commonDefault = defaultNode[COMMON_LABEL]; + const JsonNode &specificDefault = defaultNode[*viewType]; + + // for common info if (!Visit(componentNode, commonDefault, info.commonInfo)) { LOG(ERROR) << "set common info failed"; return false; } - - auto it = GetSpecificInfoMap().find(*viewType); - if (it == GetSpecificInfoMap().end()) { - LOG(ERROR) << "Can't recognize this type " << *viewType; + // for specific info + info.specificInfo = ComponentFactory::CreateSpecificInfo(*viewType); + if (info.specificInfo == nullptr) { + LOG(ERROR) << "create specific info failed, COMMON_TYPE: " << *viewType; return false; } - info.specificInfo = it->second(); - auto visitor = [&comNode, &defaultNode] (auto &args) { - const JsonNode &defaultComNode = defaultNode[Traits>::STRUCT_KEY]; - return Visit(comNode, defaultComNode, args); - }; - if (!std::visit(visitor, info.specificInfo)) { + if (!info.specificInfo->DeserializeFromJson(comNode, specificDefault)) { + LOG(ERROR) << "parse specific info failed, COMMON_TYPE: " << *viewType; return false; } - vec.push_back(std::move(info)); + + vec.emplace_back(std::move(info)); info = {}; } return true; @@ -120,11 +124,6 @@ LayoutParser &LayoutParser::GetInstance() return layoutParser; } -bool LayoutParser::LoadLayout(const std::string &layoutFile, UxPageInfo &pageInfo) const -{ - return pImpl_->LoadLayout(layoutFile, pageInfo); -} - bool LayoutParser::LoadLayout(const std::vector &layoutFiles, std::vector &vec) const { return pImpl_->LoadLayout(layoutFiles, vec); diff --git a/services/ui/view/layout/layout_parser.h b/services/ui/view/layout/layout_parser.h index f8abea4adde339f6b1328b31d33ee047badd7939..021578cfcffc8ad79353753db8b105fe6af432db 100644 --- a/services/ui/view/layout/layout_parser.h +++ b/services/ui/view/layout/layout_parser.h @@ -25,7 +25,6 @@ class LayoutParser { public: static LayoutParser &GetInstance(); bool LoadLayout(const std::vector &layoutFiles, std::vector &vec) const; - bool LoadLayout(const std::string &layoutFile, UxPageInfo &pageInfo) const; private: LayoutParser(); ~LayoutParser(); diff --git a/services/ui/view/page/base_page.cpp b/services/ui/view/page/base_page.cpp index aaf886f600f4db2f599553ffe401e117fa95d9e0..ed07d885dccec7fc134d60ef19c6c1f6c57c6215 100644 --- a/services/ui/view/page/base_page.cpp +++ b/services/ui/view/page/base_page.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -81,24 +81,42 @@ bool BasePage::BuildComs(const UxPageInfo &pageInfo) bool BasePage::BuildCom(const UxViewInfo &viewInfo, int &minY) { - if (!ComponentFactory::CheckUxComponent(viewInfo)) { + if (viewInfo.specificInfo == nullptr) { LOG(ERROR) << "component (" << viewInfo.commonInfo.id - << ") is invalid, please check your page config json"; + << ") specific info is null, please check your page config json"; return false; } - auto upView = std::make_unique(ComponentFactory::CreateUxComponent(viewInfo), - std::string("component id:") + viewInfo.commonInfo.id + ", "); - auto &view = *upView; + if (!viewInfo.specificInfo->IsValid()) { + LOG(ERROR) << "component (" << viewInfo.commonInfo.id << ") is invalid, please check your page config json"; + return false; + } + + std::unique_ptr viewPtr = + ComponentFactory::CreateView(viewInfo.specificInfo->GetType(), viewInfo); + if (viewPtr == nullptr) { + LOG(ERROR) << "create component view failed"; + return false; + } + std::string message = std::string("component id:") + viewInfo.commonInfo.id + ", "; + auto upView = std::make_unique(std::move(viewPtr), message); + + auto &viewObj = *upView; + OHOS::UIView *view = viewObj.operator->(); + if (view == nullptr) { + LOG(ERROR) << "view is nullptr"; + return false; + } + if (view->GetViewId() == nullptr) { LOG(ERROR) << "id is nullptr"; return false; } if (view->IsFocusable() && viewInfo.commonInfo.y < minY) { minY = viewInfo.commonInfo.y; - focusedView_ = view.operator->(); + focusedView_ = view; } coms_.push_back(std::move(upView)); - root_->Add(view.operator->()); + root_->Add(view); // empty id is allowed. id is needed only when get specific view by id. if (std::string(view->GetViewId()).empty()) { return true; // skip this view. build com success, but not save in map diff --git a/services/ui/view/page/view_proxy.h b/services/ui/view/page/view_proxy.h index 387d5e6c1207b2c13c36db2735d0eabb67335d26..fa278ea8bfe9f52518417b07c461b34b465f6a9a 100644 --- a/services/ui/view/page/view_proxy.h +++ b/services/ui/view/page/view_proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -19,7 +19,7 @@ #include #include #include -#include "component/component_factory.h" +#include "component/component_common.h" #include "components/ui_view.h" #include "log/log.h" @@ -45,7 +45,7 @@ public: std::string errMsg {}; return As(errMsg); } - template>* = nullptr> + template* = nullptr> T *As(std::string &errMsg) const { static T dummy; @@ -60,7 +60,7 @@ public: } return static_cast(view_.get()); } - template>* = nullptr> + template* = nullptr> T *As(std::string &errMsg) const { static T dummy; diff --git a/services/updater_init.h b/services/updater_init.h index 4a395314c642c2c26f0c20c6562f8a61296a2641..9f450a2b53b1383944995ce4c6300f7ebe7bb1b7 100644 --- a/services/updater_init.h +++ b/services/updater_init.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -25,6 +25,7 @@ enum UpdaterInitEvent { // updater UPDATER_PRE_INIT_EVENT, + UPDATER_COMPONENT_REGISTER_EVENT, UPDATER_INIT_EVENT, UPDATER_PRE_UPDATE_PACKAGE_EVENT, UPDATER_PRE_VERIFY_PACKAGE_EVENT, diff --git a/test/unittest/updater_ui_test/BUILD.gn b/test/unittest/updater_ui_test/BUILD.gn index 7bd5bfd96d2a82af01ee1149883159f3d35c3675..6d11802088d7a58b950b6761c837d70f125fa2ae 100644 --- a/test/unittest/updater_ui_test/BUILD.gn +++ b/test/unittest/updater_ui_test/BUILD.gn @@ -58,10 +58,10 @@ ohos_unittest("ui_unittest") { "${updater_path}/services/ui/language/language_ui.cpp", "${updater_path}/services/ui/strategy/ui_strategy.cpp", "${updater_path}/services/ui/view/component/box_progress_adapter.cpp", - "${updater_path}/services/ui/view/component/component_factory.cpp", "${updater_path}/services/ui/view/component/img_view_adapter.cpp", "${updater_path}/services/ui/view/component/label_btn_adapter.cpp", "${updater_path}/services/ui/view/component/text_label_adapter.cpp", + "${updater_path}/services/ui/view/component/component_register.cpp", "${updater_path}/services/ui/view/layout/auto_layout.cpp", "${updater_path}/services/ui/view/layout/layout_parser.cpp", "${updater_path}/services/ui/view/page/base_page.cpp", diff --git a/test/unittest/updater_ui_test/view/ui_component_unittest.cpp b/test/unittest/updater_ui_test/view/ui_component_unittest.cpp index 0b85ae39098f7bbd948d5ed37df7c5c7363c4148..cef472082bbc1c552d8edf0e43a5823f167ed2c0 100644 --- a/test/unittest/updater_ui_test/view/ui_component_unittest.cpp +++ b/test/unittest/updater_ui_test/view/ui_component_unittest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -14,14 +14,17 @@ */ #include -#include "gtest/gtest.h" +#include +#include "common/task_manager.h" #include "component/box_progress_adapter.h" #include "component/component_factory.h" +#include "component/component_register.h" #include "component/label_btn_adapter.h" #include "component/text_label_adapter.h" -#include "common/task_manager.h" #include "dock/focus_manager.h" +#include "gtest/gtest.h" #include "ui_test_graphic_engine.h" +#include "view/page/view_proxy.h" #include "view_api.h" using namespace testing::ext; @@ -34,9 +37,23 @@ public: { TestGraphicEngine::GetInstance(); } - static void TearDownTestCase(void) {} - void SetUp() override {} + static void TearDownTestCase(void) + { + components_.clear(); + } + void SetUp() override + { + RegisterComponents(); + } + void TearDown() override {} + +protected: + template + T *CreateAdapterProxy(UxViewCommonInfo commonInfo, typename T::SpecificInfoType specInfo); + +private: + inline static std::vector> components_; }; constexpr static int32_t MAX_PROGRESS_VALUE = 100; @@ -51,12 +68,41 @@ void CheckCommInfo(OHOS::UIView &view, const UxViewCommonInfo &common) EXPECT_EQ(view.IsVisible(), common.visible); } +template +T *UpdaterUiComponentUnitTest::CreateAdapterProxy(UxViewCommonInfo commonInfo, typename T::SpecificInfoType specInfo) +{ + UxViewInfo info {}; + info.commonInfo = commonInfo; + info.specificInfo = ComponentFactory::CreateSpecificInfo(T::COMPONENT_TYPE); + if (info.specificInfo == nullptr) { + LOG(ERROR) << "create specific info failed, COMPONENT_TYPE: " << T::COMPONENT_TYPE; + return nullptr; + } + + static_cast *>(info.specificInfo.get())->data = specInfo; + + std::unique_ptr ptr = ComponentFactory::CreateView(T::COMPONENT_TYPE, info); + if (ptr == nullptr) { + LOG(ERROR) << "create component failed, COMPONENT_TYPE: " << T::COMPONENT_TYPE; + return nullptr; + } + + CheckCommInfo(*static_cast(ptr.get()), info.commonInfo); + + std::string message = std::string("component id:") + info.commonInfo.id + ", "; + std::unique_ptr proxy = std::make_unique(std::move(ptr), message); + T* raw = proxy->As(); + components_.emplace_back(std::move(proxy)); + return raw; +} + HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_constructor, TestSize.Level0) { UxBoxProgressInfo specInfo {50, "#ffffffff", "#000000ff", "", false}; UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; - CheckCommInfo(boxProgress, commonInfo); + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; auto fgColor = StrToColor(specInfo.fgColor); auto bgColor = StrToColor(specInfo.bgColor); @@ -64,8 +110,8 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_constructor, TestSize.Lev EXPECT_EQ(boxProgress.GetBackgroundStyle(OHOS::STYLE_BACKGROUND_OPA), bgColor.alpha); EXPECT_EQ(boxProgress.GetForegroundStyle(OHOS::STYLE_BACKGROUND_COLOR), fgColor.full); EXPECT_EQ(boxProgress.GetForegroundStyle(OHOS::STYLE_BACKGROUND_OPA), fgColor.alpha); - EXPECT_EQ(boxProgress.GetValue(), static_cast(static_cast(specInfo.defaultValue) / - MAX_PROGRESS_VALUE * (commonInfo.w - 1))); + EXPECT_EQ(boxProgress.GetValue(), + static_cast(static_cast(specInfo.defaultValue) / MAX_PROGRESS_VALUE * (commonInfo.w - 1))); EXPECT_EQ(boxProgress.GetRangeMin(), 0); EXPECT_EQ(boxProgress.GetRangeMax(), commonInfo.w - 1); } @@ -85,7 +131,9 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_set_value_without_ep, Tes UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; constexpr float validValue = 40; { - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; boxProgress.SetValue(-1); EXPECT_EQ(boxProgress.GetValue(), 0); @@ -96,7 +144,10 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_set_value_without_ep, Tes } { specInfo.hasEp = true; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; + boxProgress.SetValue(validValue); EXPECT_EQ(boxProgress.GetValue(), static_cast(validValue / MAX_PROGRESS_VALUE * (commonInfo.w - 1))); } @@ -105,16 +156,22 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_set_value_without_ep, Tes HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_set_visible_without_ep, TestSize.Level0) { { - UxViewInfo info {{10, 10, 1000, 1000, "id", "UIBoxProgress", false}, - UxBoxProgressInfo {50, "#ffffffff", "#000000ff", "", false}}; - BoxProgressAdapter boxProgress {info}; + UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; + UxBoxProgressInfo specificInfo {50, "#ffffffff", "#000000ff", "", false}; + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specificInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; + boxProgress.SetVisible(true); EXPECT_TRUE(boxProgress.IsVisible()); } { - UxViewInfo info {{10, 10, 1000, 1000, "id", "UIBoxProgress", false}, - UxBoxProgressInfo {50, "#ffffffff", "#000000ff", "", true}}; - BoxProgressAdapter boxProgress {info}; + UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; + UxBoxProgressInfo specificInfo {50, "#ffffffff", "#000000ff", "", true}; + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specificInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; + boxProgress.SetVisible(true); EXPECT_TRUE(boxProgress.IsVisible()); } @@ -125,52 +182,64 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_init_endpoint, TestSize.L UxBoxProgressInfo specInfo {50, "#ffffffff", "#000000ff", "", false}; UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; { - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; - EXPECT_TRUE(boxProgress.InitEp()); + BoxProgressAdapter *boxProgress = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgress, nullptr); + EXPECT_TRUE(boxProgress->InitEp()); } { specInfo.hasEp = true; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; - EXPECT_FALSE(boxProgress.InitEp()); + BoxProgressAdapter *boxProgress = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgress, nullptr); + EXPECT_FALSE(boxProgress->InitEp()); } { + BoxProgressAdapter *boxProgress = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgress, nullptr); OHOS::UIViewGroup parent {}; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; - parent.Add(&boxProgress); - EXPECT_FALSE(boxProgress.InitEp()); + parent.Add(boxProgress); + EXPECT_FALSE(boxProgress->InitEp()); } { constexpr auto epId = "endpoint"; specInfo.endPoint = epId; - OHOS::UIViewGroup parent {}; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; + BoxProgressAdapter *boxProgress = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgress, nullptr); LabelBtnAdapter labelBtn {}; labelBtn.SetViewId(epId); - parent.Add(&boxProgress); + + OHOS::UIViewGroup parent {}; + parent.Add(boxProgress); parent.Add(&labelBtn); - EXPECT_FALSE(boxProgress.InitEp()); + EXPECT_FALSE(boxProgress->InitEp()); } { constexpr auto epId = "endpoint"; specInfo.endPoint = epId; - OHOS::UIViewGroup parent {}; - BoxProgressAdapter boxProgress {UxViewInfo {commonInfo, specInfo}}; + BoxProgressAdapter *boxProgress = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(boxProgress, nullptr); ImgViewAdapter imgView {}; imgView.SetViewId(epId); - parent.Add(&boxProgress); + + OHOS::UIViewGroup parent {}; + parent.Add(boxProgress); parent.Add(&imgView); - EXPECT_TRUE(boxProgress.InitEp()); + EXPECT_TRUE(boxProgress->InitEp()); } } HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_with_ep, TestSize.Level0) { constexpr auto epId = "endpoint"; - OHOS::UIViewGroup parent {}; + UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}; + UxBoxProgressInfo specificInfo {50, "#ffffffff", "#000000ff", epId, true}; + BoxProgressAdapter *boxProgressPtr = CreateAdapterProxy(commonInfo, specificInfo); + ASSERT_NE(boxProgressPtr, nullptr); + BoxProgressAdapter &boxProgress = *boxProgressPtr; + ImgViewAdapter epView {}; - BoxProgressAdapter boxProgress {UxViewInfo {UxViewCommonInfo {10, 10, 1000, 1000, "id", "UIBoxProgress", false}, - UxBoxProgressInfo {50, "#ffffffff", "#000000ff", epId, true}}}; epView.SetViewId(epId); + + OHOS::UIViewGroup parent {}; parent.Add(&boxProgress); parent.Add(&epView); EXPECT_TRUE(boxProgress.InitEp()); @@ -184,8 +253,8 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_box_progress_with_ep, TestSize.Level0) EXPECT_FALSE(epView.IsVisible()); boxProgress.SetVisible(true); - constexpr float testValue = 50; - constexpr float halfDivisor = 2.0; + float testValue = 50; + float halfDivisor = 2.0; boxProgress.SetValue(testValue); float rate = static_cast(boxProgress.GetValue()) / boxProgress.GetRangeMax(); EXPECT_EQ(epView.GetX(), static_cast(boxProgress.GetX() - @@ -202,8 +271,9 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_img_view_adapter_constructor, TestSize interval = 0; UxImageInfo specInfo {"", "", 100, interval}; UxViewCommonInfo commonInfo {10, 10, 1000, 1000, id, "UIImageView", false}; - ImgViewAdapter imgView {UxViewInfo {commonInfo, specInfo}}; - CheckCommInfo(imgView, commonInfo); + ImgViewAdapter *imgViewPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(imgViewPtr, nullptr); + ImgViewAdapter &imgView = *imgViewPtr; EXPECT_EQ(imgView.GetX(), commonInfo.x); EXPECT_EQ(imgView.GetY(), commonInfo.y); @@ -217,8 +287,9 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_img_view_adapter_constructor, TestSize constexpr auto id = "img"; UxImageInfo specInfo {"", "", 100, interval}; UxViewCommonInfo commonInfo {10, 10, 1000, 1000, id, "UIImageView", false}; - ImgViewAdapter imgView {UxViewInfo {commonInfo, specInfo}}; - CheckCommInfo(imgView, commonInfo); + ImgViewAdapter *imgViewPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(imgViewPtr, nullptr); + ImgViewAdapter &imgView = *imgViewPtr; ASSERT_NE(imgView.GetAnimatorCallback(), nullptr); ASSERT_NE(imgView.GetAnimator(), nullptr); @@ -252,15 +323,22 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_img_view_adapter_start_stop, TestSize. } { // non animator - ImgViewAdapter imgView {UxViewInfo {UxViewCommonInfo {10, 10, 1000, 1000, "id", "UIImageView", false}, - UxImageInfo {"respath", "", 100, 0}}}; + UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIImageView", false}; + UxImageInfo specInfo {"respath", "", 100, 0}; + ImgViewAdapter *imgViewPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(imgViewPtr, nullptr); + ImgViewAdapter &imgView = *imgViewPtr; + EXPECT_FALSE(imgView.Start()); EXPECT_FALSE(imgView.Stop()); } { using namespace std::literals::chrono_literals; - ImgViewAdapter imgView {UxViewInfo {UxViewCommonInfo {10, 10, 1000, 1000, "id", "UIImageView", false}, - UxImageInfo {"", "fileprefix", 100, 10}}}; + UxViewCommonInfo commonInfo {10, 10, 1000, 1000, "id", "UIImageView", false}; + UxImageInfo specInfo {"", "fileprefix", 100, 10}; + ImgViewAdapter *imgViewPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(imgViewPtr, nullptr); + ImgViewAdapter &imgView = *imgViewPtr; uint32_t currId = 0; EXPECT_FALSE(imgView.Stop()); // stop would fail when hasn't been started @@ -294,9 +372,9 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_label_btn_adapter_constructor, TestSiz constexpr auto labelText = "hello"; UxLabelBtnInfo specInfo {100, "hello", "#ffffffff", "#000000ff", "#000000ff", "#ffffffff", true}; UxViewCommonInfo commonInfo {0, 0, 0, 0, "id", "UILabelButton", false}; - UxViewInfo info {commonInfo, specInfo}; - LabelBtnAdapter labelBtn {info}; - CheckCommInfo(labelBtn, commonInfo); + LabelBtnAdapter *labelBtnPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(labelBtnPtr, nullptr); + LabelBtnAdapter &labelBtn = *labelBtnPtr; auto fontColor = StrToColor(specInfo.txtColor); auto bgColor = StrToColor(specInfo.bgColor); @@ -310,10 +388,18 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_label_btn_adapter_constructor, TestSiz HWTEST_F(UpdaterUiComponentUnitTest, test_label_btn_adapter_on_press, TestSize.Level0) { - LabelBtnAdapter labelBtn1 {UxViewInfo {{0, 0, 50, 50, "id", "UILabelButton", true}, - UxLabelBtnInfo {100, "", "#000000ff", "#ffffffff", "#ffffffff", "#000000ff", true}}}; - LabelBtnAdapter labelBtn2 {UxViewInfo {{100, 100, 50, 50, "id", "UILabelButton", true}, - UxLabelBtnInfo {100, "", "#000000ff", "#ffffffff", "#ffffffff", "#000000ff", true}}}; + UxViewCommonInfo commonInfo1{0, 0, 50, 50, "id", "UILabelButton", true}; + UxLabelBtnInfo specInfo1{100, "", "#000000ff", "#ffffffff", "#ffffffff", "#000000ff", true}; + LabelBtnAdapter *labelBtn1Ptr = CreateAdapterProxy(commonInfo1, specInfo1); + ASSERT_NE(labelBtn1Ptr, nullptr); + LabelBtnAdapter &labelBtn1 = *labelBtn1Ptr; + + UxViewCommonInfo commonInfo2{100, 100, 50, 50, "id", "UILabelButton", true}; + UxLabelBtnInfo specInfo2{100, "", "#000000ff", "#ffffffff", "#ffffffff", "#000000ff", true}; + LabelBtnAdapter *labelBtn2Ptr = CreateAdapterProxy(commonInfo2, specInfo2); + ASSERT_NE(labelBtn2Ptr, nullptr); + LabelBtnAdapter &labelBtn2 = *labelBtn2Ptr; + OHOS::FocusManager::GetInstance()->RequestFocus(&labelBtn2); labelBtn1.OnPressEvent(OHOS::PressEvent {OHOS::Point {}}); EXPECT_EQ(OHOS::FocusManager::GetInstance()->GetFocusedView(), &labelBtn1); @@ -337,8 +423,12 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_label_btn_adapter_is_valid, TestSize.L HWTEST_F(UpdaterUiComponentUnitTest, test_label_btn_adapter_set_text, TestSize.Level0) { - LabelBtnAdapter labelBtn {UxViewInfo {{0, 0, 0, 0, "id", "UILabelButton", false}, - UxLabelBtnInfo {100, "", "#000000ff", "#000000ff", "#000000ff", "#000000ff", false}}}; + UxViewCommonInfo commonInfo {0, 0, 0, 0, "id", "UILabelButton", false}; + UxLabelBtnInfo specInfo {100, "", "#000000ff", "#000000ff", "#000000ff", "#000000ff", false}; + LabelBtnAdapter *labelBtnPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(labelBtnPtr, nullptr); + LabelBtnAdapter &labelBtn = *labelBtnPtr; + constexpr auto testString = "test text"; labelBtn.SetText(testString); EXPECT_STREQ(labelBtn.GetText(), testString); @@ -363,9 +453,9 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_text_label_adapter_constructor, TestSi UxLabelInfo specInfo {100, "hello", "center", "#000000ff", "#000000ff", "normal", {"#000000ff", "#000000ff", false}, false, "ellipsis"}; UxViewCommonInfo commonInfo {0, 0, 0, 0, "id", "UILabel", false}; - UxViewInfo info {commonInfo, specInfo}; - TextLabelAdapter textLabel {info}; - CheckCommInfo(textLabel, commonInfo); + TextLabelAdapter *textLabelPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(textLabelPtr, nullptr); + TextLabelAdapter &textLabel = *textLabelPtr; auto fontColor = StrToColor(specInfo.fontColor); auto bgColor = StrToColor(specInfo.bgColor); @@ -379,9 +469,14 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_text_label_adapter_constructor, TestSi HWTEST_F(UpdaterUiComponentUnitTest, test_text_label_adapter_set_text, TestSize.Level0) { - TextLabelAdapter textLabel {UxViewInfo {{0, 0, 0, 0, "id", "UILabel", false}, - UxLabelInfo {255, "", "", "#000000ff", "#000000ff", "normal", - {"#000000ff", "#000000ff", false}, false, "ellipsis"}}}; + UxViewCommonInfo commonInfo {0, 0, 0, 0, "id", "UILabel", false}; + UxLabelInfo specInfo {255, "", "", "#000000ff", "#000000ff", "normal", + {"#000000ff", "#000000ff", false}, false, "ellipsis"}; + + TextLabelAdapter *textLabelPtr = CreateAdapterProxy(commonInfo, specInfo); + ASSERT_NE(textLabelPtr, nullptr); + TextLabelAdapter &textLabel = *textLabelPtr; + constexpr auto testString = "test text"; textLabel.SetText(testString); EXPECT_STREQ(textLabel.GetText(), testString); @@ -392,4 +487,4 @@ HWTEST_F(UpdaterUiComponentUnitTest, test_text_label_adapter_set_text, TestSize. textLabel.SetText(""); EXPECT_STREQ(textLabel.GetText(), ""); } -} +} // namespace diff --git a/test/unittest/updater_ui_test/view/ui_layout_unittest.cpp b/test/unittest/updater_ui_test/view/ui_layout_unittest.cpp index ec4ee4e5bfc59ff884b7c0b414aceaf0ae3fe33a..a7c4ca4c521bb7480ec9a380407a11c935f6aec0 100644 --- a/test/unittest/updater_ui_test/view/ui_layout_unittest.cpp +++ b/test/unittest/updater_ui_test/view/ui_layout_unittest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -55,10 +55,37 @@ bool operator == (const UxLabelBtnInfo &lhs, const UxLabelBtnInfo &rhs) std::tie(rhs.fontSize, rhs.text, rhs.txtColor, rhs.bgColor, rhs.focusedBgColor, rhs.focusedTxtColor); } -bool operator == (const UxViewInfo &lhs, const UxViewInfo &rhs) +template +const typename T::SpecificInfoType &CastSpecificInfoAs(const UxViewSpecificInfo *specPtr) { - return lhs.commonInfo == rhs.commonInfo && lhs.specificInfo == rhs.specificInfo; + return static_cast *>(specPtr)->data; } + +template +bool Equals(const std::unique_ptr &lhs, const std::unique_ptr &rhs) +{ + const UxViewSpecificInfo *lhsPtr = lhs.get(); + const UxViewSpecificInfo *rhsPtr = rhs.get(); + if (lhsPtr == rhsPtr) { + return true; + } + if (lhsPtr == nullptr || rhsPtr == nullptr) { + return false; + } + + if (lhsPtr->GetType() != rhsPtr->GetType()) { + return false; + } + if (lhsPtr->GetStructKey() != rhsPtr->GetStructKey()) { + return false; + } + + const typename T::SpecificInfoType &lhsRef = CastSpecificInfoAs(lhsPtr); + const typename T::SpecificInfoType &rhsRef = CastSpecificInfoAs(rhsPtr); + + return lhsRef == rhsRef; +} + } namespace { class UpdaterUiLayoutParserUnitTest : public testing::Test { @@ -67,6 +94,9 @@ public: static void TearDownTestCase(void); void SetUp() override; void TearDown() override; + +protected: + void LoadValidConfigs(const std::vector &layoutFiles, std::vector &pages); }; @@ -94,169 +124,147 @@ void UpdaterUiLayoutParserUnitTest::TearDownTestCase(void) cout << "TearDownTestCase" << endl; } +void UpdaterUiLayoutParserUnitTest::LoadValidConfigs( + const std::vector &layoutFiles, std::vector &pages) +{ + ASSERT_GE(layoutFiles.size(), 1UL); + ASSERT_TRUE(pages.empty()); + EXPECT_TRUE(LayoutParser::GetInstance().LoadLayout(layoutFiles, pages)); + ASSERT_EQ(pages.size(), layoutFiles.size()); +} + +template +UxViewInfo CreateViewInfo(UxViewCommonInfo commonInfo, typename T::SpecificInfoType specInfo) +{ + UxViewInfo info {commonInfo, ComponentFactory::CreateSpecificInfo(T::COMPONENT_TYPE)}; + EXPECT_NE(info.specificInfo.get(), nullptr); + + static_cast *>(info.specificInfo.get())->data = specInfo; + return info; +} + HWTEST_F(UpdaterUiLayoutParserUnitTest, test_label_parser, TestSize.Level0) { - UxPageInfo pageInfo; - LayoutParser::GetInstance().LoadLayout("/data/updater/ui/label.json", pageInfo); + std::vector pages; + LoadValidConfigs({"/data/updater/ui/label.json"}, pages); + UxPageInfo &pageInfo = pages[0]; + ASSERT_EQ(pageInfo.viewInfos.size(), 1UL); EXPECT_EQ(pageInfo.id, "menu"s); - UxViewInfo expectedLabel { UxViewCommonInfo { 0, 0, 100, 100, "label_id_0", "UILabel", true }, - UxLabelInfo { - 10, - "Reboot to normal system", - "center", - "#ffffffff", - "#ffffffff", - "normal", - {"#ffffffff", - "#ffffffff", - false}, - false, - "ellipsis" - } }; - EXPECT_EQ(pageInfo.viewInfos[0], expectedLabel); + UxViewInfo expectedLabel = + CreateViewInfo(UxViewCommonInfo { 0, 0, 100, 100, "label_id_0", "UILabel", true }, + UxLabelInfo {10, + "Reboot to normal system", + "center", + "#ffffffff", + "#ffffffff", + "normal", + {"#ffffffff", "#ffffffff", false}, + false, + "ellipsis"}); + EXPECT_EQ(pageInfo.viewInfos[0].commonInfo, expectedLabel.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[0].specificInfo, expectedLabel.specificInfo)); } HWTEST_F(UpdaterUiLayoutParserUnitTest, test_progress_parser, TestSize.Level0) { - UxPageInfo pageInfo; - LayoutParser::GetInstance().LoadLayout("/data/updater/ui/boxprogress.json", pageInfo); + std::vector pages; + LoadValidConfigs({"/data/updater/ui/boxprogress.json"}, pages); + UxPageInfo &pageInfo = pages[0]; + ASSERT_EQ(pageInfo.viewInfos.size(), 1UL); EXPECT_EQ(pageInfo.id, "menu"s); - UxViewInfo expectedProgress { UxViewCommonInfo { 0, 0, 100, 100, "box_progress_0", "UIBoxProgress", true }, - UxBoxProgressInfo { 10, "#ffffffff", "#ffffffff" } }; - EXPECT_EQ(pageInfo.viewInfos[0], expectedProgress); + UxViewInfo expectedProgress = + CreateViewInfo(UxViewCommonInfo {0, 0, 100, 100, "box_progress_0", "UIBoxProgress", true }, + UxBoxProgressInfo {10, "#ffffffff", "#ffffffff" }); + EXPECT_EQ(pageInfo.viewInfos[0].commonInfo, expectedProgress.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[0].specificInfo, expectedProgress.specificInfo)); } HWTEST_F(UpdaterUiLayoutParserUnitTest, test_image_view_parser, TestSize.Level0) { - UxPageInfo pageInfo; - LayoutParser::GetInstance().LoadLayout("/data/updater/ui/imageview.json", pageInfo); + std::vector pages; + LoadValidConfigs({"/data/updater/ui/imageview.json"}, pages); + UxPageInfo &pageInfo = pages[0]; + ASSERT_EQ(pageInfo.viewInfos.size(), 1UL); EXPECT_EQ(pageInfo.id, "menu"s); - UxViewInfo expectedImage { UxViewCommonInfo { 0, 0, 100, 100, "image_view", "UIImageView", true }, - UxImageInfo { "/res/images", "", 100, 1 } }; - EXPECT_EQ(pageInfo.viewInfos[0], expectedImage); + UxViewInfo expectedImage = CreateViewInfo( + UxViewCommonInfo {0, 0, 100, 100, "image_view", "UIImageView", true}, UxImageInfo {"/res/images", "", 100, 1}); + EXPECT_EQ(pageInfo.viewInfos[0].commonInfo, expectedImage.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[0].specificInfo, expectedImage.specificInfo)); } HWTEST_F(UpdaterUiLayoutParserUnitTest, test_all, TestSize.Level1) { - UxPageInfo pageInfo; - LayoutParser::GetInstance().LoadLayout("/data/updater/ui/all.json", pageInfo); + std::vector pages; + LoadValidConfigs({"/data/updater/ui/all.json"}, pages); + UxPageInfo &pageInfo = pages[0]; + ASSERT_EQ(pageInfo.viewInfos.size(), 3UL); EXPECT_EQ(pageInfo.id, "menu"s); - UxViewInfo expectedLabel { UxViewCommonInfo { 0, 0, 100, 100, "label_id_0", "UILabel", true }, - UxLabelInfo { - 10, - "Reboot to normal system", - "center", - "#ffffffff", - "#ffffffff", - "normal", - {"#ffffffff", - "#ffffffff", - false}, - false, - "ellipsis" - } }; - EXPECT_EQ(pageInfo.viewInfos[0], expectedLabel); - - UxViewInfo expectedImage { UxViewCommonInfo { 0, 0, 100, 100, "image_view", "UIImageView", true }, - UxImageInfo { "/res/images", "", 100, 1 } }; - EXPECT_EQ(pageInfo.viewInfos[1], expectedImage); - - UxViewInfo expectedProgress { UxViewCommonInfo { 0, 0, 100, 100, "box_progress_0", "UIBoxProgress", - true }, - UxBoxProgressInfo { 10, "#ffffffff", "#ffffffff", "", false } }; - EXPECT_EQ(pageInfo.viewInfos[2], expectedProgress); -} - -HWTEST_F(UpdaterUiLayoutParserUnitTest, test_all_default, TestSize.Level0) -{ - UxPageInfo pageInfo; - LayoutParser::GetInstance().LoadLayout("/data/updater/ui/menu.json", pageInfo); - - ASSERT_EQ(pageInfo.viewInfos.size(), 8UL); - EXPECT_EQ(pageInfo.id, "menu"s); + { + UxViewInfo expectedLabel = + CreateViewInfo(UxViewCommonInfo {0, 0, 100, 100, "label_id_0", "UILabel", true}, + UxLabelInfo {10, + "Reboot to normal system", + "center", + "#ffffffff", + "#ffffffff", + "normal", + {"#ffffffff", "#ffffffff", false}, + false, + "ellipsis"}); + EXPECT_EQ(pageInfo.viewInfos[0].commonInfo, expectedLabel.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[0].specificInfo, expectedLabel.specificInfo)); + } + + { + UxViewInfo expectedImage = + CreateViewInfo(UxViewCommonInfo {0, 0, 100, 100, "image_view", "UIImageView", true}, + UxImageInfo {"/res/images", "", 100, 1}); + EXPECT_EQ(pageInfo.viewInfos[1].commonInfo, expectedImage.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[1].specificInfo, expectedImage.specificInfo)); + } - UxViewInfo expected { UxViewCommonInfo { 1280, 0, 800, 200, "Label_RebootToNormalSystem", "UILabel", true }, - UxLabelInfo { - 60, - "Reboot to normal system", - "center", - "#ffffffff", - "#000000ff", - "normal", - {"#ffffffff", - "#000000ff", - false}, - false, - "ellipsis" - } }; - expected.commonInfo.visible = false; - EXPECT_EQ(expected.commonInfo, pageInfo.viewInfos[0].commonInfo); - EXPECT_EQ(expected.specificInfo, pageInfo.viewInfos[0].specificInfo); - EXPECT_EQ(expected, pageInfo.viewInfos[0]); - - expected.commonInfo = { 1280, 200, 800, 200, "Label_UserdataReset", "UILabel", true }; - std::get(expected.specificInfo).text = "Userdata reset"; - EXPECT_EQ(expected, pageInfo.viewInfos[1]); - - expected.commonInfo = { 1280, 400, 800, 200, "Label_UpdateFromSDCard", "UILabel", true }; - std::get(expected.specificInfo).text = "Update from SD Card"; - EXPECT_EQ(expected, pageInfo.viewInfos[2]); - - expected.commonInfo = { 1280, 600, 800, 200, "Label_MenuDialogTitle", "UILabel", true }; - std::get(expected.specificInfo).text = "Tip"; - std::get(expected.specificInfo).fontSize = 40; - EXPECT_EQ(expected, pageInfo.viewInfos[3]); - - expected.commonInfo = { 1280, 800, 800, 200, "Label_MenuDialogNote", "UILabel", true }; - std::get(expected.specificInfo).text = "Delete user date now..."; - EXPECT_EQ(expected, pageInfo.viewInfos[4]); - - expected.commonInfo = { 1280, 1000, 800, 200, "Label_MenuDialogNext", "UILabel", true }; - std::get(expected.specificInfo).text = "Do you want to continue?"; - EXPECT_EQ(expected, pageInfo.viewInfos[5]); - - expected.commonInfo = { 1280, 1200, 800, 200, "Label_MenuDialogOK", "UILabel", true }; - std::get(expected.specificInfo).text = "Continue"; - EXPECT_EQ(expected, pageInfo.viewInfos[6]); - - expected.commonInfo = { 1680, 1200, 800, 200, "Label_MenuDialogCancel", "UILabel", true }; - std::get(expected.specificInfo).text = "Cancel"; - EXPECT_EQ(expected, pageInfo.viewInfos[7]); + { + UxViewInfo expectedProgress = CreateViewInfo( + UxViewCommonInfo {0, 0, 100, 100, "box_progress_0", "UIBoxProgress", true}, + UxBoxProgressInfo {10, "#ffffffff", "#ffffffff", "", false}); + EXPECT_EQ(pageInfo.viewInfos[2].commonInfo, expectedProgress.commonInfo); + EXPECT_TRUE(Equals(pageInfo.viewInfos[2].specificInfo, expectedProgress.specificInfo)); + } } HWTEST_F(UpdaterUiLayoutParserUnitTest, test_load_multiple_page_info, TestSize.Level0) { - std::vector layoutFiles { "/data/updater/ui/imageview.json", "/data/updater/ui/boxprogress.json" }; std::vector pageInfos {}; - LayoutParser::GetInstance().LoadLayout(layoutFiles, pageInfos); + LoadValidConfigs({"/data/updater/ui/imageview.json", "/data/updater/ui/boxprogress.json"}, pageInfos); - ASSERT_EQ(pageInfos.size(), 2ul); - UxViewInfo expectedImage { UxViewCommonInfo { 0, 0, 100, 100, "image_view", "UIImageView", true }, - UxImageInfo { "/res/images", "", 100, 1 } }; + UxViewInfo expectedImage = CreateViewInfo( + UxViewCommonInfo {0, 0, 100, 100, "image_view", "UIImageView", true}, UxImageInfo {"/res/images", "", 100, 1}); EXPECT_EQ(pageInfos[0].id, "menu"); ASSERT_EQ(pageInfos[0].viewInfos.size(), 1ul); - EXPECT_EQ(pageInfos[0].viewInfos[0], expectedImage); + EXPECT_EQ(pageInfos[0].viewInfos[0].commonInfo, expectedImage.commonInfo); + EXPECT_TRUE(Equals(pageInfos[0].viewInfos[0].specificInfo, expectedImage.specificInfo)); - UxViewInfo expectedProgress { UxViewCommonInfo { 0, 0, 100, 100, "box_progress_0", "UIBoxProgress", true }, - UxBoxProgressInfo { 10, "#ffffffff", "#ffffffff" } }; + UxViewInfo expectedProgress = + CreateViewInfo(UxViewCommonInfo {0, 0, 100, 100, "box_progress_0", "UIBoxProgress", true}, + UxBoxProgressInfo {10, "#ffffffff", "#ffffffff"}); EXPECT_EQ(pageInfos[1].id, "menu"); ASSERT_EQ(pageInfos[1].viewInfos.size(), 1ul); EXPECT_EQ(pageInfos[1].viewInfos[0].commonInfo, expectedProgress.commonInfo); + EXPECT_TRUE(Equals(pageInfos[1].viewInfos[0].specificInfo, expectedProgress.specificInfo)); } HWTEST_F(UpdaterUiLayoutParserUnitTest, test_load_sub_page_info, TestSize.Level0) { - std::vector layoutFiles { "/data/updater/ui/subpage.json" }; std::vector pageInfos {}; - LayoutParser::GetInstance().LoadLayout(layoutFiles, pageInfos); + LoadValidConfigs({"/data/updater/ui/subpage.json"}, pageInfos); ASSERT_EQ(pageInfos.size(), 1ul); auto &subPages = pageInfos[0].subpages; @@ -277,7 +285,249 @@ HWTEST_F(UpdaterUiLayoutParserUnitTest, test_invalid_cases, TestSize.Level0) std::vector layoutFiles { file }; std::vector pageInfos {}; EXPECT_EQ(true, OHOS::FileExists(file)) << file; - EXPECT_EQ(false, LayoutParser::GetInstance().LoadLayout(layoutFiles, pageInfos)); + EXPECT_FALSE(LayoutParser::GetInstance().LoadLayout(layoutFiles, pageInfos)); + } +} + +class UpdaterUiMenuParserUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp() override; + void TearDown() override; + +protected: + struct TestMenuItem { + UxViewCommonInfo common; + UxLabelInfo label; + + friend bool operator==(const TestMenuItem &lhs, const TestMenuItem &rhs) + { + return (lhs.common == rhs.common) && (lhs.label == rhs.label); + } + }; + static bool GetMenuItem(size_t index, TestMenuItem &item); + static TestMenuItem GetDefaultValue(); + + inline static std::vector pages_; +}; + +void UpdaterUiMenuParserUnitTest::SetUp(void) +{ + cout << "Updater Unit UpdaterUiMenuParserUnitTest Begin!" << endl; + ASSERT_TRUE(LayoutParser::GetInstance().LoadLayout({"/data/updater/ui/menu.json"}, pages_)); +} + +void UpdaterUiMenuParserUnitTest::TearDown(void) +{ + cout << "Updater Unit UpdaterUiMenuParserUnitTest End!" << endl; +} + +void UpdaterUiMenuParserUnitTest::SetUpTestCase() +{ + cout << "SetUpTestCase" << endl; +} + +void UpdaterUiMenuParserUnitTest::TearDownTestCase() +{ + cout << "TearDownTestCase" << endl; +} + +bool UpdaterUiMenuParserUnitTest::GetMenuItem(size_t index, UpdaterUiMenuParserUnitTest::TestMenuItem &item) +{ + const SpecificInfoWrapper emptyItem {}; + + if (pages_.size() != 1UL) { + return false; + } + + if (index >= pages_[0].viewInfos.size()) { + return false; + } + + UxViewInfo &refInfo = pages_[0].viewInfos[index]; + item.common = refInfo.commonInfo; + + if (refInfo.specificInfo == nullptr) { + return false; + } + if (refInfo.specificInfo->GetType() != emptyItem.GetType()) { + return false; } + if (refInfo.specificInfo->GetStructKey() != emptyItem.GetStructKey()) { + return false; + } + + const UxLabelInfo &refLabel = CastSpecificInfoAs(refInfo.specificInfo.get()); + item.label = refLabel; + return true; +} + +UpdaterUiMenuParserUnitTest::TestMenuItem UpdaterUiMenuParserUnitTest::GetDefaultValue() +{ + // the default node + TestMenuItem item {.common = UxViewCommonInfo {.visible = true}, + .label = UxLabelInfo {.align = "center", + .fontColor = "#ffffffff", + .bgColor = "#000000ff", + .style = "normal", + .focusInfo = + LabelFocusInfo {.focusedFontColor = "#ffffffff", .focusedBgColor = "#000000ff", .focusable = false}, + .touchable = false, + .lineBreakMode = "ellipsis"}}; + return item; +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_basic, TestSize.Level0) +{ + ASSERT_EQ(pages_.size(), 1UL); + ASSERT_EQ(pages_[0].viewInfos.size(), 8UL); + EXPECT_EQ(pages_[0].id, "menu"s); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_00, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(0, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_RebootToNormalSystem"; + expected.common.x = 1280; + expected.common.y = 0; + expected.common.w = 800; + expected.common.h = 200; + expected.common.visible = false; + expected.label.text = "Reboot to normal system"; + expected.label.fontSize = 60; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_01, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(1, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_UserdataReset"; + expected.common.x = 1280; + expected.common.y = 200; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Userdata reset"; + expected.label.fontSize = 60; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_02, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(2, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_UpdateFromSDCard"; + expected.common.x = 1280; + expected.common.y = 400; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Update from SD Card"; + expected.label.fontSize = 60; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_03, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(3, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_MenuDialogTitle"; + expected.common.x = 1280; + expected.common.y = 600; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Tip"; + expected.label.fontSize = 40; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_04, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(4, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_MenuDialogNote"; + expected.common.x = 1280; + expected.common.y = 800; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Delete user date now..."; + expected.label.fontSize = 40; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_05, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(5, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_MenuDialogNext"; + expected.common.x = 1280; + expected.common.y = 1000; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Do you want to continue?"; + expected.label.fontSize = 40; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_06, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(6, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_MenuDialogOK"; + expected.common.x = 1280; + expected.common.y = 1200; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Continue"; + expected.label.fontSize = 40; + + EXPECT_EQ(item, expected); +} + +HWTEST_F(UpdaterUiMenuParserUnitTest, test_menu_item_07, TestSize.Level0) +{ + TestMenuItem item; + ASSERT_TRUE(GetMenuItem(7, item)); + + TestMenuItem expected = GetDefaultValue(); + expected.common.type = "UILabel"; + expected.common.id = "Label_MenuDialogCancel"; + expected.common.x = 1680; + expected.common.y = 1200; + expected.common.w = 800; + expected.common.h = 200; + expected.label.text = "Cancel"; + expected.label.fontSize = 40; + + EXPECT_EQ(item, expected); } -} // namespace + +} // namespace diff --git a/test/unittest/updater_ui_test/view/ui_page_manager_unittest.cpp b/test/unittest/updater_ui_test/view/ui_page_manager_unittest.cpp index 5d1eca4de760d8566179917a7f2874ee0b86a5ee..a9af3903aed207a38bd027815e214d30250d1c54 100644 --- a/test/unittest/updater_ui_test/view/ui_page_manager_unittest.cpp +++ b/test/unittest/updater_ui_test/view/ui_page_manager_unittest.cpp @@ -1,398 +1,453 @@ -/* - * Copyright (c) 2022 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 -#include "gtest/gtest.h" -#include "ui_test_graphic_engine.h" -#include "view/component/img_view_adapter.h" -#include "view/component/text_label_adapter.h" -#include "view/page/page_manager.h" - -using namespace Updater; -using namespace std; -using namespace testing::ext; - -namespace { -std::string ToString(const std::vector &vec) -{ - if (vec.empty()) { - return "{}"; - } - std::string res = "{"; - for (auto &str : vec) { - res += str + ","; - } - res.pop_back(); - res += "}"; - return res; -} - -class UpdaterUiPageManagerUnitTest : public testing::Test { -public: - static void SetUpTestCase(void) - { - TestGraphicEngine::GetInstance(); - } - static void TearDownTestCase(void) {} - void SetUp() override {} - void TearDown() override {} -protected: - constexpr static const char *MAIN_PAGE_ID = "page1"; - const static std::vector pageInfos_; -}; - -inline PageManager &GetInstance() -{ - return PageManager::GetInstance(); -} - -constexpr std::array VALID_COMINFOS { - std::pair {"page1", "label_id_0"}, std::pair {"page1", "image_view"}, - std::pair {"page1:subpage1", "label_id_0"}, std::pair {"page1:subpage1", "image_view"}, - std::pair {"page1:subpage2", "image_view"}, std::pair {"page1:subpage3", "label_id_0"}, - std::pair {"page2", "label_id_0"}, std::pair {"page2", "image_view"}, - std::pair {"page2:subpage1", "label_id_0"}, std::pair {"page2:subpage2", "image_view"}, - std::pair {"page3", "label_id_0"}, std::pair {"page3", "image_view"} -}; - -const std::vector UpdaterUiPageManagerUnitTest::pageInfos_ = { - {"page1", - "#000000ff", - {UxViewInfo { - UxViewCommonInfo { - 300, 400, 600, 200, "label_id_0", "UILabel", true}, - UxLabelInfo { - 50, "this is page1", "center", "#ff0000ff", "#000000ff", "normal", - {"#ff0000ff", "#000000ff", false}, false, "ellipsis"}}, - UxViewInfo { - UxViewCommonInfo { - 300, 700, 400, 400, "image_view", "UIImageView", false}, - UxImageInfo { - "/resources/img1", "empty", 100, 0 // just test page manger, image need not to exist - }}}, - {UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0", "image_view"}}, - UxSubPageInfo {"subpage2", "#000000ff", {"image_view"}}, - UxSubPageInfo {"subpage3", "#000000ff", {"label_id_0"}}}}, - {"page2", - "#ffffffff", - {UxViewInfo { - UxViewCommonInfo { - 300, 400, 600, 200, "label_id_0", "UILabel", true}, - UxLabelInfo { - 50, "this is page2", "center", "#00ff00ff", "#000000ff", "normal", - {"#00ff00ff", "#000000ff", false}, false, "ellipsis"}}, - UxViewInfo { - UxViewCommonInfo { - 300, 700, 400, 400, "image_view", "UIImageView", false}, - UxImageInfo { - "/resources/img2", "empty", 100, 0 // just test page manger, image need not to exist - }}}, - {UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}, - UxSubPageInfo {"subpage2", "#000000ff", {"image_view"}}}}, - {"page3", - "#000000ff", - {UxViewInfo { - UxViewCommonInfo { - 300, 400, 600, 200, "label_id_0", "UILabel", true}, - UxLabelInfo { - 50, "this is page2", "center", "#0000ffff", "#000000ff", "normal", - {"#0000ffff", "#000000ff", false}, false, "ellipsis"}}, - UxViewInfo { - UxViewCommonInfo { - 300, 700, 400, 400, "image_view", "UIImageView", false}, - UxImageInfo { - "/resources/img2", "empty", 100, 0 // just test page manger, image need not to exist - }}}}}; - -inline bool CheckResult(const std::vector &expected, std::vector &&checked) -{ - std::sort(checked.begin(), checked.end()); - EXPECT_TRUE(expected == checked) << ToString(expected) << "!=" << ToString(checked); - return expected == checked; -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_init_failed, TestSize.Level0) -{ - { - // invalid page id - std::vector pageInfo { { "", "#000000ff", {}, {} } }; - EXPECT_FALSE(GetInstance().Init(pageInfo, "")); - - // duplicate page id - pageInfo = { - { "page1", "#000000ff", {}, {} }, - { "page1", "#000000ff", {}, {} } - }; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page1")); - - // invalid page's view info - pageInfo = { - {"page1", - "#000000ff", - {UxViewInfo { - UxViewCommonInfo { - 300, 400, 600, 200, "label_id_0", "UILabel", true}, - UxLabelInfo { - 50, "this is page1", "center", "#ff0ff", "#0", "normal", - {"#ff0ff", "#0", false}, false, "ellipsis"}}}, {}} - }; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page1")); - } - { - GetInstance().Reset(); - // invalid subpage id - std::vector pageInfo { - {"page1", - "#000000ff", - {UxViewInfo { - UxViewCommonInfo { - 300, 400, 600, 200, "label_id_0", "UILabel", true}, - UxLabelInfo { - 50, "this is page1", "center", "#000000ff", "#000000ff", "normal", - {"#000000ff", "#000000ff", false}, false, "ellipsis"}}}, - {{UxSubPageInfo {"", "#000000ff", {"label_id_0"}}}}}}; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page1")); - - // duplicate subpage id - pageInfo[0].subpages = { UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}, - UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}}; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page1")); - - // invalid subpage's component id - pageInfo[0].subpages = {UxSubPageInfo {"subpage1", "#000000ff", {"invalid_id"}}}; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page1")); - } - { - GetInstance().Reset(); - std::vector pageInfo { - { "page1", "#000000ff", {}, {} }, - { "page2", "#000000ff", {}, {} }, - { "page3", "#000000ff", {}, {} } - }; - EXPECT_FALSE(GetInstance().Init(pageInfo, "page")); // invalid main page id - } -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_is_valid_com, TestSize.Level0) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - for (auto [pageId, comId] : VALID_COMINFOS) { - EXPECT_TRUE(GetInstance().IsValidCom(ComInfo {pageId, comId})) << pageId << "[" << comId << "] is invalid"; - } - const std::array inValidCominfos { - ComInfo {"page1", "invalid"}, ComInfo {"invalid", "image_view"}, ComInfo {"page1:subpage2", "label_id_0"} - }; - for (auto cominfo : inValidCominfos) { - EXPECT_FALSE(GetInstance().IsValidCom(cominfo)) << cominfo.pageId << "[" << cominfo.comId << "] is valid"; - } - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_operator_subscript_for_pages, TestSize.Level0) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - auto *dummyPage = &GetInstance()[""]; - for (auto pageId : { "page1", "page2", "page3", "page1:subpage1", "page1:subpage2", "page1:subpage3", - "page2:subpage1", "page2:subpage2"}) { - EXPECT_NE(&GetInstance()[pageId], dummyPage); - } - EXPECT_EQ(&GetInstance()["nonexist"], dummyPage); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_operator_subscript_for_coms, TestSize.Level0) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - - std::string errMsg {}; - for (auto [pageId, comId] : { std::pair {"page1", "label_id_0"}, std::pair {"page1:subpage1", "label_id_0"}, - std::pair {"page1:subpage3", "label_id_0"}, std::pair {"page2", "label_id_0"}, - std::pair {"page2:subpage1", "label_id_0"}, std::pair {"page3", "label_id_0"}}) { - GetInstance()[ComInfo {pageId, comId}].As(errMsg); - ASSERT_EQ(errMsg, "") << errMsg; - } - for (auto [pageId, comId] : { std::pair {"page1", "image_view"}, std::pair {"page1:subpage1", "image_view"}, - std::pair {"page1:subpage2", "image_view"}, std::pair {"page2", "image_view"}, - std::pair {"page2:subpage2", "image_view"}, std::pair {"page3", "image_view"}}) { - GetInstance()[ComInfo {pageId, comId}].As(errMsg); - ASSERT_EQ(errMsg, "") << errMsg; - } - GetInstance()[ComInfo {"", ""}].As(errMsg); - EXPECT_EQ(errMsg, " view is null"); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_after_init_success, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - EXPECT_TRUE(CheckResult(GetInstance().Report(), {})); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_main_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2"); - GetInstance().ShowMainPage(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_non_exist_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowMainPage(); - GetInstance().ShowPage("nonexist"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - GetInstance().ShowPage("page3"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_sub_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2:subpage1"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2:subpage1", "page2" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_non_exist_sub_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page2:subpage3"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_sub_pages, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page1:subpage1"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage1", "page1" })); - - GetInstance().ShowPage("page2:subpage2"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2:subpage2", "page2" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_sub_page_and_page, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowPage("page1:subpage1"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage1", "page1" })); - - GetInstance().ShowPage("page2"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - - GetInstance().ShowPage("page1:subpage2"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage2", "page1" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_go_back, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowMainPage(); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page3"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_same_page_and_goback, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowMainPage(); - GetInstance().ShowPage("page1"); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page3"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - - // don't show and enqueue page showing currently - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1" })); - GetInstance().Reset(); -} - -HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_more_page_than_queue_limit, TestSize.Level1) -{ - auto pageInfo = pageInfos_; - ASSERT_EQ(GetInstance().Init(pageInfo, MAIN_PAGE_ID), true); - GetInstance().ShowMainPage(); - GetInstance().ShowPage("page3"); - GetInstance().ShowPage("page1"); - GetInstance().ShowPage("page2"); - GetInstance().ShowPage("page3"); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - - // Don't show and enqueue page showing currently - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); - - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1" })); - - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - - // max queue size is 3, when bigger than 3, queue tail will be pop, so can't show page3 here - GetInstance().GoBack(); - EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); - GetInstance().Reset(); -} -} +/* + * Copyright (c) 2025 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 +#include "gtest/gtest.h" +#include "ui_test_graphic_engine.h" +#include "view/component/component_register.h" +#include "view/component/img_view_adapter.h" +#include "view/component/text_label_adapter.h" +#include "view/page/page_manager.h" + +using namespace Updater; +using namespace std; +using namespace testing::ext; + +namespace { +std::string ToString(const std::vector &vec) +{ + if (vec.empty()) { + return "{}"; + } + std::string res = "{"; + for (auto &str : vec) { + res += str + ","; + } + res.pop_back(); + res += "}"; + return res; +} + +template +UxViewInfo CreateViewInfo(UxViewCommonInfo commonInfo, typename T::SpecificInfoType specInfo) +{ + UxViewInfo info {commonInfo, ComponentFactory::CreateSpecificInfo(T::COMPONENT_TYPE)}; + EXPECT_NE(info.specificInfo.get(), nullptr); + static_cast *>(info.specificInfo.get())->data = specInfo; + return info; +} + +class UpdaterUiPageManagerUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) + { + TestGraphicEngine::GetInstance(); + } + static void TearDownTestCase(void) {} + void SetUp() override + { + RegisterComponents(); + pageInfos_ = MakeUxPages(); + } + void TearDown() override + { + pageInfos_.clear(); + } + +protected: + static std::vector MakeUxPages(); + +private: + static UxPageInfo MakeTestPage1(); + static UxPageInfo MakeTestPage2(); + static UxPageInfo MakeTestPage3(); + +protected: + constexpr static const char *MAIN_PAGE_ID = "page1"; + inline static std::vector pageInfos_; +}; + +inline PageManager &GetInstance() +{ + return PageManager::GetInstance(); +} + +constexpr std::array VALID_COMINFOS { + std::pair {"page1", "label_id_0"}, std::pair {"page1", "image_view"}, + std::pair {"page1:subpage1", "label_id_0"}, std::pair {"page1:subpage1", "image_view"}, + std::pair {"page1:subpage2", "image_view"}, std::pair {"page1:subpage3", "label_id_0"}, + std::pair {"page2", "label_id_0"}, std::pair {"page2", "image_view"}, + std::pair {"page2:subpage1", "label_id_0"}, std::pair {"page2:subpage2", "image_view"}, + std::pair {"page3", "label_id_0"}, std::pair {"page3", "image_view"} +}; + +UxPageInfo UpdaterUiPageManagerUnitTest::MakeTestPage1() +{ + UxPageInfo page1; + page1.id = "page1"; + page1.bgColor = "#000000ff"; + page1.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page1", "center", "#ff0000ff", "#000000ff", "normal", + {"#ff0000ff", "#000000ff", false}, false, "ellipsis"})); + // just test page manger, image need not to exist + page1.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 700, 400, 400, "image_view", "UIImageView", false}, + UxImageInfo {"/resources/img1", "empty", 100, 0})); + page1.subpages.emplace_back(UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0", "image_view"}}); + page1.subpages.emplace_back(UxSubPageInfo {"subpage2", "#000000ff", {"image_view"}}); + page1.subpages.emplace_back(UxSubPageInfo {"subpage3", "#000000ff", {"label_id_0"}}); + return page1; +} + +UxPageInfo UpdaterUiPageManagerUnitTest::MakeTestPage2() +{ + UxPageInfo page2; + page2.id = "page2"; + page2.bgColor = "#ffffffff"; + page2.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page2", "center", "#00ff00ff", "#000000ff", "normal", + {"#00ff00ff", "#000000ff", false}, false, "ellipsis"})); + // just test page manger, image need not to exist + page2.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 700, 400, 400, "image_view", "UIImageView", false}, + UxImageInfo {"/resources/img2", "empty", 100, 0})); + page2.subpages.emplace_back(UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}); + page2.subpages.emplace_back(UxSubPageInfo {"subpage2", "#000000ff", {"image_view"}}); + return page2; +} + +UxPageInfo UpdaterUiPageManagerUnitTest::MakeTestPage3() +{ + UxPageInfo page3; + page3.id = "page3"; + page3.bgColor = "#000000ff"; + page3.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page2", "center", "#0000ffff", "#000000ff", "normal", + {"#0000ffff", "#000000ff", false}, false, "ellipsis"})); + // just test page manger, image need not to exist + page3.viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 700, 400, 400, "image_view", "UIImageView", false}, + UxImageInfo {"/resources/img2", "empty", 100, 0})); + return page3; +} + +std::vector UpdaterUiPageManagerUnitTest::MakeUxPages() +{ + std::vector pages; + + pages.emplace_back(MakeTestPage1()); + pages.emplace_back(MakeTestPage2()); + pages.emplace_back(MakeTestPage3()); + return pages; +} + +inline bool CheckResult(const std::vector &expected, std::vector &&checked) +{ + std::sort(checked.begin(), checked.end()); + EXPECT_TRUE(expected == checked) << ToString(expected) << "!=" << ToString(checked); + return expected == checked; +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_invalid_page_id, TestSize.Level0) +{ + // invalid page id + std::vector invalidPageId; + invalidPageId.emplace_back(UxPageInfo {"", "#000000ff", {}, {}}); + EXPECT_FALSE(GetInstance().Init(invalidPageId, "")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_duplicate_page_id, TestSize.Level0) +{ + // duplicate page id + std::vector duplicatePageIds; + duplicatePageIds.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + duplicatePageIds.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + EXPECT_FALSE(GetInstance().Init(duplicatePageIds, "page1")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_invalid_page_view, TestSize.Level0) +{ + // invalid page's view info + std::vector invalidPageView; + invalidPageView.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + invalidPageView[0].viewInfos.emplace_back(CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page1", "center", "#ff0ff", "#0", "normal", + {"#ff0ff", "#0", false}, false, "ellipsis"})); + EXPECT_FALSE(GetInstance().Init(invalidPageView, "page1")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_invalid_subpage_id, TestSize.Level0) +{ + GetInstance().Reset(); + // invalid subpage id + std::vector invalidSubpageId; + invalidSubpageId.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + invalidSubpageId[0].viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page1", "center", "#000000ff", "#000000ff", "normal", + {"#000000ff", "#000000ff", false}, false, "ellipsis"})); + invalidSubpageId[0].subpages.emplace_back(UxSubPageInfo {"", "#000000ff", {"label_id_0"}}); + EXPECT_FALSE(GetInstance().Init(invalidSubpageId, "page1")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_duplicate_subpage_ids, TestSize.Level0) +{ + // duplicate subpage id + std::vector duplicateSubpageIds; + duplicateSubpageIds.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + duplicateSubpageIds[0].viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page1", "center", "#000000ff", "#000000ff", "normal", + {"#000000ff", "#000000ff", false}, false, "ellipsis"})); + duplicateSubpageIds[0].subpages.emplace_back(UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}); + duplicateSubpageIds[0].subpages.emplace_back(UxSubPageInfo {"subpage1", "#000000ff", {"label_id_0"}}); + EXPECT_FALSE(GetInstance().Init(duplicateSubpageIds, "page1")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_invalid_subpage_component_id, TestSize.Level0) +{ + // invalid subpage's component id + std::vector invalidSubpageComponentId; + invalidSubpageComponentId.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + invalidSubpageComponentId[0].viewInfos.emplace_back( + CreateViewInfo( + UxViewCommonInfo {300, 400, 600, 200, "label_id_0", "UILabel", true}, + UxLabelInfo {50, "this is page1", "center", "#000000ff", "#000000ff", "normal", + {"#000000ff", "#000000ff", false}, false, "ellipsis"})); + invalidSubpageComponentId[0].subpages.emplace_back(UxSubPageInfo {"subpage1", "#000000ff", {"invalid_id"}}); + EXPECT_FALSE(GetInstance().Init(invalidSubpageComponentId, "page1")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_init_failed_invalid_main_page_id, TestSize.Level0) +{ + GetInstance().Reset(); + + // invalid main page id + std::vector invalidMainPageId; + invalidMainPageId.emplace_back(UxPageInfo {"page1", "#000000ff", {}, {}}); + invalidMainPageId.emplace_back(UxPageInfo {"page2", "#000000ff", {}, {}}); + invalidMainPageId.emplace_back(UxPageInfo {"page3", "#000000ff", {}, {}}); + + EXPECT_FALSE(GetInstance().Init(invalidMainPageId, "page")); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_is_valid_com, TestSize.Level0) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + for (auto [pageId, comId] : VALID_COMINFOS) { + EXPECT_TRUE(GetInstance().IsValidCom(ComInfo {pageId, comId})) << pageId << "[" << comId << "] is invalid"; + } + const std::array inValidCominfos { + ComInfo {"page1", "invalid"}, ComInfo {"invalid", "image_view"}, ComInfo {"page1:subpage2", "label_id_0"} + }; + for (auto cominfo : inValidCominfos) { + EXPECT_FALSE(GetInstance().IsValidCom(cominfo)) << cominfo.pageId << "[" << cominfo.comId << "] is valid"; + } + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_operator_subscript_for_pages, TestSize.Level0) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + auto *dummyPage = &GetInstance()[""]; + for (auto pageId : { "page1", "page2", "page3", "page1:subpage1", "page1:subpage2", "page1:subpage3", + "page2:subpage1", "page2:subpage2"}) { + EXPECT_NE(&GetInstance()[pageId], dummyPage); + } + EXPECT_EQ(&GetInstance()["nonexist"], dummyPage); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_operator_subscript_for_coms, TestSize.Level0) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + + std::string errMsg {}; + for (auto [pageId, comId] : { std::pair {"page1", "label_id_0"}, std::pair {"page1:subpage1", "label_id_0"}, + std::pair {"page1:subpage3", "label_id_0"}, std::pair {"page2", "label_id_0"}, + std::pair {"page2:subpage1", "label_id_0"}, std::pair {"page3", "label_id_0"}}) { + GetInstance()[ComInfo {pageId, comId}].As(errMsg); + ASSERT_EQ(errMsg, "") << errMsg; + } + for (auto [pageId, comId] : { std::pair {"page1", "image_view"}, std::pair {"page1:subpage1", "image_view"}, + std::pair {"page1:subpage2", "image_view"}, std::pair {"page2", "image_view"}, + std::pair {"page2:subpage2", "image_view"}, std::pair {"page3", "image_view"}}) { + GetInstance()[ComInfo {pageId, comId}].As(errMsg); + ASSERT_EQ(errMsg, "") << errMsg; + } + GetInstance()[ComInfo {"", ""}].As(errMsg); + EXPECT_EQ(errMsg, " view is null"); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_after_init_success, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + EXPECT_TRUE(CheckResult(GetInstance().Report(), {})); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_main_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2"); + GetInstance().ShowMainPage(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_non_exist_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowMainPage(); + GetInstance().ShowPage("nonexist"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + GetInstance().ShowPage("page3"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_sub_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2:subpage1"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2:subpage1", "page2" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_non_exist_sub_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page2:subpage3"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_sub_pages, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page1:subpage1"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage1", "page1" })); + + GetInstance().ShowPage("page2:subpage2"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2:subpage2", "page2" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_switch_between_sub_page_and_page, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowPage("page1:subpage1"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage1", "page1" })); + + GetInstance().ShowPage("page2"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + + GetInstance().ShowPage("page1:subpage2"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1:subpage2", "page1" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_go_back, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowMainPage(); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page3"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { MAIN_PAGE_ID })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_same_page_and_goback, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowMainPage(); + GetInstance().ShowPage("page1"); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page3"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + + // don't show and enqueue page showing currently + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1" })); + GetInstance().Reset(); +} + +HWTEST_F(UpdaterUiPageManagerUnitTest, test_page_manager_show_more_page_than_queue_limit, TestSize.Level1) +{ + ASSERT_EQ(GetInstance().Init(pageInfos_, MAIN_PAGE_ID), true); + GetInstance().ShowMainPage(); + GetInstance().ShowPage("page3"); + GetInstance().ShowPage("page1"); + GetInstance().ShowPage("page2"); + GetInstance().ShowPage("page3"); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + + // Don't show and enqueue page showing currently + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page2" })); + + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page1" })); + + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + + // max queue size is 3, when bigger than 3, queue tail will be pop, so can't show page3 here + GetInstance().GoBack(); + EXPECT_TRUE(CheckResult(GetInstance().Report(), { "page3" })); + GetInstance().Reset(); +} +} // namespace