* 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 "common_components/heap/heap.h"
#include "base_runtime.h"
#include "common_components/tests/test_helper.h"
#include <thread>
namespace common::test {
class BaseRuntimeTest : public BaseTestWithScope {
protected:
void SetUp() override {}
void TearDown() override {}
void ResetRuntime()
{
if (auto* instance = BaseRuntime::GetInstance()) {
BaseRuntime::DestroyInstance();
}
}
};
HWTEST_F_L0(BaseRuntimeTest, RequestGC_Test1)
{
BaseRuntime* runtime = BaseRuntime::GetInstance();
ASSERT_TRUE(runtime != nullptr);
runtime->RequestGC(static_cast<GCReason>(-1), false, static_cast<GCType>(-1));
BaseObject obj;
RefField<false> field(reinterpret_cast<HeapAddress>(&obj));
auto result = runtime->ReadBarrier(reinterpret_cast<void*>(&field));
EXPECT_TRUE(result != nullptr);
}
HWTEST_F_L0(BaseRuntimeTest, GetInstance_NotNull) {
auto* instance = BaseRuntime::GetInstance();
ASSERT_NE(instance, nullptr);
}
HWTEST_F_L0(BaseRuntimeTest, DestroyInstance_SafeIfUninitialized) {
auto* instance = BaseRuntime::GetInstance();
ASSERT_NE(instance, nullptr);
EXPECT_NO_FATAL_FAILURE(BaseRuntime::DestroyInstance());
instance = BaseRuntime::GetInstance();
ASSERT_NE(instance, nullptr);
}
HWTEST_F_L0(BaseRuntimeTest, GetInstance_ReturnsValidInstance) {
ResetRuntime();
BaseRuntime* instance1 = BaseRuntime::GetInstance();
BaseRuntime* instance2 = BaseRuntime::GetInstance();
ASSERT_NE(instance1, nullptr);
EXPECT_EQ(instance1, instance2);
}
HWTEST_F_L0(BaseRuntimeTest, ThreadSafe_GetInstance) {
ResetRuntime();
constexpr int kThreads = 4;
std::vector<BaseRuntime*> instances(kThreads);
std::vector<std::thread> threads;
for (int i = 0; i < kThreads; ++i) {
threads.emplace_back([&instances, i]() {
instances[i] = BaseRuntime::GetInstance();
});
}
for (auto& t : threads) {
t.join();
}
for (int i = 1; i < kThreads; ++i) {
EXPECT_EQ(instances[0], instances[i]);
}
}
HWTEST_F_L0(BaseRuntimeTest, RequestGC_Sync_CallsHeapManager) {
auto* runtime = BaseRuntime::GetInstance();
ASSERT_NE(runtime, nullptr);
runtime->InitFromDynamic();
struct TestCase {
GCReason reason;
bool async;
GCType gcType;
};
const std::vector<TestCase> testCases = {
{GC_REASON_USER, false, GC_TYPE_FULL},
{GC_REASON_USER, true, GC_TYPE_FULL},
{GC_REASON_BACKUP, false, GC_TYPE_FULL},
{GC_REASON_APPSPAWN, false, GC_TYPE_FULL}
};
for (TestCase tc : testCases) {
testing::internal::CaptureStderr();
EXPECT_NO_FATAL_FAILURE(runtime->RequestGC(tc.reason, tc.async, tc.gcType));
std::string output = testing::internal::GetCapturedStderr();
EXPECT_TRUE(output.empty()) << "GC reason " << static_cast<int>(tc.reason)
<< " produced unexpected stderr output.";
}
runtime->Fini();
BaseRuntime::DestroyInstance();
}
}