Clang Project

clang_source_code/unittests/Format/SortImportsTestJS.cpp
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
16namespace clang {
17namespace format {
18namespace {
19
20class SortImportsTestJS : public ::testing::Test {
21protected:
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
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
47TEST_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
60TEST_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
72TEST_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
82TEST_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
92TEST_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
107TEST_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
114TEST_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
135TEST_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
144TEST_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
151TEST_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
163TEST_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
181TEST_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
208TEST_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
221TEST_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
247TEST_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
260TEST_F(SortImportsTestJS, TrailingComma) {
261  verifySort("import {A, B,} from 'aa';\n", "import {B, A,} from 'aa';\n");
262}
263
264TEST_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
285TEST_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
302TEST_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