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_api_test.h"
17 #include "lsp/include/internal_api.h"
18
19 namespace {
20
21 using ark::es2panda::lsp::Initializer;
22
23 class LSPClassInfoTests : public LSPAPITests {};
24
AssertClassConstructorInfo(const std::vector<FileTextChanges> & fileTextChanges,const std::vector<FileTextChanges> & expectedFileTextChanges)25 void AssertClassConstructorInfo(const std::vector<FileTextChanges> &fileTextChanges,
26 const std::vector<FileTextChanges> &expectedFileTextChanges)
27 {
28 auto emptyCheck = fileTextChanges.empty();
29 ASSERT_FALSE(emptyCheck) << "The result is empty.";
30
31 auto curFileChanges = fileTextChanges.at(0);
32 auto expectedFileChanges = expectedFileTextChanges.at(0);
33 bool check = false;
34 if (curFileChanges.fileName != expectedFileChanges.fileName) {
35 check = true;
36 }
37 ASSERT_FALSE(check) << "The fileName is not expected.";
38
39 auto textChangeEmptyCheck = curFileChanges.textChanges.empty();
40 ASSERT_FALSE(textChangeEmptyCheck) << "The modified file content is empty.";
41
42 auto curTextChange = curFileChanges.textChanges.at(0);
43 auto expectedTextChange = expectedFileChanges.textChanges.at(0);
44 if (curTextChange.span.start != expectedTextChange.span.start) {
45 check = true;
46 }
47 ASSERT_FALSE(check) << "The insertPosition is not expected.";
48 if (curTextChange.newText != expectedTextChange.newText) {
49 check = true;
50 }
51 ASSERT_FALSE(check) << "The newText is not expected.";
52 }
53
TEST_F(LSPClassInfoTests,getClassConstructorInfo1)54 TEST_F(LSPClassInfoTests, getClassConstructorInfo1)
55 {
56 std::vector<std::string> fileNames = {"getClassConstructorInfo1.ets"};
57 std::vector<std::string> fileContents = {
58 R"(
59 class FooParent {
60 f: number = 0;
61 str: string = "aaa";
62 constructor (f: number, str: string) {
63 this.f = f;
64 this.str = str;
65 }
66 };
67
68 enum Colors {Red = "#FF0000", Green = "#00FF00", Blue = "#0000FF"};
69 export class Foo extends FooParent {
70 name: string = "unassigned";
71 isActive: boolean = true;
72 items: string[] = ["aaa", "bbb"];
73 point: [number, number] = [0, 0];
74 primaryColor: Colors = Colors.Blue;
75 optionalValue?:string|null|undefined;
76 x: number = 1;
77 static y: number = 2;
78 z: number = 3;
79 };)"};
80 auto filePaths = CreateTempFile(fileNames, fileContents);
81
82 int const expectedFileCount = 1;
83 ASSERT_EQ(filePaths.size(), expectedFileCount);
84
85 LSPAPI const *lspApi = GetImpl();
86 size_t const offset = 400;
87 std::vector<std::string> properties = {"name", "x", "z"};
88 Initializer initializer = Initializer();
89 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
90 auto res = lspApi->getClassConstructorInfo(ctx, offset, properties);
91 std::vector<FileTextChanges> expectedFileTextChanges;
92 std::string text =
93 "constructor(f: number, str: string, name: string, x: number, z: number) {\n super(f, str);\n this.name = "
94 "name;\n this.x = x;\n this.z = z;\n}";
95 size_t const insertPosition = 269;
96 TextSpan span(insertPosition, text.size());
97 std::vector<TextChange> textChanges;
98 textChanges.emplace_back(TextChange(span, text));
99 FileTextChanges textChange(filePaths.at(0), textChanges);
100 expectedFileTextChanges.push_back(textChange);
101 AssertClassConstructorInfo(res.GetFileTextChanges(), expectedFileTextChanges);
102 initializer.DestroyContext(ctx);
103 }
104
TEST_F(LSPClassInfoTests,getClassConstructorInfo2)105 TEST_F(LSPClassInfoTests, getClassConstructorInfo2)
106 {
107 std::vector<std::string> files = {"getClassConstructorInfo2.ets"};
108 std::vector<std::string> texts = {
109 R"(
110 class Foo {
111 f: number = 0;
112 str: string = "aaa";
113 };)"};
114 auto filePaths = CreateTempFile(files, texts);
115
116 int const expectedFileCount = 1;
117 ASSERT_EQ(filePaths.size(), expectedFileCount);
118
119 LSPAPI const *lspApi = GetImpl();
120 size_t const offset = 30;
121 std::vector<std::string> properties = {"f", "str"};
122 Initializer initializer = Initializer();
123 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
124 auto res = lspApi->getClassConstructorInfo(ctx, offset, properties);
125 std::vector<FileTextChanges> expectedFileTextChanges;
126 std::string text = "constructor(f: number, str: string) {\n this.f = f;\n this.str = str;\n}";
127 size_t const insertPosition = 17;
128 TextSpan span(insertPosition, text.size());
129 std::vector<TextChange> textChanges;
130 textChanges.emplace_back(TextChange(span, text));
131 FileTextChanges textChange(filePaths.at(0), textChanges);
132 expectedFileTextChanges.push_back(textChange);
133 AssertClassConstructorInfo(res.GetFileTextChanges(), expectedFileTextChanges);
134 initializer.DestroyContext(ctx);
135 }
136
TEST_F(LSPClassInfoTests,getClassConstructorInfo3)137 TEST_F(LSPClassInfoTests, getClassConstructorInfo3)
138 {
139 std::vector<std::string> files = {"getClassConstructorInfo3.ets"};
140 std::vector<std::string> texts = {
141 R"(
142 class Foo {
143 };)"};
144 auto filePaths = CreateTempFile(files, texts);
145
146 int const expectedFileCount = 1;
147 ASSERT_EQ(filePaths.size(), expectedFileCount);
148
149 LSPAPI const *lspApi = GetImpl();
150 size_t const offset = 10;
151 std::vector<std::string> properties = {};
152 Initializer initializer = Initializer();
153 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
154 auto res = lspApi->getClassConstructorInfo(ctx, offset, properties);
155 std::vector<FileTextChanges> expectedFileTextChanges;
156 std::string text = "constructor() {\n}";
157 size_t const insertPosition = 13;
158 TextSpan span(insertPosition, text.size());
159 std::vector<TextChange> textChanges;
160 textChanges.emplace_back(TextChange(span, text));
161 FileTextChanges textChange(filePaths.at(0), textChanges);
162 expectedFileTextChanges.push_back(textChange);
163 AssertClassConstructorInfo(res.GetFileTextChanges(), expectedFileTextChanges);
164 initializer.DestroyContext(ctx);
165 }
166
TEST_F(LSPClassInfoTests,getClassConstructorInfo4)167 TEST_F(LSPClassInfoTests, getClassConstructorInfo4)
168 {
169 std::vector<std::string> files = {"getClassConstructorInfo4.ets"};
170 std::vector<std::string> texts = {
171 R"(
172 namespace space {
173 export class classInSpace {
174 c: number = 2;
175
176 function print() {
177 return 2;
178 }
179 }
180 })"};
181 auto filePaths = CreateTempFile(files, texts);
182
183 int const expectedFileCount = 1;
184 ASSERT_EQ(filePaths.size(), expectedFileCount);
185
186 LSPAPI const *lspApi = GetImpl();
187 size_t const offset = 35;
188 std::vector<std::string> properties = {"c"};
189 Initializer initializer = Initializer();
190 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
191 auto res = lspApi->getClassConstructorInfo(ctx, offset, properties);
192 std::vector<FileTextChanges> expectedFileTextChanges;
193 std::string text = "constructor(c: number) {\n this.c = c;\n}";
194 size_t const insertPosition = 59;
195 TextSpan span(insertPosition, text.size());
196 std::vector<TextChange> textChanges;
197 textChanges.emplace_back(TextChange(span, text));
198 FileTextChanges textChange(filePaths.at(0), textChanges);
199 expectedFileTextChanges.push_back(textChange);
200 AssertClassConstructorInfo(res.GetFileTextChanges(), expectedFileTextChanges);
201 initializer.DestroyContext(ctx);
202 }
203
204 } // namespace