xref: /llvm-project/clang/unittests/Format/SortImportsTestJS.cpp (revision 1c58208d899285318c89e069268145c85ec33368)
1c4a0dd49SMartin Probst //===- unittest/Format/SortImportsTestJS.cpp - JS import sort unit tests --===//
2c4a0dd49SMartin Probst //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c4a0dd49SMartin Probst //
7c4a0dd49SMartin Probst //===----------------------------------------------------------------------===//
8c4a0dd49SMartin Probst 
9c4a0dd49SMartin Probst #include "FormatTestUtils.h"
10c4a0dd49SMartin Probst #include "clang/Format/Format.h"
11c4a0dd49SMartin Probst #include "llvm/Support/Debug.h"
12c4a0dd49SMartin Probst #include "gtest/gtest.h"
13c4a0dd49SMartin Probst 
14c4a0dd49SMartin Probst #define DEBUG_TYPE "format-test"
15c4a0dd49SMartin Probst 
16c4a0dd49SMartin Probst namespace clang {
17c4a0dd49SMartin Probst namespace format {
18c4a0dd49SMartin Probst namespace {
19c4a0dd49SMartin Probst 
20*1c58208dSOwen Pan class SortImportsTestJS : public testing::Test {
21c4a0dd49SMartin Probst protected:
sort(StringRef Code,unsigned Offset=0,unsigned Length=0)22c4a0dd49SMartin Probst   std::string sort(StringRef Code, unsigned Offset = 0, unsigned Length = 0) {
23c4a0dd49SMartin Probst     StringRef FileName = "input.js";
24c4a0dd49SMartin Probst     if (Length == 0U)
25c4a0dd49SMartin Probst       Length = Code.size() - Offset;
26c4a0dd49SMartin Probst     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
274f8d9943SEric Liu     auto Sorted =
28c4a0dd49SMartin Probst         applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName));
294f8d9943SEric Liu     EXPECT_TRUE(static_cast<bool>(Sorted));
304f8d9943SEric Liu     auto Formatted = applyAllReplacements(
314f8d9943SEric Liu         *Sorted, reformat(Style, *Sorted, Ranges, FileName));
324f8d9943SEric Liu     EXPECT_TRUE(static_cast<bool>(Formatted));
334f8d9943SEric Liu     return *Formatted;
34c4a0dd49SMartin Probst   }
35c4a0dd49SMartin Probst 
_verifySort(const char * File,int Line,StringRef Expected,StringRef Code,unsigned Offset=0,unsigned Length=0)36*1c58208dSOwen Pan   void _verifySort(const char *File, int Line, StringRef Expected,
37*1c58208dSOwen Pan                    StringRef Code, unsigned Offset = 0, unsigned Length = 0) {
38*1c58208dSOwen Pan     testing::ScopedTrace t(File, Line, testing::Message() << Code.str());
39c4a0dd49SMartin Probst     std::string Result = sort(Code, Offset, Length);
40c4a0dd49SMartin Probst     EXPECT_EQ(Expected.str(), Result) << "Expected:\n"
41c4a0dd49SMartin Probst                                       << Expected << "\nActual:\n"
42c4a0dd49SMartin Probst                                       << Result;
43c4a0dd49SMartin Probst   }
44c4a0dd49SMartin Probst 
45c4a0dd49SMartin Probst   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
46c4a0dd49SMartin Probst };
47c4a0dd49SMartin Probst 
4869ecd248SMarek Kurdej #define verifySort(...) _verifySort(__FILE__, __LINE__, __VA_ARGS__)
4969ecd248SMarek Kurdej 
TEST_F(SortImportsTestJS,AlreadySorted)50c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, AlreadySorted) {
51c4a0dd49SMartin Probst   verifySort("import {sym} from 'a';\n"
52c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
53c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
54c4a0dd49SMartin Probst              "\n"
55c4a0dd49SMartin Probst              "let x = 1;",
56c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
57c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
58c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
59c4a0dd49SMartin Probst              "\n"
60c4a0dd49SMartin Probst              "let x = 1;");
61c4a0dd49SMartin Probst }
62c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,BasicSorting)63c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, BasicSorting) {
64c4a0dd49SMartin Probst   verifySort("import {sym} from 'a';\n"
65c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
66c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
67c4a0dd49SMartin Probst              "\n"
68c4a0dd49SMartin Probst              "let x = 1;",
69c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
70c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
71c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
72c4a0dd49SMartin Probst              "let x = 1;");
73c4a0dd49SMartin Probst }
74c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,DefaultBinding)756918dcafSMartin Probst TEST_F(SortImportsTestJS, DefaultBinding) {
766918dcafSMartin Probst   verifySort("import A from 'a';\n"
776918dcafSMartin Probst              "import B from 'b';\n"
786918dcafSMartin Probst              "\n"
796918dcafSMartin Probst              "let x = 1;",
806918dcafSMartin Probst              "import B from 'b';\n"
816918dcafSMartin Probst              "import A from 'a';\n"
826918dcafSMartin Probst              "let x = 1;");
836918dcafSMartin Probst }
846918dcafSMartin Probst 
TEST_F(SortImportsTestJS,DefaultAndNamedBinding)856918dcafSMartin Probst TEST_F(SortImportsTestJS, DefaultAndNamedBinding) {
866918dcafSMartin Probst   verifySort("import A, {a} from 'a';\n"
876918dcafSMartin Probst              "import B, {b} from 'b';\n"
886918dcafSMartin Probst              "\n"
896918dcafSMartin Probst              "let x = 1;",
906918dcafSMartin Probst              "import B, {b} from 'b';\n"
916918dcafSMartin Probst              "import A, {a} from 'a';\n"
926918dcafSMartin Probst              "let x = 1;");
936918dcafSMartin Probst }
946918dcafSMartin Probst 
TEST_F(SortImportsTestJS,WrappedImportStatements)95081f176aSMartin Probst TEST_F(SortImportsTestJS, WrappedImportStatements) {
96081f176aSMartin Probst   verifySort("import {sym1, sym2} from 'a';\n"
97081f176aSMartin Probst              "import {sym} from 'b';\n"
98081f176aSMartin Probst              "\n"
99081f176aSMartin Probst              "1;",
100081f176aSMartin Probst              "import\n"
101081f176aSMartin Probst              "  {sym}\n"
102081f176aSMartin Probst              "  from 'b';\n"
103081f176aSMartin Probst              "import {\n"
104081f176aSMartin Probst              "  sym1,\n"
105081f176aSMartin Probst              "  sym2\n"
106081f176aSMartin Probst              "} from 'a';\n"
107081f176aSMartin Probst              "1;");
108081f176aSMartin Probst }
109081f176aSMartin Probst 
TEST_F(SortImportsTestJS,SeparateMainCodeBody)110c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, SeparateMainCodeBody) {
111c4a0dd49SMartin Probst   verifySort("import {sym} from 'a';"
112c4a0dd49SMartin Probst              "\n"
113e3ecdf7dSOwen Pan              "let x = 1;",
114e3ecdf7dSOwen Pan              "import {sym} from 'a'; let x = 1;");
115c4a0dd49SMartin Probst }
116c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,Comments)117c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, Comments) {
118c4a0dd49SMartin Probst   verifySort("/** @fileoverview This is a great file. */\n"
119c4a0dd49SMartin Probst              "// A very important import follows.\n"
120c4a0dd49SMartin Probst              "import {sym} from 'a';  /* more comments */\n"
121c4a0dd49SMartin Probst              "import {sym} from 'b';  // from //foo:bar\n",
122c4a0dd49SMartin Probst              "/** @fileoverview This is a great file. */\n"
123c4a0dd49SMartin Probst              "import {sym} from 'b';  // from //foo:bar\n"
124c4a0dd49SMartin Probst              "// A very important import follows.\n"
125e3ecdf7dSOwen Pan              "import {sym} from 'a';  /* more comments */");
12663014581SMartin Probst   verifySort("import {sym} from 'a';\n"
12763014581SMartin Probst              "import {sym} from 'b';\n"
12863014581SMartin Probst              "\n"
12963014581SMartin Probst              "/** Comment on variable. */\n"
130e3ecdf7dSOwen Pan              "const x = 1;",
13163014581SMartin Probst              "import {sym} from 'b';\n"
13263014581SMartin Probst              "import {sym} from 'a';\n"
13363014581SMartin Probst              "\n"
13463014581SMartin Probst              "/** Comment on variable. */\n"
135e3ecdf7dSOwen Pan              "const x = 1;");
136c4a0dd49SMartin Probst }
137c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,SortStar)138c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, SortStar) {
139c4a0dd49SMartin Probst   verifySort("import * as foo from 'a';\n"
140c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
141c4a0dd49SMartin Probst              "import * as bar from 'b';\n",
142c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
143c4a0dd49SMartin Probst              "import * as foo from 'a';\n"
144e3ecdf7dSOwen Pan              "import * as bar from 'b';");
145c4a0dd49SMartin Probst }
146c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,AliasesSymbols)147c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, AliasesSymbols) {
148c4a0dd49SMartin Probst   verifySort("import {sym1 as alias1} from 'b';\n"
149c4a0dd49SMartin Probst              "import {sym2 as alias2, sym3 as alias3} from 'c';\n",
150c4a0dd49SMartin Probst              "import {sym2 as alias2, sym3 as alias3} from 'c';\n"
151e3ecdf7dSOwen Pan              "import {sym1 as alias1} from 'b';");
152c4a0dd49SMartin Probst }
153c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,SortSymbols)154081f176aSMartin Probst TEST_F(SortImportsTestJS, SortSymbols) {
155081f176aSMartin Probst   verifySort("import {sym1, sym2 as a, sym3} from 'b';\n",
156e3ecdf7dSOwen Pan              "import {sym2 as a, sym1, sym3} from 'b';");
157081f176aSMartin Probst   verifySort("import {sym1 /* important! */, /*!*/ sym2 as a} from 'b';\n",
158e3ecdf7dSOwen Pan              "import {/*!*/ sym2 as a, sym1 /* important! */} from 'b';");
159081f176aSMartin Probst   verifySort("import {sym1, sym2} from 'b';\n", "import {\n"
160081f176aSMartin Probst                                                 "  sym2 \n"
161081f176aSMartin Probst                                                 ",\n"
162081f176aSMartin Probst                                                 " sym1 \n"
163e3ecdf7dSOwen Pan                                                 "} from 'b';");
164081f176aSMartin Probst }
165081f176aSMartin Probst 
TEST_F(SortImportsTestJS,GroupImports)166c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, GroupImports) {
167c4a0dd49SMartin Probst   verifySort("import {a} from 'absolute';\n"
168c4a0dd49SMartin Probst              "\n"
169c4a0dd49SMartin Probst              "import {b} from '../parent';\n"
170c4a0dd49SMartin Probst              "import {b} from '../parent/nested';\n"
171c4a0dd49SMartin Probst              "\n"
172c4a0dd49SMartin Probst              "import {b} from './relative/path';\n"
173c4a0dd49SMartin Probst              "import {b} from './relative/path/nested';\n"
174c4a0dd49SMartin Probst              "\n"
175e3ecdf7dSOwen Pan              "let x = 1;",
176c4a0dd49SMartin Probst              "import {b} from './relative/path/nested';\n"
177c4a0dd49SMartin Probst              "import {b} from './relative/path';\n"
178c4a0dd49SMartin Probst              "import {b} from '../parent/nested';\n"
179c4a0dd49SMartin Probst              "import {b} from '../parent';\n"
180c4a0dd49SMartin Probst              "import {a} from 'absolute';\n"
181e3ecdf7dSOwen Pan              "let x = 1;");
182c4a0dd49SMartin Probst }
183c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,Exports)184c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, Exports) {
185c4a0dd49SMartin Probst   verifySort("import {S} from 'bpath';\n"
186c4a0dd49SMartin Probst              "\n"
187c4a0dd49SMartin Probst              "import {T} from './cpath';\n"
188c4a0dd49SMartin Probst              "\n"
189c4a0dd49SMartin Probst              "export {A, B} from 'apath';\n"
190c4a0dd49SMartin Probst              "export {P} from '../parent';\n"
191c4a0dd49SMartin Probst              "export {R} from './relative';\n"
192c4a0dd49SMartin Probst              "export {S};\n"
193c4a0dd49SMartin Probst              "\n"
194c4a0dd49SMartin Probst              "let x = 1;\n"
195e3ecdf7dSOwen Pan              "export y = 1;",
196c4a0dd49SMartin Probst              "export {R} from './relative';\n"
197c4a0dd49SMartin Probst              "import {T} from './cpath';\n"
198c4a0dd49SMartin Probst              "export {S};\n"
199c4a0dd49SMartin Probst              "export {A, B} from 'apath';\n"
200c4a0dd49SMartin Probst              "import {S} from 'bpath';\n"
201c4a0dd49SMartin Probst              "export {P} from '../parent';\n"
202c4a0dd49SMartin Probst              "let x = 1;\n"
203e3ecdf7dSOwen Pan              "export y = 1;");
204c4a0dd49SMartin Probst   verifySort("import {S} from 'bpath';\n"
205c4a0dd49SMartin Probst              "\n"
206c4a0dd49SMartin Probst              "export {T} from 'epath';\n",
207c4a0dd49SMartin Probst              "export {T} from 'epath';\n"
208e3ecdf7dSOwen Pan              "import {S} from 'bpath';");
209c4a0dd49SMartin Probst }
210c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,SideEffectImports)211c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, SideEffectImports) {
212c4a0dd49SMartin Probst   verifySort("import 'ZZside-effect';\n"
213c4a0dd49SMartin Probst              "import 'AAside-effect';\n"
214c4a0dd49SMartin Probst              "\n"
215c4a0dd49SMartin Probst              "import {A} from 'absolute';\n"
216c4a0dd49SMartin Probst              "\n"
217c4a0dd49SMartin Probst              "import {R} from './relative';\n",
218c4a0dd49SMartin Probst              "import {R} from './relative';\n"
219c4a0dd49SMartin Probst              "import 'ZZside-effect';\n"
220c4a0dd49SMartin Probst              "import {A} from 'absolute';\n"
221e3ecdf7dSOwen Pan              "import 'AAside-effect';");
222c4a0dd49SMartin Probst }
223c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,AffectedRange)224c4a0dd49SMartin Probst TEST_F(SortImportsTestJS, AffectedRange) {
225b480ffbcSMartin Probst   // Affected range inside of import statements.
226b480ffbcSMartin Probst   verifySort("import {sym} from 'a';\n"
227b480ffbcSMartin Probst              "import {sym} from 'b';\n"
228c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
229b480ffbcSMartin Probst              "\n"
230c4a0dd49SMartin Probst              "let x = 1;",
231c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
232c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
233c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
234c4a0dd49SMartin Probst              "let x = 1;",
235c4a0dd49SMartin Probst              0, 30);
236b480ffbcSMartin Probst   // Affected range outside of import statements.
237c4a0dd49SMartin Probst   verifySort("import {sym} from 'c';\n"
238c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
239b480ffbcSMartin Probst              "import {sym} from 'a';\n"
240c4a0dd49SMartin Probst              "\n"
241c4a0dd49SMartin Probst              "let x = 1;",
242c4a0dd49SMartin Probst              "import {sym} from 'c';\n"
243c4a0dd49SMartin Probst              "import {sym} from 'b';\n"
244c4a0dd49SMartin Probst              "import {sym} from 'a';\n"
245c4a0dd49SMartin Probst              "\n"
246c4a0dd49SMartin Probst              "let x = 1;",
247b480ffbcSMartin Probst              70, 1);
248c4a0dd49SMartin Probst }
249c4a0dd49SMartin Probst 
TEST_F(SortImportsTestJS,SortingCanShrink)2506f43efbdSMartin Probst TEST_F(SortImportsTestJS, SortingCanShrink) {
2516f43efbdSMartin Probst   // Sort excluding a suffix.
2526f43efbdSMartin Probst   verifySort("import {B} from 'a';\n"
2536f43efbdSMartin Probst              "import {A} from 'b';\n"
2546f43efbdSMartin Probst              "\n"
2556f43efbdSMartin Probst              "1;",
2566f43efbdSMartin Probst              "import {A} from 'b';\n"
2576f43efbdSMartin Probst              "\n"
2586f43efbdSMartin Probst              "import {B} from 'a';\n"
2596f43efbdSMartin Probst              "\n"
2606f43efbdSMartin Probst              "1;");
2616f43efbdSMartin Probst }
2626f43efbdSMartin Probst 
TEST_F(SortImportsTestJS,TrailingComma)263a8c9d154SMartin Probst TEST_F(SortImportsTestJS, TrailingComma) {
264e3ecdf7dSOwen Pan   verifySort("import {A, B,} from 'aa';\n", "import {B, A,} from 'aa';");
265a8c9d154SMartin Probst }
266a8c9d154SMartin Probst 
TEST_F(SortImportsTestJS,SortCaseInsensitive)2672a19454aSMartin Probst TEST_F(SortImportsTestJS, SortCaseInsensitive) {
2682a19454aSMartin Probst   verifySort("import {A} from 'aa';\n"
2692a19454aSMartin Probst              "import {A} from 'Ab';\n"
2702a19454aSMartin Probst              "import {A} from 'b';\n"
2712a19454aSMartin Probst              "import {A} from 'Bc';\n"
2722a19454aSMartin Probst              "\n"
2732a19454aSMartin Probst              "1;",
2742a19454aSMartin Probst              "import {A} from 'b';\n"
2752a19454aSMartin Probst              "import {A} from 'Bc';\n"
2762a19454aSMartin Probst              "import {A} from 'Ab';\n"
2772a19454aSMartin Probst              "import {A} from 'aa';\n"
2782a19454aSMartin Probst              "\n"
2792a19454aSMartin Probst              "1;");
2802a19454aSMartin Probst   verifySort("import {aa, Ab, b, Bc} from 'x';\n"
2812a19454aSMartin Probst              "\n"
2822a19454aSMartin Probst              "1;",
2832a19454aSMartin Probst              "import {b, Bc, Ab, aa} from 'x';\n"
2842a19454aSMartin Probst              "\n"
2852a19454aSMartin Probst              "1;");
2862a19454aSMartin Probst }
2872a19454aSMartin Probst 
TEST_F(SortImportsTestJS,SortMultiLine)28893008f01SMartin Probst TEST_F(SortImportsTestJS, SortMultiLine) {
28993008f01SMartin Probst   // Reproduces issue where multi-line import was not parsed correctly.
29093008f01SMartin Probst   verifySort("import {A} from 'a';\n"
29193008f01SMartin Probst              "import {A} from 'b';\n"
29293008f01SMartin Probst              "\n"
29393008f01SMartin Probst              "1;",
29493008f01SMartin Probst              "import\n"
29593008f01SMartin Probst              "{\n"
29693008f01SMartin Probst              "A\n"
29793008f01SMartin Probst              "}\n"
29893008f01SMartin Probst              "from\n"
29993008f01SMartin Probst              "'b';\n"
30093008f01SMartin Probst              "import {A} from 'a';\n"
30193008f01SMartin Probst              "\n"
30293008f01SMartin Probst              "1;");
30393008f01SMartin Probst }
30493008f01SMartin Probst 
TEST_F(SortImportsTestJS,SortDefaultImports)3054bf1d7adSMartin Probst TEST_F(SortImportsTestJS, SortDefaultImports) {
3064bf1d7adSMartin Probst   // Reproduces issue where multi-line import was not parsed correctly.
3074bf1d7adSMartin Probst   verifySort("import {A} from 'a';\n"
3084bf1d7adSMartin Probst              "import {default as B} from 'b';\n",
3094bf1d7adSMartin Probst              "import {default as B} from 'b';\n"
310e3ecdf7dSOwen Pan              "import {A} from 'a';");
3114bf1d7adSMartin Probst }
3124bf1d7adSMartin Probst 
TEST_F(SortImportsTestJS,MergeImports)313d45df0d2SMartin Probst TEST_F(SortImportsTestJS, MergeImports) {
314d45df0d2SMartin Probst   // basic operation
315d45df0d2SMartin Probst   verifySort("import {X, Y} from 'a';\n"
316d45df0d2SMartin Probst              "import {Z} from 'z';\n"
317d45df0d2SMartin Probst              "\n"
318e3ecdf7dSOwen Pan              "X + Y + Z;",
319d45df0d2SMartin Probst              "import {X} from 'a';\n"
320d45df0d2SMartin Probst              "import {Z} from 'z';\n"
321d45df0d2SMartin Probst              "import {Y} from 'a';\n"
322d45df0d2SMartin Probst              "\n"
323e3ecdf7dSOwen Pan              "X + Y + Z;");
324d45df0d2SMartin Probst 
3254d195f1bSMartin Probst   // merge only, no resorting.
3264d195f1bSMartin Probst   verifySort("import {A, B} from 'foo';\n", "import {A} from 'foo';\n"
3274d195f1bSMartin Probst                                             "import {B} from 'foo';");
3284d195f1bSMartin Probst 
329d45df0d2SMartin Probst   // empty imports
330d45df0d2SMartin Probst   verifySort("import {A} from 'foo';\n", "import {} from 'foo';\n"
331d45df0d2SMartin Probst                                          "import {A} from 'foo';");
332d45df0d2SMartin Probst 
333d45df0d2SMartin Probst   // ignores import *
334d45df0d2SMartin Probst   verifySort("import * as foo from 'foo';\n"
335e3ecdf7dSOwen Pan              "import {A} from 'foo';",
336d45df0d2SMartin Probst              "import   * as foo from 'foo';\n"
337e3ecdf7dSOwen Pan              "import {A} from 'foo';");
338d45df0d2SMartin Probst 
339d45df0d2SMartin Probst   // ignores default import
340d45df0d2SMartin Probst   verifySort("import X from 'foo';\n"
341e3ecdf7dSOwen Pan              "import {A} from 'foo';",
342d45df0d2SMartin Probst              "import    X from 'foo';\n"
343e3ecdf7dSOwen Pan              "import {A} from 'foo';");
344d45df0d2SMartin Probst 
345d45df0d2SMartin Probst   // keeps comments
346d45df0d2SMartin Probst   // known issue: loses the 'also a' comment.
347d45df0d2SMartin Probst   verifySort("// a\n"
348d45df0d2SMartin Probst              "import {/* x */ X, /* y */ Y} from 'a';\n"
349d45df0d2SMartin Probst              "// z\n"
350d45df0d2SMartin Probst              "import {Z} from 'z';\n"
351d45df0d2SMartin Probst              "\n"
352e3ecdf7dSOwen Pan              "X + Y + Z;",
353d45df0d2SMartin Probst              "// a\n"
354d45df0d2SMartin Probst              "import {/* y */ Y} from 'a';\n"
355d45df0d2SMartin Probst              "// z\n"
356d45df0d2SMartin Probst              "import {Z} from 'z';\n"
357d45df0d2SMartin Probst              "// also a\n"
358d45df0d2SMartin Probst              "import {/* x */ X} from 'a';\n"
359d45df0d2SMartin Probst              "\n"
360e3ecdf7dSOwen Pan              "X + Y + Z;");
3613d4a6037SMartin Probst 
3623d4a6037SMartin Probst   // do not merge imports and exports
3633d4a6037SMartin Probst   verifySort("import {A} from 'foo';\n"
364b2780cd7SMartin Probst              "\n"
365b2780cd7SMartin Probst              "export {B} from 'foo';\n",
3663d4a6037SMartin Probst              "import {A} from 'foo';\n"
3673d4a6037SMartin Probst              "export   {B} from 'foo';");
3683d4a6037SMartin Probst   // do merge exports
3693d4a6037SMartin Probst   verifySort("export {A, B} from 'foo';\n", "export {A} from 'foo';\n"
3703d4a6037SMartin Probst                                             "export   {B} from 'foo';");
371fbc6f42dSMartin Probst 
372fbc6f42dSMartin Probst   // do not merge side effect imports with named ones
373fbc6f42dSMartin Probst   verifySort("import './a';\n"
374fbc6f42dSMartin Probst              "\n"
375fbc6f42dSMartin Probst              "import {bar} from './a';\n",
376fbc6f42dSMartin Probst              "import {bar} from './a';\n"
377e3ecdf7dSOwen Pan              "import './a';");
378d45df0d2SMartin Probst }
379d45df0d2SMartin Probst 
TEST_F(SortImportsTestJS,RespectsClangFormatOff)380b2780cd7SMartin Probst TEST_F(SortImportsTestJS, RespectsClangFormatOff) {
381b2780cd7SMartin Probst   verifySort("// clang-format off\n"
382b2780cd7SMartin Probst              "import {B} from './b';\n"
383b2780cd7SMartin Probst              "import {A} from './a';\n"
384e3ecdf7dSOwen Pan              "// clang-format on",
385b2780cd7SMartin Probst              "// clang-format off\n"
386b2780cd7SMartin Probst              "import {B} from './b';\n"
387b2780cd7SMartin Probst              "import {A} from './a';\n"
388e3ecdf7dSOwen Pan              "// clang-format on");
389b2780cd7SMartin Probst 
390b2780cd7SMartin Probst   verifySort("import {A} from './sorted1_a';\n"
391b2780cd7SMartin Probst              "import {B} from './sorted1_b';\n"
392b2780cd7SMartin Probst              "// clang-format off\n"
393b2780cd7SMartin Probst              "import {B} from './unsorted_b';\n"
394b2780cd7SMartin Probst              "import {A} from './unsorted_a';\n"
395b2780cd7SMartin Probst              "// clang-format on\n"
396b2780cd7SMartin Probst              "import {A} from './sorted2_a';\n"
397b2780cd7SMartin Probst              "import {B} from './sorted2_b';\n",
398b2780cd7SMartin Probst              "import {B} from './sorted1_b';\n"
399b2780cd7SMartin Probst              "import {A} from './sorted1_a';\n"
400b2780cd7SMartin Probst              "// clang-format off\n"
401b2780cd7SMartin Probst              "import {B} from './unsorted_b';\n"
402b2780cd7SMartin Probst              "import {A} from './unsorted_a';\n"
403b2780cd7SMartin Probst              "// clang-format on\n"
404b2780cd7SMartin Probst              "import {B} from './sorted2_b';\n"
405e3ecdf7dSOwen Pan              "import {A} from './sorted2_a';");
406b2780cd7SMartin Probst 
407b2780cd7SMartin Probst   // Boundary cases
408e3ecdf7dSOwen Pan   verifySort("// clang-format on", "// clang-format on");
409e3ecdf7dSOwen Pan   verifySort("// clang-format off", "// clang-format off");
410b2780cd7SMartin Probst   verifySort("// clang-format on\n"
411e3ecdf7dSOwen Pan              "// clang-format off",
412b2780cd7SMartin Probst              "// clang-format on\n"
413e3ecdf7dSOwen Pan              "// clang-format off");
414b2780cd7SMartin Probst   verifySort("// clang-format off\n"
415b2780cd7SMartin Probst              "// clang-format on\n"
416b2780cd7SMartin Probst              "import {A} from './a';\n"
417b2780cd7SMartin Probst              "import {B} from './b';\n",
418b2780cd7SMartin Probst              "// clang-format off\n"
419b2780cd7SMartin Probst              "// clang-format on\n"
420b2780cd7SMartin Probst              "import {B} from './b';\n"
421e3ecdf7dSOwen Pan              "import {A} from './a';");
422b2780cd7SMartin Probst   // section ends with comment
423b2780cd7SMartin Probst   verifySort("// clang-format on\n"
424b2780cd7SMartin Probst              "import {A} from './a';\n"
425b2780cd7SMartin Probst              "import {B} from './b';\n"
426b2780cd7SMartin Probst              "import {C} from './c';\n"
427b2780cd7SMartin Probst              "\n" // inserted empty line is working as intended: splits imports
428b2780cd7SMartin Probst                   // section from main code body
429e3ecdf7dSOwen Pan              "// clang-format off",
430b2780cd7SMartin Probst              "// clang-format on\n"
431b2780cd7SMartin Probst              "import {C} from './c';\n"
432b2780cd7SMartin Probst              "import {B} from './b';\n"
433b2780cd7SMartin Probst              "import {A} from './a';\n"
434e3ecdf7dSOwen Pan              "// clang-format off");
435b2780cd7SMartin Probst }
436b2780cd7SMartin Probst 
TEST_F(SortImportsTestJS,RespectsClangFormatOffInNamedImports)43763042d46SMartin Probst TEST_F(SortImportsTestJS, RespectsClangFormatOffInNamedImports) {
43863042d46SMartin Probst   verifySort("// clang-format off\n"
43963042d46SMartin Probst              "import {B, A} from './b';\n"
44063042d46SMartin Probst              "// clang-format on\n"
44163042d46SMartin Probst              "const x = 1;",
44263042d46SMartin Probst              "// clang-format off\n"
44363042d46SMartin Probst              "import {B, A} from './b';\n"
44463042d46SMartin Probst              "// clang-format on\n"
44563042d46SMartin Probst              "const x =   1;");
44663042d46SMartin Probst }
44763042d46SMartin Probst 
TEST_F(SortImportsTestJS,ImportEqAliases)44803c59765SMartin Probst TEST_F(SortImportsTestJS, ImportEqAliases) {
44903c59765SMartin Probst   verifySort("import {B} from 'bar';\n"
45003c59765SMartin Probst              "import {A} from 'foo';\n"
45103c59765SMartin Probst              "\n"
45203c59765SMartin Probst              "import Z = A.C;\n"
45303c59765SMartin Probst              "import Y = B.C.Z;\n"
45403c59765SMartin Probst              "\n"
45503c59765SMartin Probst              "export {Z};\n"
45603c59765SMartin Probst              "\n"
457e3ecdf7dSOwen Pan              "console.log(Z);",
45803c59765SMartin Probst              "import {A} from 'foo';\n"
45903c59765SMartin Probst              "import Z = A.C;\n"
46003c59765SMartin Probst              "export {Z};\n"
46103c59765SMartin Probst              "import {B} from 'bar';\n"
46203c59765SMartin Probst              "import Y = B.C.Z;\n"
46303c59765SMartin Probst              "\n"
464e3ecdf7dSOwen Pan              "console.log(Z);");
46503c59765SMartin Probst }
46603c59765SMartin Probst 
TEST_F(SortImportsTestJS,ImportExportType)46734b422baSJan Kuhle TEST_F(SortImportsTestJS, ImportExportType) {
46834b422baSJan Kuhle   verifySort("import type {sym} from 'a';\n"
46934b422baSJan Kuhle              "import {type sym} from 'b';\n"
47034b422baSJan Kuhle              "import {sym} from 'c';\n"
47134b422baSJan Kuhle              "import type sym from 'd';\n"
47234b422baSJan Kuhle              "import type * as sym from 'e';\n"
47334b422baSJan Kuhle              "\n"
47434b422baSJan Kuhle              "let x = 1;",
47534b422baSJan Kuhle              "import {sym} from 'c';\n"
47634b422baSJan Kuhle              "import type {sym} from 'a';\n"
47734b422baSJan Kuhle              "import type * as sym from 'e';\n"
47834b422baSJan Kuhle              "import type sym from 'd';\n"
47934b422baSJan Kuhle              "import {type sym} from 'b';\n"
48034b422baSJan Kuhle              "let x = 1;");
48134b422baSJan Kuhle 
48234b422baSJan Kuhle   // Symbols within import statement
48334b422baSJan Kuhle   verifySort("import {type sym1, type sym2 as a, sym3} from 'b';\n",
484e3ecdf7dSOwen Pan              "import {type sym2 as a, type sym1, sym3} from 'b';");
48534b422baSJan Kuhle 
48634b422baSJan Kuhle   // Merging
48734b422baSJan Kuhle   verifySort("import {X, type Z} from 'a';\n"
48834b422baSJan Kuhle              "import type {Y} from 'a';\n"
48934b422baSJan Kuhle              "\n"
490e3ecdf7dSOwen Pan              "X + Y + Z;",
49134b422baSJan Kuhle              "import {X} from 'a';\n"
49234b422baSJan Kuhle              "import {type Z} from 'a';\n"
49334b422baSJan Kuhle              "import type {Y} from 'a';\n"
49434b422baSJan Kuhle              "\n"
495e3ecdf7dSOwen Pan              "X + Y + Z;");
49634b422baSJan Kuhle 
49734b422baSJan Kuhle   // Merging: empty imports
49834b422baSJan Kuhle   verifySort("import type {A} from 'foo';\n", "import type {} from 'foo';\n"
49934b422baSJan Kuhle                                               "import type {A} from 'foo';");
50034b422baSJan Kuhle 
50134b422baSJan Kuhle   // Merging: exports
50234b422baSJan Kuhle   verifySort("export {A, type B} from 'foo';\n",
50334b422baSJan Kuhle              "export {A} from 'foo';\n"
50434b422baSJan Kuhle              "export   {type B} from 'foo';");
505e1f34b73SJan Kuhle 
506e1f34b73SJan Kuhle   // `export type X = Y;` should terminate import sorting. The following export
507e1f34b73SJan Kuhle   // statements should therefore not merge.
508e1f34b73SJan Kuhle   verifySort("export type A = B;\n"
509e1f34b73SJan Kuhle              "export {X};\n"
510e3ecdf7dSOwen Pan              "export {Y};",
511e1f34b73SJan Kuhle              "export type A = B;\n"
512e1f34b73SJan Kuhle              "export {X};\n"
513e3ecdf7dSOwen Pan              "export {Y};");
51434b422baSJan Kuhle }
51534b422baSJan Kuhle 
TEST_F(SortImportsTestJS,TemplateKeyword)516265ed681SOwen Pan TEST_F(SortImportsTestJS, TemplateKeyword) {
517265ed681SOwen Pan   // Reproduces issue where importing "template" disables imports sorting.
518265ed681SOwen Pan   verifySort("import {template} from './a';\n"
519265ed681SOwen Pan              "import {b} from './b';\n",
520265ed681SOwen Pan              "import {b} from './b';\n"
521265ed681SOwen Pan              "import {template} from './a';");
522265ed681SOwen Pan }
523265ed681SOwen Pan 
524c4a0dd49SMartin Probst } // end namespace
525c4a0dd49SMartin Probst } // end namespace format
526c4a0dd49SMartin Probst } // end namespace clang
527