xref: /llvm-project/clang/unittests/Format/SortImportsTestJS.cpp (revision 6918dcafe8ea256ae1ff0b51a95d4a5d076cd380)
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 }
125 
126 TEST_F(SortImportsTestJS, SortStar) {
127   verifySort("import * as foo from 'a';\n"
128              "import {sym} from 'a';\n"
129              "import * as bar from 'b';\n",
130              "import {sym} from 'a';\n"
131              "import * as foo from 'a';\n"
132              "import * as bar from 'b';\n");
133 }
134 
135 TEST_F(SortImportsTestJS, AliasesSymbols) {
136   verifySort("import {sym1 as alias1} from 'b';\n"
137              "import {sym2 as alias2, sym3 as alias3} from 'c';\n",
138              "import {sym2 as alias2, sym3 as alias3} from 'c';\n"
139              "import {sym1 as alias1} from 'b';\n");
140 }
141 
142 TEST_F(SortImportsTestJS, SortSymbols) {
143   verifySort("import {sym1, sym2 as a, sym3} from 'b';\n",
144              "import {sym2 as a, sym1, sym3} from 'b';\n");
145   verifySort("import {sym1 /* important! */, /*!*/ sym2 as a} from 'b';\n",
146              "import {/*!*/ sym2 as a, sym1 /* important! */} from 'b';\n");
147   verifySort("import {sym1, sym2} from 'b';\n", "import {\n"
148                                                 "  sym2 \n"
149                                                 ",\n"
150                                                 " sym1 \n"
151                                                 "} from 'b';\n");
152 }
153 
154 TEST_F(SortImportsTestJS, GroupImports) {
155   verifySort("import {a} from 'absolute';\n"
156              "\n"
157              "import {b} from '../parent';\n"
158              "import {b} from '../parent/nested';\n"
159              "\n"
160              "import {b} from './relative/path';\n"
161              "import {b} from './relative/path/nested';\n"
162              "\n"
163              "let x = 1;\n",
164              "import {b} from './relative/path/nested';\n"
165              "import {b} from './relative/path';\n"
166              "import {b} from '../parent/nested';\n"
167              "import {b} from '../parent';\n"
168              "import {a} from 'absolute';\n"
169              "let x = 1;\n");
170 }
171 
172 TEST_F(SortImportsTestJS, Exports) {
173   verifySort("import {S} from 'bpath';\n"
174              "\n"
175              "import {T} from './cpath';\n"
176              "\n"
177              "export {A, B} from 'apath';\n"
178              "export {P} from '../parent';\n"
179              "export {R} from './relative';\n"
180              "export {S};\n"
181              "\n"
182              "let x = 1;\n"
183              "export y = 1;\n",
184              "export {R} from './relative';\n"
185              "import {T} from './cpath';\n"
186              "export {S};\n"
187              "export {A, B} from 'apath';\n"
188              "import {S} from 'bpath';\n"
189              "export {P} from '../parent';\n"
190              "let x = 1;\n"
191              "export y = 1;\n");
192   verifySort("import {S} from 'bpath';\n"
193              "\n"
194              "export {T} from 'epath';\n",
195              "export {T} from 'epath';\n"
196              "import {S} from 'bpath';\n");
197 }
198 
199 TEST_F(SortImportsTestJS, SideEffectImports) {
200   verifySort("import 'ZZside-effect';\n"
201              "import 'AAside-effect';\n"
202              "\n"
203              "import {A} from 'absolute';\n"
204              "\n"
205              "import {R} from './relative';\n",
206              "import {R} from './relative';\n"
207              "import 'ZZside-effect';\n"
208              "import {A} from 'absolute';\n"
209              "import 'AAside-effect';\n");
210 }
211 
212 TEST_F(SortImportsTestJS, AffectedRange) {
213   // Affected range inside of import statements.
214   verifySort("import {sym} from 'a';\n"
215              "import {sym} from 'b';\n"
216              "import {sym} from 'c';\n"
217              "\n"
218              "let x = 1;",
219              "import {sym} from 'c';\n"
220              "import {sym} from 'b';\n"
221              "import {sym} from 'a';\n"
222              "let x = 1;",
223              0, 30);
224   // Affected range outside of import statements.
225   verifySort("import {sym} from 'c';\n"
226              "import {sym} from 'b';\n"
227              "import {sym} from 'a';\n"
228              "\n"
229              "let x = 1;",
230              "import {sym} from 'c';\n"
231              "import {sym} from 'b';\n"
232              "import {sym} from 'a';\n"
233              "\n"
234              "let x = 1;",
235              70, 1);
236 }
237 
238 TEST_F(SortImportsTestJS, SortingCanShrink) {
239   // Sort excluding a suffix.
240   verifySort("import {B} from 'a';\n"
241              "import {A} from 'b';\n"
242              "\n"
243              "1;",
244              "import {A} from 'b';\n"
245              "\n"
246              "import {B} from 'a';\n"
247              "\n"
248              "1;");
249 }
250 
251 TEST_F(SortImportsTestJS, TrailingComma) {
252   verifySort("import {A, B,} from 'aa';\n", "import {B, A,} from 'aa';\n");
253 }
254 
255 TEST_F(SortImportsTestJS, SortCaseInsensitive) {
256   verifySort("import {A} from 'aa';\n"
257              "import {A} from 'Ab';\n"
258              "import {A} from 'b';\n"
259              "import {A} from 'Bc';\n"
260              "\n"
261              "1;",
262              "import {A} from 'b';\n"
263              "import {A} from 'Bc';\n"
264              "import {A} from 'Ab';\n"
265              "import {A} from 'aa';\n"
266              "\n"
267              "1;");
268   verifySort("import {aa, Ab, b, Bc} from 'x';\n"
269              "\n"
270              "1;",
271              "import {b, Bc, Ab, aa} from 'x';\n"
272              "\n"
273              "1;");
274 }
275 
276 } // end namespace
277 } // end namespace format
278 } // end namespace clang
279