1/**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <gtest/gtest.h>
17#include <algorithm>
18#include "macros.h"
19
20#include "test/unit/node_creator.h"
21#include "compiler/lowering/scopesInit/scopesInitPhase.h"
22#include "varbinder/tsBinding.h"
23#include "varbinder/ETSBinder.h"
24
25namespace ark::es2panda {
26
27class ScopesInitPhaseTest : public testing::Test {
28public:
29    ~ScopesInitPhaseTest() override = default;
30
31    ScopesInitPhaseTest()
32        : allocator_(std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER)), nodeGen_(allocator_.get())
33    {
34    }
35
36    static void SetUpTestCase()
37    {
38        constexpr auto COMPILER_SIZE = operator""_MB(256ULL);
39        mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0);
40        PoolManager::Initialize();
41    }
42
43    ArenaAllocator *Allocator()
44    {
45        return allocator_.get();
46    }
47
48    gtests::NodeGenerator &NodeGen()
49    {
50        return nodeGen_;
51    }
52
53    /*
54     * Shortcut to convert single elemnt block expression body to it's name
55     * Example: { let x; } => x
56     */
57    static ir::Identifier *BodyToFirstName(ir::Statement *body)
58    {
59        return body->AsBlockStatement()
60            ->Statements()
61            .front()
62            ->AsVariableDeclaration()
63            ->Declarators()
64            .front()
65            ->Id()
66            ->AsIdentifier();
67    }
68
69    NO_COPY_SEMANTIC(ScopesInitPhaseTest);
70    NO_MOVE_SEMANTIC(ScopesInitPhaseTest);
71
72private:
73    std::unique_ptr<ArenaAllocator> allocator_;
74    gtests::NodeGenerator nodeGen_;
75};
76
77TEST_F(ScopesInitPhaseTest, TestForUpdateLoop)
78{
79    /*
80     * for (int x = 0; x < 10; x++ ) { let x; }
81     */
82    auto varbinder = varbinder::VarBinder(Allocator());
83    auto forNode = NodeGen().CreateForUpdate();
84    compiler::InitScopesPhaseETS::RunExternalNode(forNode, &varbinder);
85
86    auto blockScope = forNode->Body()->AsBlockStatement()->Scope();
87    auto loopScope = forNode->Scope();
88    auto parScope = loopScope->Parent();
89    ASSERT_EQ(blockScope->Parent(), loopScope);
90
91    const auto &scopeBindings = blockScope->Bindings();
92    const auto &parBindings = parScope->Bindings();
93
94    ASSERT_EQ(scopeBindings.size(), 1);
95    ASSERT_EQ(parBindings.size(), 1);
96
97    auto parName = forNode->Init()->AsVariableDeclaration()->Declarators()[0]->Id()->AsIdentifier();
98    auto name = BodyToFirstName(forNode->Body());
99    ASSERT_EQ(scopeBindings.begin()->first, name->Name());
100    ASSERT_EQ(parBindings.begin()->first, parName->Name());
101    ASSERT_EQ(scopeBindings.begin()->second, name->Variable());
102    ASSERT_EQ(parBindings.begin()->second, parName->Variable());
103    ASSERT_NE(parName->Variable(), name->Variable());
104}
105
106TEST_F(ScopesInitPhaseTest, CreateWhile)
107{
108    /*
109     * while (x < 10) { let x; }
110     */
111    auto varbinder = varbinder::VarBinder(Allocator());
112    auto whileNode = NodeGen().CreateWhile();
113
114    compiler::InitScopesPhaseETS::RunExternalNode(whileNode, &varbinder);
115
116    auto whileScope = whileNode->Scope();
117    auto bodyScope = whileNode->Body()->AsBlockStatement()->Scope();
118    ASSERT_EQ(bodyScope->Parent(), whileScope);
119
120    const auto &bodyBindings = bodyScope->Bindings();
121    auto name = BodyToFirstName(whileNode->Body());
122    ASSERT_EQ(bodyBindings.size(), 1);
123    ASSERT_EQ(bodyBindings.begin()->first, name->Name());
124    ASSERT_EQ(bodyBindings.begin()->second, name->Variable());
125}
126
127}  // namespace ark::es2panda
128