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 TEST_F(SortImportsTestJS, SortDefaultImports) { 304 // Reproduces issue where multi-line import was not parsed correctly. 305 verifySort("import {A} from 'a';\n" 306 "import {default as B} from 'b';\n", 307 "import {default as B} from 'b';\n" 308 "import {A} from 'a';\n"); 309 } 310 311 } // end namespace 312 } // end namespace format 313 } // end namespace clang 314