* 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 <parser/context/parserContext.h>
#include <parser/program/program.h>
#include <gtest/gtest.h>
#include <mem/pool_manager.h>
#include <util/ustring.h>
namespace panda::es2panda::parser {
using mem::MemConfig;
class MemManager {
public:
explicit MemManager()
{
constexpr auto COMPILER_SIZE = 8192_MB;
MemConfig::Initialize(0, 0, COMPILER_SIZE, 0);
PoolManager::Initialize(PoolType::MMAP);
}
NO_COPY_SEMANTIC(MemManager);
NO_MOVE_SEMANTIC(MemManager);
~MemManager()
{
PoolManager::Finalize();
MemConfig::Finalize();
}
};
class ParserContextTest : public ::testing::Test {
protected:
void SetUp() override
{
mm_ = std::make_unique<MemManager>();
}
void TearDown() override
{
mm_.reset();
}
std::unique_ptr<MemManager> mm_;
};
TEST_F(ParserContextTest, Constructor_Program_SetsProgram)
{
Program *program = nullptr;
ParserContext context(program);
EXPECT_EQ(context.GetProgram(), program);
EXPECT_EQ(context.Prev(), nullptr);
EXPECT_EQ(context.Status(), ParserStatus::NO_OPTS);
}
TEST_F(ParserContextTest, Constructor_WithEmptyLabel_SetsLabel)
{
Program *program = nullptr;
ParserContext parentContext(program);
util::StringView emptyLabel = "";
ParserContext childContext(&parentContext, ParserStatus::FUNCTION, emptyLabel);
EXPECT_EQ(childContext.GetProgram(), program);
EXPECT_EQ(childContext.Prev(), &parentContext);
EXPECT_TRUE(childContext.Status() & ParserStatus::FUNCTION);
}
TEST_F(ParserContextTest, Constructor_WithLabel_SetsLabel)
{
Program *program = nullptr;
ParserContext parentContext(program);
util::StringView label = "myLabel";
ParserContext childContext(&parentContext, ParserStatus::IN_LABELED, label);
EXPECT_EQ(childContext.GetProgram(), program);
EXPECT_EQ(childContext.Prev(), &parentContext);
EXPECT_TRUE(childContext.Status() & ParserStatus::IN_LABELED);
}
TEST_F(ParserContextTest, Constructor_ChildContext_PreservesInheritedFlags)
{
Program *program = nullptr;
ParserContext parentContext(program);
parentContext.Status() |= ParserStatus::MODULE;
ParserContext childContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_TRUE(childContext.Status() & ParserStatus::MODULE);
EXPECT_TRUE(childContext.Status() & ParserStatus::FUNCTION);
}
TEST_F(ParserContextTest, GetProgram_ReturnsCorrectProgram)
{
Program *program = nullptr;
ParserContext context(program);
EXPECT_EQ(context.GetProgram(), program);
}
TEST_F(ParserContextTest, Prev_RootContext_ReturnsNullptr)
{
Program *program = nullptr;
ParserContext context(program);
EXPECT_EQ(context.Prev(), nullptr);
}
TEST_F(ParserContextTest, Prev_ChildContext_ReturnsParent)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext childContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_EQ(childContext.Prev(), &parentContext);
}
TEST_F(ParserContextTest, Status_Setter_ModifiesStatus)
{
Program *program = nullptr;
ParserContext context(program);
context.Status() = ParserStatus::FUNCTION;
EXPECT_TRUE(context.Status() & ParserStatus::FUNCTION);
}
TEST_F(ParserContextTest, Status_ConstGetter_ReturnsStatus)
{
Program *program = nullptr;
ParserContext context(program);
const ParserContext &constContext = context;
EXPECT_EQ(constContext.Status(), ParserStatus::NO_OPTS);
}
TEST_F(ParserContextTest, IsGenerator_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext generatorContext(&parentContext, ParserStatus::GENERATOR_FUNCTION);
EXPECT_TRUE(generatorContext.IsGenerator());
}
TEST_F(ParserContextTest, IsGenerator_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext normalContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(normalContext.IsGenerator());
}
TEST_F(ParserContextTest, IsAsync_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext asyncContext(&parentContext, ParserStatus::ASYNC_FUNCTION);
EXPECT_TRUE(asyncContext.IsAsync());
}
TEST_F(ParserContextTest, IsAsync_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext syncContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(syncContext.IsAsync());
}
TEST_F(ParserContextTest, AllowYield_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext yieldContext(&parentContext, ParserStatus::ALLOW_YIELD);
EXPECT_TRUE(yieldContext.AllowYield());
}
TEST_F(ParserContextTest, AllowYield_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext noYieldContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(noYieldContext.AllowYield());
}
TEST_F(ParserContextTest, DisallowAwait_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext disallowAwaitContext(&parentContext, ParserStatus::DISALLOW_AWAIT);
EXPECT_TRUE(disallowAwaitContext.DisallowAwait());
}
TEST_F(ParserContextTest, DisallowAwait_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext allowAwaitContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(allowAwaitContext.DisallowAwait());
}
TEST_F(ParserContextTest, DisallowArguments_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext disallowArgsContext(&parentContext, ParserStatus::DISALLOW_ARGUMENTS);
EXPECT_TRUE(disallowArgsContext.DisallowArguments());
}
TEST_F(ParserContextTest, DisallowArguments_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext allowArgsContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(allowArgsContext.DisallowArguments());
}
TEST_F(ParserContextTest, IsModule_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext moduleContext(&parentContext, ParserStatus::MODULE);
EXPECT_TRUE(moduleContext.IsModule());
}
TEST_F(ParserContextTest, IsModule_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext scriptContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(scriptContext.IsModule());
}
TEST_F(ParserContextTest, IsTsModule_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext tsModuleContext(&parentContext, ParserStatus::TS_MODULE);
EXPECT_TRUE(tsModuleContext.IsTsModule());
}
TEST_F(ParserContextTest, IsTsModule_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext nonTsModuleContext(&parentContext, ParserStatus::MODULE);
EXPECT_FALSE(nonTsModuleContext.IsTsModule());
}
TEST_F(ParserContextTest, IsStaticBlock_WithFlag_ReturnsTrue)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext staticBlockContext(&parentContext, ParserStatus::STATIC_BLOCK);
EXPECT_TRUE(staticBlockContext.IsStaticBlock());
}
TEST_F(ParserContextTest, IsStaticBlock_WithoutFlag_ReturnsFalse)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext nonStaticContext(&parentContext, ParserStatus::FUNCTION);
EXPECT_FALSE(nonStaticContext.IsStaticBlock());
}
TEST_F(ParserContextTest, FindLabel_EmptyLabel_ReturnsNullptr)
{
Program *program = nullptr;
ParserContext rootContext(program);
util::StringView emptyLabel = "";
const auto *result = rootContext.FindLabel(emptyLabel);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, FindLabel_CallerWithoutLabel_ReturnsNullptr)
{
Program *program = nullptr;
ParserContext rootContext(program);
util::StringView searchLabel = "loop";
const auto *result = rootContext.FindLabel(searchLabel);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, FindLabel_SameContext_ReturnsThisContext)
{
Program *program = nullptr;
ParserContext rootContext(program);
util::StringView label = "loop";
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, label);
const auto *result = labeledContext.FindLabel(label);
EXPECT_NE(result, nullptr);
EXPECT_EQ(result, &labeledContext);
}
TEST_F(ParserContextTest, FindLabel_ParentContext_ReturnsParent)
{
Program *program = nullptr;
util::StringView label = "outer";
ParserContext rootContext(program);
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, label);
const auto *result = labeledContext.FindLabel(label);
EXPECT_NE(result, nullptr);
EXPECT_EQ(result, &labeledContext);
}
TEST_F(ParserContextTest, FindLabel_NotFound_ReturnsNullptr)
{
Program *program = nullptr;
util::StringView existingLabel = "existing";
util::StringView searchLabel = "nonexistent";
ParserContext rootContext(program);
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, existingLabel);
const auto *result = labeledContext.FindLabel(searchLabel);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, FindLabel_DeepChain_FindsRootLabel)
{
Program *program = nullptr;
util::StringView label = "rootLabel";
ParserContext rootContext(program);
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, label);
ParserContext middleContext(&labeledContext, ParserStatus::FUNCTION);
const auto *result = middleContext.FindLabel(label);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, FindLabel_MiddleContextWithEmptyLabel_ReturnsNullptr)
{
Program *program = nullptr;
util::StringView label = "rootLabel";
ParserContext rootContext(program);
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, label);
ParserContext middleContext(&labeledContext, ParserStatus::FUNCTION);
ParserContext deepContext(&middleContext, ParserStatus::FUNCTION);
const auto *result = deepContext.FindLabel(label);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, FindLabel_LabeledContext_SearchEmptyLabel)
{
Program *program = nullptr;
util::StringView label = "myLabel";
util::StringView emptyLabel = "";
ParserContext rootContext(program);
ParserContext labeledContext(&rootContext, ParserStatus::IN_LABELED, label);
const auto *result = labeledContext.FindLabel(emptyLabel);
EXPECT_EQ(result, nullptr);
}
TEST_F(ParserContextTest, MultipleStatusFlags_Combined_WorksCorrectly)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserStatus combined = ParserStatus::ASYNC_FUNCTION | ParserStatus::GENERATOR_FUNCTION;
ParserContext context(&parentContext, combined);
EXPECT_TRUE(context.IsAsync());
EXPECT_TRUE(context.IsGenerator());
}
TEST_F(ParserContextTest, VariousStatusFlags_CanBeSet)
{
Program *program = nullptr;
ParserContext parentContext(program);
ParserContext context(&parentContext, ParserStatus::ARROW_FUNCTION);
EXPECT_TRUE(context.Status() & ParserStatus::ARROW_FUNCTION);
EXPECT_FALSE(context.Status() & ParserStatus::FUNCTION);
}
TEST_F(ParserContextTest, CopyConstructor_PreservesStatus)
{
Program *program = nullptr;
ParserContext original(program);
original.Status() = ParserStatus::FUNCTION;
ParserContext copy = original;
EXPECT_EQ(copy.Status(), original.Status());
EXPECT_EQ(copy.GetProgram(), original.GetProgram());
}
TEST_F(ParserContextTest, MoveConstructor_TransfersStatus)
{
Program *program = nullptr;
ParserContext original(program);
original.Status() = ParserStatus::FUNCTION;
ParserContext moved = std::move(original);
EXPECT_TRUE(moved.Status() & ParserStatus::FUNCTION);
EXPECT_EQ(moved.GetProgram(), program);
}
}