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 <gtest/gtest.h>
17 #include <cstddef>
18 #include <string>
19 #include "lsp_api_test.h"
20 #include "lsp/include/internal_api.h"
21
22 using ark::es2panda::lsp::Initializer;
23
24 class LspGetDefTests : public LSPAPITests {};
25
TEST_F(LspGetDefTests,GetDefinitionAtPosition1)26 TEST_F(LspGetDefTests, GetDefinitionAtPosition1)
27 {
28 std::vector<std::string> files = {"getDefinitionAtPosition1.ets", "getDefinitionAtPosition2.ets"};
29 std::vector<std::string> texts = {R"(export function A(a:number, b:number): number {
30 return a + b;
31 })",
32 R"(import {A} from './getDefinitionAtPosition1';
33 A(1, 2);)"};
34 auto filePaths = CreateTempFile(files, texts);
35 size_t const expectedFileCount = 2;
36 ASSERT_EQ(filePaths.size(), expectedFileCount);
37
38 LSPAPI const *lspApi = GetImpl();
39 size_t const offset = 46;
40 Initializer initializer = Initializer();
41 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
42 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
43 initializer.DestroyContext(ctx);
44 std::string expectedFileName = filePaths[0];
45 size_t const expectedStart = 16;
46 size_t const expectedLength = 1;
47 ASSERT_EQ(result.fileName, expectedFileName);
48 ASSERT_EQ(result.start, expectedStart);
49 ASSERT_EQ(result.length, expectedLength);
50 }
51
TEST_F(LspGetDefTests,GetDefinitionAtPosition2)52 TEST_F(LspGetDefTests, GetDefinitionAtPosition2)
53 {
54 std::vector<std::string> files = {"getDefinitionAtPosition3.ets"};
55 std::vector<std::string> texts = {R"(
56 function A(a:number, b:number) {
57 return a + b;
58 }
59 A(1, 2);
60 function A(a:number) {
61 return a;
62 }
63 A(1);)"};
64 auto filePaths = CreateTempFile(files, texts);
65 int const expectedFileCount = 1;
66 ASSERT_EQ(filePaths.size(), expectedFileCount);
67
68 LSPAPI const *lspApi = GetImpl();
69 size_t const offset = 70;
70 Initializer initializer = Initializer();
71 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
72 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
73 initializer.DestroyContext(ctx);
74 std::string expectedFileName = filePaths[0];
75 size_t const expectedStart = 14;
76 size_t const expectedLength = 1;
77 ASSERT_EQ(result.fileName, expectedFileName);
78 ASSERT_EQ(result.start, expectedStart);
79 ASSERT_EQ(result.length, expectedLength);
80
81 size_t const offset1 = 134;
82 auto ctx1 = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
83 auto result1 = lspApi->getDefinitionAtPosition(ctx1, offset1);
84 initializer.DestroyContext(ctx1);
85 std::string expectedFileName1 = filePaths[0];
86 size_t const expectedStart1 = 92;
87 size_t const expectedLength1 = 1;
88 ASSERT_EQ(result1.fileName, expectedFileName1);
89 ASSERT_EQ(result1.start, expectedStart1);
90 ASSERT_EQ(result1.length, expectedLength1);
91 }
92
TEST_F(LspGetDefTests,GetDefinitionAtPosition3)93 TEST_F(LspGetDefTests, GetDefinitionAtPosition3)
94 {
95 std::vector<std::string> files = {"getDefinitionAtPosition4.ets", "getDefinitionAtPosition5.ets"};
96 std::vector<std::string> texts = {R"(export function A(a:number, b:number): number {
97 return a + b;
98 })",
99 R"(import * as All from './getDefinitionAtPosition4';
100 All.A(1, 2);)"};
101 auto filePaths = CreateTempFile(files, texts);
102 size_t const expectedFileCount = 2;
103 ASSERT_EQ(filePaths.size(), expectedFileCount);
104
105 LSPAPI const *lspApi = GetImpl();
106 size_t const offset = 55;
107 Initializer initializer = Initializer();
108 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
109 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
110 initializer.DestroyContext(ctx);
111 std::string expectedFileName = filePaths[0];
112 size_t const expectedStart = 16;
113 size_t const expectedLength = 1;
114 ASSERT_EQ(result.fileName, expectedFileName);
115 ASSERT_EQ(result.start, expectedStart);
116 ASSERT_EQ(result.length, expectedLength);
117 }
118
TEST_F(LspGetDefTests,GetDefinitionAtPosition4)119 TEST_F(LspGetDefTests, GetDefinitionAtPosition4)
120 {
121 std::vector<std::string> files = {"getDefinitionAtPosition6.ets", "getDefinitionAtPosition7.ets"};
122 std::vector<std::string> texts = {R"(export class A {
123 Foo(a:number, b:number): number {
124 return a + b;
125 }})",
126 R"(import * as All from './getDefinitionAtPosition6';
127 let a = new All.A();
128 a.Foo(1, 2);)"};
129 auto filePaths = CreateTempFile(files, texts);
130 size_t const expectedFileCount = 2;
131 ASSERT_EQ(filePaths.size(), expectedFileCount);
132
133 LSPAPI const *lspApi = GetImpl();
134 size_t const offset = 74;
135 Initializer initializer = Initializer();
136 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
137 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
138 initializer.DestroyContext(ctx);
139 std::string expectedFileName = filePaths[0];
140 size_t const expectedStart = 17;
141 size_t const expectedLength = 3;
142 ASSERT_EQ(result.fileName, expectedFileName);
143 ASSERT_EQ(result.start, expectedStart);
144 ASSERT_EQ(result.length, expectedLength);
145 }
146
TEST_F(LspGetDefTests,GetDefinitionAtPosition5)147 TEST_F(LspGetDefTests, GetDefinitionAtPosition5)
148 {
149 std::vector<std::string> files = {"getDefinitionAtPosition8.ets", "getDefinitionAtPosition9.ets"};
150 std::vector<std::string> texts = {R"(export enum A {
151 a,
152 b})",
153 R"(import * as All from './getDefinitionAtPosition8';
154 All.A.a;)"};
155 auto filePaths = CreateTempFile(files, texts);
156 size_t const expectedFileCount = 2;
157 ASSERT_EQ(filePaths.size(), expectedFileCount);
158
159 LSPAPI const *lspApi = GetImpl();
160 size_t const offset = 57;
161 Initializer initializer = Initializer();
162 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
163 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
164 initializer.DestroyContext(ctx);
165 std::string expectedFileName = filePaths[0];
166 size_t const expectedStart = 16;
167 size_t const expectedLength = 1;
168 ASSERT_EQ(result.fileName, expectedFileName);
169 ASSERT_EQ(result.start, expectedStart);
170 ASSERT_EQ(result.length, expectedLength);
171 }
172
TEST_F(LspGetDefTests,GetDefinitionAtPosition6)173 TEST_F(LspGetDefTests, GetDefinitionAtPosition6)
174 {
175 std::vector<std::string> files = {"getDefinitionAtPosition10.ets", "getDefinitionAtPosition11.ets"};
176 std::vector<std::string> texts = {R"(export class A {
177 Foo(a:number, b:number): number {
178 return a + b;
179 }};
180 )",
181 R"(import {A} from './getDefinitionAtPosition10';
182 let a = new A();
183 a.Foo(1, 2);)"};
184 auto filePaths = CreateTempFile(files, texts);
185 size_t const expectedFileCount = 2;
186 ASSERT_EQ(filePaths.size(), expectedFileCount);
187
188 LSPAPI const *lspApi = GetImpl();
189 size_t const offset = 66;
190 Initializer initializer = Initializer();
191 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
192 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
193 initializer.DestroyContext(ctx);
194 std::string expectedFileName = filePaths[0];
195 size_t const expectedStart = 17;
196 size_t const expectedLength = 3;
197 ASSERT_EQ(result.fileName, expectedFileName);
198 ASSERT_EQ(result.start, expectedStart);
199 ASSERT_EQ(result.length, expectedLength);
200 }
201
TEST_F(LspGetDefTests,GetDefinitionAtPosition7)202 TEST_F(LspGetDefTests, GetDefinitionAtPosition7)
203 {
204 std::vector<std::string> files = {"getDefinitionAtPosition12.ets", "getDefinitionAtPosition13.ets"};
205 std::vector<std::string> texts = {R"(export let a = 1;)",
206 R"(import {a} from './getDefinitionAtPosition12';
207 let b = a;)"};
208 auto filePaths = CreateTempFile(files, texts);
209 size_t const expectedFileCount = 2;
210 ASSERT_EQ(filePaths.size(), expectedFileCount);
211
212 LSPAPI const *lspApi = GetImpl();
213 size_t const offset = 55;
214 Initializer initializer = Initializer();
215 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
216 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
217 initializer.DestroyContext(ctx);
218 std::string expectedFileName = filePaths[0];
219 size_t const expectedStart = 11;
220 size_t const expectedLength = 1;
221 ASSERT_EQ(result.fileName, expectedFileName);
222 ASSERT_EQ(result.start, expectedStart);
223 ASSERT_EQ(result.length, expectedLength);
224 }
225
TEST_F(LspGetDefTests,GetDefinitionAtPosition8)226 TEST_F(LspGetDefTests, GetDefinitionAtPosition8)
227 {
228 std::vector<std::string> files = {"getDefinitionAtPosition14.ets", "getDefinitionAtPosition15.ets"};
229 std::vector<std::string> texts = {R"(export interface I {})",
230 R"(import {I} from './getDefinitionAtPosition14';
231 import * as All from './getDefinitionAtPosition14';
232 class A implements All.I {};)"};
233 auto filePaths = CreateTempFile(files, texts);
234 size_t const expectedFileCount = 2;
235 ASSERT_EQ(filePaths.size(), expectedFileCount);
236
237 LSPAPI const *lspApi = GetImpl();
238 size_t const offset = 8;
239 Initializer initializer = Initializer();
240 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
241 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
242 initializer.DestroyContext(ctx);
243 std::string expectedFileName = filePaths[0];
244 size_t const expectedStart = 17;
245 size_t const expectedLength = 1;
246 ASSERT_EQ(result.fileName, expectedFileName);
247 ASSERT_EQ(result.start, expectedStart);
248 ASSERT_EQ(result.length, expectedLength);
249
250 size_t const offset1 = 122;
251 ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
252 result = lspApi->getDefinitionAtPosition(ctx, offset1);
253 initializer.DestroyContext(ctx);
254 ASSERT_EQ(result.fileName, expectedFileName);
255 ASSERT_EQ(result.start, expectedStart);
256 ASSERT_EQ(result.length, expectedLength);
257 }
258
TEST_F(LspGetDefTests,GetDefinitionAtPosition9)259 TEST_F(LspGetDefTests, GetDefinitionAtPosition9)
260 {
261 std::vector<std::string> files = {"getDefinitionAtPosition16.ets", "getDefinitionAtPosition17.ets"};
262 std::vector<std::string> texts = {R"(export class Foo {
263 Foo(a:number, b:number): number {
264 return a + b;
265 }})",
266 R"(import * as All from './getDefinitionAtPosition16';
267 let a = new All.Foo();
268 a.Foo(1, 2);)"};
269 auto filePaths = CreateTempFile(files, texts);
270 size_t const expectedFileCount = 2;
271 ASSERT_EQ(filePaths.size(), expectedFileCount);
272
273 LSPAPI const *lspApi = GetImpl();
274 size_t const offset = 68;
275 Initializer initializer = Initializer();
276 auto ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
277 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
278 initializer.DestroyContext(ctx);
279 std::string expectedFileName = filePaths[0];
280 size_t const expectedStart = 13;
281 size_t const expectedLength = 3;
282 ASSERT_EQ(result.fileName, expectedFileName);
283 ASSERT_EQ(result.start, expectedStart);
284 ASSERT_EQ(result.length, expectedLength);
285
286 size_t const offset1 = 77;
287 ctx = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED);
288 auto result1 = lspApi->getDefinitionAtPosition(ctx, offset1);
289 initializer.DestroyContext(ctx);
290 std::string expectedFileName1 = filePaths[0];
291 size_t const expectedStart1 = 19;
292 size_t const expectedLength1 = 3;
293 ASSERT_EQ(result1.fileName, expectedFileName1);
294 ASSERT_EQ(result1.start, expectedStart1);
295 ASSERT_EQ(result1.length, expectedLength1);
296 }
297
TEST_F(LspGetDefTests,GetDefinitionAtPositionForStdLibraryTaskPool)298 TEST_F(LspGetDefTests, GetDefinitionAtPositionForStdLibraryTaskPool)
299 {
300 std::vector<std::string> files = {"getDefinitionAtPositionForStdLibraryTaskPool.ets"};
301 std::vector<std::string> texts = {R"(const task = new taskpool.Task(()=>{});)"};
302 auto filePaths = CreateTempFile(files, texts);
303 size_t const expectedFileCount = 1;
304 ASSERT_EQ(filePaths.size(), expectedFileCount);
305
306 LSPAPI const *lspApi = GetImpl();
307 size_t const offset = 21;
308 Initializer initializer = Initializer();
309 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
310 auto result = lspApi->getDefinitionAtPosition(ctx, offset);
311 initializer.DestroyContext(ctx);
312 std::string expectedFileName = "taskpool.ets";
313 size_t const expectedLength = 8;
314 ASSERT_TRUE(result.fileName.find(expectedFileName) != std::string::npos);
315 ASSERT_EQ(result.length, expectedLength);
316 }
317