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/internal_api.h"
17 #include "lsp/include/classifier.h"
18 #include "lsp_api_test.h"
19 #include "public/es2panda_lib.h"
20
21 using ark::es2panda::lsp::Initializer;
22
23 class LspDiagnosticsTests : public LSPAPITests {};
24
TEST_F(LspDiagnosticsTests,GetSemanticDiagnostics1)25 TEST_F(LspDiagnosticsTests, GetSemanticDiagnostics1)
26 {
27 Initializer initializer = Initializer();
28 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
29 R"(function add(a: number, b: number) {
30 return a + b;
31 }
32 let n = 333;
33 let res = add(n, n);)");
34 LSPAPI const *lspApi = GetImpl();
35 DiagnosticReferences result = lspApi->getSemanticDiagnostics(ctx);
36 initializer.DestroyContext(ctx);
37 ASSERT_EQ(result.diagnostic.size(), 0);
38 }
39
TEST_F(LspDiagnosticsTests,GetSemanticDiagnostics2)40 TEST_F(LspDiagnosticsTests, GetSemanticDiagnostics2)
41 {
42 Initializer initializer = Initializer();
43 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
44 R"(const a: number = "hello";
45 function add(a: number, b: number): number {
46 return a + b;
47 }
48 add("1", 2);)");
49 LSPAPI const *lspApi = GetImpl();
50 DiagnosticReferences result = lspApi->getSemanticDiagnostics(ctx);
51 initializer.DestroyContext(ctx);
52 auto const expectedErrorCount = 3;
53 ASSERT_EQ(result.diagnostic.size(), expectedErrorCount);
54 auto const thirdIndex = 2;
55 auto const expectedFirstStartLine = 1;
56 auto const expectedFirstStartCharacter = 19;
57 auto const expectedFirstEndLine = 1;
58 auto const expectedFirstEndCharacter = 26;
59 ASSERT_EQ(result.diagnostic[thirdIndex].range_.start.line_, expectedFirstStartLine);
60 ASSERT_EQ(result.diagnostic[thirdIndex].range_.start.character_, expectedFirstStartCharacter);
61 ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.line_, expectedFirstEndLine);
62 ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.character_, expectedFirstEndCharacter);
63 ASSERT_EQ(result.diagnostic[thirdIndex].severity_, DiagnosticSeverity::Error);
64 ASSERT_NE(std::get<int>(result.diagnostic[thirdIndex].code_), 0);
65 ASSERT_EQ(result.diagnostic[thirdIndex].message_, R"(Type '"hello"' cannot be assigned to type 'double')");
66 ASSERT_EQ(result.diagnostic[thirdIndex].codeDescription_.href_, "test code description");
67 auto const expectedSecondStartLine = 5;
68 auto const expectedSecondStartCharacter = 5;
69 auto const expectedSecondEndLine = 5;
70 auto const expectedSecondEndCharacter = 8;
71 ASSERT_EQ(result.diagnostic[0].range_.start.line_, expectedSecondStartLine);
72 ASSERT_EQ(result.diagnostic[0].range_.start.character_, expectedSecondStartCharacter);
73 ASSERT_EQ(result.diagnostic[0].range_.end.line_, expectedSecondEndLine);
74 ASSERT_EQ(result.diagnostic[0].range_.end.character_, expectedSecondEndCharacter);
75 ASSERT_EQ(result.diagnostic[0].severity_, DiagnosticSeverity::Error);
76 ASSERT_NE(std::get<int>(result.diagnostic[0].code_), 0);
77 ASSERT_EQ(result.diagnostic[0].message_, R"(Type '"1"' is not compatible with type 'double' at index 1)");
78 ASSERT_EQ(result.diagnostic[0].codeDescription_.href_, "test code description");
79 }
80
TEST_F(LspDiagnosticsTests,GetSyntacticDiagnostics1)81 TEST_F(LspDiagnosticsTests, GetSyntacticDiagnostics1)
82 {
83 Initializer initializer = Initializer();
84 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
85 R"(function add(a: number, b: number) {
86 return a + b;
87 }
88 let n = 333;
89 let res = add(n, n);)");
90 LSPAPI const *lspApi = GetImpl();
91 auto result = lspApi->getSyntacticDiagnostics(ctx);
92 initializer.DestroyContext(ctx);
93 ASSERT_EQ(result.diagnostic.size(), 0);
94 }
95
TEST_F(LspDiagnosticsTests,GetSyntacticDiagnostics2)96 TEST_F(LspDiagnosticsTests, GetSyntacticDiagnostics2)
97 {
98 Initializer initializer = Initializer();
99 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
100 R"(functon add(a: number, b: number) {
101 return a + b;
102 }
103 let n = 333;
104 let res = add(n, n);)");
105 LSPAPI const *lspApi = GetImpl();
106 auto result = lspApi->getSyntacticDiagnostics(ctx);
107 initializer.DestroyContext(ctx);
108 auto const expectedErrorCount = 13;
109 ASSERT_EQ(result.diagnostic.size(), expectedErrorCount);
110 auto const expectedFirstStartLine = 1;
111 auto const expectedFirstStartCharacter = 9;
112 auto const expectedFirstEndLine = 1;
113 auto const expectedFirstEndCharacter = 12;
114 ASSERT_EQ(result.diagnostic[0].range_.start.line_, expectedFirstStartLine);
115 ASSERT_EQ(result.diagnostic[0].range_.start.character_, expectedFirstStartCharacter);
116 ASSERT_EQ(result.diagnostic[0].range_.end.line_, expectedFirstEndLine);
117 ASSERT_EQ(result.diagnostic[0].range_.end.character_, expectedFirstEndCharacter);
118 ASSERT_EQ(result.diagnostic[0].severity_, DiagnosticSeverity::Error);
119 ASSERT_NE(std::get<int>(result.diagnostic[0].code_), 0);
120 auto const expectedSecondStartLine = 1;
121 auto const expectedSecondStartCharacter = 14;
122 auto const expectedSecondEndLine = 1;
123 auto const expectedSecondEndCharacter = 15;
124 ASSERT_EQ(result.diagnostic[1].range_.start.line_, expectedSecondStartLine);
125 ASSERT_EQ(result.diagnostic[1].range_.start.character_, expectedSecondStartCharacter);
126 ASSERT_EQ(result.diagnostic[1].range_.end.line_, expectedSecondEndLine);
127 ASSERT_EQ(result.diagnostic[1].range_.end.character_, expectedSecondEndCharacter);
128 ASSERT_EQ(result.diagnostic[1].severity_, DiagnosticSeverity::Error);
129 ASSERT_NE(std::get<int>(result.diagnostic[1].code_), 0);
130 auto const thirdIndex = 2;
131 auto const expectedThirdStartLine = 1;
132 auto const expectedThirdStartCharacter = 14;
133 auto const expectedThirdEndLine = 1;
134 auto const expectedThirdEndCharacter = 15;
135 ASSERT_EQ(result.diagnostic[thirdIndex].range_.start.line_, expectedThirdStartLine);
136 ASSERT_EQ(result.diagnostic[thirdIndex].range_.start.character_, expectedThirdStartCharacter);
137 ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.line_, expectedThirdEndLine);
138 ASSERT_EQ(result.diagnostic[thirdIndex].range_.end.character_, expectedThirdEndCharacter);
139 ASSERT_EQ(result.diagnostic[thirdIndex].severity_, DiagnosticSeverity::Error);
140 ASSERT_NE(std::get<int>(result.diagnostic[thirdIndex].code_), 0);
141 ASSERT_EQ(result.diagnostic[thirdIndex].message_, R"(Unexpected token ':'.)");
142 }
143
TEST_F(LspDiagnosticsTests,GetSyntacticDiagnostics3)144 TEST_F(LspDiagnosticsTests, GetSyntacticDiagnostics3)
145 {
146 Initializer initializer = Initializer();
147 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
148 R"(functon add(a: number, b: number) {
149 return a + b;
150 }
151 let n = 333;
152 let res = add(n, n);)");
153 LSPAPI const *lspApi = GetImpl();
154 auto result = lspApi->getSyntacticDiagnostics(ctx);
155 initializer.DestroyContext(ctx);
156 auto const forthIndex = 5;
157 auto const expectedForthStartLine = 1;
158 auto const expectedForthStartCharacter = 22;
159 auto const expectedForthEndLine = 1;
160 auto const expectedForthEndCharacter = 23;
161 ASSERT_EQ(result.diagnostic[forthIndex].range_.start.line_, expectedForthStartLine);
162 ASSERT_EQ(result.diagnostic[forthIndex].range_.start.character_, expectedForthStartCharacter);
163 ASSERT_EQ(result.diagnostic[forthIndex].range_.end.line_, expectedForthEndLine);
164 ASSERT_EQ(result.diagnostic[forthIndex].range_.end.character_, expectedForthEndCharacter);
165 ASSERT_EQ(result.diagnostic[forthIndex].severity_, DiagnosticSeverity::Error);
166 ASSERT_NE(std::get<int>(result.diagnostic[forthIndex].code_), 0);
167 ASSERT_EQ(result.diagnostic[forthIndex].message_, R"(Unexpected token ','.)");
168 ASSERT_EQ(result.diagnostic[forthIndex].codeDescription_.href_, "test code description");
169 auto const fifthIndex = 8;
170 auto const expectedFifththStartLine = 1;
171 auto const expectedFifthStartCharacter = 27;
172 auto const expectedFifthEndLine = 1;
173 auto const expectedFifthEndCharacter = 33;
174 ASSERT_EQ(result.diagnostic[fifthIndex].range_.start.line_, expectedFifththStartLine);
175 ASSERT_EQ(result.diagnostic[fifthIndex].range_.start.character_, expectedFifthStartCharacter);
176 ASSERT_EQ(result.diagnostic[fifthIndex].range_.end.line_, expectedFifthEndLine);
177 ASSERT_EQ(result.diagnostic[fifthIndex].range_.end.character_, expectedFifthEndCharacter);
178 ASSERT_EQ(result.diagnostic[fifthIndex].severity_, DiagnosticSeverity::Error);
179 ASSERT_NE(std::get<int>(result.diagnostic[fifthIndex].code_), 0);
180 ASSERT_EQ(result.diagnostic[fifthIndex].message_, R"(Label must be followed by a loop statement.)");
181 ASSERT_EQ(result.diagnostic[fifthIndex].codeDescription_.href_, "test code description");
182 }
183
TEST_F(LspDiagnosticsTests,GetSyntacticDiagnosticsForFile4)184 TEST_F(LspDiagnosticsTests, GetSyntacticDiagnosticsForFile4)
185 {
186 Initializer initializer = Initializer();
187 es2panda_Context *ctx = initializer.CreateContext("GetSemanticDiagnosticsNoError1.ets", ES2PANDA_STATE_CHECKED,
188 R"(functon add(a: number, b: number) {
189 return a + b;
190 }
191 let n = 333;
192 let res = add(n, n);)");
193 LSPAPI const *lspApi = GetImpl();
194 auto result = lspApi->getSyntacticDiagnostics(ctx);
195 initializer.DestroyContext(ctx);
196 auto const sixthIndex = 9;
197 auto const expectedSixthStartLine = 1;
198 auto const expectedSixthStartCharacter = 33;
199 auto const expectedSixthEndLine = 1;
200 auto const expectedSixthEndCharacter = 34;
201 ASSERT_EQ(result.diagnostic[sixthIndex].range_.start.line_, expectedSixthStartLine);
202 ASSERT_EQ(result.diagnostic[sixthIndex].range_.start.character_, expectedSixthStartCharacter);
203 ASSERT_EQ(result.diagnostic[sixthIndex].range_.end.line_, expectedSixthEndLine);
204 ASSERT_EQ(result.diagnostic[sixthIndex].range_.end.character_, expectedSixthEndCharacter);
205 ASSERT_EQ(result.diagnostic[sixthIndex].severity_, DiagnosticSeverity::Error);
206 ASSERT_NE(std::get<int>(result.diagnostic[sixthIndex].code_), 0);
207 ASSERT_EQ(result.diagnostic[sixthIndex].message_, R"(Unexpected token ')'.)");
208 ASSERT_EQ(result.diagnostic[sixthIndex].codeDescription_.href_, "test code description");
209 auto const sevenIndex = 12;
210 auto const expectedSeventhStartLine = 2;
211 auto const expectedSeventhStartCharacter = 5;
212 auto const expectedSeventhEndLine = 2;
213 auto const expectedSeventhEndCharacter = 18;
214 ASSERT_EQ(result.diagnostic[sevenIndex].range_.start.line_, expectedSeventhStartLine);
215 ASSERT_EQ(result.diagnostic[sevenIndex].range_.start.character_, expectedSeventhStartCharacter);
216 ASSERT_EQ(result.diagnostic[sevenIndex].range_.end.line_, expectedSeventhEndLine);
217 ASSERT_EQ(result.diagnostic[sevenIndex].range_.end.character_, expectedSeventhEndCharacter);
218 ASSERT_EQ(result.diagnostic[sevenIndex].severity_, DiagnosticSeverity::Error);
219 ASSERT_NE(std::get<int>(result.diagnostic[sevenIndex].code_), 0);
220 ASSERT_EQ(result.diagnostic[sevenIndex].message_, R"(return keyword should be used in function body.)");
221 ASSERT_EQ(result.diagnostic[sevenIndex].codeDescription_.href_, "test code description");
222 }
223