/*
* Copyright 2012 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_CONSTRUCTOR_MISSING;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_CONSTRUCTOR_NOT_VALID;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_CONSTRUCTOR_ON_INTERFACE;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_DESCRIPTOR_NOT_VALID;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_ES6_ARROW_FUNCTION_NOT_SUPPORTED;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_ES6_COMPUTED_PROP_NAMES_NOT_SUPPORTED;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_ES6_SHORTHAND_ASSIGNMENT_NOT_SUPPORTED;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_NG_INJECT_ON_CLASS;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_STATICS_NOT_VALID;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_SUPER_CLASS_NOT_VALID;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_TARGET_INVALID;
import static com.google.javascript.jscomp.ClosureRewriteClass.GOOG_CLASS_UNEXPECTED_PARAMS;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
/**
* Unit tests for ClosureRewriteGoogClass
* @author johnlenz@google.com (John Lenz)
*/
public final class ClosureRewriteClassTest extends CompilerTestCase {
private static final String EXTERNS =
"var goog = {};\n"
+ "goog.inherits = function(a,b) {};\n"
+ "goog.defineClass = function(a,b) {};\n"
+ "var use\n";
public ClosureRewriteClassTest() {
super(EXTERNS);
}
@Override
protected CompilerPass getProcessor(Compiler compiler) {
return new ClosureRewriteClass(compiler);
}
@Override
protected void setUp() throws Exception {
super.setUp();
disableTypeCheck();
runTypeCheckAfterProcessing = true;
compareJsDoc = true;
}
@Override
protected int getNumRepetitions() {
return 1;
}
private void testRewrite(String code, String expected, LanguageMode lang) {
setAcceptedLanguage(lang);
test(code, expected);
}
private void testRewrite(String code, String expected){
testRewrite(code, expected, LanguageMode.ECMASCRIPT3);
testRewrite(code, expected, LanguageMode.ECMASCRIPT_2015);
}
private void testRewriteError(String js, DiagnosticType error, LanguageMode lang) {
setAcceptedLanguage(lang);
testError(js, error);
}
private void testRewriteError(String js, DiagnosticType error){
testRewriteError(js, error, LanguageMode.ECMASCRIPT3);
testRewriteError(js, error, LanguageMode.ECMASCRIPT_2015);
}
private void testRewriteWarning(String code, String expected,
DiagnosticType warning, LanguageMode lang) {
setAcceptedLanguage(lang);
test(code, expected, null, warning);
}
private void testRewriteWarning(String code, String expected, DiagnosticType warning) {
testRewriteWarning(code, expected, warning, LanguageMode.ECMASCRIPT3);
testRewriteWarning(code, expected, warning, LanguageMode.ECMASCRIPT_2015);
}
public void testBasic1() {
testRewrite(
"var x = goog.defineClass(null, {\n"
+ " constructor: function(){}\n"
+ "});",
"/** @constructor @struct */"
+ "var x = function() {};");
}
public void testBasic2() {
testRewrite(
"var x = {};\n"
+ "x.y = goog.defineClass(null, {\n"
+ " constructor: function(){}\n"
+ "});",
"var x = {};"
+ "/** @constructor @struct */"
+ "x.y = function() {};");
}
public void testBasic3() {
// verify we don't add a goog.inherits for Object
testRewrite(
"var x = goog.defineClass(Object, {\n"
+ " constructor: function(){}\n"
+ "});",
"/** @constructor @struct */"
+ "var x = function() {};");
}
public void testLet() {
testRewrite(
"let x = goog.defineClass(null, {\n" + " constructor: function(){}\n" + "});",
"/** @constructor @struct */" + "let x = function() {};",
LanguageMode.ECMASCRIPT_2015);
}
public void testConst() {
testRewrite(
"const x = goog.defineClass(null, {\n" + " constructor: function(){}\n" + "});",
"/** @constructor @struct */" + "const x = function() {};",
LanguageMode.ECMASCRIPT_2015);
}
public void testAnnotations1() {
// verify goog.defineClass values are constructible, by default
enableTypeCheck();
testRewrite(
"var x = goog.defineClass(Object, {\n"
+ " constructor: function(){}\n"
+ "});"
+ "new x();",
"/** @constructor @struct */"
+ "var x = function() {};"
+ "new x();");
}
public void testAnnotations2a() {
// @interface is preserved
enableTypeCheck();
testRewriteWarning(
"var x = goog.defineClass(null, {\n"
+ " /** @interface */\n"
+ " constructor: function(){}\n"
+ "});"
+ "new x();",
"/** @struct @interface */\n"
+ "var x = function() {};"
+ "new x();",
TypeCheck.NOT_A_CONSTRUCTOR);
}
public void testAnnotations2b() {
// @interface is preserved, at the class level too
enableTypeCheck();
testRewriteWarning(
"/** @interface */\n"
+ "var x = goog.defineClass(null, {});"
+ "new x();",
"/** @struct @interface */\n"
+ "var x = function() {};"
+ "new x();",
TypeCheck.NOT_A_CONSTRUCTOR);
}
public void testAnnotations3a() {
// verify goog.defineClass is a @struct by default
enableTypeCheck();
testRewriteWarning(
"var y = goog.defineClass(null, {\n"
+ " constructor: function(){}\n"
+ "});\n"
+ "var x = goog.defineClass(y, {\n"
+ " constructor: function(){this.a = 1}\n"
+ "});\n"
+ "use(new y().a);\n",
"/** @constructor @struct */"
+ "var y = function () {};\n"
+ "/** @constructor @struct @extends {y} */"
+ "var x = function() {this.a = 1};\n"
+ "goog.inherits(x,y);\n"
+ "use(new y().a);\n",
TypeCheck.INEXISTENT_PROPERTY);
}
public void testAnnotations3b() {
// verify goog.defineClass is a @struct by default, but can be overridden
enableTypeCheck();
testRewrite(
"/** @unrestricted */"
+ "var y = goog.defineClass(null, {\n"
+ " constructor: function(){}\n"
+ "});\n"
+ "var x = goog.defineClass(y, {\n"
+ " constructor: function(){this.a = 1}\n"
+ "});\n"
+ "use(new y().a);\n",
"/** @constructor @unrestricted */"
+ "var y = function () {};\n"
+ "/** @constructor @struct @extends {y} */"
+ "var x = function() {this.a = 1};\n"
+ "goog.inherits(x,y);\n"
+ "use(new y().a);\n");
}
public void testRecordAnnotations() {
// @record is preserved
testRewrite(
"/** @record */\n"
+ "var Rec = goog.defineClass(null, {f : function() {}});",
"/** @struct @record */\n"
+ "var Rec = function() {};\n"
+ "Rec.prototype.f = function() {};");
}
public void testRecordAnnotations2() {
enableTypeCheck();
testRewrite(
"/** @record */\n"
+ "var Rec = goog.defineClass(null, {f : function() {}});\n"
+ "var /** !Rec */ r = { f : function() {} };",
"/** @struct @record */\n"
+ "var Rec = function() {};\n"
+ "Rec.prototype.f = function() {};\n"
+ "var /** !Rec */ r = { f : function() {} };");
}
public void testAbstract1() {
// @abstract is preserved
enableTypeCheck();
testRewriteWarning(
LINE_JOINER.join(
"var x = goog.defineClass(null, {",
" /** @abstract */",
" constructor: function() {}",
"});",
"new x();"),
LINE_JOINER.join(
"/** @abstract @struct @constructor */",
"var x = function() {};",
"new x();"),
TypeCheck.INSTANTIATE_ABSTRACT_CLASS);
}
public void testAbstract2() {
// @abstract is preserved, at the class level too
enableTypeCheck();
testRewriteWarning(
LINE_JOINER.join(
"/** @abstract */",
"var x = goog.defineClass(null, {",
" constructor: function() {}",
"});",
"new x();"),
LINE_JOINER.join(
"/** @abstract @struct @constructor */",
"var x = function() {};",
"new x();"),
TypeCheck.INSTANTIATE_ABSTRACT_CLASS);
}
public void testInnerClass1() {
testRewrite(
"var x = goog.defineClass(some.Super, {\n"
+ " constructor: function(){\n"
+ " this.foo = 1;\n"
+ " },\n"
+ " statics: {\n"
+ " inner: goog.defineClass(x,{\n"
+ " constructor: function(){\n"
+ " this.bar = 1;\n"
+ " }\n"
+ " })\n"
+ " }\n"
+ "});",
"/** @constructor @struct @extends {some.Super} */\n"
+ "var x = function() { this.foo = 1; };\n"
+ "goog.inherits(x, some.Super);\n"
+ "/** @constructor @struct @extends {x} */\n"
+ "x.inner = function() { this.bar = 1; };\n"
+ "goog.inherits(x.inner, x);");
}
public void testComplete1() {
testRewrite(
"var x = goog.defineClass(some.Super, {\n"
+ " constructor: function(){\n"
+ " this.foo = 1;\n"
+ " },\n"
+ " statics: {\n"
+ " prop1: 1,\n"
+ " /** @const */\n"
+ " PROP2: 2\n"
+ " },\n"
+ " anotherProp: 1,\n"
+ " aMethod: function() {}\n"
+ "});",
"/** @constructor @struct @extends {some.Super} */\n"
+ "var x=function(){this.foo=1};\n"
+ "goog.inherits(x, some.Super);\n"
+ "x.prop1=1;\n"
+ "/** @const */\n"
+ "x.PROP2=2;\n"
+ "x.prototype.anotherProp = 1;\n"
+ "x.prototype.aMethod = function(){};");
}
public void testComplete2() {
testRewrite(
"x.y = goog.defineClass(some.Super, {\n"
+ " constructor: function(){\n"
+ " this.foo = 1;\n"
+ " },\n"
+ " statics: {\n"
+ " prop1: 1,\n"
+ " /** @const */\n"
+ " PROP2: 2\n"
+ " },\n"
+ " anotherProp: 1,\n"
+ " aMethod: function() {}\n"
+ "});",
"/** @constructor @struct @extends {some.Super} */\n"
+ "x.y=function(){this.foo=1};\n"
+ "goog.inherits(x.y,some.Super);\n"
+ "x.y.prop1 = 1;\n"
+ "/** @const */\n"
+ "x.y.PROP2 = 2;\n"
+ "x.y.prototype.anotherProp = 1;\n"
+ "x.y.prototype.aMethod=function(){};");
}
public void testClassWithStaticInitFn() {
testRewrite(
"x.y = goog.defineClass(some.Super, {\n"
+ " constructor: function(){\n"
+ " this.foo = 1;\n"
+ " },\n"
+ " statics: function(cls) {\n"
+ " cls.prop1 = 1;\n"
+ " /** @const */\n"
+ " cls.PROP2 = 2;\n"
+ " },\n"
+ " anotherProp: 1,\n"
+ " aMethod: function() {}\n"
+ "});",
LINE_JOINER.join(
"/** @constructor @struct @extends {some.Super} */",
"x.y = function() { this.foo = 1; };",
"goog.inherits(x.y, some.Super);",
"x.y.prototype.anotherProp = 1;",
"x.y.prototype.aMethod = function() {};",
"(function(cls) {",
" x.y.prop1 = 1;",
" /** @const */",
" x.y.PROP2 = 2;",
"})(x.y);"));
}
public void testPrivate1() {
testRewrite(
LINE_JOINER.join(
"/** @private */",
"x.y_ = goog.defineClass(null, {",
" constructor: function() {}",
"});"),
"/** @private @constructor @struct */ x.y_ = function() {};");
}
public void testPrivate2() {
testRewrite(
LINE_JOINER.join(
"/** @private */",
"x.y_ = goog.defineClass(null, {",
" /** @param {string} s */",
" constructor: function(s) {}",
"});"),
LINE_JOINER.join(
"/**",
" * @private",
" * @constructor",
" * @struct",
" * @param {string} s",
" */",
"x.y_ = function(s) {};"));
}
public void testInvalid1() {
testRewriteError("var x = goog.defineClass();", GOOG_CLASS_SUPER_CLASS_NOT_VALID);
testRewriteError("var x = goog.defineClass('foo');", GOOG_CLASS_SUPER_CLASS_NOT_VALID);
testRewriteError("var x = goog.defineClass(foo());", GOOG_CLASS_SUPER_CLASS_NOT_VALID);
testRewriteError("var x = goog.defineClass({'foo':1});", GOOG_CLASS_SUPER_CLASS_NOT_VALID);
testRewriteError("var x = goog.defineClass({1:1});", GOOG_CLASS_SUPER_CLASS_NOT_VALID);
testRewriteError(
"var x = goog.defineClass({get foo() {return 1}});",
GOOG_CLASS_SUPER_CLASS_NOT_VALID, LanguageMode.ECMASCRIPT5);
testRewriteError(
"var x = goog.defineClass({set foo(a) {}});",
GOOG_CLASS_SUPER_CLASS_NOT_VALID, LanguageMode.ECMASCRIPT5);
}
public void testInvalid2() {
testRewriteError("var x = goog.defineClass(null);", GOOG_CLASS_DESCRIPTOR_NOT_VALID);
testRewriteError("var x = goog.defineClass(null, null);", GOOG_CLASS_DESCRIPTOR_NOT_VALID);
testRewriteError("var x = goog.defineClass(null, foo());", GOOG_CLASS_DESCRIPTOR_NOT_VALID);
}
public void testInvalid3() {
testRewriteError("var x = goog.defineClass(null, {});", GOOG_CLASS_CONSTRUCTOR_MISSING);
testRewriteError(
"/** @interface */\n" + "var x = goog.defineClass(null, { constructor: function() {} });",
GOOG_CLASS_CONSTRUCTOR_ON_INTERFACE);
}
public void testInvalid4() {
testRewriteError(
"var x = goog.defineClass(null, {"
+ " constructor: function(){},"
+ " statics: null"
+ "});",
GOOG_CLASS_STATICS_NOT_VALID);
testRewriteError(
"var x = goog.defineClass(null, {"
+ " constructor: function(){},"
+ " statics: foo"
+ "});",
GOOG_CLASS_STATICS_NOT_VALID);
testRewriteError(
"var x = goog.defineClass(null, {"
+ " constructor: function(){},"
+ " statics: {'foo': 1}"
+ "});",
GOOG_CLASS_STATICS_NOT_VALID);
testRewriteError(
"var x = goog.defineClass(null, {"
+ " constructor: function(){},"
+ " statics: {1: 1}"
+ "});",
GOOG_CLASS_STATICS_NOT_VALID);
}
public void testInvalid5() {
testRewriteError(
"var x = goog.defineClass(null, {" + " constructor: function(){}" + "}, null);",
GOOG_CLASS_UNEXPECTED_PARAMS);
}
public void testInvalid6() {
testRewriteError("goog.defineClass();", GOOG_CLASS_TARGET_INVALID);
testRewriteError("var x = goog.defineClass() || null;", GOOG_CLASS_TARGET_INVALID);
testRewriteError("({foo: goog.defineClass()});", GOOG_CLASS_TARGET_INVALID);
}
public void testInvalid7() {
testRewriteError(LINE_JOINER.join(
"var x = goog.defineClass(null, {",
" constructor: foo",
"});"),
GOOG_CLASS_CONSTRUCTOR_NOT_VALID);
}
public void testNgInject() {
testRewrite(
"var x = goog.defineClass(Object, {\n"
+ " /** @ngInject */ constructor: function(x, y) {}\n"
+ "});",
"/** @ngInject @constructor @struct */\n"
+ "var x = function(x, y) {};");
}
public void testNgInject_onClass() {
testRewriteWarning(
"/** @ngInject */\n"
+ "var x = goog.defineClass(Object, {\n"
+ " constructor: function(x, y) {}\n"
+ "});",
"/** @ngInject @constructor @struct */\n"
+ "var x = function(x, y) {};",
GOOG_CLASS_NG_INJECT_ON_CLASS);
}
// The two following tests are just to make sure that these functionalities in
// Es6 does not break the compiler during this pass
public void testDestructParamOnFunction() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function({a, b, c}) {}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
"var FancyClass = function({a, b, c}) {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testDefaultParamOnFunction() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function(a = 1) {}",
"});"),
LINE_JOINER.join("/** @constructor @struct */", "var FancyClass = function(a = 1) {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitMethodDefinition1() {
testRewrite(
LINE_JOINER.join("var FancyClass = goog.defineClass(null, {", " constructor() {}", "});"),
LINE_JOINER.join("/** @constructor @struct */", "var FancyClass = function() {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitMethodDefinition2() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" someMethod1() {},",
" someMethod2() {}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
"var FancyClass = function() {};",
"FancyClass.prototype.someMethod1 = function() {};",
"FancyClass.prototype.someMethod2 = function() {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitMethodDefinition3() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor() {},",
" someMethod1() {},",
" someMethod2() {}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
"var FancyClass = function() {};",
"FancyClass.prototype.someMethod1 = function() {};",
"FancyClass.prototype.someMethod2 = function() {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitMethodDefinition4() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor() {},",
" statics:{",
" someMethod1() {}",
" },",
" someMethod2() {}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
"var FancyClass = function() {};",
"FancyClass.someMethod1 = function() {};",
"FancyClass.prototype.someMethod2 = function() {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitArrowFunction1() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" someArrowFunc: value => value",
"});"),
GOOG_CLASS_ES6_ARROW_FUNCTION_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitArrowFunction2() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" statics:{",
" someArrowFunc: value => value",
" }",
"});"),
GOOG_CLASS_ES6_ARROW_FUNCTION_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitArrowFunction3() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" statics:{",
" someFunction() {",
" return () => 42",
" }",
" }",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
" var FancyClass = function() {};",
" FancyClass.someFunction = function() {",
" return () => 42",
" };"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitArrowFunction4() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" someFunction: function() {",
" return () => 42",
" }",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
" var FancyClass = function() {};",
" FancyClass.prototype.someFunction = function(){",
" return () => 42",
" };"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitComputedPropName1() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" ['someCompProp_' + 42]: 47,",
" someMember: 49,",
" constructor: function() {},",
"});"),
GOOG_CLASS_ES6_COMPUTED_PROP_NAMES_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitComputedPropName2() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" statics:{",
" ['someCompProp_' + 1999]: 47",
" }",
"});"),
GOOG_CLASS_ES6_COMPUTED_PROP_NAMES_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitShorthandAssignment1() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" someShorthand, ",
" constructor: function(){},",
" someMethod: function() {}",
"});"),
GOOG_CLASS_ES6_SHORTHAND_ASSIGNMENT_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjShorthandAssignment2() {
testRewriteError(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" statics:{",
" someShorthand",
" }",
"});"),
GOOG_CLASS_ES6_SHORTHAND_ASSIGNMENT_NOT_SUPPORTED,
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitSuperCall1() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" someMethod: function() {",
" super.someMethod();",
" }",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
" var FancyClass = function() {};",
" FancyClass.prototype.someMethod = function() {",
" super.someMethod();",
" };"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitSuperCall2() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {super();},",
" someMethod: function() {}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
" var FancyClass = function() {super();};",
" FancyClass.prototype.someMethod = function() {};"),
LanguageMode.ECMASCRIPT_2015);
}
public void testExtendedObjLitSuperCall3() {
testRewrite(
LINE_JOINER.join(
"var FancyClass = goog.defineClass(null, {",
" constructor: function() {},",
" someMethod: function() {super();}",
"});"),
LINE_JOINER.join(
"/** @constructor @struct */",
"var FancyClass = function() {};",
"FancyClass.prototype.someMethod = function() {super();};"),
LanguageMode.ECMASCRIPT_2015);
}
//public void testNestedObjectLiteral(){
//testRewriteError(
// LINE_JOINER.join(
// "var FancyClass = goog.defineClass(null, {",
// " constructor: function() {},",
// " someNestedObjLit:{}",
// "});"),
// GOOG_CLASS_NESTED_OBJECT_LITERAL_FOUND, LanguageMode.ECMASCRIPT_2015);
//testRewriteError(
// LINE_JOINER.join(
// "var FancyClass = goog.defineClass(null, {",
// " constructor() {},",
// " statics:{",
// " someNestedObjLit:{}",
// " }",
// "});"),
// GOOG_CLASS_NESTED_OBJECT_LITERAL_FOUND, LanguageMode.ECMASCRIPT_2015);
//}
}