* Copyright (c) 2026 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 <cstdint>
#include "gtest/gtest.h"
#include "interfaces/inner_api/ace/ace_forward_compatibility.h"
#include "interfaces/inner_api/ace/declarative_module_preloader.h"
#include "interfaces/inner_api/ace/utils.h"
namespace OHOS::Ace {
namespace {
constexpr int32_t CALL_COUNT_NONE = 0;
constexpr int32_t CALL_COUNT_ONCE = 1;
constexpr uintptr_t MOCK_HANDLE_VALUE = 0x1234;
constexpr uintptr_t TEST_RUNTIME_VALUE = 0x5678;
constexpr uintptr_t TEST_HAP_PATH_MAP_VALUE = 0x9abc;
constexpr int32_t TEST_FORM_CONFIG_VALUE = static_cast<int32_t>(FormJsXNodeLoadMode::FULL);
constexpr char TEST_BUNDLE_NAME[] = "com.test.bundle";
constexpr char MOCK_LIB_NAME[] = "libace_test_mock.z.so";
}
void* g_mockLoadLibResult = nullptr;
void* g_mockLoadSymResult = nullptr;
int32_t g_loadLibCallCount = 0;
int32_t g_loadSymCallCount = 0;
int32_t g_freeLibCallCount = 0;
void* g_lastHandle = nullptr;
const char* LAST_LIB_PATH = nullptr;
const char* LAST_SYMBOL = nullptr;
bool g_createEntryCalled = false;
void* g_createEntryRuntime = nullptr;
bool g_cardEntryCalled = false;
void* g_cardEntryRuntime = nullptr;
const char* CARD_ENTRY_BUNDLE_NAME = nullptr;
const void* g_cardEntryHapPathMap = nullptr;
bool g_formEntryCalled = false;
void* g_formEntryRuntime = nullptr;
int32_t g_formEntryConfig = CALL_COUNT_NONE;
void MockFreeLib(void* libHandle)
{
g_freeLibCallCount++;
g_lastHandle = libHandle;
}
void* MockLoadLib(const char* libPath)
{
g_loadLibCallCount++;
LAST_LIB_PATH = libPath;
return g_mockLoadLibResult;
}
void* MockLoadSym(void* libHandle, const char* symbol)
{
g_loadSymCallCount++;
g_lastHandle = libHandle;
LAST_SYMBOL = symbol;
return g_mockLoadSymResult;
}
const char* AceForwardCompatibility::GetAceLibName()
{
return MOCK_LIB_NAME;
}
}
#undef LOADLIB
#undef LOADSYM
#undef FREELIB
#define LOADLIB OHOS::Ace::MockLoadLib
#define LOADSYM OHOS::Ace::MockLoadSym
#define FREELIB OHOS::Ace::MockFreeLib
#include "interfaces/inner_api/ace/declarative_module_preloader.cpp"
namespace OHOS::Ace {
using namespace testing;
using namespace testing::ext;
class DeclarativeModulePreloaderTest : public testing::Test {
public:
void SetUp() override
{
g_mockLoadLibResult = nullptr;
g_mockLoadSymResult = nullptr;
g_loadLibCallCount = CALL_COUNT_NONE;
g_loadSymCallCount = CALL_COUNT_NONE;
g_freeLibCallCount = CALL_COUNT_NONE;
g_lastHandle = nullptr;
LAST_LIB_PATH = nullptr;
LAST_SYMBOL = nullptr;
g_createEntryCalled = false;
g_createEntryRuntime = nullptr;
g_cardEntryCalled = false;
g_cardEntryRuntime = nullptr;
CARD_ENTRY_BUNDLE_NAME = nullptr;
g_cardEntryHapPathMap = nullptr;
g_formEntryCalled = false;
g_formEntryRuntime = nullptr;
g_formEntryConfig = CALL_COUNT_NONE;
}
};
* @tc.name: DeclarativeModulePreloaderTest001
* @tc.desc: Test InitAceModule when library loading fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest001, TestSize.Level1)
{
InitAceModule(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_NONE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_FALSE(g_createEntryCalled);
EXPECT_STREQ(LAST_LIB_PATH, MOCK_LIB_NAME);
EXPECT_EQ(LAST_SYMBOL, nullptr);
}
* @tc.name: DeclarativeModulePreloaderTest002
* @tc.desc: Test InitAceModule when symbol lookup fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest002, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
InitAceModule(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_ONCE);
EXPECT_FALSE(g_createEntryCalled);
EXPECT_EQ(g_lastHandle, g_mockLoadLibResult);
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC);
}
* @tc.name: DeclarativeModulePreloaderTest003
* @tc.desc: Test InitAceModule when symbol lookup succeeds.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest003, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
g_mockLoadSymResult = reinterpret_cast<void*>(+[](void* runtime) {
g_createEntryCalled = true;
g_createEntryRuntime = runtime;
});
InitAceModule(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_TRUE(g_createEntryCalled);
EXPECT_EQ(g_createEntryRuntime, reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC);
}
* @tc.name: DeclarativeModulePreloaderTest004
* @tc.desc: Test InitAceModuleCard when library loading fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest004, TestSize.Level1)
{
InitAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_NONE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_FALSE(g_cardEntryCalled);
EXPECT_STREQ(LAST_LIB_PATH, MOCK_LIB_NAME);
EXPECT_EQ(LAST_SYMBOL, nullptr);
}
* @tc.name: DeclarativeModulePreloaderTest005
* @tc.desc: Test InitAceModuleCard when symbol lookup fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest005, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
InitAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_ONCE);
EXPECT_FALSE(g_cardEntryCalled);
EXPECT_EQ(g_lastHandle, g_mockLoadLibResult);
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC_CARD);
}
* @tc.name: DeclarativeModulePreloaderTest006
* @tc.desc: Test InitAceModuleCard when symbol lookup succeeds.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest006, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
g_mockLoadSymResult = reinterpret_cast<void*>(+[](void* runtime, const char* bundleName, const void* hapPathMap) {
g_cardEntryCalled = true;
g_cardEntryRuntime = runtime;
CARD_ENTRY_BUNDLE_NAME = bundleName;
g_cardEntryHapPathMap = hapPathMap;
});
InitAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_TRUE(g_cardEntryCalled);
EXPECT_EQ(g_cardEntryRuntime, reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_STREQ(CARD_ENTRY_BUNDLE_NAME, TEST_BUNDLE_NAME);
EXPECT_EQ(g_cardEntryHapPathMap, reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC_CARD);
}
* @tc.name: DeclarativeModulePreloaderTest007
* @tc.desc: Test ReloadAceModuleCard when library loading fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest007, TestSize.Level1)
{
ReloadAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_NONE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_FALSE(g_cardEntryCalled);
EXPECT_STREQ(LAST_LIB_PATH, MOCK_LIB_NAME);
EXPECT_EQ(LAST_SYMBOL, nullptr);
}
* @tc.name: DeclarativeModulePreloaderTest008
* @tc.desc: Test ReloadAceModuleCard when symbol lookup fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest008, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
ReloadAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_ONCE);
EXPECT_FALSE(g_cardEntryCalled);
EXPECT_EQ(g_lastHandle, g_mockLoadLibResult);
EXPECT_STREQ(LAST_SYMBOL, RELOAD_ACE_MODULE_FUNC_CARD);
}
* @tc.name: DeclarativeModulePreloaderTest009
* @tc.desc: Test ReloadAceModuleCard when symbol lookup succeeds.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest009, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
g_mockLoadSymResult = reinterpret_cast<void*>(+[](void* runtime, const char* bundleName, const void* hapPathMap) {
g_cardEntryCalled = true;
g_cardEntryRuntime = runtime;
CARD_ENTRY_BUNDLE_NAME = bundleName;
g_cardEntryHapPathMap = hapPathMap;
});
ReloadAceModuleCard(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_BUNDLE_NAME,
reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_TRUE(g_cardEntryCalled);
EXPECT_EQ(g_cardEntryRuntime, reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_STREQ(CARD_ENTRY_BUNDLE_NAME, TEST_BUNDLE_NAME);
EXPECT_EQ(g_cardEntryHapPathMap, reinterpret_cast<const void*>(TEST_HAP_PATH_MAP_VALUE));
EXPECT_STREQ(LAST_SYMBOL, RELOAD_ACE_MODULE_FUNC_CARD);
}
* @tc.name: DeclarativeModulePreloaderTest010
* @tc.desc: Test LoadJsXNodeForm when library loading fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest010, TestSize.Level1)
{
LoadJsXNodeForm(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_FORM_CONFIG_VALUE);
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_NONE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_FALSE(g_formEntryCalled);
EXPECT_STREQ(LAST_LIB_PATH, MOCK_LIB_NAME);
EXPECT_EQ(LAST_SYMBOL, nullptr);
}
* @tc.name: DeclarativeModulePreloaderTest011
* @tc.desc: Test LoadJsXNodeForm when symbol lookup fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest011, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
LoadJsXNodeForm(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_FORM_CONFIG_VALUE);
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_ONCE);
EXPECT_FALSE(g_formEntryCalled);
EXPECT_EQ(g_lastHandle, g_mockLoadLibResult);
EXPECT_STREQ(LAST_SYMBOL, LOAD_JS_XNODE_FUNC_FORM);
}
* @tc.name: DeclarativeModulePreloaderTest012
* @tc.desc: Test LoadJsXNodeForm when symbol lookup succeeds.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest012, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
g_mockLoadSymResult = reinterpret_cast<void*>(+[](void* runtime, int32_t config) {
g_formEntryCalled = true;
g_formEntryRuntime = runtime;
g_formEntryConfig = config;
});
LoadJsXNodeForm(reinterpret_cast<void*>(TEST_RUNTIME_VALUE), TEST_FORM_CONFIG_VALUE);
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_TRUE(g_formEntryCalled);
EXPECT_EQ(g_formEntryRuntime, reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_formEntryConfig, TEST_FORM_CONFIG_VALUE);
EXPECT_STREQ(LAST_SYMBOL, LOAD_JS_XNODE_FUNC_FORM);
}
* @tc.name: DeclarativeModulePreloaderTest013
* @tc.desc: Test InitAceModuleWorker when library loading fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest013, TestSize.Level1)
{
InitAceModuleWorker(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_NONE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_FALSE(g_createEntryCalled);
EXPECT_STREQ(LAST_LIB_PATH, MOCK_LIB_NAME);
EXPECT_EQ(LAST_SYMBOL, nullptr);
}
* @tc.name: DeclarativeModulePreloaderTest014
* @tc.desc: Test InitAceModuleWorker when symbol lookup fails.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest014, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
InitAceModuleWorker(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_ONCE);
EXPECT_FALSE(g_createEntryCalled);
EXPECT_EQ(g_lastHandle, g_mockLoadLibResult);
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC_WORKER);
}
* @tc.name: DeclarativeModulePreloaderTest015
* @tc.desc: Test InitAceModuleWorker when symbol lookup succeeds.
* @tc.type: FUNC
*/
HWTEST_F(DeclarativeModulePreloaderTest, DeclarativeModulePreloaderTest015, TestSize.Level1)
{
g_mockLoadLibResult = reinterpret_cast<void*>(MOCK_HANDLE_VALUE);
g_mockLoadSymResult = reinterpret_cast<void*>(+[](void* runtime) {
g_createEntryCalled = true;
g_createEntryRuntime = runtime;
});
InitAceModuleWorker(reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_EQ(g_loadLibCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_loadSymCallCount, CALL_COUNT_ONCE);
EXPECT_EQ(g_freeLibCallCount, CALL_COUNT_NONE);
EXPECT_TRUE(g_createEntryCalled);
EXPECT_EQ(g_createEntryRuntime, reinterpret_cast<void*>(TEST_RUNTIME_VALUE));
EXPECT_STREQ(LAST_SYMBOL, PRE_INIT_ACE_MODULE_FUNC_WORKER);
}
}