/*
 * 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_manager.h"
#include "common_components/mutator/mutator.h"
#include "common_components/mutator/mutator_manager.h"
#include "common_components/tests/test_helper.h"
#include "base_runtime.h"
#include "objects/base_object.h"

using namespace common;

namespace common::test {
class TestMutator : public Mutator {
public:
    using Mutator::VisitRawObjects;
};
class MutatorTest : public BaseTestWithScope {
protected:
    static void SetUpTestCase()
    {
        BaseRuntime::GetInstance()->InitFromDynamic();
    }
    static void TearDownTestCase() {}
};

HWTEST_F_L0(MutatorTest, GetThreadLocalData_Test1)
{
    ThreadLocalData *ret = GetThreadLocalData();
    ASSERT_TRUE(ret != nullptr);
}

HWTEST_F_L0(MutatorTest, TransitionGCPhase_Test1)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    bool ret = mutatorBase.TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);

    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE;
    mutatorBase.SetSuspensionFlag(flag);

    ret = mutatorBase.TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);

    ret = mutatorBase.TransitionGCPhase(true);
    EXPECT_TRUE(ret == true);
    ret = mutatorBase.TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test0)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();

    MutatorBase::SuspensionType  flag = MutatorBase::SuspensionType::SUSPENSION_FOR_STW;
    mutatorBase.SetSuspensionFlag(flag);

    mutatorBase.HandleSuspensionRequest();
    EXPECT_TRUE(mutatorBase.InSaferegion() == false);

    flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE;
    mutatorBase.SetSuspensionFlag(flag);
    mutatorBase.HandleSuspensionRequest();
    EXPECT_TRUE(mutatorBase.InSaferegion() == false);
}

HWTEST_F_L0(MutatorTest, SuspendForStw_Test0)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();

    mutatorBase.SuspendForStw();
    EXPECT_TRUE(mutatorBase.InSaferegion() == false);
}

HWTEST_F_L0(MutatorTest, VisitRawObjects_Nullptr_NoCall)
{
    TestMutator mutator;
    mutator.Init();
    mutator.PushRawObject(nullptr);

    bool called = false;
    RootVisitor func = [&called](const ObjectRef& obj) {
        called = true;
    };
    mutator.VisitRawObjects(func);
    EXPECT_FALSE(called);
}

HWTEST_F_L0(MutatorTest, VisitRawObjects_NonNull_Call)
{
    TestMutator mutator;
    mutator.Init();
    BaseObject mockObj;
    mutator.PushRawObject(&mockObj);

    bool called = false;
    RootVisitor func = [&called, &mockObj](const ObjectRef& obj) {
        called = true;
        EXPECT_EQ(obj.object, &mockObj);
    };

    mutator.VisitRawObjects(func);
    EXPECT_TRUE(called);
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test1)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_STW;
    mutatorBase.SetSuspensionFlag(flag);
    flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE;
    mutatorBase.SetSuspensionFlag(flag);
    mutatorBase.HandleSuspensionRequest();
    EXPECT_FALSE(mutatorBase.InSaferegion());
    EXPECT_TRUE(mutatorBase.FinishedTransition());
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test2)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_CPU_PROFILE;
    mutatorBase.SetSuspensionFlag(flag);
    mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE);
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    });
    mutatorBase.HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase.InSaferegion());
    EXPECT_TRUE(mutatorBase.FinishedCpuProfile());
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test3)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_STW);
    mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE);
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    });
    mutatorBase.HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase.InSaferegion());
    EXPECT_TRUE(mutatorBase.FinishedCpuProfile());
}

HWTEST_F_L0(MutatorTest, HandleGCPhase_SatbNodeNotNull)
{
    Mutator* mutator = MutatorManager::Instance().CreateRuntimeMutator(ThreadType::ARK_PROCESSOR);
    HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::MOVEABLE_OBJECT, true);
    BaseObject *mockObj = reinterpret_cast<BaseObject*>(addr);
    new (mockObj) BaseObject();
    mutator->RememberObjectInSatbBuffer(mockObj);
    EXPECT_NE(mutator->GetSatbBufferNode(), nullptr);
    MutatorBase* base = static_cast<MutatorBase*>(mutator->GetMutatorBasePtr());
    base->TransitionToGCPhaseExclusive(GCPhase::GC_PHASE_REMARK_SATB);
    EXPECT_EQ(mutator->GetSatbBufferNode(), nullptr);
    MutatorManager::Instance().DestroyRuntimeMutator(ThreadType::ARK_PROCESSOR);
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_LeaveSaferegion1)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    mutatorBase.IncObserver();
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase.DecObserver();
    });
    mutatorBase.HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase.InSaferegion());
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_LeaveSaferegion2)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_CPU_PROFILE;
    mutatorBase.SetSuspensionFlag(flag);
    mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE);
    mutatorBase.IncObserver();
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
        mutatorBase.DecObserver();
    });
    mutatorBase.HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase.InSaferegion());
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test4)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_STW);
    EXPECT_NO_FATAL_FAILURE(mutatorBase.HandleSuspensionRequest());
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test5)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();
    mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_GC_PHASE);
    EXPECT_NO_FATAL_FAILURE(mutatorBase.HandleSuspensionRequest());
}

HWTEST_F_L0(MutatorTest, TransitionToGCPhaseExclusive_TestEnum)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();

    GCPhase phase = GCPhase::GC_PHASE_ENUM;
    EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase));
}

HWTEST_F_L0(MutatorTest, TransitionToGCPhaseExclusive_TestPrecopy)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();

    GCPhase phase = GCPhase::GC_PHASE_PRECOPY;
    EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase));
}

HWTEST_F_L0(MutatorTest, TransitionToGCPhaseExclusive_TestIdle)
{
    MutatorBase mutatorBase;
    mutatorBase.Init();

    GCPhase phase = GCPhase::GC_PHASE_IDLE;
    EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase));
}
}  // namespace common::test