This repository has been archived on 2023-06-18. You can view files and clone it, but cannot push or open issues or pull requests.
ima02/resources/defects4j-checkout-closure-1f/test/com/google/javascript/jscomp/CommandLineRunnerTest.java

1339 lines
43 KiB
Java
Raw Permalink Normal View History

2023-04-25 11:33:41 +00:00
/*
* Copyright 2009 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 com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.javascript.jscomp.AbstractCommandLineRunner.FlagUsageException;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.rhino.Node;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
/**
* Tests for {@link CommandLineRunner}.
*
* @author nicksantos@google.com (Nick Santos)
*/
public class CommandLineRunnerTest extends TestCase {
private Compiler lastCompiler = null;
private CommandLineRunner lastCommandLineRunner = null;
private List<Integer> exitCodes = null;
private ByteArrayOutputStream outReader = null;
private ByteArrayOutputStream errReader = null;
private Map<Integer,String> filenames;
// If set, this will be appended to the end of the args list.
// For testing args parsing.
private String lastArg = null;
// If set to true, uses comparison by string instead of by AST.
private boolean useStringComparison = false;
private ModulePattern useModules = ModulePattern.NONE;
private enum ModulePattern {
NONE,
CHAIN,
STAR
}
private List<String> args = Lists.newArrayList();
/** Externs for the test */
private final List<SourceFile> DEFAULT_EXTERNS = ImmutableList.of(
SourceFile.fromCode("externs",
"var arguments;"
+ "/**\n"
+ " * @constructor\n"
+ " * @param {...*} var_args\n"
+ " * @nosideeffects\n"
+ " * @throws {Error}\n"
+ " */\n"
+ "function Function(var_args) {}\n"
+ "/**\n"
+ " * @param {...*} var_args\n"
+ " * @return {*}\n"
+ " */\n"
+ "Function.prototype.call = function(var_args) {};"
+ "/**\n"
+ " * @constructor\n"
+ " * @param {...*} var_args\n"
+ " * @return {!Array}\n"
+ " */\n"
+ "function Array(var_args) {}"
+ "/**\n"
+ " * @param {*=} opt_begin\n"
+ " * @param {*=} opt_end\n"
+ " * @return {!Array}\n"
+ " * @this {Object}\n"
+ " */\n"
+ "Array.prototype.slice = function(opt_begin, opt_end) {};"
+ "/** @constructor */ function Window() {}\n"
+ "/** @type {string} */ Window.prototype.name;\n"
+ "/** @type {Window} */ var window;"
+ "/** @constructor */ function Element() {}"
+ "Element.prototype.offsetWidth;"
+ "/** @nosideeffects */ function noSideEffects() {}\n"
+ "/** @param {...*} x */ function alert(x) {}\n")
);
private List<SourceFile> externs;
@Override
public void setUp() throws Exception {
super.setUp();
externs = DEFAULT_EXTERNS;
filenames = Maps.newHashMap();
lastCompiler = null;
lastArg = null;
outReader = new ByteArrayOutputStream();
errReader = new ByteArrayOutputStream();
useStringComparison = false;
useModules = ModulePattern.NONE;
args.clear();
exitCodes = Lists.newArrayList();
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
public void testWarningGuardOrdering1() {
args.add("--jscomp_error=globalThis");
args.add("--jscomp_off=globalThis");
testSame("function f() { this.a = 3; }");
}
public void testWarningGuardOrdering2() {
args.add("--jscomp_off=globalThis");
args.add("--jscomp_error=globalThis");
test("function f() { this.a = 3; }", CheckGlobalThis.GLOBAL_THIS);
}
public void testWarningGuardOrdering3() {
args.add("--jscomp_warning=globalThis");
args.add("--jscomp_off=globalThis");
testSame("function f() { this.a = 3; }");
}
public void testWarningGuardOrdering4() {
args.add("--jscomp_off=globalThis");
args.add("--jscomp_warning=globalThis");
test("function f() { this.a = 3; }", CheckGlobalThis.GLOBAL_THIS);
}
public void testSimpleModeLeavesUnusedParams() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
testSame("window.f = function(a) {};");
}
public void testAdvancedModeRemovesUnusedParams() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("window.f = function(a) {};", "window.a = function() {};");
}
public void testCheckGlobalThisOffByDefault() {
testSame("function f() { this.a = 3; }");
}
public void testCheckGlobalThisOnWithAdvancedMode() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("function f() { this.a = 3; }", CheckGlobalThis.GLOBAL_THIS);
}
public void testCheckGlobalThisOnWithErrorFlag() {
args.add("--jscomp_error=globalThis");
test("function f() { this.a = 3; }", CheckGlobalThis.GLOBAL_THIS);
}
public void testCheckGlobalThisOff() {
args.add("--warning_level=VERBOSE");
args.add("--jscomp_off=globalThis");
testSame("function f() { this.a = 3; }");
}
public void testTypeCheckingOffByDefault() {
test("function f(x) { return x; } f();",
"function f(a) { return a; } f();");
}
public void testReflectedMethods() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test(
"/** @constructor */" +
"function Foo() {}" +
"Foo.prototype.handle = function(x, y) { alert(y); };" +
"var x = goog.reflect.object(Foo, {handle: 1});" +
"for (var i in x) { x[i].call(x); }" +
"window['Foo'] = Foo;",
"function a() {}" +
"a.prototype.a = function(e, d) { alert(d); };" +
"var b = goog.c.b(a, {a: 1}),c;" +
"for (c in b) { b[c].call(b); }" +
"window.Foo = a;");
}
public void testInlineVariables() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test(
"/** @constructor */ function F() { this.a = 0; }" +
"F.prototype.inc = function() { this.a++; return 10; };" +
"F.prototype.bar = function() { " +
" var c = 3; var val = inc(); this.a += val + c;" +
"};" +
"window['f'] = new F();" +
"window['f']['bar'] = window['f'].bar;",
"function a(){ this.a = 0; }" +
"a.prototype.b = function(){ var b=inc(); this.a += b + 3; };" +
"window.f = new a;" +
"window.f.bar = window.f.b");
}
public void testTypedAdvanced() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
args.add("--use_types_for_optimization");
test(
"/** @constructor */\n" +
"function Foo() {}\n" +
"Foo.prototype.handle1 = function(x, y) { alert(y); };\n" +
"/** @constructor */\n" +
"function Bar() {}\n" +
"Bar.prototype.handle1 = function(x, y) {};\n" +
"new Foo().handle1(1, 2);\n" +
"new Bar().handle1(1, 2);\n",
"alert(2)");
}
public void testTypeCheckingOnWithVerbose() {
args.add("--warning_level=VERBOSE");
test("function f(x) { return x; } f();", TypeCheck.WRONG_ARGUMENT_COUNT);
}
public void testTypeParsingOffByDefault() {
testSame("/** @return {number */ function f(a) { return a; }");
}
public void testTypeParsingOnWithVerbose() {
args.add("--warning_level=VERBOSE");
test("/** @return {number */ function f(a) { return a; }",
RhinoErrorReporter.TYPE_PARSE_ERROR);
test("/** @return {n} */ function f(a) { return a; }",
RhinoErrorReporter.TYPE_PARSE_ERROR);
}
public void testTypeCheckOverride1() {
args.add("--warning_level=VERBOSE");
args.add("--jscomp_off=checkTypes");
testSame("var x = x || {}; x.f = function() {}; x.f(3);");
}
public void testTypeCheckOverride2() {
args.add("--warning_level=DEFAULT");
testSame("var x = x || {}; x.f = function() {}; x.f(3);");
args.add("--jscomp_warning=checkTypes");
test("var x = x || {}; x.f = function() {}; x.f(3);",
TypeCheck.WRONG_ARGUMENT_COUNT);
}
public void testCheckSymbolsOffForDefault() {
args.add("--warning_level=DEFAULT");
test("x = 3; var y; var y;", "x=3; var y;");
}
public void testCheckSymbolsOnForVerbose() {
args.add("--warning_level=VERBOSE");
test("x = 3;", VarCheck.UNDEFINED_VAR_ERROR);
test("var y; var y;", SyntacticScopeCreator.VAR_MULTIPLY_DECLARED_ERROR);
}
public void testCheckSymbolsOverrideForVerbose() {
args.add("--warning_level=VERBOSE");
args.add("--jscomp_off=undefinedVars");
testSame("x = 3;");
}
public void testCheckSymbolsOverrideForQuiet() {
args.add("--warning_level=QUIET");
args.add("--jscomp_error=undefinedVars");
test("x = 3;", VarCheck.UNDEFINED_VAR_ERROR);
}
public void testCheckUndefinedProperties1() {
args.add("--warning_level=VERBOSE");
args.add("--jscomp_error=missingProperties");
test("var x = {}; var y = x.bar;", TypeCheck.INEXISTENT_PROPERTY);
}
public void testCheckUndefinedProperties2() {
args.add("--warning_level=VERBOSE");
args.add("--jscomp_off=missingProperties");
test("var x = {}; var y = x.bar;", CheckGlobalNames.UNDEFINED_NAME_WARNING);
}
public void testCheckUndefinedProperties3() {
args.add("--warning_level=VERBOSE");
test("function f() {var x = {}; var y = x.bar;}",
TypeCheck.INEXISTENT_PROPERTY);
}
public void testDuplicateParams() {
test("function f(a, a) {}", RhinoErrorReporter.DUPLICATE_PARAM);
assertTrue(lastCompiler.hasHaltingErrors());
}
public void testDefineFlag() {
args.add("--define=FOO");
args.add("--define=\"BAR=5\"");
args.add("--D"); args.add("CCC");
args.add("-D"); args.add("DDD");
test("/** @define {boolean} */ var FOO = false;" +
"/** @define {number} */ var BAR = 3;" +
"/** @define {boolean} */ var CCC = false;" +
"/** @define {boolean} */ var DDD = false;",
"var FOO = !0, BAR = 5, CCC = !0, DDD = !0;");
}
public void testDefineFlag2() {
args.add("--define=FOO='x\"'");
test("/** @define {string} */ var FOO = \"a\";",
"var FOO = \"x\\\"\";");
}
public void testDefineFlag3() {
args.add("--define=FOO=\"x'\"");
test("/** @define {string} */ var FOO = \"a\";",
"var FOO = \"x'\";");
}
public void testScriptStrictModeNoWarning() {
test("'use strict';", "");
test("'no use strict';", CheckSideEffects.USELESS_CODE_ERROR);
}
public void testFunctionStrictModeNoWarning() {
test("function f() {'use strict';}", "function f() {}");
test("function f() {'no use strict';}",
CheckSideEffects.USELESS_CODE_ERROR);
}
public void testQuietMode() {
args.add("--warning_level=DEFAULT");
test("/** @const \n * @const */ var x;",
RhinoErrorReporter.PARSE_ERROR);
args.add("--warning_level=QUIET");
testSame("/** @const \n * @const */ var x;");
}
public void testProcessClosurePrimitives() {
test("var goog = {}; goog.provide('goog.dom');",
"var goog = {dom:{}};");
args.add("--process_closure_primitives=false");
testSame("var goog = {}; goog.provide('goog.dom');");
}
public void testGetMsgWiring() throws Exception {
test("var goog = {}; goog.getMsg = function(x) { return x; };" +
"/** @desc A real foo. */ var MSG_FOO = goog.getMsg('foo');",
"var goog={getMsg:function(a){return a}}, " +
"MSG_FOO=goog.getMsg('foo');");
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("var goog = {}; goog.getMsg = function(x) { return x; };" +
"/** @desc A real foo. */ var MSG_FOO = goog.getMsg('foo');" +
"window['foo'] = MSG_FOO;",
"window.foo = 'foo';");
}
public void testCssNameWiring() throws Exception {
test("var goog = {}; goog.getCssName = function() {};" +
"goog.setCssNameMapping = function() {};" +
"goog.setCssNameMapping({'goog': 'a', 'button': 'b'});" +
"var a = goog.getCssName('goog-button');" +
"var b = goog.getCssName('css-button');" +
"var c = goog.getCssName('goog-menu');" +
"var d = goog.getCssName('css-menu');",
"var goog = { getCssName: function() {}," +
" setCssNameMapping: function() {} }," +
" a = 'a-b'," +
" b = 'css-b'," +
" c = 'a-menu'," +
" d = 'css-menu';");
}
//////////////////////////////////////////////////////////////////////////////
// Integration tests
public void testIssue70a() {
test("function foo({}) {}", RhinoErrorReporter.PARSE_ERROR);
}
public void testIssue70b() {
test("function foo([]) {}", RhinoErrorReporter.PARSE_ERROR);
}
public void testIssue81() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
useStringComparison = true;
test("eval('1'); var x = eval; x('2');",
"eval(\"1\");(0,eval)(\"2\");");
}
public void testIssue115() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
args.add("--jscomp_off=es5Strict");
args.add("--warning_level=VERBOSE");
test("function f() { " +
" var arguments = Array.prototype.slice.call(arguments, 0);" +
" return arguments[0]; " +
"}",
"function f() { " +
" arguments = Array.prototype.slice.call(arguments, 0);" +
" return arguments[0]; " +
"}");
}
public void testIssue297() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
test("function f(p) {" +
" var x;" +
" return ((x=p.id) && (x=parseInt(x.substr(1))) && x>0);" +
"}",
"function f(b) {" +
" var a;" +
" return ((a=b.id) && (a=parseInt(a.substr(1))) && 0<a);" +
"}");
}
public void testHiddenSideEffect() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("element.offsetWidth;",
"element.offsetWidth", CheckSideEffects.USELESS_CODE_ERROR);
}
public void testIssue504() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("void function() { alert('hi'); }();",
"alert('hi');void 0", CheckSideEffects.USELESS_CODE_ERROR);
}
public void testIssue601() {
args.add("--compilation_level=WHITESPACE_ONLY");
test("function f() { return '\\v' == 'v'; } window['f'] = f;",
"function f(){return'\\v'=='v'}window['f']=f");
}
public void testIssue601b() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("function f() { return '\\v' == 'v'; } window['f'] = f;",
"window.f=function(){return'\\v'=='v'}");
}
public void testIssue601c() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("function f() { return '\\u000B' == 'v'; } window['f'] = f;",
"window.f=function(){return'\\u000B'=='v'}");
}
public void testIssue846() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
testSame(
"try { new Function('this is an error'); } catch(a) { alert('x'); }");
}
public void testDebugFlag1() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
args.add("--debug=false");
test("function foo(a) {}",
"function foo(a) {}");
}
public void testDebugFlag2() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
args.add("--debug=true");
test("function foo(a) {alert(a)}",
"function foo($a$$) {alert($a$$)}");
}
public void testDebugFlag3() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
args.add("--warning_level=QUIET");
args.add("--debug=false");
test("function Foo() {}" +
"Foo.x = 1;" +
"function f() {throw new Foo().x;} f();",
"throw (new function() {}).a;");
}
public void testDebugFlag4() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
args.add("--warning_level=QUIET");
args.add("--debug=true");
test("function Foo() {}" +
"Foo.x = 1;" +
"function f() {throw new Foo().x;} f();",
"throw (new function Foo() {}).$x$;");
}
public void testBooleanFlag1() {
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
args.add("--debug");
test("function foo(a) {alert(a)}",
"function foo($a$$) {alert($a$$)}");
}
public void testBooleanFlag2() {
args.add("--debug");
args.add("--compilation_level=SIMPLE_OPTIMIZATIONS");
test("function foo(a) {alert(a)}",
"function foo($a$$) {alert($a$$)}");
}
public void testHelpFlag() {
args.add("--help");
assertFalse(
createCommandLineRunner(
new String[] {"function f() {}"}).shouldRunCompiler());
}
public void testExternsLifting1() throws Exception{
String code = "/** @externs */ function f() {}";
test(new String[] {code},
new String[] {});
assertEquals(2, lastCompiler.getExternsForTesting().size());
CompilerInput extern = lastCompiler.getExternsForTesting().get(1);
assertNull(extern.getModule());
assertTrue(extern.isExtern());
assertEquals(code, extern.getCode());
assertEquals(1, lastCompiler.getInputsForTesting().size());
CompilerInput input = lastCompiler.getInputsForTesting().get(0);
assertNotNull(input.getModule());
assertFalse(input.isExtern());
assertEquals("", input.getCode());
}
public void testExternsLifting2() {
args.add("--warning_level=VERBOSE");
test(new String[] {"/** @externs */ function f() {}", "f(3);"},
new String[] {"f(3);"},
TypeCheck.WRONG_ARGUMENT_COUNT);
}
public void testSourceSortingOff() {
args.add("--compilation_level=WHITESPACE_ONLY");
testSame(
new String[] {
"goog.require('beer');",
"goog.provide('beer');"
});
}
public void testSourceSortingOn() {
test(new String[] {
"goog.require('beer');",
"goog.provide('beer');"
},
new String[] {
"var beer = {};",
""
});
}
public void testSourceSortingOn2() {
test(new String[] {
"goog.provide('a');",
"goog.require('a');\n" +
"var COMPILED = false;",
},
new String[] {
"var a={};",
"var COMPILED=!1"
});
}
public void testSourceSortingOn3() {
args.add("--manage_closure_dependencies=true");
test(new String[] {
"goog.addDependency('sym', [], []);\nvar x = 3;",
"var COMPILED = false;",
},
new String[] {
"var COMPILED = !1;",
"var x = 3;"
});
}
public void testSourceSortingCircularDeps1() {
args.add("--manage_closure_dependencies=true");
test(new String[] {
"goog.provide('gin'); goog.require('tonic'); var gin = {};",
"goog.provide('tonic'); goog.require('gin'); var tonic = {};",
"goog.require('gin'); goog.require('tonic');"
},
JSModule.CIRCULAR_DEPENDENCY_ERROR);
}
public void testSourceSortingCircularDeps2() {
args.add("--manage_closure_dependencies=true");
test(new String[] {
"goog.provide('roses.lime.juice');",
"goog.provide('gin'); goog.require('tonic'); var gin = {};",
"goog.provide('tonic'); goog.require('gin'); var tonic = {};",
"goog.require('gin'); goog.require('tonic');",
"goog.provide('gimlet');" +
" goog.require('gin'); goog.require('roses.lime.juice');"
},
JSModule.CIRCULAR_DEPENDENCY_ERROR);
}
public void testSourcePruningOn1() {
args.add("--manage_closure_dependencies=true");
test(new String[] {
"goog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
new String[] {
"var beer = {};",
""
});
}
public void testSourcePruningOn2() {
args.add("--closure_entry_point=guinness");
test(new String[] {
"goog.provide('guinness');\ngoog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
new String[] {
"var beer = {};",
"var guinness = {};"
});
}
public void testSourcePruningOn3() {
args.add("--closure_entry_point=scotch");
test(new String[] {
"goog.provide('guinness');\ngoog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
new String[] {
"var scotch = {}, x = 3;",
});
}
public void testSourcePruningOn4() {
args.add("--closure_entry_point=scotch");
args.add("--closure_entry_point=beer");
test(new String[] {
"goog.provide('guinness');\ngoog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
new String[] {
"var beer = {};",
"var scotch = {}, x = 3;",
});
}
public void testSourcePruningOn5() {
args.add("--closure_entry_point=shiraz");
test(new String[] {
"goog.provide('guinness');\ngoog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
Compiler.MISSING_ENTRY_ERROR);
}
public void testSourcePruningOn6() {
args.add("--closure_entry_point=scotch");
test(new String[] {
"goog.require('beer');",
"goog.provide('beer');",
"goog.provide('scotch'); var x = 3;"
},
new String[] {
"var beer = {};",
"",
"var scotch = {}, x = 3;",
});
}
public void testSourcePruningOn7() {
args.add("--manage_closure_dependencies=true");
test(new String[] {
"var COMPILED = false;",
},
new String[] {
"var COMPILED = !1;",
});
}
public void testSourcePruningOn8() {
args.add("--only_closure_dependencies");
args.add("--closure_entry_point=scotch");
args.add("--warning_level=VERBOSE");
test(new String[] {
"/** @externs */\n" +
"var externVar;",
"goog.provide('scotch'); var x = externVar;"
},
new String[] {
"var scotch = {}, x = externVar;",
});
}
public void testNoCompile() {
args.add("--warning_level=VERBOSE");
test(new String[] {
"/** @nocompile */\n" +
"goog.provide('x');\n" +
"var dupeVar;",
"var dupeVar;"
},
new String[] {
"var dupeVar;"
});
}
public void testDependencySortingWhitespaceMode() {
args.add("--manage_closure_dependencies");
args.add("--compilation_level=WHITESPACE_ONLY");
test(new String[] {
"goog.require('beer');",
"goog.provide('beer');\ngoog.require('hops');",
"goog.provide('hops');",
},
new String[] {
"goog.provide('hops');",
"goog.provide('beer');\ngoog.require('hops');",
"goog.require('beer');"
});
}
public void testForwardDeclareDroppedTypes() {
args.add("--manage_closure_dependencies=true");
args.add("--warning_level=VERBOSE");
test(new String[] {
"goog.require('beer');",
"goog.provide('beer'); /** @param {Scotch} x */ function f(x) {}",
"goog.provide('Scotch'); var x = 3;"
},
new String[] {
"var beer = {}; function f(a) {}",
""
});
test(new String[] {
"goog.require('beer');",
"goog.provide('beer'); /** @param {Scotch} x */ function f(x) {}"
},
new String[] {
"var beer = {}; function f(a) {}",
""
},
RhinoErrorReporter.TYPE_PARSE_ERROR);
}
public void testOnlyClosureDependenciesEmptyEntryPoints() throws Exception {
// Prevents this from trying to load externs.zip
args.add("--use_only_custom_externs=true");
args.add("--only_closure_dependencies=true");
try {
CommandLineRunner runner = createCommandLineRunner(new String[0]);
runner.doRun();
fail("Expected FlagUsageException");
} catch (FlagUsageException e) {
assertTrue(e.getMessage(),
e.getMessage().contains("only_closure_dependencies"));
}
}
public void testOnlyClosureDependenciesOneEntryPoint() throws Exception {
args.add("--only_closure_dependencies=true");
args.add("--closure_entry_point=beer");
test(new String[] {
"goog.require('beer'); var beerRequired = 1;",
"goog.provide('beer');\ngoog.require('hops');\nvar beerProvided = 1;",
"goog.provide('hops'); var hopsProvided = 1;",
"goog.provide('scotch'); var scotchProvided = 1;",
"goog.require('scotch');\nvar includeFileWithoutProvides = 1;",
"/** This is base.js */\nvar COMPILED = false;",
},
new String[] {
"var COMPILED = !1;",
"var hops = {}, hopsProvided = 1;",
"var beer = {}, beerProvided = 1;"
});
}
public void testSourceMapExpansion1() {
args.add("--js_output_file");
args.add("/path/to/out.js");
args.add("--create_source_map=%outname%.map");
testSame("var x = 3;");
assertEquals("/path/to/out.js.map",
lastCommandLineRunner.expandSourceMapPath(
lastCompiler.getOptions(), null));
}
public void testSourceMapExpansion2() {
useModules = ModulePattern.CHAIN;
args.add("--create_source_map=%outname%.map");
args.add("--module_output_path_prefix=foo");
testSame(new String[] {"var x = 3;", "var y = 5;"});
assertEquals("foo.map",
lastCommandLineRunner.expandSourceMapPath(
lastCompiler.getOptions(), null));
}
public void testSourceMapExpansion3() {
useModules = ModulePattern.CHAIN;
args.add("--create_source_map=%outname%.map");
args.add("--module_output_path_prefix=foo_");
testSame(new String[] {"var x = 3;", "var y = 5;"});
assertEquals("foo_m0.js.map",
lastCommandLineRunner.expandSourceMapPath(
lastCompiler.getOptions(),
lastCompiler.getModuleGraph().getRootModule()));
}
public void testSourceMapFormat1() {
args.add("--js_output_file");
args.add("/path/to/out.js");
testSame("var x = 3;");
assertEquals(SourceMap.Format.DEFAULT,
lastCompiler.getOptions().sourceMapFormat);
}
public void testSourceMapFormat2() {
args.add("--js_output_file");
args.add("/path/to/out.js");
args.add("--source_map_format=V3");
testSame("var x = 3;");
assertEquals(SourceMap.Format.V3,
lastCompiler.getOptions().sourceMapFormat);
}
public void testModuleWrapperBaseNameExpansion() throws Exception {
useModules = ModulePattern.CHAIN;
args.add("--module_wrapper=m0:%s // %basename%");
testSame(new String[] {
"var x = 3;",
"var y = 4;"
});
StringBuilder builder = new StringBuilder();
lastCommandLineRunner.writeModuleOutput(
builder,
lastCompiler.getModuleGraph().getRootModule());
assertEquals("var x=3; // m0.js\n", builder.toString());
}
public void testCharSetExpansion() {
testSame("");
assertEquals("US-ASCII", lastCompiler.getOptions().outputCharset);
args.add("--charset=UTF-8");
testSame("");
assertEquals("UTF-8", lastCompiler.getOptions().outputCharset);
}
public void testChainModuleManifest() throws Exception {
useModules = ModulePattern.CHAIN;
testSame(new String[] {
"var x = 3;", "var y = 5;", "var z = 7;", "var a = 9;"});
StringBuilder builder = new StringBuilder();
lastCommandLineRunner.printModuleGraphManifestOrBundleTo(
lastCompiler.getModuleGraph(), builder, true);
assertEquals(
"{m0}\n" +
"i0\n" +
"\n" +
"{m1:m0}\n" +
"i1\n" +
"\n" +
"{m2:m1}\n" +
"i2\n" +
"\n" +
"{m3:m2}\n" +
"i3\n",
builder.toString());
}
public void testStarModuleManifest() throws Exception {
useModules = ModulePattern.STAR;
testSame(new String[] {
"var x = 3;", "var y = 5;", "var z = 7;", "var a = 9;"});
StringBuilder builder = new StringBuilder();
lastCommandLineRunner.printModuleGraphManifestOrBundleTo(
lastCompiler.getModuleGraph(), builder, true);
assertEquals(
"{m0}\n" +
"i0\n" +
"\n" +
"{m1:m0}\n" +
"i1\n" +
"\n" +
"{m2:m0}\n" +
"i2\n" +
"\n" +
"{m3:m0}\n" +
"i3\n",
builder.toString());
}
public void testOutputModuleGraphJson() throws Exception {
useModules = ModulePattern.STAR;
testSame(new String[] {
"var x = 3;", "var y = 5;", "var z = 7;", "var a = 9;"});
StringBuilder builder = new StringBuilder();
lastCommandLineRunner.printModuleGraphJsonTo(
lastCompiler.getModuleGraph(), builder);
assertTrue(builder.toString().indexOf("transitive-dependencies") != -1);
}
public void testVersionFlag() {
args.add("--version");
testSame("");
assertEquals(
0,
new String(errReader.toByteArray()).indexOf(
"Closure Compiler (http://code.google.com/closure/compiler)\n" +
"Version: "));
}
public void testVersionFlag2() {
lastArg = "--version";
testSame("");
assertEquals(
0,
new String(errReader.toByteArray()).indexOf(
"Closure Compiler (http://code.google.com/closure/compiler)\n" +
"Version: "));
}
public void testPrintAstFlag() {
args.add("--print_ast=true");
testSame("");
assertEquals(
"digraph AST {\n" +
" node [color=lightblue2, style=filled];\n" +
" node0 [label=\"BLOCK\"];\n" +
" node1 [label=\"SCRIPT\"];\n" +
" node0 -> node1 [weight=1];\n" +
" node1 -> RETURN [label=\"UNCOND\", " +
"fontcolor=\"red\", weight=0.01, color=\"red\"];\n" +
" node0 -> RETURN [label=\"SYN_BLOCK\", " +
"fontcolor=\"red\", weight=0.01, color=\"red\"];\n" +
" node0 -> node1 [label=\"UNCOND\", " +
"fontcolor=\"red\", weight=0.01, color=\"red\"];\n" +
"}\n\n",
new String(outReader.toByteArray()));
}
public void testSyntheticExterns() {
externs = ImmutableList.of(
SourceFile.fromCode("externs", "myVar.property;"));
test("var theirVar = {}; var myVar = {}; var yourVar = {};",
VarCheck.UNDEFINED_EXTERN_VAR_ERROR);
args.add("--jscomp_off=externsValidation");
args.add("--warning_level=VERBOSE");
test("var theirVar = {}; var myVar = {}; var yourVar = {};",
"var theirVar={},myVar={},yourVar={};");
args.add("--jscomp_off=externsValidation");
args.add("--warning_level=VERBOSE");
test("var theirVar = {}; var myVar = {}; var myVar = {};",
SyntacticScopeCreator.VAR_MULTIPLY_DECLARED_ERROR);
}
public void testGoogAssertStripping() {
args.add("--compilation_level=ADVANCED_OPTIMIZATIONS");
test("goog.asserts.assert(false)",
"");
args.add("--debug");
test("goog.asserts.assert(false)", "goog.$asserts$.$assert$(!1)");
}
public void testMissingReturnCheckOnWithVerbose() {
args.add("--warning_level=VERBOSE");
test("/** @return {number} */ function f() {f()} f();",
CheckMissingReturn.MISSING_RETURN_STATEMENT);
}
public void testGenerateExports() {
args.add("--generate_exports=true");
test("/** @export */ foo.prototype.x = function() {};",
"foo.prototype.x=function(){};"+
"goog.exportSymbol(\"foo.prototype.x\",foo.prototype.x);");
}
public void testDepreciationWithVerbose() {
args.add("--warning_level=VERBOSE");
test("/** @deprecated */ function f() {}; f()",
CheckAccessControls.DEPRECATED_NAME);
}
public void testTwoParseErrors() {
// If parse errors are reported in different files, make
// sure all of them are reported.
Compiler compiler = compile(new String[] {
"var a b;",
"var b c;"
});
assertEquals(2, compiler.getErrors().length);
}
public void testES3ByDefault() {
test("var x = f.function", RhinoErrorReporter.PARSE_ERROR);
}
public void testES5ChecksByDefault() {
testSame("var x = 3; delete x;");
}
public void testES5ChecksInVerbose() {
args.add("--warning_level=VERBOSE");
test("function f(x) { delete x; }", StrictModeCheck.DELETE_VARIABLE);
}
public void testES5() {
args.add("--language_in=ECMASCRIPT5");
test("var x = f.function", "var x = f.function");
test("var let", "var let");
}
public void testES5Strict() {
args.add("--language_in=ECMASCRIPT5_STRICT");
test("var x = f.function", "'use strict';var x = f.function");
test("var let", RhinoErrorReporter.PARSE_ERROR);
test("function f(x) { delete x; }", StrictModeCheck.DELETE_VARIABLE);
}
public void testES5StrictUseStrict() {
args.add("--language_in=ECMASCRIPT5_STRICT");
Compiler compiler = compile(new String[] {"var x = f.function"});
String outputSource = compiler.toSource();
assertEquals("'use strict'", outputSource.substring(0, 12));
}
public void testES5StrictUseStrictMultipleInputs() {
args.add("--language_in=ECMASCRIPT5_STRICT");
Compiler compiler = compile(new String[] {"var x = f.function",
"var y = f.function", "var z = f.function"});
String outputSource = compiler.toSource();
assertEquals("'use strict'", outputSource.substring(0, 12));
assertEquals(outputSource.substring(13).indexOf("'use strict'"), -1);
}
public void testWithKeywordDefault() {
test("var x = {}; with (x) {}", ControlStructureCheck.USE_OF_WITH);
}
public void testWithKeywordWithEs5ChecksOff() {
args.add("--jscomp_off=es5Strict");
testSame("var x = {}; with (x) {}");
}
public void testNoSrCFilesWithManifest() throws IOException {
args.add("--use_only_custom_externs=true");
args.add("--output_manifest=test.MF");
CommandLineRunner runner = createCommandLineRunner(new String[0]);
String expectedMessage = "";
try {
runner.doRun();
} catch (FlagUsageException e) {
expectedMessage = e.getMessage();
}
assertEquals(expectedMessage, "Bad --js flag. " +
"Manifest files cannot be generated when the input is from stdin.");
}
public void testTransformAMD() {
args.add("--transform_amd_modules");
test("define({test: 1})", "exports = {test: 1}");
}
public void testProcessCJS() {
useStringComparison = true;
args.add("--process_common_js_modules");
args.add("--common_js_entry_module=foo/bar");
setFilename(0, "foo/bar.js");
String expected = "var module$foo$bar={test:1};";
test("exports.test = 1", expected);
assertEquals(expected + "\n", outReader.toString());
}
public void testProcessCJSWithModuleOutput() {
useStringComparison = true;
args.add("--process_common_js_modules");
args.add("--common_js_entry_module=foo/bar");
args.add("--module=auto");
setFilename(0, "foo/bar.js");
test("exports.test = 1",
"var module$foo$bar={test:1};");
// With modules=auto no direct output is created.
assertEquals("", outReader.toString());
}
public void testFormattingSingleQuote() {
testSame("var x = '';");
assertEquals("var x=\"\";", lastCompiler.toSource());
args.add("--formatting=SINGLE_QUOTES");
testSame("var x = '';");
assertEquals("var x='';", lastCompiler.toSource());
}
public void testTransformAMDAndProcessCJS() {
useStringComparison = true;
args.add("--transform_amd_modules");
args.add("--process_common_js_modules");
args.add("--common_js_entry_module=foo/bar");
setFilename(0, "foo/bar.js");
test("define({foo: 1})",
"var module$foo$bar={},module$foo$bar={foo:1};");
}
public void testModuleJSON() {
useStringComparison = true;
args.add("--transform_amd_modules");
args.add("--process_common_js_modules");
args.add("--common_js_entry_module=foo/bar");
args.add("--output_module_dependencies=test.json");
setFilename(0, "foo/bar.js");
test("define({foo: 1})",
"var module$foo$bar={},module$foo$bar={foo:1};");
}
public void testOutputSameAsInput() {
args.add("--js_output_file=" + getFilename(0));
test("", AbstractCommandLineRunner.OUTPUT_SAME_AS_INPUT_ERROR);
}
/* Helper functions */
private void testSame(String original) {
testSame(new String[] { original });
}
private void testSame(String[] original) {
test(original, original);
}
private void test(String original, String compiled) {
test(new String[] { original }, new String[] { compiled });
}
/**
* Asserts that when compiling with the given compiler options,
* {@code original} is transformed into {@code compiled}.
*/
private void test(String[] original, String[] compiled) {
test(original, compiled, null);
}
/**
* Asserts that when compiling with the given compiler options,
* {@code original} is transformed into {@code compiled}.
* If {@code warning} is non-null, we will also check if the given
* warning type was emitted.
*/
private void test(String[] original, String[] compiled,
DiagnosticType warning) {
Compiler compiler = compile(original);
if (warning == null) {
assertEquals("Expected no warnings or errors\n" +
"Errors: \n" + Joiner.on("\n").join(compiler.getErrors()) +
"Warnings: \n" + Joiner.on("\n").join(compiler.getWarnings()),
0, compiler.getErrors().length + compiler.getWarnings().length);
} else {
assertEquals(1, compiler.getWarnings().length);
assertEquals(warning, compiler.getWarnings()[0].getType());
}
Node root = compiler.getRoot().getLastChild();
if (useStringComparison) {
assertEquals(Joiner.on("").join(compiled), compiler.toSource());
} else {
Node expectedRoot = parse(compiled);
String explanation = expectedRoot.checkTreeEquals(root);
assertNull("\nExpected: " + compiler.toSource(expectedRoot) +
"\nResult: " + compiler.toSource(root) +
"\n" + explanation, explanation);
}
}
/**
* Asserts that when compiling, there is an error or warning.
*/
private void test(String original, DiagnosticType warning) {
test(new String[] { original }, warning);
}
private void test(String original, String expected, DiagnosticType warning) {
test(new String[] { original }, new String[] { expected }, warning);
}
/**
* Asserts that when compiling, there is an error or warning.
*/
private void test(String[] original, DiagnosticType warning) {
Compiler compiler = compile(original);
assertEquals("Expected exactly one warning or error " +
"Errors: \n" + Joiner.on("\n").join(compiler.getErrors()) +
"Warnings: \n" + Joiner.on("\n").join(compiler.getWarnings()),
1, compiler.getErrors().length + compiler.getWarnings().length);
assertTrue(exitCodes.size() > 0);
int lastExitCode = exitCodes.get(exitCodes.size() - 1);
if (compiler.getErrors().length > 0) {
assertEquals(1, compiler.getErrors().length);
assertEquals(warning, compiler.getErrors()[0].getType());
assertEquals(1, lastExitCode);
} else {
assertEquals(1, compiler.getWarnings().length);
assertEquals(warning, compiler.getWarnings()[0].getType());
assertEquals(0, lastExitCode);
}
}
private CommandLineRunner createCommandLineRunner(String[] original) {
for (int i = 0; i < original.length; i++) {
args.add("--js");
args.add("/path/to/input" + i + ".js");
if (useModules == ModulePattern.CHAIN) {
args.add("--module");
args.add("m" + i + ":1" + (i > 0 ? (":m" + (i - 1)) : ""));
} else if (useModules == ModulePattern.STAR) {
args.add("--module");
args.add("m" + i + ":1" + (i > 0 ? ":m0" : ""));
}
}
if (lastArg != null) {
args.add(lastArg);
}
String[] argStrings = args.toArray(new String[] {});
return new CommandLineRunner(
argStrings,
new PrintStream(outReader),
new PrintStream(errReader));
}
private Compiler compile(String[] original) {
CommandLineRunner runner = createCommandLineRunner(original);
assertTrue(new String(errReader.toByteArray()), runner.shouldRunCompiler());
Supplier<List<SourceFile>> inputsSupplier = null;
Supplier<List<JSModule>> modulesSupplier = null;
if (useModules == ModulePattern.NONE) {
List<SourceFile> inputs = Lists.newArrayList();
for (int i = 0; i < original.length; i++) {
inputs.add(SourceFile.fromCode(getFilename(i), original[i]));
}
inputsSupplier = Suppliers.ofInstance(inputs);
} else if (useModules == ModulePattern.STAR) {
modulesSupplier = Suppliers.<List<JSModule>>ofInstance(
Lists.<JSModule>newArrayList(
CompilerTestCase.createModuleStar(original)));
} else if (useModules == ModulePattern.CHAIN) {
modulesSupplier = Suppliers.<List<JSModule>>ofInstance(
Lists.<JSModule>newArrayList(
CompilerTestCase.createModuleChain(original)));
} else {
throw new IllegalArgumentException("Unknown module type: " + useModules);
}
runner.enableTestMode(
Suppliers.<List<SourceFile>>ofInstance(externs),
inputsSupplier,
modulesSupplier,
new Function<Integer, Boolean>() {
@Override
public Boolean apply(Integer code) {
return exitCodes.add(code);
}
});
runner.run();
lastCompiler = runner.getCompiler();
lastCommandLineRunner = runner;
return lastCompiler;
}
private Node parse(String[] original) {
String[] argStrings = args.toArray(new String[] {});
CommandLineRunner runner = new CommandLineRunner(argStrings);
Compiler compiler = runner.createCompiler();
List<SourceFile> inputs = Lists.newArrayList();
for (int i = 0; i < original.length; i++) {
inputs.add(SourceFile.fromCode(getFilename(i), original[i]));
}
CompilerOptions options = new CompilerOptions();
// ECMASCRIPT5 is the most forgiving.
options.setLanguageIn(LanguageMode.ECMASCRIPT5);
compiler.init(externs, inputs, options);
Node all = compiler.parseInputs();
Preconditions.checkState(compiler.getErrorCount() == 0);
Preconditions.checkNotNull(all);
Node n = all.getLastChild();
return n;
}
private void setFilename(int i, String filename) {
this.filenames.put(i, filename);
}
private String getFilename(int i) {
if (filenames.isEmpty()) {
return "input" + i;
}
return filenames.get(i);
}
}