1 /**
2 * Copyright (c) 2025 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 "lsp/include/brace_matching.h"
17 #include <gtest/gtest.h>
18 #include "lsp_api_test.h"
19 #include "lsp/include/api.h"
20
21 using ark::es2panda::lsp::Initializer;
22
23 class BraceMatchingTests : public LSPAPITests {};
24
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionAtEndOfFile)25 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionAtEndOfFile)
26 {
27 using ark::es2panda::ir::AstNode;
28 using ark::es2panda::public_lib::Context;
29
30 // Initialize context with an empty function
31 Initializer initializer = Initializer();
32 es2panda_Context *ctx = initializer.CreateContext("at-eof.ets", ES2PANDA_STATE_CHECKED, "function main() {}");
33
34 // Test position at the end of the file
35 const size_t eofPos = 18;
36 const int expectedMapSize = 0; // No matching
37
38 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, eofPos);
39
40 ASSERT_EQ(result.size(), expectedMapSize);
41
42 initializer.DestroyContext(ctx);
43 }
44
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionMiddleOfToken)45 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionMiddleOfToken)
46 {
47 using ark::es2panda::ir::AstNode;
48 using ark::es2panda::public_lib::Context;
49
50 // Initialize context with a function containing braces
51 Initializer initializer = Initializer();
52 es2panda_Context *ctx =
53 initializer.CreateContext("middleoftoken.ets", ES2PANDA_STATE_CHECKED, "function main() { let x = 10; }");
54
55 // Test position inside a keyword ("function" at position 5)
56 const size_t insideTokenPos = 5;
57 const int expectedMapSize = 0; // No matching brace since it's inside a token
58
59 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, insideTokenPos);
60
61 ASSERT_EQ(result.size(), expectedMapSize);
62
63 initializer.DestroyContext(ctx);
64 }
65
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionEmptyBraces)66 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionEmptyBraces)
67 {
68 using ark::es2panda::ir::AstNode;
69 using ark::es2panda::public_lib::Context;
70
71 Initializer initializer = Initializer();
72 es2panda_Context *ctx = initializer.CreateContext("emptybraces.ets", ES2PANDA_STATE_CHECKED, "function main() { }");
73
74 const size_t position = 16; // pos of {
75 const int expectedMapSize = 2;
76
77 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, position);
78
79 int const expectedStart = 16; // pos of {
80 int const expectedEnd = 19; // pos of }
81
82 ASSERT_EQ(result.size(), expectedMapSize);
83 ASSERT_EQ(result[0].start, expectedStart);
84 ASSERT_EQ(result[1].start, expectedEnd);
85
86 // Cleanup
87 initializer.DestroyContext(ctx);
88 }
89
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionValidBraces)90 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionValidBraces)
91 {
92 using ark::es2panda::ir::AstNode;
93 using ark::es2panda::public_lib::Context;
94
95 Initializer initializer = Initializer();
96 es2panda_Context *ctx =
97 initializer.CreateContext("validbraces.ets", ES2PANDA_STATE_CHECKED, "function main() { let x = (2 + 3); }");
98
99 // Test opening brace '{'
100 const size_t openBracePos = 16;
101 const int expectedMapSize = 2;
102 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, openBracePos);
103
104 int const expectedStart = 16; // '{' position
105 int const expectedEnd = 36; // Matching '}'
106
107 ASSERT_EQ(result.size(), expectedMapSize);
108 ASSERT_EQ(result[0].start, expectedStart);
109 ASSERT_EQ(result[1].start, expectedEnd);
110
111 initializer.DestroyContext(ctx);
112 }
113
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionParamInstantiation)114 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionParamInstantiation)
115 {
116 using ark::es2panda::ir::AstNode;
117 using ark::es2panda::public_lib::Context;
118
119 Initializer initializer = Initializer();
120 es2panda_Context *ctx =
121 initializer.CreateContext("paraminst.ets", ES2PANDA_STATE_CHECKED, "let z = new Map<Object, number>()");
122
123 // Test '<'
124 const size_t pos = 15;
125 const int expectedMapSize = 2;
126 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, pos);
127
128 int const expectedStart = 15; // '<' position
129 int const expectedEnd = 31; // Matching '>'
130
131 ASSERT_EQ(result.size(), expectedMapSize);
132 ASSERT_EQ(result[0].start, expectedStart);
133 ASSERT_EQ(result[1].start, expectedEnd);
134
135 initializer.DestroyContext(ctx);
136 }
137
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionParamDeclaration)138 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionParamDeclaration)
139 {
140 using ark::es2panda::ir::AstNode;
141 using ark::es2panda::public_lib::Context;
142
143 Initializer initializer = Initializer();
144 es2panda_Context *ctx = initializer.CreateContext("paramdec.ets", ES2PANDA_STATE_CHECKED, "export class B<T>{}");
145
146 // Test '<'
147 const size_t pos = 14;
148 const int expectedMapSize = 2;
149 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, pos);
150
151 int const expectedStart = 14; // '<' position
152 int const expectedEnd = 17; // Matching '>'
153
154 ASSERT_EQ(result.size(), expectedMapSize);
155 ASSERT_EQ(result[0].start, expectedStart);
156 ASSERT_EQ(result[1].start, expectedEnd);
157
158 initializer.DestroyContext(ctx);
159 }
160
TEST_F(BraceMatchingTests,GetBraceMatchingAtPositionInnerBlock)161 TEST_F(BraceMatchingTests, GetBraceMatchingAtPositionInnerBlock)
162 {
163 using ark::es2panda::ir::AstNode;
164 using ark::es2panda::public_lib::Context;
165
166 Initializer initializer = Initializer();
167 es2panda_Context *ctx =
168 initializer.CreateContext("paramdec.ets", ES2PANDA_STATE_CHECKED, "function main() { { Math.random() < 5; } }");
169
170 // Test inner '{'
171 const size_t pos = 18;
172 const int expectedMapSize = 2;
173 std::vector<TextSpan> result = ark::es2panda::lsp::GetBraceMatchingAtPosition(ctx, pos);
174
175 int const expectedStart = 18; // inner '{' position
176 int const expectedEnd = 40; // inner '}' match
177
178 ASSERT_EQ(result.size(), expectedMapSize);
179 ASSERT_EQ(result[0].start, expectedStart);
180 ASSERT_EQ(result[1].start, expectedEnd);
181
182 initializer.DestroyContext(ctx);
183 }