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