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