• 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 <gtest/gtest.h>
17 #include "lsp/include/organize_imports.h"
18 #include "lsp/include/api.h"
19 #include "lsp/include/internal_api.h"
20 #include "test/unit/lsp/lsp_api_test.h"
21 
22 namespace {
23 using ark::es2panda::lsp::Initializer;
24 using ark::es2panda::lsp::OrganizeImports;
25 }  // namespace
26 
27 class OrganizeImportsTest : public LSPAPITests {};
28 
TEST_F(OrganizeImportsTest,NormalImports)29 TEST_F(OrganizeImportsTest, NormalImports)
30 {
31     std::vector<std::string> files = {"normal-imports-test.ets", "organize-imports-1.ets", "organize-imports-2.ets"};
32     std::vector<std::string> texts = {
33         R"(
34         import {B, C, A} from "./organize-imports-1";
35         import { X } from "./organize-imports-2";
36         const a = B;
37         const b = C;
38         )",
39         R"(export const A = 1; export const B = 2; export const C = 3;)", R"(export const X = 1;)"};
40     auto filePaths = CreateTempFile(files, texts);
41 
42     Initializer initializer;
43     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
44 
45     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
46 
47     ASSERT_EQ(changes.size(), 1);
48     ASSERT_EQ(changes[0].textChanges.size(), 1);
49 
50     std::string result = changes[0].textChanges[0].newText;
51 
52     EXPECT_TRUE(result.find("import { X } from \'./organize-imports-2\';") == std::string::npos);
53     EXPECT_TRUE(result.find("import { B, C } from \'./organize-imports-1\';") != std::string::npos);
54 
55     initializer.DestroyContext(ctx);
56 }
57 
TEST_F(OrganizeImportsTest,TypeOnlyImports)58 TEST_F(OrganizeImportsTest, TypeOnlyImports)
59 {
60     std::vector<std::string> files = {"typeonly-imports-test.ets", "typeonly-index.ets"};
61     std::vector<std::string> texts = {
62         R"(
63         import type { T } from "./typeonly-index";
64         import type {T as T1} from "./typeonly-index";
65         import type {T as T2} from "./typeonly-index";
66         let t: T1;
67         function foo(arg: T2) {};
68         )",
69         R"(export type T = string;)"};
70 
71     auto filePaths = CreateTempFile(files, texts);
72     Initializer initializer;
73     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
74 
75     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
76 
77     ASSERT_EQ(changes.size(), 1);
78 
79     std::string result = changes[0].textChanges[0].newText;
80 
81     EXPECT_TRUE(result.find("import type { T } from \'./typeonly-index\';") == std::string::npos);
82     EXPECT_TRUE(result.find("import type { T as T1 } from \'./typeonly-index\';") != std::string::npos);
83     EXPECT_TRUE(result.find("import type { T as T2 } from \'./typeonly-index\';") != std::string::npos);
84 
85     initializer.DestroyContext(ctx);
86 }
87 
TEST_F(OrganizeImportsTest,NamespaceImports)88 TEST_F(OrganizeImportsTest, NamespaceImports)
89 {
90     std::vector<std::string> files = {"namespace-imports-test.ets", "namespace-imports-index.ets"};
91     std::vector<std::string> texts = {
92         R"(
93         import * as NS1 from "./namespace-imports-index";
94         import * as NS2 from "./namespace-imports-index";
95         const b = NS1.color.red;
96         )",
97         R"(export const A = 1; export const B = 2;export enum color{red, blue, yellow};)"};
98     auto filePaths = CreateTempFile(files, texts);
99 
100     Initializer initializer;
101     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
102 
103     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
104 
105     ASSERT_EQ(changes.size(), 1);
106 
107     std::string result = changes[0].textChanges[0].newText;
108 
109     EXPECT_TRUE(result.find("import * as NS1 from \'./namespace-imports-index\';") != std::string::npos);
110     EXPECT_TRUE(result.find("import * as NS2 from \'./namespace-imports-index\';") == std::string::npos);
111 
112     initializer.DestroyContext(ctx);
113 }
114 
TEST_F(OrganizeImportsTest,AliasImports)115 TEST_F(OrganizeImportsTest, AliasImports)
116 {
117     std::vector<std::string> files = {"alias-imports-test.ets", "alias-imports-index.ets"};
118     std::vector<std::string> texts = {
119         R"(
120         import {B as B1, C} from "./alias-imports-index";
121         import { B as B2 } from "./alias-imports-index";
122         const b = B1;
123         )",
124         R"(export const B = 2; export const C = 3;)"};
125 
126     auto filePaths = CreateTempFile(files, texts);
127     Initializer initializer;
128     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
129 
130     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
131 
132     ASSERT_EQ(changes.size(), 1);
133 
134     std::string result = changes[0].textChanges[0].newText;
135 
136     EXPECT_TRUE(result.find("import { B as B1 } from \'./alias-imports-index\'") != std::string::npos);
137     EXPECT_TRUE(result.find("import { B as B2 } from \'./alias-imports-index\'") == std::string::npos);
138 
139     initializer.DestroyContext(ctx);
140 }
141 
TEST_F(OrganizeImportsTest,DefaultImports)142 TEST_F(OrganizeImportsTest, DefaultImports)
143 {
144     std::vector<std::string> files = {"default-imports-test.ets", "default-imports-index.ets"};
145     std::vector<std::string> texts = {
146         R"(
147         import B from "./default-imports-index";
148         import {C as C1} from "./default-imports-index";
149         const b = B;
150         const c = C1;
151         )",
152         R"(export default const B = 2; export const C = 3;)"};
153 
154     auto filePaths = CreateTempFile(files, texts);
155     Initializer initializer;
156     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
157 
158     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
159 
160     ASSERT_EQ(changes.size(), 1);
161 
162     std::string result = changes[0].textChanges[0].newText;
163 
164     EXPECT_TRUE(result.find("import B from \'./default-imports-index\'") != std::string::npos);
165     EXPECT_TRUE(result.find("import { C as C1 } from \'./default-imports-index\'") != std::string::npos);
166 
167     initializer.DestroyContext(ctx);
168 }
169 
TEST_F(OrganizeImportsTest,SystemDefaultImports)170 TEST_F(OrganizeImportsTest, SystemDefaultImports)
171 {
172     std::vector<std::string> files = {"system-default-imports-test.ets", "system-default-index.ets"};
173     std::vector<std::string> texts = {
174         R"(
175         import * as T1 from "./system-default-index";
176         import * as T2 from "./system-default-index";
177         let t: T2.T = "hello";
178         )",
179         R"(export type T = string;)"};
180 
181     auto filePaths = CreateTempFile(files, texts);
182     Initializer initializer;
183     es2panda_Context *ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
184 
185     std::vector<FileTextChanges> changes = OrganizeImports::Organize(ctx, filePaths[0]);
186 
187     ASSERT_EQ(changes.size(), 1);
188 
189     std::string result = changes[0].textChanges[0].newText;
190 
191     EXPECT_TRUE(result.find("import * as T1 from \'./system-default-index\';") == std::string::npos);
192     EXPECT_TRUE(result.find("import * as T2 from \'./system-default-index\';") != std::string::npos);
193 
194     initializer.DestroyContext(ctx);
195 }
196