• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
17 #include <vector>
18 #include "lsp_api_test.h"
19 #include "lsp/include/internal_api.h"
20 #include "util/arktsconfig.h"
21 #include "public/public.h"
22 
23 using ark::es2panda::lsp::Initializer;
24 
25 class LSPGetCompilerOptionsDiagnosticsTests : public LSPAPITests {
26 public:
27     LSPGetCompilerOptionsDiagnosticsTests() = default;
28     ~LSPGetCompilerOptionsDiagnosticsTests() override = default;
29 
30     NO_COPY_SEMANTIC(LSPGetCompilerOptionsDiagnosticsTests);
31     NO_MOVE_SEMANTIC(LSPGetCompilerOptionsDiagnosticsTests);
32 
MockGetGlobalDiagnostics(std::vector<std::string> & files,std::vector<std::string> & texts)33     DiagnosticReferences MockGetGlobalDiagnostics(std::vector<std::string> &files, std::vector<std::string> &texts)
34     {
35         auto filePaths = CreateTempFile(files, texts);
36         Initializer initializer;
37         DiagnosticReferences diagnostics;
38 
39         for (auto const &file : filePaths) {
40             auto ctx = initializer.CreateContext(file.c_str(), ES2PANDA_STATE_CHECKED);
41             ark::es2panda::lsp::GetGlobalDiagnostics(ctx, diagnostics);
42             initializer.DestroyContext(ctx);
43         }
44 
45         return diagnostics;
46     }
47 
MockGetOptionDiagnostics(std::vector<std::string> & files,std::vector<std::string> & texts)48     DiagnosticReferences MockGetOptionDiagnostics(std::vector<std::string> &files, std::vector<std::string> &texts)
49     {
50         auto filePaths = CreateTempFile(files, texts);
51 
52         DiagnosticReferences diagnostics;
53         int const expectedFileCount = 1;
54 
55         if (filePaths.size() < expectedFileCount) {
56             return diagnostics;
57         }
58 
59         Initializer initializer;
60         auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
61         ark::es2panda::util::DiagnosticEngine *diagnosticEngine =
62             reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->diagnosticEngine;
63         auto config = ark::es2panda::ArkTsConfig {filePaths[1], *diagnosticEngine};
64         std::unordered_set<std::string> parsedConfigPath;
65         config.Parse(parsedConfigPath);
66         ark::es2panda::lsp::GetOptionDiagnostics(ctx, diagnostics);
67         initializer.DestroyContext(ctx);
68 
69         return diagnostics;
70     }
71 };
72 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetGlobalDiagnostics1)73 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetGlobalDiagnostics1)
74 {
75     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets"};
76     std::vector<std::string> texts = {
77         R"(
78 import { test } from "";
79 )"};
80 
81     DiagnosticReferences diagnostics = MockGetGlobalDiagnostics(files, texts);
82 
83     int const defaultDiagnosticsSize = 0;
84     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
85 
86     const auto &diag = diagnostics.diagnostic[0];
87     ASSERT_EQ(diag.severity_, DiagnosticSeverity::Error);
88     ASSERT_NE(diag.message_.find("Import path cannot be empty"), std::string::npos);
89 }
90 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetGlobalDiagnostics2)91 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetGlobalDiagnostics2)
92 {
93     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets"};
94     std::vector<std::string> texts = {
95         R"(
96 import { test } from "@unknown/package";
97 )"};
98 
99     DiagnosticReferences diagnostics = MockGetGlobalDiagnostics(files, texts);
100 
101     int const defaultDiagnosticsSize = 0;
102     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
103 
104     const auto &diag = diagnostics.diagnostic[0];
105     ASSERT_EQ(diag.severity_, DiagnosticSeverity::Error);
106     ASSERT_NE(diag.message_.find("Can't find prefix for"), std::string::npos);
107 }
108 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetGlobalDiagnostics3)109 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetGlobalDiagnostics3)
110 {
111     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets"};
112     std::vector<std::string> texts = {
113         R"(
114 import { test2 } from "./non_existent.ets";
115 )"};
116 
117     DiagnosticReferences diagnostics = MockGetGlobalDiagnostics(files, texts);
118 
119     int const defaultDiagnosticsSize = 0;
120     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
121 
122     const auto &diag = diagnostics.diagnostic[0];
123     ASSERT_EQ(diag.severity_, DiagnosticSeverity::Error);
124 
125     bool isPathError = (diag.message_.find("Not supported path:") != std::string::npos) ||
126                        (diag.message_.find("Not an available source path:") != std::string::npos);
127     ASSERT_TRUE(isPathError);
128 }
129 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetGlobalDiagnostics4)130 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetGlobalDiagnostics4)
131 {
132     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets",
133                                       "get_compiler_options_diagnostics_test_helper.ets",
134                                       "get_compiler_options_diagnostics_test_utils.ets"};
135     std::vector<std::string> texts = {
136         R"(
137 import { helper } from "./get_compiler_options_diagnostics_test_helper.ets";
138 import { utils } from "./get_compiler_options_diagnostics_test_utils.ets";
139 import { missing } from "./missing.ets";
140 
141 function main() {
142     helper(utils.getValue());
143 }
144 )",
145         R"(
146 import { test1 } from "";
147 export function helper(value: number) {
148     return value * 2;
149 }
150 )",
151         R"(
152 import { test2 } from "./non_existent.ets";
153 export const utils = {
154     getValue: () => helper(5)
155 })"};
156 
157     DiagnosticReferences diagnostics = MockGetGlobalDiagnostics(files, texts);
158 
159     int const defaultDiagnosticsSize = 0;
160     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
161 
162     bool foundEmptyPath = false;
163     bool foundPathError = false;
164 
165     for (const auto &diag : diagnostics.diagnostic) {
166         ASSERT_EQ(diag.severity_, DiagnosticSeverity::Error);
167         if (diag.message_.find("Import path cannot be empty") != std::string::npos) {
168             foundEmptyPath = true;
169         }
170         if (diag.message_.find("Not supported path:") != std::string::npos) {
171             foundPathError = true;
172         }
173     }
174 
175     ASSERT_TRUE(foundEmptyPath);
176     ASSERT_TRUE(foundPathError);
177 }
178 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetOptionDiagnostics1)179 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetOptionDiagnostics1)
180 {
181     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets", "arktsconfig.json"};
182     std::vector<std::string> texts = {
183         R"(
184 function A(a:number, b:number) {
185     return a + b;
186 }
187 )",
188         R"({
189     "invalid json"
190 })"};
191 
192     DiagnosticReferences diagnostics = MockGetOptionDiagnostics(files, texts);
193 
194     int const defaultDiagnosticsSize = 0;
195     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
196     bool found = false;
197     for (const auto &diag : diagnostics.diagnostic) {
198         if (diag.message_.find("ArkTsConfig is not valid json") != std::string::npos) {
199             found = true;
200         }
201     }
202 
203     ASSERT_TRUE(found);
204 }
205 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetOptionDiagnostics2)206 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetOptionDiagnostics2)
207 {
208     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets", "arktsconfig.json"};
209     std::vector<std::string> texts = {
210         R"(
211 function A(a:number, b:number) {
212     return a + b;
213 }
214 )",
215         R"({
216     "extends": "./arktsconfig.json",
217     "compilerOptions": {
218         "baseUrl": "./temp"
219     }
220 })"};
221 
222     DiagnosticReferences diagnostics = MockGetOptionDiagnostics(files, texts);
223 
224     int const defaultDiagnosticsSize = 0;
225     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
226     bool found = false;
227     for (const auto &diag : diagnostics.diagnostic) {
228         if (diag.message_.find("Encountered cyclic import in") != std::string::npos) {
229             found = true;
230         }
231     }
232 
233     ASSERT_TRUE(found);
234 }
235 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetOptionDiagnostics3)236 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetOptionDiagnostics3)
237 {
238     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets", "arktsconfig.json"};
239     std::vector<std::string> texts = {
240         R"(
241 function A(a:number, b:number) {
242     return a + b;
243 }
244 )",
245         R"({
246     "compilerOptions": {
247         "paths": {
248             "std": []
249         }
250     }
251 })"};
252 
253     DiagnosticReferences diagnostics = MockGetOptionDiagnostics(files, texts);
254 
255     int const defaultDiagnosticsSize = 0;
256     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
257     bool found = false;
258     for (const auto &diag : diagnostics.diagnostic) {
259         if (diag.message_.find("Substitutions for pattern") != std::string::npos) {
260             found = true;
261         }
262     }
263 
264     ASSERT_TRUE(found);
265 }
266 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetOptionDiagnostics4)267 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetOptionDiagnostics4)
268 {
269     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets", "arktsconfig.json"};
270     std::vector<std::string> texts = {
271         R"(
272 function A(a:number, b:number) {
273     return a + b;
274 }
275 )",
276         R"({
277     "compilerOptions": {
278         "baseUrl": "/path",
279         "paths": {
280             "std": ["./path1"]
281         },
282         "dynamicPaths": {
283             "dynamic_import_tests": {
284                 "language": "invalid_lang",
285                 "hasDecl": true
286             }
287         }
288     }
289 })"};
290 
291     DiagnosticReferences diagnostics = MockGetOptionDiagnostics(files, texts);
292 
293     int const defaultDiagnosticsSize = 0;
294     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
295     bool found = false;
296     for (const auto &diag : diagnostics.diagnostic) {
297         if (diag.message_.find("value for dynamic path with key") != std::string::npos) {
298             found = true;
299         }
300     }
301 
302     ASSERT_TRUE(found);
303 }
304 
TEST_F(LSPGetCompilerOptionsDiagnosticsTests,GetOptionDiagnostics5)305 TEST_F(LSPGetCompilerOptionsDiagnosticsTests, GetOptionDiagnostics5)
306 {
307     std::vector<std::string> files = {"get_compiler_options_diagnostics_test_main.ets", "arktsconfig.json"};
308     std::vector<std::string> texts = {
309         R"(
310 function A(a:number, b:number) {
311     return a + b;
312 }
313 )",
314         R"({
315     "compilerOptions": {
316         "baseUrl": "./temp",
317         "paths": {
318             "std": ["./path1"]
319         },
320         "dynamicPaths": {
321             "dynamic_import_tests": {
322                 "language": "ts",
323                 "hasDecl": true
324             }
325         }
326     }
327 })"};
328 
329     DiagnosticReferences diagnostics = MockGetOptionDiagnostics(files, texts);
330 
331     int const defaultDiagnosticsSize = 0;
332     ASSERT_GT(diagnostics.diagnostic.size(), defaultDiagnosticsSize);
333     bool found = false;
334     for (const auto &diag : diagnostics.diagnostic) {
335         if (diag.message_.find("Interoperability with language") != std::string::npos) {
336             found = true;
337         }
338     }
339 
340     ASSERT_TRUE(found);
341 }