1 //===- unittest/Format/SortImportsTestJS.cpp - JS import sort unit tests --===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
11 #include "llvm/Support/Debug.h"
12 #include "gtest/gtest.h"
13
14 #define DEBUG_TYPE "format-test"
15
16 namespace clang {
17 namespace format {
18 namespace {
19
20 class SortImportsTestJS : public ::testing::Test {
21 protected:
sort(StringRef Code,unsigned Offset=0,unsigned Length=0)22 std::string sort(StringRef Code, unsigned Offset = 0, unsigned Length = 0) {
23 StringRef FileName = "input.js";
24 if (Length == 0U)
25 Length = Code.size() - Offset;
26 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
27 auto Sorted =
28 applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName));
29 EXPECT_TRUE(static_cast<bool>(Sorted));
30 auto Formatted = applyAllReplacements(
31 *Sorted, reformat(Style, *Sorted, Ranges, FileName));
32 EXPECT_TRUE(static_cast<bool>(Formatted));
33 return *Formatted;
34 }
35
verifySort(llvm::StringRef Expected,llvm::StringRef Code,unsigned Offset=0,unsigned Length=0)36 void verifySort(llvm::StringRef Expected, llvm::StringRef Code,
37 unsigned Offset = 0, unsigned Length = 0) {
38 std::string Result = sort(Code, Offset, Length);
39 EXPECT_EQ(Expected.str(), Result) << "Expected:\n"
40 << Expected << "\nActual:\n"
41 << Result;
42 }
43
44 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
45 };
46
TEST_F(SortImportsTestJS,AlreadySorted)47 TEST_F(SortImportsTestJS, AlreadySorted) {
48 verifySort("import {sym} from 'a';\n"
49 "import {sym} from 'b';\n"
50 "import {sym} from 'c';\n"
51 "\n"
52 "let x = 1;",
53 "import {sym} from 'a';\n"
54 "import {sym} from 'b';\n"
55 "import {sym} from 'c';\n"
56 "\n"
57 "let x = 1;");
58 }
59
TEST_F(SortImportsTestJS,BasicSorting)60 TEST_F(SortImportsTestJS, BasicSorting) {
61 verifySort("import {sym} from 'a';\n"
62 "import {sym} from 'b';\n"
63 "import {sym} from 'c';\n"
64 "\n"
65 "let x = 1;",
66 "import {sym} from 'a';\n"
67 "import {sym} from 'c';\n"
68 "import {sym} from 'b';\n"
69 "let x = 1;");
70 }
71
TEST_F(SortImportsTestJS,DefaultBinding)72 TEST_F(SortImportsTestJS, DefaultBinding) {
73 verifySort("import A from 'a';\n"
74 "import B from 'b';\n"
75 "\n"
76 "let x = 1;",
77 "import B from 'b';\n"
78 "import A from 'a';\n"
79 "let x = 1;");
80 }
81
TEST_F(SortImportsTestJS,DefaultAndNamedBinding)82 TEST_F(SortImportsTestJS, DefaultAndNamedBinding) {
83 verifySort("import A, {a} from 'a';\n"
84 "import B, {b} from 'b';\n"
85 "\n"
86 "let x = 1;",
87 "import B, {b} from 'b';\n"
88 "import A, {a} from 'a';\n"
89 "let x = 1;");
90 }
91
TEST_F(SortImportsTestJS,WrappedImportStatements)92 TEST_F(SortImportsTestJS, WrappedImportStatements) {
93 verifySort("import {sym1, sym2} from 'a';\n"
94 "import {sym} from 'b';\n"
95 "\n"
96 "1;",
97 "import\n"
98 " {sym}\n"
99 " from 'b';\n"
100 "import {\n"
101 " sym1,\n"
102 " sym2\n"
103 "} from 'a';\n"
104 "1;");
105 }
106
TEST_F(SortImportsTestJS,SeparateMainCodeBody)107 TEST_F(SortImportsTestJS, SeparateMainCodeBody) {
108 verifySort("import {sym} from 'a';"
109 "\n"
110 "let x = 1;\n",
111 "import {sym} from 'a'; let x = 1;\n");
112 }
113
TEST_F(SortImportsTestJS,Comments)114 TEST_F(SortImportsTestJS, Comments) {
115 verifySort("/** @fileoverview This is a great file. */\n"
116 "// A very important import follows.\n"
117 "import {sym} from 'a'; /* more comments */\n"
118 "import {sym} from 'b'; // from //foo:bar\n",
119 "/** @fileoverview This is a great file. */\n"
120 "import {sym} from 'b'; // from //foo:bar\n"
121 "// A very important import follows.\n"
122 "import {sym} from 'a'; /* more comments */\n");
123 verifySort("import {sym} from 'a';\n"
124 "import {sym} from 'b';\n"
125 "\n"
126 "/** Comment on variable. */\n"
127 "const x = 1;\n",
128 "import {sym} from 'b';\n"
129 "import {sym} from 'a';\n"
130 "\n"
131 "/** Comment on variable. */\n"
132 "const x = 1;\n");
133 }
134
TEST_F(SortImportsTestJS,SortStar)135 TEST_F(SortImportsTestJS, SortStar) {
136 verifySort("import * as foo from 'a';\n"
137 "import {sym} from 'a';\n"
138 "import * as bar from 'b';\n",
139 "import {sym} from 'a';\n"
140 "import * as foo from 'a';\n"
141 "import * as bar from 'b';\n");
142 }
143
TEST_F(SortImportsTestJS,AliasesSymbols)144 TEST_F(SortImportsTestJS, AliasesSymbols) {
145 verifySort("import {sym1 as alias1} from 'b';\n"
146 "import {sym2 as alias2, sym3 as alias3} from 'c';\n",
147 "import {sym2 as alias2, sym3 as alias3} from 'c';\n"
148 "import {sym1 as alias1} from 'b';\n");
149 }
150
TEST_F(SortImportsTestJS,SortSymbols)151 TEST_F(SortImportsTestJS, SortSymbols) {
152 verifySort("import {sym1, sym2 as a, sym3} from 'b';\n",
153 "import {sym2 as a, sym1, sym3} from 'b';\n");
154 verifySort("import {sym1 /* important! */, /*!*/ sym2 as a} from 'b';\n",
155 "import {/*!*/ sym2 as a, sym1 /* important! */} from 'b';\n");
156 verifySort("import {sym1, sym2} from 'b';\n", "import {\n"
157 " sym2 \n"
158 ",\n"
159 " sym1 \n"
160 "} from 'b';\n");
161 }
162
TEST_F(SortImportsTestJS,GroupImports)163 TEST_F(SortImportsTestJS, GroupImports) {
164 verifySort("import {a} from 'absolute';\n"
165 "\n"
166 "import {b} from '../parent';\n"
167 "import {b} from '../parent/nested';\n"
168 "\n"
169 "import {b} from './relative/path';\n"
170 "import {b} from './relative/path/nested';\n"
171 "\n"
172 "let x = 1;\n",
173 "import {b} from './relative/path/nested';\n"
174 "import {b} from './relative/path';\n"
175 "import {b} from '../parent/nested';\n"
176 "import {b} from '../parent';\n"
177 "import {a} from 'absolute';\n"
178 "let x = 1;\n");
179 }
180
TEST_F(SortImportsTestJS,Exports)181 TEST_F(SortImportsTestJS, Exports) {
182 verifySort("import {S} from 'bpath';\n"
183 "\n"
184 "import {T} from './cpath';\n"
185 "\n"
186 "export {A, B} from 'apath';\n"
187 "export {P} from '../parent';\n"
188 "export {R} from './relative';\n"
189 "export {S};\n"
190 "\n"
191 "let x = 1;\n"
192 "export y = 1;\n",
193 "export {R} from './relative';\n"
194 "import {T} from './cpath';\n"
195 "export {S};\n"
196 "export {A, B} from 'apath';\n"
197 "import {S} from 'bpath';\n"
198 "export {P} from '../parent';\n"
199 "let x = 1;\n"
200 "export y = 1;\n");
201 verifySort("import {S} from 'bpath';\n"
202 "\n"
203 "export {T} from 'epath';\n",
204 "export {T} from 'epath';\n"
205 "import {S} from 'bpath';\n");
206 }
207
TEST_F(SortImportsTestJS,SideEffectImports)208 TEST_F(SortImportsTestJS, SideEffectImports) {
209 verifySort("import 'ZZside-effect';\n"
210 "import 'AAside-effect';\n"
211 "\n"
212 "import {A} from 'absolute';\n"
213 "\n"
214 "import {R} from './relative';\n",
215 "import {R} from './relative';\n"
216 "import 'ZZside-effect';\n"
217 "import {A} from 'absolute';\n"
218 "import 'AAside-effect';\n");
219 }
220
TEST_F(SortImportsTestJS,AffectedRange)221 TEST_F(SortImportsTestJS, AffectedRange) {
222 // Affected range inside of import statements.
223 verifySort("import {sym} from 'a';\n"
224 "import {sym} from 'b';\n"
225 "import {sym} from 'c';\n"
226 "\n"
227 "let x = 1;",
228 "import {sym} from 'c';\n"
229 "import {sym} from 'b';\n"
230 "import {sym} from 'a';\n"
231 "let x = 1;",
232 0, 30);
233 // Affected range outside of import statements.
234 verifySort("import {sym} from 'c';\n"
235 "import {sym} from 'b';\n"
236 "import {sym} from 'a';\n"
237 "\n"
238 "let x = 1;",
239 "import {sym} from 'c';\n"
240 "import {sym} from 'b';\n"
241 "import {sym} from 'a';\n"
242 "\n"
243 "let x = 1;",
244 70, 1);
245 }
246
TEST_F(SortImportsTestJS,SortingCanShrink)247 TEST_F(SortImportsTestJS, SortingCanShrink) {
248 // Sort excluding a suffix.
249 verifySort("import {B} from 'a';\n"
250 "import {A} from 'b';\n"
251 "\n"
252 "1;",
253 "import {A} from 'b';\n"
254 "\n"
255 "import {B} from 'a';\n"
256 "\n"
257 "1;");
258 }
259
TEST_F(SortImportsTestJS,TrailingComma)260 TEST_F(SortImportsTestJS, TrailingComma) {
261 verifySort("import {A, B,} from 'aa';\n", "import {B, A,} from 'aa';\n");
262 }
263
TEST_F(SortImportsTestJS,SortCaseInsensitive)264 TEST_F(SortImportsTestJS, SortCaseInsensitive) {
265 verifySort("import {A} from 'aa';\n"
266 "import {A} from 'Ab';\n"
267 "import {A} from 'b';\n"
268 "import {A} from 'Bc';\n"
269 "\n"
270 "1;",
271 "import {A} from 'b';\n"
272 "import {A} from 'Bc';\n"
273 "import {A} from 'Ab';\n"
274 "import {A} from 'aa';\n"
275 "\n"
276 "1;");
277 verifySort("import {aa, Ab, b, Bc} from 'x';\n"
278 "\n"
279 "1;",
280 "import {b, Bc, Ab, aa} from 'x';\n"
281 "\n"
282 "1;");
283 }
284
TEST_F(SortImportsTestJS,SortMultiLine)285 TEST_F(SortImportsTestJS, SortMultiLine) {
286 // Reproduces issue where multi-line import was not parsed correctly.
287 verifySort("import {A} from 'a';\n"
288 "import {A} from 'b';\n"
289 "\n"
290 "1;",
291 "import\n"
292 "{\n"
293 "A\n"
294 "}\n"
295 "from\n"
296 "'b';\n"
297 "import {A} from 'a';\n"
298 "\n"
299 "1;");
300 }
301
TEST_F(SortImportsTestJS,SortDefaultImports)302 TEST_F(SortImportsTestJS, SortDefaultImports) {
303 // Reproduces issue where multi-line import was not parsed correctly.
304 verifySort("import {A} from 'a';\n"
305 "import {default as B} from 'b';\n",
306 "import {default as B} from 'b';\n"
307 "import {A} from 'a';\n");
308 }
309
310 } // end namespace
311 } // end namespace format
312 } // end namespace clang
313