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     bool IncompleteFormat = false;
     28     tooling::Replacements Replaces =
     29         reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
     30     EXPECT_FALSE(IncompleteFormat);
     31     std::string Result = applyAllReplacements(Code, Replaces);
     32     EXPECT_NE("", Result);
     33     DEBUG(llvm::errs() << "\n" << Result << "\n\n");
     34     return Result;
     35   }
     36 
     37   static std::string format(
     38       llvm::StringRef Code,
     39       const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
     40     return format(Code, 0, Code.size(), Style);
     41   }
     42 
     43   static FormatStyle getGoogleJSStyleWithColumns(unsigned ColumnLimit) {
     44     FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
     45     Style.ColumnLimit = ColumnLimit;
     46     return Style;
     47   }
     48 
     49   static void verifyFormat(
     50       llvm::StringRef Code,
     51       const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
     52     std::string result = format(test::messUp(Code), Style);
     53     EXPECT_EQ(Code.str(), result) << "Formatted:\n" << result;
     54   }
     55 };
     56 
     57 TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
     58   verifyFormat("a == = b;");
     59   verifyFormat("a != = b;");
     60 
     61   verifyFormat("a === b;");
     62   verifyFormat("aaaaaaa ===\n    b;", getGoogleJSStyleWithColumns(10));
     63   verifyFormat("a !== b;");
     64   verifyFormat("aaaaaaa !==\n    b;", getGoogleJSStyleWithColumns(10));
     65   verifyFormat("if (a + b + c +\n"
     66                "        d !==\n"
     67                "    e + f + g)\n"
     68                "  q();",
     69                getGoogleJSStyleWithColumns(20));
     70 
     71   verifyFormat("a >> >= b;");
     72 
     73   verifyFormat("a >>> b;");
     74   verifyFormat("aaaaaaa >>>\n    b;", getGoogleJSStyleWithColumns(10));
     75   verifyFormat("a >>>= b;");
     76   verifyFormat("aaaaaaa >>>=\n    b;", getGoogleJSStyleWithColumns(10));
     77   verifyFormat("if (a + b + c +\n"
     78                "        d >>>\n"
     79                "    e + f + g)\n"
     80                "  q();",
     81                getGoogleJSStyleWithColumns(20));
     82   verifyFormat("var x = aaaaaaaaaa ?\n"
     83                "    bbbbbb :\n"
     84                "    ccc;",
     85                getGoogleJSStyleWithColumns(20));
     86 
     87   verifyFormat("var b = a.map((x) => x + 1);");
     88   verifyFormat("return ('aaa') in bbbb;");
     89 
     90   // ES6 spread operator.
     91   verifyFormat("someFunction(...a);");
     92   verifyFormat("var x = [1, ...a, 2];");
     93 }
     94 
     95 TEST_F(FormatTestJS, UnderstandsAmpAmp) {
     96   verifyFormat("e && e.SomeFunction();");
     97 }
     98 
     99 TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) {
    100   verifyFormat("not.and.or.not_eq = 1;");
    101 }
    102 
    103 TEST_F(FormatTestJS, ReservedWords) {
    104   // JavaScript reserved words (aka keywords) are only illegal when used as
    105   // Identifiers, but are legal as IdentifierNames.
    106   verifyFormat("x.class.struct = 1;");
    107   verifyFormat("x.case = 1;");
    108   verifyFormat("x.interface = 1;");
    109   verifyFormat("x = {\n"
    110                "  a: 12,\n"
    111                "  interface: 1,\n"
    112                "  switch: 1,\n"
    113                "};");
    114   verifyFormat("var struct = 2;");
    115   verifyFormat("var union = 2;");
    116 }
    117 
    118 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
    119   verifyFormat("var [a, b, c] = [1, 2, 3];");
    120   verifyFormat("let [a, b, c] = [1, 2, 3];");
    121   verifyFormat("var {a, b} = {a: 1, b: 2};");
    122   verifyFormat("let {a, b} = {a: 1, b: 2};");
    123 }
    124 
    125 TEST_F(FormatTestJS, ContainerLiterals) {
    126   verifyFormat("var x = {y: function(a) { return a; }};");
    127   verifyFormat("return {\n"
    128                "  link: function() {\n"
    129                "    f();  //\n"
    130                "  }\n"
    131                "};");
    132   verifyFormat("return {\n"
    133                "  a: a,\n"
    134                "  link: function() {\n"
    135                "    f();  //\n"
    136                "  }\n"
    137                "};");
    138   verifyFormat("return {\n"
    139                "  a: a,\n"
    140                "  link: function() {\n"
    141                "    f();  //\n"
    142                "  },\n"
    143                "  link: function() {\n"
    144                "    f();  //\n"
    145                "  }\n"
    146                "};");
    147   verifyFormat("var stuff = {\n"
    148                "  // comment for update\n"
    149                "  update: false,\n"
    150                "  // comment for modules\n"
    151                "  modules: false,\n"
    152                "  // comment for tasks\n"
    153                "  tasks: false\n"
    154                "};");
    155   verifyFormat("return {\n"
    156                "  'finish':\n"
    157                "      //\n"
    158                "      a\n"
    159                "};");
    160   verifyFormat("var obj = {\n"
    161                "  fooooooooo: function(x) {\n"
    162                "    return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
    163                "  }\n"
    164                "};");
    165   // Simple object literal, as opposed to enum style below.
    166   verifyFormat("var obj = {a: 123};");
    167   // Enum style top level assignment.
    168   verifyFormat("X = {\n  a: 123\n};");
    169   verifyFormat("X.Y = {\n  a: 123\n};");
    170   // But only on the top level, otherwise its a plain object literal assignment.
    171   verifyFormat("function x() {\n"
    172                "  y = {z: 1};\n"
    173                "}");
    174   verifyFormat("x = foo && {a: 123};");
    175 
    176   // Arrow functions in object literals.
    177   verifyFormat("var x = {y: (a) => { return a; }};");
    178   verifyFormat("var x = {y: (a) => a};");
    179 
    180   // Computed keys.
    181   verifyFormat("var x = {[a]: 1, b: 2, [c]: 3};");
    182   verifyFormat("var x = {\n"
    183                "  [a]: 1,\n"
    184                "  b: 2,\n"
    185                "  [c]: 3,\n"
    186                "};");
    187 }
    188 
    189 TEST_F(FormatTestJS, MethodsInObjectLiterals) {
    190   verifyFormat("var o = {\n"
    191                "  value: 'test',\n"
    192                "  get value() {  // getter\n"
    193                "    return this.value;\n"
    194                "  }\n"
    195                "};");
    196   verifyFormat("var o = {\n"
    197                "  value: 'test',\n"
    198                "  set value(val) {  // setter\n"
    199                "    this.value = val;\n"
    200                "  }\n"
    201                "};");
    202   verifyFormat("var o = {\n"
    203                "  value: 'test',\n"
    204                "  someMethod(val) {  // method\n"
    205                "    doSomething(this.value + val);\n"
    206                "  }\n"
    207                "};");
    208   verifyFormat("var o = {\n"
    209                "  someMethod(val) {  // method\n"
    210                "    doSomething(this.value + val);\n"
    211                "  },\n"
    212                "  someOtherMethod(val) {  // method\n"
    213                "    doSomething(this.value + val);\n"
    214                "  }\n"
    215                "};");
    216 }
    217 
    218 TEST_F(FormatTestJS, SpacesInContainerLiterals) {
    219   verifyFormat("var arr = [1, 2, 3];");
    220   verifyFormat("f({a: 1, b: 2, c: 3});");
    221 
    222   verifyFormat("var object_literal_with_long_name = {\n"
    223                "  a: 'aaaaaaaaaaaaaaaaaa',\n"
    224                "  b: 'bbbbbbbbbbbbbbbbbb'\n"
    225                "};");
    226 
    227   verifyFormat("f({a: 1, b: 2, c: 3});",
    228                getChromiumStyle(FormatStyle::LK_JavaScript));
    229   verifyFormat("f({'a': [{}]});");
    230 }
    231 
    232 TEST_F(FormatTestJS, SingleQuoteStrings) {
    233   verifyFormat("this.function('', true);");
    234 }
    235 
    236 TEST_F(FormatTestJS, GoogScopes) {
    237   verifyFormat("goog.scope(function() {\n"
    238                "var x = a.b;\n"
    239                "var y = c.d;\n"
    240                "});  // goog.scope");
    241   verifyFormat("goog.scope(function() {\n"
    242                "// test\n"
    243                "var x = 0;\n"
    244                "// test\n"
    245                "});");
    246 }
    247 
    248 TEST_F(FormatTestJS, GoogModules) {
    249   verifyFormat("goog.module('this.is.really.absurdly.long');",
    250                getGoogleJSStyleWithColumns(40));
    251   verifyFormat("goog.require('this.is.really.absurdly.long');",
    252                getGoogleJSStyleWithColumns(40));
    253   verifyFormat("goog.provide('this.is.really.absurdly.long');",
    254                getGoogleJSStyleWithColumns(40));
    255   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
    256                getGoogleJSStyleWithColumns(40));
    257   verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');",
    258                getGoogleJSStyleWithColumns(40));
    259 
    260   // These should be wrapped normally.
    261   verifyFormat(
    262       "var MyLongClassName =\n"
    263       "    goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
    264 }
    265 
    266 TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
    267   verifyFormat("function outer1(a, b) {\n"
    268                "  function inner1(a, b) { return a; }\n"
    269                "  inner1(a, b);\n"
    270                "}\n"
    271                "function outer2(a, b) {\n"
    272                "  function inner2(a, b) { return a; }\n"
    273                "  inner2(a, b);\n"
    274                "}");
    275   verifyFormat("function f() {}");
    276 }
    277 
    278 TEST_F(FormatTestJS, ArrayLiterals) {
    279   verifyFormat("var aaaaa: List<SomeThing> =\n"
    280                "    [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");
    281   verifyFormat("return [\n"
    282                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    283                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
    284                "  ccccccccccccccccccccccccccc\n"
    285                "];");
    286   verifyFormat("var someVariable = SomeFunction([\n"
    287                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    288                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
    289                "  ccccccccccccccccccccccccccc\n"
    290                "]);");
    291   verifyFormat("var someVariable = SomeFunction([\n"
    292                "  [aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb],\n"
    293                "]);",
    294                getGoogleJSStyleWithColumns(51));
    295   verifyFormat("var someVariable = SomeFunction(aaaa, [\n"
    296                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    297                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
    298                "  ccccccccccccccccccccccccccc\n"
    299                "]);");
    300   verifyFormat("var someVariable = SomeFunction(\n"
    301                "    aaaa,\n"
    302                "    [\n"
    303                "      aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    304                "      bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
    305                "      ccccccccccccccccccccccccccc\n"
    306                "    ],\n"
    307                "    aaaa);");
    308 
    309   verifyFormat("someFunction([], {a: a});");
    310 }
    311 
    312 TEST_F(FormatTestJS, FunctionLiterals) {
    313   verifyFormat("doFoo(function() {});");
    314   verifyFormat("doFoo(function() { return 1; });");
    315   verifyFormat("var func = function() {\n"
    316                "  return 1;\n"
    317                "};");
    318   verifyFormat("var func =  //\n"
    319                "    function() {\n"
    320                "  return 1;\n"
    321                "};");
    322   verifyFormat("return {\n"
    323                "  body: {\n"
    324                "    setAttribute: function(key, val) { this[key] = val; },\n"
    325                "    getAttribute: function(key) { return this[key]; },\n"
    326                "    style: {direction: ''}\n"
    327                "  }\n"
    328                "};");
    329   verifyFormat("abc = xyz ? function() {\n"
    330                "  return 1;\n"
    331                "} : function() {\n"
    332                "  return -1;\n"
    333                "};");
    334 
    335   verifyFormat("var closure = goog.bind(\n"
    336                "    function() {  // comment\n"
    337                "      foo();\n"
    338                "      bar();\n"
    339                "    },\n"
    340                "    this, arg1IsReallyLongAndNeeedsLineBreaks,\n"
    341                "    arg3IsReallyLongAndNeeedsLineBreaks);");
    342   verifyFormat("var closure = goog.bind(function() {  // comment\n"
    343                "  foo();\n"
    344                "  bar();\n"
    345                "}, this);");
    346   verifyFormat("return {\n"
    347                "  a: 'E',\n"
    348                "  b: function() {\n"
    349                "    return function() {\n"
    350                "      f();  //\n"
    351                "    };\n"
    352                "  }\n"
    353                "};");
    354   verifyFormat("{\n"
    355                "  var someVariable = function(x) {\n"
    356                "    return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
    357                "  };\n"
    358                "}");
    359   verifyFormat("someLooooooooongFunction(\n"
    360                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    361                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    362                "    function(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
    363                "      // code\n"
    364                "    });");
    365 
    366   verifyFormat("f({a: function() { return 1; }});",
    367                getGoogleJSStyleWithColumns(33));
    368   verifyFormat("f({\n"
    369                "  a: function() { return 1; }\n"
    370                "});",
    371                getGoogleJSStyleWithColumns(32));
    372 
    373   verifyFormat("return {\n"
    374                "  a: function SomeFunction() {\n"
    375                "    // ...\n"
    376                "    return 1;\n"
    377                "  }\n"
    378                "};");
    379   verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
    380                "    .then(goog.bind(function(aaaaaaaaaaa) {\n"
    381                "      someFunction();\n"
    382                "      someFunction();\n"
    383                "    }, this), aaaaaaaaaaaaaaaaa);");
    384 
    385   verifyFormat("someFunction(goog.bind(function() {\n"
    386                "  doSomething();\n"
    387                "  doSomething();\n"
    388                "}, this), goog.bind(function() {\n"
    389                "  doSomething();\n"
    390                "  doSomething();\n"
    391                "}, this));");
    392 
    393   // FIXME: This is bad, we should be wrapping before "function() {".
    394   verifyFormat("someFunction(function() {\n"
    395                "  doSomething();  // break\n"
    396                "})\n"
    397                "    .doSomethingElse(\n"
    398                "        // break\n"
    399                "        );");
    400 }
    401 
    402 TEST_F(FormatTestJS, InliningFunctionLiterals) {
    403   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
    404   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
    405   verifyFormat("var func = function() {\n"
    406                "  return 1;\n"
    407                "};",
    408                Style);
    409   verifyFormat("var func = doSomething(function() { return 1; });", Style);
    410   verifyFormat("var outer = function() {\n"
    411                "  var inner = function() { return 1; }\n"
    412                "};",
    413                Style);
    414   verifyFormat("function outer1(a, b) {\n"
    415                "  function inner1(a, b) { return a; }\n"
    416                "}",
    417                Style);
    418 
    419   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
    420   verifyFormat("var func = function() { return 1; };", Style);
    421   verifyFormat("var func = doSomething(function() { return 1; });", Style);
    422   verifyFormat(
    423       "var outer = function() { var inner = function() { return 1; } };",
    424       Style);
    425   verifyFormat("function outer1(a, b) {\n"
    426                "  function inner1(a, b) { return a; }\n"
    427                "}",
    428                Style);
    429 
    430   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
    431   verifyFormat("var func = function() {\n"
    432                "  return 1;\n"
    433                "};",
    434                Style);
    435   verifyFormat("var func = doSomething(function() {\n"
    436                "  return 1;\n"
    437                "});",
    438                Style);
    439   verifyFormat("var outer = function() {\n"
    440                "  var inner = function() {\n"
    441                "    return 1;\n"
    442                "  }\n"
    443                "};",
    444                Style);
    445   verifyFormat("function outer1(a, b) {\n"
    446                "  function inner1(a, b) {\n"
    447                "    return a;\n"
    448                "  }\n"
    449                "}",
    450                Style);
    451 
    452   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
    453   verifyFormat("var func = function() {\n"
    454                "  return 1;\n"
    455                "};",
    456                Style);
    457 }
    458 
    459 TEST_F(FormatTestJS, MultipleFunctionLiterals) {
    460   verifyFormat("promise.then(\n"
    461                "    function success() {\n"
    462                "      doFoo();\n"
    463                "      doBar();\n"
    464                "    },\n"
    465                "    function error() {\n"
    466                "      doFoo();\n"
    467                "      doBaz();\n"
    468                "    },\n"
    469                "    []);\n");
    470   verifyFormat("promise.then(\n"
    471                "    function success() {\n"
    472                "      doFoo();\n"
    473                "      doBar();\n"
    474                "    },\n"
    475                "    [],\n"
    476                "    function error() {\n"
    477                "      doFoo();\n"
    478                "      doBaz();\n"
    479                "    });\n");
    480   verifyFormat("promise.then(\n"
    481                "    [],\n"
    482                "    function success() {\n"
    483                "      doFoo();\n"
    484                "      doBar();\n"
    485                "    },\n"
    486                "    function error() {\n"
    487                "      doFoo();\n"
    488                "      doBaz();\n"
    489                "    });\n");
    490 
    491   verifyFormat("getSomeLongPromise()\n"
    492                "    .then(function(value) { body(); })\n"
    493                "    .thenCatch(function(error) {\n"
    494                "      body();\n"
    495                "      body();\n"
    496                "    });");
    497   verifyFormat("getSomeLongPromise()\n"
    498                "    .then(function(value) {\n"
    499                "      body();\n"
    500                "      body();\n"
    501                "    })\n"
    502                "    .thenCatch(function(error) {\n"
    503                "      body();\n"
    504                "      body();\n"
    505                "    });");
    506 
    507   verifyFormat("getSomeLongPromise()\n"
    508                "    .then(function(value) { body(); })\n"
    509                "    .thenCatch(function(error) { body(); });");
    510 }
    511 
    512 TEST_F(FormatTestJS, ArrowFunctions) {
    513   verifyFormat("var x = (a) => {\n"
    514                "  return a;\n"
    515                "};");
    516   verifyFormat("var x = (a) => {\n"
    517                "  function y() { return 42; }\n"
    518                "  return a;\n"
    519                "};");
    520   verifyFormat("var x = (a: type): {some: type} => {\n"
    521                "  return a;\n"
    522                "};");
    523   verifyFormat("var x = (a) => a;");
    524   verifyFormat("return () => [];");
    525   verifyFormat("var aaaaaaaaaaaaaaaaaaaa = {\n"
    526                "  aaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n"
    527                "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    528                "       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n"
    529                "          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
    530                "};");
    531   verifyFormat("var a = a.aaaaaaa(\n"
    532                "    (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n"
    533                "        aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
    534   verifyFormat("var a = a.aaaaaaa(\n"
    535                "    (a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n"
    536                "        aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n"
    537                "        aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
    538 
    539   // FIXME: This is bad, we should be wrapping before "() => {".
    540   verifyFormat("someFunction(() => {\n"
    541                "  doSomething();  // break\n"
    542                "})\n"
    543                "    .doSomethingElse(\n"
    544                "        // break\n"
    545                "        );");
    546 }
    547 
    548 TEST_F(FormatTestJS, ReturnStatements) {
    549   verifyFormat("function() {\n"
    550                "  return [hello, world];\n"
    551                "}");
    552 }
    553 
    554 TEST_F(FormatTestJS, ForLoops) {
    555   verifyFormat("for (var i in [2, 3]) {\n"
    556                "}");
    557 }
    558 
    559 TEST_F(FormatTestJS, AutomaticSemicolonInsertion) {
    560   // The following statements must not wrap, as otherwise the program meaning
    561   // would change due to automatic semicolon insertion.
    562   // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1.
    563   verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10));
    564   verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10));
    565   verifyFormat("break aaaaa;", getGoogleJSStyleWithColumns(10));
    566   verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10));
    567   verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10));
    568   verifyFormat("aaaaaaaaa--;", getGoogleJSStyleWithColumns(10));
    569 }
    570 
    571 TEST_F(FormatTestJS, ClosureStyleCasts) {
    572   verifyFormat("var x = /** @type {foo} */ (bar);");
    573 }
    574 
    575 TEST_F(FormatTestJS, TryCatch) {
    576   verifyFormat("try {\n"
    577                "  f();\n"
    578                "} catch (e) {\n"
    579                "  g();\n"
    580                "} finally {\n"
    581                "  h();\n"
    582                "}");
    583 
    584   // But, of course, "catch" is a perfectly fine function name in JavaScript.
    585   verifyFormat("someObject.catch();");
    586   verifyFormat("someObject.new();");
    587   verifyFormat("someObject.delete();");
    588 }
    589 
    590 TEST_F(FormatTestJS, StringLiteralConcatenation) {
    591   verifyFormat("var literal = 'hello ' +\n"
    592                "    'world';");
    593 }
    594 
    595 TEST_F(FormatTestJS, RegexLiteralClassification) {
    596   // Regex literals.
    597   verifyFormat("var regex = /abc/;");
    598   verifyFormat("f(/abc/);");
    599   verifyFormat("f(abc, /abc/);");
    600   verifyFormat("some_map[/abc/];");
    601   verifyFormat("var x = a ? /abc/ : /abc/;");
    602   verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}");
    603   verifyFormat("var x = !/abc/.test(y);");
    604   verifyFormat("var x = a && /abc/.test(y);");
    605   verifyFormat("var x = a || /abc/.test(y);");
    606   verifyFormat("var x = a + /abc/.search(y);");
    607   verifyFormat("/abc/.search(y);");
    608   verifyFormat("var regexs = {/abc/, /abc/};");
    609   verifyFormat("return /abc/;");
    610 
    611   // Not regex literals.
    612   verifyFormat("var a = a / 2 + b / 3;");
    613   verifyFormat("var a = a++ / 2;");
    614   // Prefix unary can operate on regex literals, not that it makes sense.
    615   verifyFormat("var a = ++/a/;");
    616 
    617   // This is a known issue, regular expressions are incorrectly detected if
    618   // directly following a closing parenthesis.
    619   verifyFormat("if (foo) / bar /.exec(baz);");
    620 }
    621 
    622 TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) {
    623   verifyFormat("var regex = /=/;");
    624   verifyFormat("var regex = /a*/;");
    625   verifyFormat("var regex = /a+/;");
    626   verifyFormat("var regex = /a?/;");
    627   verifyFormat("var regex = /.a./;");
    628   verifyFormat("var regex = /a\\*/;");
    629   verifyFormat("var regex = /^a$/;");
    630   verifyFormat("var regex = /\\/a/;");
    631   verifyFormat("var regex = /(?:x)/;");
    632   verifyFormat("var regex = /x(?=y)/;");
    633   verifyFormat("var regex = /x(?!y)/;");
    634   verifyFormat("var regex = /x|y/;");
    635   verifyFormat("var regex = /a{2}/;");
    636   verifyFormat("var regex = /a{1,3}/;");
    637 
    638   verifyFormat("var regex = /[abc]/;");
    639   verifyFormat("var regex = /[^abc]/;");
    640   verifyFormat("var regex = /[\\b]/;");
    641   verifyFormat("var regex = /[/]/;");
    642   verifyFormat("var regex = /[\\/]/;");
    643   verifyFormat("var regex = /\\[/;");
    644   verifyFormat("var regex = /\\\\[/]/;");
    645   verifyFormat("var regex = /}[\"]/;");
    646   verifyFormat("var regex = /}[/\"]/;");
    647   verifyFormat("var regex = /}[\"/]/;");
    648 
    649   verifyFormat("var regex = /\\b/;");
    650   verifyFormat("var regex = /\\B/;");
    651   verifyFormat("var regex = /\\d/;");
    652   verifyFormat("var regex = /\\D/;");
    653   verifyFormat("var regex = /\\f/;");
    654   verifyFormat("var regex = /\\n/;");
    655   verifyFormat("var regex = /\\r/;");
    656   verifyFormat("var regex = /\\s/;");
    657   verifyFormat("var regex = /\\S/;");
    658   verifyFormat("var regex = /\\t/;");
    659   verifyFormat("var regex = /\\v/;");
    660   verifyFormat("var regex = /\\w/;");
    661   verifyFormat("var regex = /\\W/;");
    662   verifyFormat("var regex = /a(a)\\1/;");
    663   verifyFormat("var regex = /\\0/;");
    664   verifyFormat("var regex = /\\\\/g;");
    665   verifyFormat("var regex = /\\a\\\\/g;");
    666   verifyFormat("var regex = /\a\\//g;");
    667   verifyFormat("var regex = /a\\//;\n"
    668                "var x = 0;");
    669   EXPECT_EQ("var regex = /'/g;", format("var regex = /'/g ;"));
    670   EXPECT_EQ("var regex = /'/g;  //'", format("var regex = /'/g ; //'"));
    671   EXPECT_EQ("var regex = /\\/*/;\n"
    672             "var x = 0;",
    673             format("var regex = /\\/*/;\n"
    674                    "var x=0;"));
    675   EXPECT_EQ("var x = /a\\//;", format("var x = /a\\//  \n;"));
    676   verifyFormat("var regex = /\"/;", getGoogleJSStyleWithColumns(16));
    677   verifyFormat("var regex =\n"
    678                "    /\"/;",
    679                getGoogleJSStyleWithColumns(15));
    680   verifyFormat("var regex =  //\n"
    681                "    /a/;");
    682   verifyFormat("var regexs = [\n"
    683                "  /d/,   //\n"
    684                "  /aa/,  //\n"
    685                "];");
    686 }
    687 
    688 TEST_F(FormatTestJS, RegexLiteralModifiers) {
    689   verifyFormat("var regex = /abc/g;");
    690   verifyFormat("var regex = /abc/i;");
    691   verifyFormat("var regex = /abc/m;");
    692   verifyFormat("var regex = /abc/y;");
    693 }
    694 
    695 TEST_F(FormatTestJS, RegexLiteralLength) {
    696   verifyFormat("var regex = /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
    697                getGoogleJSStyleWithColumns(60));
    698   verifyFormat("var regex =\n"
    699                "    /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
    700                getGoogleJSStyleWithColumns(60));
    701   verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
    702                getGoogleJSStyleWithColumns(50));
    703 }
    704 
    705 TEST_F(FormatTestJS, RegexLiteralExamples) {
    706   verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);");
    707 }
    708 
    709 TEST_F(FormatTestJS, TypeAnnotations) {
    710   verifyFormat("var x: string;");
    711   verifyFormat("function x(): string {\n  return 'x';\n}");
    712   verifyFormat("function x(): {x: string} {\n  return {x: 'x'};\n}");
    713   verifyFormat("function x(y: string): string {\n  return 'x';\n}");
    714   verifyFormat("for (var y: string in x) {\n  x();\n}");
    715   verifyFormat("((a: string, b: number): string => a + b);");
    716   verifyFormat("var x: (y: number) => string;");
    717   verifyFormat("var x: P<string, (a: number) => string>;");
    718   verifyFormat("var x = {y: function(): z { return 1; }};");
    719   verifyFormat("var x = {y: function(): {a: number} { return 1; }};");
    720 }
    721 
    722 TEST_F(FormatTestJS, ClassDeclarations) {
    723   verifyFormat("class C {\n  x: string = 12;\n}");
    724   verifyFormat("class C {\n  x(): string => 12;\n}");
    725   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
    726   verifyFormat("class C {\n  private x: string = 12;\n}");
    727   verifyFormat("class C {\n  private static x: string = 12;\n}");
    728   verifyFormat("class C {\n  static x(): string { return 'asd'; }\n}");
    729   verifyFormat("class C extends P implements I {}");
    730   verifyFormat("class C extends p.P implements i.I {}");
    731   verifyFormat("class Test {\n"
    732                "  aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
    733                "      aaaaaaaaaaaaaaaaaaaaaa {}\n"
    734                "}");
    735 
    736   // ':' is not a type declaration here.
    737   verifyFormat("class X {\n"
    738                "  subs = {\n"
    739                "    'b': {\n"
    740                "      'c': 1,\n"
    741                "    },\n"
    742                "  };\n"
    743                "}");
    744 }
    745 
    746 TEST_F(FormatTestJS, InterfaceDeclarations) {
    747   verifyFormat("interface I {\n"
    748                "  x: string;\n"
    749                "}\n"
    750                "var y;");
    751   // Ensure that state is reset after parsing the interface.
    752   verifyFormat("interface a {}\n"
    753                "export function b() {}\n"
    754                "var x;");
    755 }
    756 
    757 TEST_F(FormatTestJS, EnumDeclarations) {
    758   verifyFormat("enum Foo {\n"
    759                "  A = 1,\n"
    760                "  B\n"
    761                "}");
    762   verifyFormat("export /* somecomment*/ enum Foo {\n"
    763                "  A = 1,\n"
    764                "  B\n"
    765                "}");
    766   verifyFormat("enum Foo {\n"
    767                "  A = 1,  // comment\n"
    768                "  B\n"
    769                "}\n"
    770                "var x = 1;");
    771 }
    772 
    773 TEST_F(FormatTestJS, MetadataAnnotations) {
    774   verifyFormat("@A\nclass C {\n}");
    775   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
    776   verifyFormat("@A\n@B\nclass C {\n}");
    777   verifyFormat("class C {\n  @A x: string;\n}");
    778   verifyFormat("class C {\n"
    779                "  @A\n"
    780                "  private x(): string {\n"
    781                "    return 'y';\n"
    782                "  }\n"
    783                "}");
    784   verifyFormat("class X {}\n"
    785                "class Y {}");
    786 }
    787 
    788 TEST_F(FormatTestJS, Modules) {
    789   verifyFormat("import SomeThing from 'some/module.js';");
    790   verifyFormat("import {X, Y} from 'some/module.js';");
    791   verifyFormat("import {\n"
    792                "  VeryLongImportsAreAnnoying,\n"
    793                "  VeryLongImportsAreAnnoying,\n"
    794                "  VeryLongImportsAreAnnoying,\n"
    795                "  VeryLongImportsAreAnnoying\n"
    796                "} from 'some/module.js';");
    797   verifyFormat("import {\n"
    798                "  X,\n"
    799                "  Y,\n"
    800                "} from 'some/module.js';");
    801   verifyFormat("import {\n"
    802                "  X,\n"
    803                "  Y,\n"
    804                "} from 'some/long/module.js';",
    805                getGoogleJSStyleWithColumns(20));
    806   verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';");
    807   verifyFormat("import * as lib from 'some/module.js';");
    808   verifyFormat("var x = {import: 1};\nx.import = 2;");
    809 
    810   verifyFormat("export function fn() {\n"
    811                "  return 'fn';\n"
    812                "}");
    813   verifyFormat("export function A() {}\n"
    814                "export default function B() {}\n"
    815                "export function C() {}");
    816   verifyFormat("export const x = 12;");
    817   verifyFormat("export default class X {}");
    818   verifyFormat("export {X, Y} from 'some/module.js';");
    819   verifyFormat("export {\n"
    820                "  X,\n"
    821                "  Y,\n"
    822                "} from 'some/module.js';");
    823   verifyFormat("export class C {\n"
    824                "  x: number;\n"
    825                "  y: string;\n"
    826                "}");
    827   verifyFormat("export class X { y: number; }");
    828   verifyFormat("export default class X { y: number }");
    829   verifyFormat("export default function() {\n  return 1;\n}");
    830   verifyFormat("export var x = 12;");
    831   verifyFormat("class C {}\n"
    832                "export function f() {}\n"
    833                "var v;");
    834   verifyFormat("export var x: number = 12;");
    835   verifyFormat("export const y = {\n"
    836                "  a: 1,\n"
    837                "  b: 2\n"
    838                "};");
    839   verifyFormat("export enum Foo {\n"
    840                "  BAR,\n"
    841                "  // adsdasd\n"
    842                "  BAZ\n"
    843                "}");
    844 }
    845 
    846 TEST_F(FormatTestJS, TemplateStrings) {
    847   // Keeps any whitespace/indentation within the template string.
    848   EXPECT_EQ("var x = `hello\n"
    849             "     ${  name    }\n"
    850             "  !`;",
    851             format("var x    =    `hello\n"
    852                    "     ${  name    }\n"
    853                    "  !`;"));
    854 
    855   verifyFormat("var x =\n"
    856                "    `hello ${world}` >= some();",
    857                getGoogleJSStyleWithColumns(34)); // Barely doesn't fit.
    858   verifyFormat("var x = `hello ${world}` >= some();",
    859                getGoogleJSStyleWithColumns(35)); // Barely fits.
    860   EXPECT_EQ("var x = `hello\n"
    861             "  ${world}` >=\n"
    862             "    some();",
    863             format("var x =\n"
    864                    "    `hello\n"
    865                    "  ${world}` >= some();",
    866                    getGoogleJSStyleWithColumns(21))); // Barely doesn't fit.
    867   EXPECT_EQ("var x = `hello\n"
    868             "  ${world}` >= some();",
    869             format("var x =\n"
    870                    "    `hello\n"
    871                    "  ${world}` >= some();",
    872                    getGoogleJSStyleWithColumns(22))); // Barely fits.
    873 
    874   verifyFormat("var x =\n"
    875                "    `h`;",
    876                getGoogleJSStyleWithColumns(11));
    877   EXPECT_EQ(
    878       "var x =\n    `multi\n  line`;",
    879       format("var x = `multi\n  line`;", getGoogleJSStyleWithColumns(13)));
    880   verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
    881                "    `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`);");
    882 
    883   // Make sure template strings get a proper ColumnWidth assigned, even if they
    884   // are first token in line.
    885   verifyFormat(
    886       "var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
    887       "    `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;");
    888 
    889   // Two template strings.
    890   verifyFormat("var x = `hello` == `hello`;");
    891 
    892   // Comments in template strings.
    893   EXPECT_EQ("var x = `//a`;\n"
    894             "var y;",
    895             format("var x =\n `//a`;\n"
    896                    "var y  ;"));
    897   EXPECT_EQ("var x = `/*a`;\n"
    898             "var y;",
    899             format("var x =\n `/*a`;\n"
    900                    "var y;"));
    901   // Unterminated string literals in a template string.
    902   verifyFormat("var x = `'`;  // comment with matching quote '\n"
    903                "var y;");
    904   verifyFormat("var x = `\"`;  // comment with matching quote \"\n"
    905                "var y;");
    906   // Backticks in a comment - not a template string.
    907   EXPECT_EQ("var x = 1  // `/*a`;\n"
    908             "    ;",
    909             format("var x =\n 1  // `/*a`;\n"
    910                    "    ;"));
    911   EXPECT_EQ("/* ` */ var x = 1; /* ` */",
    912             format("/* ` */ var x\n= 1; /* ` */"));
    913   // Comment spans multiple template strings.
    914   EXPECT_EQ("var x = `/*a`;\n"
    915             "var y = ` */ `;",
    916             format("var x =\n `/*a`;\n"
    917                    "var y =\n ` */ `;"));
    918   // Escaped backtick.
    919   EXPECT_EQ("var x = ` \\` a`;\n"
    920             "var y;",
    921             format("var x = ` \\` a`;\n"
    922                    "var y;"));
    923 }
    924 
    925 TEST_F(FormatTestJS, CastSyntax) { verifyFormat("var x = <type>foo;"); }
    926 
    927 TEST_F(FormatTestJS, TypeArguments) {
    928   verifyFormat("class X<Y> {}");
    929   verifyFormat("new X<Y>();");
    930   verifyFormat("foo<Y>(a);");
    931   verifyFormat("var x: X<Y>[];");
    932   verifyFormat("class C extends D<E> implements F<G>, H<I> {}");
    933   verifyFormat("function f(a: List<any> = null) {}");
    934   verifyFormat("function f(): List<any> {}");
    935   verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n"
    936                "    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}");
    937   verifyFormat("function aaaaaaaaaa(\n"
    938                "    aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa,\n"
    939                "    aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa):\n"
    940                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}");
    941 }
    942 
    943 TEST_F(FormatTestJS, OptionalTypes) {
    944   verifyFormat("function x(a?: b, c?, d?) {}");
    945   verifyFormat("class X {\n"
    946                "  y?: z;\n"
    947                "  z?;\n"
    948                "}");
    949   verifyFormat("interface X {\n"
    950                "  y?(): z;\n"
    951                "}");
    952   verifyFormat("x ? 1 : 2;");
    953   verifyFormat("constructor({aa}: {\n"
    954                "  aa?: string,\n"
    955                "  aaaaaaaa?: string,\n"
    956                "  aaaaaaaaaaaaaaa?: boolean,\n"
    957                "  aaaaaa?: List<string>\n"
    958                "}) {}");
    959 }
    960 
    961 TEST_F(FormatTestJS, IndexSignature) {
    962   verifyFormat("var x: {[k: string]: v};");
    963 }
    964 
    965 TEST_F(FormatTestJS, WrapAfterParen) {
    966   verifyFormat("xxxxxxxxxxx(\n"
    967                "    aaa, aaa);",
    968                getGoogleJSStyleWithColumns(20));
    969   verifyFormat("xxxxxxxxxxx(\n"
    970                "    aaa, aaa, aaa,\n"
    971                "    aaa, aaa, aaa);",
    972                getGoogleJSStyleWithColumns(20));
    973   verifyFormat("xxxxxxxxxxx(\n"
    974                "    aaaaaaaaaaaaaaaaaaaaaaaa,\n"
    975                "    function(x) {\n"
    976                "      y();  //\n"
    977                "    });",
    978                getGoogleJSStyleWithColumns(40));
    979   verifyFormat("while (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n"
    980                "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
    981 }
    982 
    983 } // end namespace tooling
    984 } // end namespace clang
    985