summaryrefslogtreecommitdiff
path: root/unittests/Format/FormatTestJS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Format/FormatTestJS.cpp')
-rw-r--r--unittests/Format/FormatTestJS.cpp356
1 files changed, 326 insertions, 30 deletions
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index c256ebe462635..2a929563f7544 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -65,6 +65,167 @@ protected:
TEST_F(FormatTestJS, BlockComments) {
verifyFormat("/* aaaaaaaaaaaaa */ aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ // Breaks after a single line block comment.
+ EXPECT_EQ("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /** @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */\n"
+ " mediaMessage);",
+ format("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /** "
+ "@type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */ "
+ "mediaMessage);",
+ getGoogleJSStyleWithColumns(70)));
+ // Breaks after a multiline block comment.
+ EXPECT_EQ(
+ "aaaaa = bbbb.ccccccccccccccc(\n"
+ " /**\n"
+ " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
+ " */\n"
+ " mediaMessage);",
+ format("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /**\n"
+ " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
+ " */ mediaMessage);",
+ getGoogleJSStyleWithColumns(70)));
+}
+
+TEST_F(FormatTestJS, JSDocComments) {
+ // Break the first line of a multiline jsdoc comment.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 1\n"
+ " * jsdoc line 2\n"
+ " */",
+ format("/** jsdoc line 1\n"
+ " * jsdoc line 2\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+ // Both break after '/**' and break the line itself.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line long\n"
+ " * long jsdoc line 2\n"
+ " */",
+ format("/** jsdoc line long long\n"
+ " * jsdoc line 2\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+ // Break a short first line if the ending '*/' is on a newline.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 1\n"
+ " */",
+ format("/** jsdoc line 1\n"
+ " */", getGoogleJSStyleWithColumns(20)));
+ // Don't break the first line of a short single line jsdoc comment.
+ EXPECT_EQ("/** jsdoc line 1 */",
+ format("/** jsdoc line 1 */", getGoogleJSStyleWithColumns(20)));
+ // Don't break the first line of a single line jsdoc comment if it just fits
+ // the column limit.
+ EXPECT_EQ("/** jsdoc line 12 */",
+ format("/** jsdoc line 12 */", getGoogleJSStyleWithColumns(20)));
+ // Don't break after '/**' and before '*/' if there is no space between
+ // '/**' and the content.
+ EXPECT_EQ(
+ "/*** nonjsdoc long\n"
+ " * line */",
+ format("/*** nonjsdoc long line */", getGoogleJSStyleWithColumns(20)));
+ EXPECT_EQ(
+ "/**strange long long\n"
+ " * line */",
+ format("/**strange long long line */", getGoogleJSStyleWithColumns(20)));
+ // Break the first line of a single line jsdoc comment if it just exceeds the
+ // column limit.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break also if the leading indent of the first line is more than 1 column.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break also if the leading indent of the first line is more than 1 column.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break after the content of the last line.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */",
+ format("/**\n"
+ " * line 1\n"
+ " * line 2 */",
+ getGoogleJSStyleWithColumns(20)));
+ // Break both the content and after the content of the last line.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line long long\n"
+ " * long\n"
+ " */",
+ format("/**\n"
+ " * line 1\n"
+ " * line long long long */",
+ getGoogleJSStyleWithColumns(20)));
+
+ // The comment block gets indented.
+ EXPECT_EQ("function f() {\n"
+ " /**\n"
+ " * comment about\n"
+ " * x\n"
+ " */\n"
+ " var x = 1;\n"
+ "}",
+ format("function f() {\n"
+ "/** comment about x */\n"
+ "var x = 1;\n"
+ "}",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Don't break the first line of a single line short jsdoc comment pragma.
+ EXPECT_EQ("/** @returns j */",
+ format("/** @returns j */",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Break a single line long jsdoc comment pragma.
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12*/",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Fix a multiline jsdoc comment ending in a comment pragma.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** line 1\n"
+ " * line 2\n"
+ " * @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " *\n"
+ " * @returns j\n"
+ " */",
+ format("/** line 1\n"
+ " * line 2\n"
+ " *\n"
+ " * @returns j */",
+ getGoogleJSStyleWithColumns(20)));
}
TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
@@ -131,14 +292,21 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("x.case = 1;");
verifyFormat("x.interface = 1;");
verifyFormat("x.for = 1;");
- verifyFormat("x.of() = 1;");
+ verifyFormat("x.of();");
verifyFormat("of(null);");
verifyFormat("import {of} from 'x';");
- verifyFormat("x.in() = 1;");
- verifyFormat("x.let() = 1;");
- verifyFormat("x.var() = 1;");
- verifyFormat("x.for() = 1;");
- verifyFormat("x.as() = 1;");
+ verifyFormat("x.in();");
+ verifyFormat("x.let();");
+ verifyFormat("x.var();");
+ verifyFormat("x.for();");
+ verifyFormat("x.as();");
+ verifyFormat("x.instanceof();");
+ verifyFormat("x.switch();");
+ verifyFormat("x.case();");
+ verifyFormat("x.delete();");
+ verifyFormat("x.throw();");
+ verifyFormat("x.throws();");
+ verifyFormat("x.if();");
verifyFormat("x = {\n"
" a: 12,\n"
" interface: 1,\n"
@@ -149,6 +317,17 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("var interface = 2;");
verifyFormat("interface = 2;");
verifyFormat("x = interface instanceof y;");
+ verifyFormat("interface Test {\n"
+ " x: string;\n"
+ " switch: string;\n"
+ " case: string;\n"
+ " default: string;\n"
+ "}\n");
+ verifyFormat("const Axis = {\n"
+ " for: 'for',\n"
+ " x: 'x'\n"
+ "};",
+ "const Axis = {for: 'for', x: 'x'};");
}
TEST_F(FormatTestJS, ReservedWordsMethods) {
@@ -166,6 +345,16 @@ TEST_F(FormatTestJS, ReservedWordsMethods) {
"}\n");
}
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+ // All of these are statements using the keyword, not function calls.
+ verifyFormat("throw (x + y);\n"
+ "await (await x).y;\n"
+ "typeof (x) === 'string';\n"
+ "void (0);\n"
+ "delete (x.y);\n"
+ "return (x);\n");
+}
+
TEST_F(FormatTestJS, CppKeywords) {
// Make sure we don't mess stuff up because of C++ keywords.
verifyFormat("return operator && (aa);");
@@ -395,8 +584,6 @@ TEST_F(FormatTestJS, GoogModules) {
getGoogleJSStyleWithColumns(40));
verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
- verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');",
- getGoogleJSStyleWithColumns(40));
verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
@@ -404,6 +591,12 @@ TEST_F(FormatTestJS, GoogModules) {
verifyFormat(
"var MyLongClassName =\n"
" goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
+ verifyFormat("function a() {\n"
+ " goog.setTestOnly();\n"
+ "}\n",
+ "function a() {\n"
+ "goog.setTestOnly();\n"
+ "}\n");
}
TEST_F(FormatTestJS, FormatsNamespaces) {
@@ -739,6 +932,15 @@ TEST_F(FormatTestJS, FunctionLiterals) {
}
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of([]));");
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of({}));");
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of(()));");
+}
+
TEST_F(FormatTestJS, InliningFunctionLiterals) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
@@ -895,6 +1097,9 @@ TEST_F(FormatTestJS, ArrowFunctions) {
" .doSomethingElse(\n"
" // break\n"
" );");
+ verifyFormat("const f = (x: string|null): string|null => {\n"
+ " return x;\n"
+ "}\n");
}
TEST_F(FormatTestJS, ReturnStatements) {
@@ -910,6 +1115,10 @@ TEST_F(FormatTestJS, ForLoops) {
"}");
verifyFormat("for (let {a, b} of x) {\n"
"}");
+ verifyFormat("for (let {a, b} of [x]) {\n"
+ "}");
+ verifyFormat("for (let [a, b] of [x]) {\n"
+ "}");
verifyFormat("for (let {a, b} in x) {\n"
"}");
}
@@ -919,6 +1128,7 @@ TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) {
// would change due to automatic semicolon insertion.
// See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1.
verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("yield aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("return /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("continue /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
@@ -938,6 +1148,15 @@ TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) {
" readonly ratherLongField = 1;\n"
"}",
getGoogleJSStyleWithColumns(20));
+ verifyFormat("const x = (5 + 9)\n"
+ "const y = 3\n",
+ "const x = ( 5 + 9)\n"
+ "const y = 3\n");
+ // Ideally the foo() bit should be indented relative to the async function().
+ verifyFormat("async function\n"
+ "foo() {}",
+ getGoogleJSStyleWithColumns(10));
+ verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
}
TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
@@ -988,6 +1207,8 @@ TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
"String");
verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
" bar) {}");
+ verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
+ " bar) {}");
verifyFormat("a = true\n"
"return 1",
"a = true\n"
@@ -1056,7 +1277,6 @@ TEST_F(FormatTestJS, TryCatch) {
// But, of course, "catch" is a perfectly fine function name in JavaScript.
verifyFormat("someObject.catch();");
verifyFormat("someObject.new();");
- verifyFormat("someObject.delete();");
}
TEST_F(FormatTestJS, StringLiteralConcatenation) {
@@ -1199,6 +1419,7 @@ TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("function x(y: {a?: number;} = {}): number {\n"
" return 12;\n"
"}");
+ verifyFormat("const x: Array<{a: number; b: string;}> = [];");
verifyFormat("((a: string, b: number): string => a + b);");
verifyFormat("var x: (y: number) => string;");
verifyFormat("var x: P<string, (a: number) => string>;");
@@ -1218,6 +1439,8 @@ TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat(
"var someValue = (v as aaaaaaaaaaaaaaaaaaaa<T>[])\n"
" .someFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("const xIsALongIdent:\n"" YJustBarelyFitsLinex[];",
+ getGoogleJSStyleWithColumns(20));
}
TEST_F(FormatTestJS, UnionIntersectionTypes) {
@@ -1242,6 +1465,18 @@ TEST_F(FormatTestJS, UnionIntersectionTypes) {
"};");
}
+TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) {
+ verifyFormat("let x: {x: number|null} = {x: number | null};");
+ verifyFormat("let nested: {x: {y: number|null}};");
+ verifyFormat("let mixed: {x: [number|null, {w: number}]};");
+ verifyFormat("class X {\n"
+ " contructor(x: {\n"
+ " a: a|null,\n"
+ " b: b|null,\n"
+ " }) {}\n"
+ "}");
+}
+
TEST_F(FormatTestJS, ClassDeclarations) {
verifyFormat("class C {\n x: string = 12;\n}");
verifyFormat("class C {\n x(): string => 12;\n}");
@@ -1307,6 +1542,17 @@ TEST_F(FormatTestJS, InterfaceDeclarations) {
"}");
}
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+ verifyFormat("class C extends {} {}");
+ verifyFormat("class C implements {bar: number} {}");
+ // Somewhat odd, but probably closest to reasonable formatting?
+ verifyFormat("class C implements {\n"
+ " bar: number,\n"
+ " baz: string,\n"
+ "} {}");
+ verifyFormat("class C<P extends {}> {}");
+}
+
TEST_F(FormatTestJS, EnumDeclarations) {
verifyFormat("enum Foo {\n"
" A = 1,\n"
@@ -1321,9 +1567,17 @@ TEST_F(FormatTestJS, EnumDeclarations) {
" B\n"
"}\n"
"var x = 1;");
+ verifyFormat("const enum Foo {\n"
+ " A = 1,\n"
+ " B\n"
+ "}");
+ verifyFormat("export const enum Foo {\n"
+ " A = 1,\n"
+ " B\n"
+ "}");
}
-TEST_F(FormatTestJS, MetadataAnnotations) {
+TEST_F(FormatTestJS, Decorators) {
verifyFormat("@A\nclass C {\n}");
verifyFormat("@A({arg: 'value'})\nclass C {\n}");
verifyFormat("@A\n@B\nclass C {\n}");
@@ -1352,6 +1606,10 @@ TEST_F(FormatTestJS, TypeAliases) {
" y: number\n"
"};\n"
"class C {}");
+ verifyFormat("export type X = {\n"
+ " a: string,\n"
+ " b?: string,\n"
+ "};\n");
}
TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
@@ -1368,6 +1626,17 @@ TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
Style);
}
+TEST_F(FormatTestJS, RemoveEmptyLinesInArrowFunctions) {
+ verifyFormat("x = () => {\n"
+ " foo();\n"
+ "};\n",
+ "x = () => {\n"
+ "\n"
+ " foo();\n"
+ "\n"
+ "};\n");
+}
+
TEST_F(FormatTestJS, Modules) {
verifyFormat("import SomeThing from 'some/module.js';");
verifyFormat("import {X, Y} from 'some/module.js';");
@@ -1410,9 +1679,15 @@ TEST_F(FormatTestJS, Modules) {
" x: number;\n"
" y: string;\n"
"}");
- verifyFormat("export class X { y: number; }");
- verifyFormat("export abstract class X { y: number; }");
- verifyFormat("export default class X { y: number }");
+ verifyFormat("export class X {\n"
+ " y: number;\n"
+ "}");
+ verifyFormat("export abstract class X {\n"
+ " y: number;\n"
+ "}");
+ verifyFormat("export default class X {\n"
+ " y: number\n"
+ "}");
verifyFormat("export default function() {\n return 1;\n}");
verifyFormat("export var x = 12;");
verifyFormat("class C {}\n"
@@ -1434,7 +1709,9 @@ TEST_F(FormatTestJS, Modules) {
"];");
verifyFormat("export default [];");
verifyFormat("export default () => {};");
- verifyFormat("export interface Foo { foo: number; }\n"
+ verifyFormat("export interface Foo {\n"
+ " foo: number;\n"
+ "}\n"
"export class Bar {\n"
" blah(): string {\n"
" return this.blah;\n"
@@ -1580,32 +1857,28 @@ TEST_F(FormatTestJS, TemplateStrings) {
verifyFormat("var x = someFunction(`${})`) //\n"
" .oooooooooooooooooon();");
verifyFormat("var x = someFunction(`${aaaa}${\n"
- " aaaaa( //\n"
- " aaaaa)\n"
- " })`);");
+ " aaaaa( //\n"
+ " aaaaa)})`);");
}
TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n"
- " aaaaa + //\n"
- " bbbb\n"
- " }`;",
+ " aaaaa + //\n"
+ " bbbb}`;",
"var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa + //\n"
" bbbb}`;");
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${\n"
- " aaaaa + //\n"
- " bbbb\n"
- " }`;",
+ " aaaaa + //\n"
+ " bbbb}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${ aaaaa + //\n"
" bbbb }`;");
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${\n"
- " someFunction(\n"
- " aaaaa + //\n"
- " bbbb)\n"
- " }`;",
+ " someFunction(\n"
+ " aaaaa + //\n"
+ " bbbb)}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction (\n"
" aaaaa + //\n"
@@ -1614,9 +1887,9 @@ TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
// It might be preferable to wrap before "someFunction".
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction({\n"
- " aaaa: aaaaa,\n"
- " bbbb: bbbbb,\n"
- " })}`;",
+ " aaaa: aaaaa,\n"
+ " bbbb: bbbbb,\n"
+ "})}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction ({\n"
" aaaa: aaaaa,\n"
@@ -1659,6 +1932,7 @@ TEST_F(FormatTestJS, CastSyntax) {
verifyFormat("x = x as {a: string};");
verifyFormat("x = x as (string);");
verifyFormat("x = x! as (string);");
+ verifyFormat("x = y! in z;");
verifyFormat("var x = something.someFunction() as\n"
" something;",
getGoogleJSStyleWithColumns(40));
@@ -1934,5 +2208,27 @@ TEST_F(FormatTestJS, NestedLiterals) {
"};", FourSpaces);
}
+TEST_F(FormatTestJS, BackslashesInComments) {
+ verifyFormat("// hello \\\n"
+ "if (x) foo();\n",
+ "// hello \\\n"
+ " if ( x) \n"
+ " foo();\n");
+ verifyFormat("/* ignore \\\n"
+ " */\n"
+ "if (x) foo();\n",
+ "/* ignore \\\n"
+ " */\n"
+ " if ( x) foo();\n");
+ verifyFormat("// st \\ art\\\n"
+ "// comment"
+ "// continue \\\n"
+ "formatMe();\n",
+ "// st \\ art\\\n"
+ "// comment"
+ "// continue \\\n"
+ "formatMe( );\n");
+}
+
} // end namespace tooling
} // end namespace clang