Home | History | Annotate | Download | only in Format
      1 //===- unittest/Format/FormatTestJS.cpp - Formatting unit tests for JS ----===//
      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 
     20 class FormatTestJS : public ::testing::Test {
     21 protected:
     22   static std::string format(llvm::StringRef Code, unsigned Offset,
     23                             unsigned Length, const FormatStyle &Style) {
     24     DEBUG(llvm::errs() << "---\n");
     25     DEBUG(llvm::errs() << Code << "\n\n");
     26     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
     27     tooling::Replacements Replaces = reformat(Style, Code, Ranges);
     28     std::string Result = applyAllReplacements(Code, Replaces);
     29     EXPECT_NE("", Result);
     30     DEBUG(llvm::errs() << "\n" << Result << "\n\n");
     31     return Result;
     32   }
     33 
     34   static std::string format(
     35       llvm::StringRef Code,
     36       const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
     37     return format(Code, 0, Code.size(), Style);
     38   }
     39 
     40   static FormatStyle getGoogleJSStyleWithColumns(unsigned ColumnLimit) {
     41     FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
     42     Style.ColumnLimit = ColumnLimit;
     43     return Style;
     44   }
     45 
     46   static void verifyFormat(
     47       llvm::StringRef Code,
     48       const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
     49     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
     50   }
     51 };
     52 
     53 TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
     54   verifyFormat("a == = b;");
     55   verifyFormat("a != = b;");
     56 
     57   verifyFormat("a === b;");
     58   verifyFormat("aaaaaaa ===\n    b;", getGoogleJSStyleWithColumns(10));
     59   verifyFormat("a !== b;");
     60   verifyFormat("aaaaaaa !==\n    b;", getGoogleJSStyleWithColumns(10));
     61   verifyFormat("if (a + b + c +\n"
     62                "        d !==\n"
     63                "    e + f + g)\n"
     64                "  q();",
     65                getGoogleJSStyleWithColumns(20));
     66 
     67   verifyFormat("a >> >= b;");
     68 
     69   verifyFormat("a >>> b;");
     70   verifyFormat("aaaaaaa >>>\n    b;", getGoogleJSStyleWithColumns(10));
     71   verifyFormat("a >>>= b;");
     72   verifyFormat("aaaaaaa >>>=\n    b;", getGoogleJSStyleWithColumns(10));
     73   verifyFormat("if (a + b + c +\n"
     74                "        d >>>\n"
     75                "    e + f + g)\n"
     76                "  q();",
     77                getGoogleJSStyleWithColumns(20));
     78   verifyFormat("var x = aaaaaaaaaa ?\n"
     79                "            bbbbbb :\n"
     80                "            ccc;",
     81                getGoogleJSStyleWithColumns(20));
     82 
     83   verifyFormat("var b = a.map((x) => x + 1);");
     84 }
     85 
     86 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
     87   verifyFormat("var [a, b, c] = [1, 2, 3];");
     88   verifyFormat("var {a, b} = {a: 1, b: 2};");
     89 }
     90 
     91 TEST_F(FormatTestJS, ContainerLiterals) {
     92   verifyFormat("return {\n"
     93                "  link: function() {\n"
     94                "    f();  //\n"
     95                "  }\n"
     96                "};");
     97   verifyFormat("return {\n"
     98                "  a: a,\n"
     99                "  link: function() {\n"
    100                "    f();  //\n"
    101                "  }\n"
    102                "};");
    103   verifyFormat("return {\n"
    104                "  a: a,\n"
    105                "  link:\n"
    106                "      function() {\n"
    107                "        f();  //\n"
    108                "      },\n"
    109                "  link:\n"
    110                "      function() {\n"
    111                "        f();  //\n"
    112                "      }\n"
    113                "};");
    114 }
    115 
    116 TEST_F(FormatTestJS, SpacesInContainerLiterals) {
    117   verifyFormat("var arr = [1, 2, 3];");
    118   verifyFormat("var obj = {a: 1, b: 2, c: 3};");
    119 
    120   verifyFormat("var object_literal_with_long_name = {\n"
    121                "  a: 'aaaaaaaaaaaaaaaaaa',\n"
    122                "  b: 'bbbbbbbbbbbbbbbbbb'\n"
    123                "};");
    124 
    125   verifyFormat("var obj = {a: 1, b: 2, c: 3};",
    126                getChromiumStyle(FormatStyle::LK_JavaScript));
    127   verifyFormat("someVariable = {'a': [{}]};");
    128 }
    129 
    130 TEST_F(FormatTestJS, SingleQuoteStrings) {
    131   verifyFormat("this.function('', true);");
    132 }
    133 
    134 TEST_F(FormatTestJS, GoogScopes) {
    135   verifyFormat("goog.scope(function() {\n"
    136                "var x = a.b;\n"
    137                "var y = c.d;\n"
    138                "});  // goog.scope");
    139 }
    140 
    141 TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
    142   verifyFormat("function outer1(a, b) {\n"
    143                "  function inner1(a, b) { return a; }\n"
    144                "  inner1(a, b);\n"
    145                "}\n"
    146                "function outer2(a, b) {\n"
    147                "  function inner2(a, b) { return a; }\n"
    148                "  inner2(a, b);\n"
    149                "}");
    150 }
    151 
    152 TEST_F(FormatTestJS, FunctionLiterals) {
    153   verifyFormat("doFoo(function() { return 1; });");
    154   verifyFormat("var func = function() { return 1; };");
    155   verifyFormat("return {\n"
    156                "  body: {\n"
    157                "    setAttribute: function(key, val) { this[key] = val; },\n"
    158                "    getAttribute: function(key) { return this[key]; },\n"
    159                "    style: {direction: ''}\n"
    160                "  }\n"
    161                "};");
    162   EXPECT_EQ("abc = xyz ? function() { return 1; } : function() { return -1; };",
    163             format("abc=xyz?function(){return 1;}:function(){return -1;};"));
    164 
    165   verifyFormat("var closure = goog.bind(\n"
    166                "    function() {  // comment\n"
    167                "      foo();\n"
    168                "      bar();\n"
    169                "    },\n"
    170                "    this, arg1IsReallyLongAndNeeedsLineBreaks,\n"
    171                "    arg3IsReallyLongAndNeeedsLineBreaks);");
    172   verifyFormat("var closure = goog.bind(function() {  // comment\n"
    173                "  foo();\n"
    174                "  bar();\n"
    175                "}, this);");
    176   verifyFormat("return {\n"
    177                "  a: 'E',\n"
    178                "  b: function() {\n"
    179                "    return function() {\n"
    180                "      f();  //\n"
    181                "    };\n"
    182                "  }\n"
    183                "};");
    184 
    185   verifyFormat("var x = {a: function() { return 1; }};",
    186                getGoogleJSStyleWithColumns(38));
    187   verifyFormat("var x = {\n"
    188                "  a: function() { return 1; }\n"
    189                "};",
    190                getGoogleJSStyleWithColumns(37));
    191 
    192   verifyFormat("return {\n"
    193                "  a: function SomeFunction() {\n"
    194                "    // ...\n"
    195                "    return 1;\n"
    196                "  }\n"
    197                "};");
    198 }
    199 
    200 TEST_F(FormatTestJS, MultipleFunctionLiterals) {
    201   verifyFormat("promise.then(\n"
    202                "    function success() {\n"
    203                "      doFoo();\n"
    204                "      doBar();\n"
    205                "    },\n"
    206                "    function error() {\n"
    207                "      doFoo();\n"
    208                "      doBaz();\n"
    209                "    },\n"
    210                "    []);\n");
    211   verifyFormat("promise.then(\n"
    212                "    function success() {\n"
    213                "      doFoo();\n"
    214                "      doBar();\n"
    215                "    },\n"
    216                "    [],\n"
    217                "    function error() {\n"
    218                "      doFoo();\n"
    219                "      doBaz();\n"
    220                "    });\n");
    221   // FIXME: Here, we should probably break right after the "(" for consistency.
    222   verifyFormat("promise.then([],\n"
    223                "             function success() {\n"
    224                "               doFoo();\n"
    225                "               doBar();\n"
    226                "             },\n"
    227                "             function error() {\n"
    228                "               doFoo();\n"
    229                "               doBaz();\n"
    230                "             });\n");
    231 }
    232 
    233 TEST_F(FormatTestJS, ReturnStatements) {
    234   verifyFormat("function() { return [hello, world]; }");
    235 }
    236 
    237 TEST_F(FormatTestJS, ClosureStyleComments) {
    238   verifyFormat("var x = /** @type {foo} */ (bar);");
    239 }
    240 
    241 TEST_F(FormatTestJS, TryCatch) {
    242   verifyFormat("try {\n"
    243                "  f();\n"
    244                "} catch (e) {\n"
    245                "  g();\n"
    246                "} finally {\n"
    247                "  h();\n"
    248                "}");
    249 }
    250 
    251 TEST_F(FormatTestJS, StringLiteralConcatenation) {
    252   verifyFormat("var literal = 'hello ' +\n"
    253                "              'world';");
    254 }
    255 
    256 TEST_F(FormatTestJS, RegexLiteralClassification) {
    257   // Regex literals.
    258   verifyFormat("var regex = /abc/;");
    259   verifyFormat("f(/abc/);");
    260   verifyFormat("f(abc, /abc/);");
    261   verifyFormat("some_map[/abc/];");
    262   verifyFormat("var x = a ? /abc/ : /abc/;");
    263   verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}");
    264   verifyFormat("var x = !/abc/.test(y);");
    265   verifyFormat("var x = a && /abc/.test(y);");
    266   verifyFormat("var x = a || /abc/.test(y);");
    267   verifyFormat("var x = a + /abc/.search(y);");
    268   verifyFormat("var regexs = {/abc/, /abc/};");
    269   verifyFormat("return /abc/;");
    270 
    271   // Not regex literals.
    272   verifyFormat("var a = a / 2 + b / 3;");
    273 }
    274 
    275 TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) {
    276   verifyFormat("var regex = /a*/;");
    277   verifyFormat("var regex = /a+/;");
    278   verifyFormat("var regex = /a?/;");
    279   verifyFormat("var regex = /.a./;");
    280   verifyFormat("var regex = /a\\*/;");
    281   verifyFormat("var regex = /^a$/;");
    282   verifyFormat("var regex = /\\/a/;");
    283   verifyFormat("var regex = /(?:x)/;");
    284   verifyFormat("var regex = /x(?=y)/;");
    285   verifyFormat("var regex = /x(?!y)/;");
    286   verifyFormat("var regex = /x|y/;");
    287   verifyFormat("var regex = /a{2}/;");
    288   verifyFormat("var regex = /a{1,3}/;");
    289   verifyFormat("var regex = /[abc]/;");
    290   verifyFormat("var regex = /[^abc]/;");
    291   verifyFormat("var regex = /[\\b]/;");
    292   verifyFormat("var regex = /\\b/;");
    293   verifyFormat("var regex = /\\B/;");
    294   verifyFormat("var regex = /\\d/;");
    295   verifyFormat("var regex = /\\D/;");
    296   verifyFormat("var regex = /\\f/;");
    297   verifyFormat("var regex = /\\n/;");
    298   verifyFormat("var regex = /\\r/;");
    299   verifyFormat("var regex = /\\s/;");
    300   verifyFormat("var regex = /\\S/;");
    301   verifyFormat("var regex = /\\t/;");
    302   verifyFormat("var regex = /\\v/;");
    303   verifyFormat("var regex = /\\w/;");
    304   verifyFormat("var regex = /\\W/;");
    305   verifyFormat("var regex = /a(a)\\1/;");
    306   verifyFormat("var regex = /\\0/;");
    307   verifyFormat("var regex = /\\\\/g;");
    308   verifyFormat("var regex = /\\a\\\\/g;");
    309   verifyFormat("var regex = /\a\\//g;");
    310 }
    311 
    312 TEST_F(FormatTestJS, RegexLiteralModifiers) {
    313   verifyFormat("var regex = /abc/g;");
    314   verifyFormat("var regex = /abc/i;");
    315   verifyFormat("var regex = /abc/m;");
    316   verifyFormat("var regex = /abc/y;");
    317 }
    318 
    319 TEST_F(FormatTestJS, RegexLiteralLength) {
    320   verifyFormat("var regex = /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
    321                getGoogleJSStyleWithColumns(60));
    322   verifyFormat("var regex =\n"
    323                "    /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
    324                getGoogleJSStyleWithColumns(60));
    325 }
    326 
    327 TEST_F(FormatTestJS, RegexLiteralExamples) {
    328   verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);");
    329 }
    330 
    331 } // end namespace tooling
    332 } // end namespace clang
    333