/*
 * Copyright (c) 2024 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 "gtest/gtest.h"

#define private public
#define protected public
#include "frameworks/bridge/common/utils/module_buffer_reader.h"
#include "frameworks/bridge/common/utils/transform_convertor.h"
#include "frameworks/bridge/common/utils/utils.h"

#undef private
#undef protected

using namespace testing;
using namespace testing::ext;

namespace OHOS::Ace::Framework {
class UtilsTest : public testing::Test {
public:
    static void SetUpTestSuite() {}
    static void TearDownTestSuite() {}
};

/**
 * @tc.name: UtilsTest001
 * @tc.desc: StepsCurveCreator
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest001, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string curve = "";

    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return Curves::EASE_IN_OUT.
     */
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "123)";
    EXPECT_EQ(CreateCurve(curve, false), nullptr);
    curve = "123)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "()";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "steps()";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "(test)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "steps(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "steps(0,aaaa)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "abc(1,aaaa)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "steps(1,aaaa)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "steps(1)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return Curve.
     */
    curve = "steps(1,start)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "steps(1,end)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "ease";
    EXPECT_NE(CreateCurve(curve), nullptr);
}

/**
 * @tc.name: UtilsTest002
 * @tc.desc: CubicCurveCreator、 SpringCurveCreator and InterpolatingSpringCreator
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest002, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */

    std::string curve = "";
    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return Curves::EASE_IN_OUT.
     */

    curve = "cubic-bezier(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "spring(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "interpolating-spring(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "spring-motion(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    curve = "responsive-spring-motion(1,2,3,4,5)";
    EXPECT_EQ(CreateCurve(curve), Curves::EASE_IN_OUT);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return Curve.
     */

    curve = "cubic-bezier(10,10,10,10)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "spring(10,10,10,10)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "interpolating-spring(10,10,10,10)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "spring-motion(10,10)";
    EXPECT_NE(CreateCurve(curve), nullptr);
    curve = "responsive-spring-motion(10,10)";
    EXPECT_NE(CreateCurve(curve), nullptr);
}

/**
 * @tc.name: UtilsTest003
 * @tc.desc: ParseBackgroundImagePosition
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest003, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */

    std::string value = "";
    BackgroundImagePosition backgroundImagePosition;
    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return true or false.
     */
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "10";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "top";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "10 10";
    ParseImageObjectPosition(value);
    EXPECT_FALSE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "top 10";
    ParseImageObjectPosition(value);
    EXPECT_FALSE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "10 left";
    ParseImageObjectPosition(value);
    EXPECT_FALSE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "top left";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "left top";
    ParseImageObjectPosition(value);
    value = "center center";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return true or false.
     */
    value = "10% 10%";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
    value = "10px 10px";
    ParseImageObjectPosition(value);
    EXPECT_TRUE(ParseBackgroundImagePosition(value, backgroundImagePosition));
}

/**
 * @tc.name: UtilsTest004
 * @tc.desc: ParseRadialGradientSize
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest004, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string value = "";
    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return std::nullopt.
     */
    EXPECT_EQ(ParseRadialGradientSize(value), std::nullopt);
    value = "10 10";
    EXPECT_EQ(ParseRadialGradientSize(value), std::nullopt);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return RadialSizeType.
     */
    value = "closest-corner";
    EXPECT_EQ(ParseRadialGradientSize(value), RadialSizeType::CLOSEST_CORNER);
}

/**
 * @tc.name: UtilsTest005
 * @tc.desc: ParseRadialGradientSize
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest005, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string value = "";
    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return nullptr.
     */
    EXPECT_EQ(CreateClipPath(value), nullptr);
    value = "test";
    EXPECT_EQ(CreateClipPath(value), nullptr);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return ClipPath.
     */
    value = "border-box circle(";
    EXPECT_NE(CreateClipPath(value), nullptr);
}

/**
 * @tc.name: UtilsTest006
 * @tc.desc: ParseRadialGradientSize
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest006, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string value = "";
    BackgroundImageSize bgImgSize;
    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return true.
     */
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10 10";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10% 10%";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10px 10px";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return true or false.
     */
    value = "contain";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10%";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
    value = "10px";
    EXPECT_TRUE(ParseBackgroundImageSize(value, bgImgSize));
}

/**
 * @tc.name: UtilsTest007
 * @tc.desc: ParseTransitionType
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest007, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string value = "";

    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return TransitionType::ALL.
     */

    EXPECT_EQ(ParseTransitionType(value), TransitionType::ALL);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return TransitionType.
     */

    value = "All";
    EXPECT_EQ(ParseTransitionType(value), TransitionType::ALL);
    value = "Insert";
    EXPECT_EQ(ParseTransitionType(value), TransitionType::APPEARING);
    value = "Delete";
    EXPECT_EQ(ParseTransitionType(value), TransitionType::DISAPPEARING);
}

/**
 * @tc.name: UtilsTest008
 * @tc.desc: ParseTransitionType
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest008, TestSize.Level1)
{
    /**
     * @tc.steps: step1. Create a string container.
     */
    std::string value = "";

    /**
     * @tc.steps: step2. Testing illegal values.
     * @tc.expected: return nullptr.
     */
    std::function<float(float)> fun;

    EXPECT_EQ(CreateCurve(fun), Curves::EASE_IN_OUT);
    EXPECT_NE(CreateCurveExceptSpring(value, fun), nullptr);
    /**
     * @tc.steps: step3. Normal testing
     * @tc.expected: return Curve.
     */

    value = "ease";
    EXPECT_NE(CreateCurveExceptSpring(value, fun), nullptr);
    value = "cubic-bezier";
    EXPECT_NE(CreateCurveExceptSpring(value, fun), nullptr);
    fun = [](float num) { return num; };
    EXPECT_NE(CreateCurveExceptSpring(value, fun), nullptr);
    EXPECT_NE(CreateCurve(fun), nullptr);
}

/**
 * @tc.name: UtilsTest009
 * @tc.desc: CreateCurveExceptSpring
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, UtilsTest009, TestSize.Level1)
{
    /**
     * @tc.steps: step1. construct params
     */
    std::string value = "aaa(int a,int b)";
    std::function<float(float)> fun = nullptr;
    EXPECT_EQ(CreateCurveExceptSpring(value, fun) == Curves::EASE_IN_OUT, true);
}

/**
 * @tc.name: transformConvertorTest001
 * @tc.desc: test func Convert
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest001, TestSize.Level1)
{
    /**
     * @tc.steps: step1. construct params for Convert
     */
    TransformConvertor transformConvertor;
    std::string key = "aaa";
    std::string value = "bbb";
    double time = 0.0;
    transformConvertor.Convert(key, value, time);
    key = "translate";
    transformConvertor.Convert(key, value, time);

    /**
     * @tc.steps: step2. construct params for AddAnimationToTweenOption
     */
    TweenOption tweenOption;
    transformConvertor.AddAnimationToTweenOption(tweenOption);
    EXPECT_EQ(tweenOption.GetTransformAnimations().size(), 1);
    transformConvertor.InsertIdentityKeyframe(time);
    EXPECT_EQ(transformConvertor.noneKeyframeTimes_.size() == 1, true);
    transformConvertor.AddAnimationToTweenOption(tweenOption);
    EXPECT_EQ(tweenOption.GetTransformAnimations().size(), 2);
    AnimationType type = AnimationType::TRANSLATE;
    RefPtr<Keyframe<TransformOperation>> keyframe;
    transformConvertor.AddKeyframe(type, keyframe);

    /**
     * @tc.steps: step3. construct params for ApplyCurve
     */
    RefPtr<Curve> curve;
    transformConvertor.ApplyCurve(curve);
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest002
 * @tc.desc: test func ClearAnimations
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest002, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    transformConvertor.ClearAnimations();

    EXPECT_EQ(transformConvertor.operationList_.size(), 0);
}

/**
 * @tc.name: transformConvertorTest003
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest003, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    TranslateOperation translate;
    transformConvertor.AddKeyframe(type, time, translate);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest004
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest004, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    SkewOperation skew(1.0f, 1.0f);
    transformConvertor.AddKeyframe(type, time, skew);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest005
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest005, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    ScaleOperation scale(1.0f, 1.0f, 1.0f);
    transformConvertor.AddKeyframe(type, time, scale);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest006
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest006, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    RotateOperation rotate(1.0f, 1.0f, 1.0f, 1.0f);
    transformConvertor.AddKeyframe(type, time, rotate);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest007
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest007, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    Matrix4 matrix4 = Matrix4::CreateIdentity();
    transformConvertor.AddKeyframe(type, time, matrix4);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: transformConvertorTest008
 * @tc.desc: test func AddKeyframe
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, transformConvertorTest008, TestSize.Level1)
{
    TransformConvertor transformConvertor;
    AnimationType type = AnimationType::TRANSLATE;
    double time = 1.0;
    PerspectiveOperation distance;
    transformConvertor.AddKeyframe(type, time, distance);
    
    EXPECT_EQ(transformConvertor.operationList_.size(), 1);
}

/**
 * @tc.name: moduleBufferReaderTest001
 * @tc.desc: test func ReadModuleBuffer
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, moduleBufferReaderTest001, TestSize.Level1)
{
    auto result = ModuleBufferReader::GetInstance().ReadModuleBuffer("request", nullptr, nullptr);
    EXPECT_EQ(result, false);

    // set impl.
    ModuleBufferReader::GetInstance().SetBufferReaderImpl(
        [](const std::string&, uint8_t**, size_t*) -> bool { return true; });
    result = ModuleBufferReader::GetInstance().ReadModuleBuffer("request", nullptr, nullptr);
    EXPECT_EQ(result, true);
}

/**
 * @tc.name: fontWeightNumericValueTest001
 * @tc.desc: Test GetFontWeightNumericValue function with standard weights (W100-W900)
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, fontWeightNumericValueTest001, TestSize.Level1)
{
    // Test standard weight values W100-W900
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W100), 100);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W200), 200);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W300), 300);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W400), 400);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W500), 500);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W600), 600);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W700), 700);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W800), 800);
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::W900), 900);
}

/**
 * @tc.name: fontWeightNumericValueTest002
 * @tc.desc: Test GetFontWeightNumericValue function with named weights (BOLD, NORMAL, etc.)
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, fontWeightNumericValueTest002, TestSize.Level1)
{
    // Test named weight values that should be converted
    // BOLD -> W700 -> 700
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::BOLD), 700);
    // NORMAL -> W400 -> 400
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::NORMAL), 400);
    // BOLDER -> W900 -> 900
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::BOLDER), 900);
    // LIGHTER -> W100 -> 100
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::LIGHTER), 100);
    // MEDIUM -> W500 -> 500
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::MEDIUM), 500);
    // REGULAR -> W400 -> 400
    EXPECT_EQ(GetFontWeightNumericValue(FontWeight::REGULAR), 400);
}

/**
 * @tc.name: fontWeightStringToNumericTest001
 * @tc.desc: Test complete flow from string weight to numeric value (e.g., "bold" -> 700)
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, fontWeightStringToNumericTest001, TestSize.Level1)
{
    // Test complete flow: string -> FontWeight enum -> numeric value
    // This verifies the integration between ConvertStrToFontWeight and GetFontWeightNumericValue

    // Test "bold" -> FontWeight::BOLD -> 700
    FontWeight boldEnum = ConvertStrToFontWeight("bold");
    EXPECT_EQ(GetFontWeightNumericValue(boldEnum), 700);

    // Test "normal" -> FontWeight::NORMAL -> 400
    FontWeight normalEnum = ConvertStrToFontWeight("normal");
    EXPECT_EQ(GetFontWeightNumericValue(normalEnum), 400);

    // Test "700" -> FontWeight::W700 -> 700
    FontWeight w700Enum = ConvertStrToFontWeight("700");
    EXPECT_EQ(GetFontWeightNumericValue(w700Enum), 700);

    // Test "400" -> FontWeight::W400 -> 400
    FontWeight w400Enum = ConvertStrToFontWeight("400");
    EXPECT_EQ(GetFontWeightNumericValue(w400Enum), 400);

    // Test "medium" -> FontWeight::MEDIUM -> 500
    FontWeight mediumEnum = ConvertStrToFontWeight("medium");
    EXPECT_EQ(GetFontWeightNumericValue(mediumEnum), 500);
}

/**
 * @tc.name: fontWeightStringToNumericTest002
 * @tc.desc: Test invalid variable font weight string fallback behavior
 * @tc.type: FUNC
 */
HWTEST_F(UtilsTest, fontWeightStringToNumericTest002, TestSize.Level1)
{
    const std::string invalidWeight = "100%";

    EXPECT_FALSE(OHOS::Ace::StringUtils::IsNumber(invalidWeight));

    auto parseResult = ParseFontWeight(invalidWeight);
    EXPECT_FALSE(parseResult.first);
    EXPECT_EQ(parseResult.second, FontWeight::NORMAL);

    FontWeight defaultEnum = ConvertStrToFontWeight(invalidWeight);
    EXPECT_EQ(defaultEnum, FontWeight::NORMAL);
    EXPECT_EQ(GetFontWeightNumericValue(defaultEnum), 400);
}

} // namespace OHOS::Ace::Framework