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     std::string Sorted =
29         applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName));
30     return applyAllReplacements(Sorted,
31                                 reformat(Style, Sorted, Ranges, FileName));
32   }
33 
34   void verifySort(llvm::StringRef Expected, llvm::StringRef Code,
35                   unsigned Offset = 0, unsigned Length = 0) {
36     std::string Result = sort(Code, Offset, Length);
37     EXPECT_EQ(Expected.str(), Result) << "Expected:\n"
38                                       << Expected << "\nActual:\n"
39                                       << Result;
40   }
41 
42   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
43 };
44 
45 TEST_F(SortImportsTestJS, AlreadySorted) {
46   verifySort("import {sym} from 'a';\n"
47              "import {sym} from 'b';\n"
48              "import {sym} from 'c';\n"
49              "\n"
50              "let x = 1;",
51              "import {sym} from 'a';\n"
52              "import {sym} from 'b';\n"
53              "import {sym} from 'c';\n"
54              "\n"
55              "let x = 1;");
56 }
57 
58 TEST_F(SortImportsTestJS, BasicSorting) {
59   verifySort("import {sym} from 'a';\n"
60              "import {sym} from 'b';\n"
61              "import {sym} from 'c';\n"
62              "\n"
63              "let x = 1;",
64              "import {sym} from 'a';\n"
65              "import {sym} from 'c';\n"
66              "import {sym} from 'b';\n"
67              "let x = 1;");
68 }
69 
70 TEST_F(SortImportsTestJS, WrappedImportStatements) {
71   verifySort("import {sym1, sym2} from 'a';\n"
72              "import {sym} from 'b';\n"
73              "\n"
74              "1;",
75              "import\n"
76              "  {sym}\n"
77              "  from 'b';\n"
78              "import {\n"
79              "  sym1,\n"
80              "  sym2\n"
81              "} from 'a';\n"
82              "1;");
83 }
84 
85 TEST_F(SortImportsTestJS, SeparateMainCodeBody) {
86   verifySort("import {sym} from 'a';"
87              "\n"
88              "let x = 1;\n",
89              "import {sym} from 'a'; let x = 1;\n");
90 }
91 
92 TEST_F(SortImportsTestJS, Comments) {
93   verifySort("/** @fileoverview This is a great file. */\n"
94              "// A very important import follows.\n"
95              "import {sym} from 'a'; /* more comments */\n"
96              "import {sym} from 'b'; // from //foo:bar\n",
97              "/** @fileoverview This is a great file. */\n"
98              "import {sym} from 'b'; // from //foo:bar\n"
99              "// A very important import follows.\n"
100              "import {sym} from 'a'; /* more comments */\n");
101 }
102 
103 TEST_F(SortImportsTestJS, SortStar) {
104   verifySort("import * as foo from 'a';\n"
105              "import {sym} from 'a';\n"
106              "import * as bar from 'b';\n",
107              "import {sym} from 'a';\n"
108              "import * as foo from 'a';\n"
109              "import * as bar from 'b';\n");
110 }
111 
112 TEST_F(SortImportsTestJS, AliasesSymbols) {
113   verifySort("import {sym1 as alias1} from 'b';\n"
114              "import {sym2 as alias2, sym3 as alias3} from 'c';\n",
115              "import {sym2 as alias2, sym3 as alias3} from 'c';\n"
116              "import {sym1 as alias1} from 'b';\n");
117 }
118 
119 TEST_F(SortImportsTestJS, SortSymbols) {
120   verifySort("import {sym1, sym2 as a, sym3} from 'b';\n",
121              "import {sym2 as a, sym1, sym3} from 'b';\n");
122   verifySort("import {sym1 /* important! */, /*!*/ sym2 as a} from 'b';\n",
123              "import {/*!*/ sym2 as a, sym1 /* important! */} from 'b';\n");
124   verifySort("import {sym1, sym2} from 'b';\n", "import {\n"
125                                                 "  sym2 \n"
126                                                 ",\n"
127                                                 " sym1 \n"
128                                                 "} from 'b';\n");
129 }
130 
131 TEST_F(SortImportsTestJS, GroupImports) {
132   verifySort("import {a} from 'absolute';\n"
133              "\n"
134              "import {b} from '../parent';\n"
135              "import {b} from '../parent/nested';\n"
136              "\n"
137              "import {b} from './relative/path';\n"
138              "import {b} from './relative/path/nested';\n"
139              "\n"
140              "let x = 1;\n",
141              "import {b} from './relative/path/nested';\n"
142              "import {b} from './relative/path';\n"
143              "import {b} from '../parent/nested';\n"
144              "import {b} from '../parent';\n"
145              "import {a} from 'absolute';\n"
146              "let x = 1;\n");
147 }
148 
149 TEST_F(SortImportsTestJS, Exports) {
150   verifySort("import {S} from 'bpath';\n"
151              "\n"
152              "import {T} from './cpath';\n"
153              "\n"
154              "export {A, B} from 'apath';\n"
155              "export {P} from '../parent';\n"
156              "export {R} from './relative';\n"
157              "export {S};\n"
158              "\n"
159              "let x = 1;\n"
160              "export y = 1;\n",
161              "export {R} from './relative';\n"
162              "import {T} from './cpath';\n"
163              "export {S};\n"
164              "export {A, B} from 'apath';\n"
165              "import {S} from 'bpath';\n"
166              "export {P} from '../parent';\n"
167              "let x = 1;\n"
168              "export y = 1;\n");
169   verifySort("import {S} from 'bpath';\n"
170              "\n"
171              "export {T} from 'epath';\n",
172              "export {T} from 'epath';\n"
173              "import {S} from 'bpath';\n");
174 }
175 
176 TEST_F(SortImportsTestJS, SideEffectImports) {
177   verifySort("import 'ZZside-effect';\n"
178              "import 'AAside-effect';\n"
179              "\n"
180              "import {A} from 'absolute';\n"
181              "\n"
182              "import {R} from './relative';\n",
183              "import {R} from './relative';\n"
184              "import 'ZZside-effect';\n"
185              "import {A} from 'absolute';\n"
186              "import 'AAside-effect';\n");
187 }
188 
189 TEST_F(SortImportsTestJS, AffectedRange) {
190   // Sort excluding a suffix.
191   verifySort("import {sym} from 'b';\n"
192              "import {sym} from 'c';\n"
193              "import {sym} from 'a';\n"
194              "let x = 1;",
195              "import {sym} from 'c';\n"
196              "import {sym} from 'b';\n"
197              "import {sym} from 'a';\n"
198              "let x = 1;",
199              0, 30);
200   // Sort excluding a prefix.
201   verifySort("import {sym} from 'c';\n"
202              "import {sym} from 'a';\n"
203              "import {sym} from 'b';\n"
204              "\n"
205              "let x = 1;",
206              "import {sym} from 'c';\n"
207              "import {sym} from 'b';\n"
208              "import {sym} from 'a';\n"
209              "\n"
210              "let x = 1;",
211              30, 0);
212   // Sort a range within imports.
213   verifySort("import {sym} from 'c';\n"
214              "import {sym} from 'a';\n"
215              "import {sym} from 'b';\n"
216              "import {sym} from 'c';\n"
217              "let x = 1;",
218              "import {sym} from 'c';\n"
219              "import {sym} from 'b';\n"
220              "import {sym} from 'a';\n"
221              "import {sym} from 'c';\n"
222              "let x = 1;",
223              24, 30);
224 }
225 
226 } // end namespace
227 } // end namespace format
228 } // end namespace clang
229