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/AliasExternalsTest.java
github-classroom[bot] e42e547e48
Initial commit
2023-04-25 11:33:41 +00:00

396 lines
13 KiB
Java

/*
* Copyright 2006 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;
/**
* Tests for {@link AliasExternals}.
*
*/
public class AliasExternalsTest extends CompilerTestCase {
private static String EXTERNS =
// Globals
"/** @const */ var window;" +
"/** @const */ var document;" +
"var arguments;var _USER_ID;var ActiveXObject;" +
"function eval(x) {}" +
// Properties
"window.setTimeout;" +
"window.eval;" +
"props.window;props.innerHTML;props.length;props.prototype;props.length;" +
// More globals
"/** @noalias */ var RangeObject; " +
"var /** @noalias */ RuntimeObject, SelectionObject;" +
"/** @noalias */ function NoAliasFunction() {};";
// Blacklist and whitelist of globals. Assign to these before running test
// if you want to factor them in to the test, otherwise they will be null.
private String unaliasableGlobals;
private String aliasableGlobals;
public AliasExternalsTest() {
super(EXTERNS);
}
@Override
protected int getNumRepetitions() {
// This pass only runs once.
return 1;
}
@Override
public void setUp() {
super.enableLineNumberCheck(false);
super.enableNormalize();
unaliasableGlobals = null;
aliasableGlobals = null;
}
/**
* Test standard global aliasing.
*/
public void testGlobalAlias() {
test("window.setTimeout(function() {}, 0);" +
"var doc=window.document;" +
"window.alert(\"foo\");" +
"window.eval(\"1\");" +
"window.location.href=\"http://www.example.com\";" +
"function foo() {var window = \"bar\"; return window}foo();",
"var GLOBAL_window=window;" +
formatPropNameDecl("setTimeout") +
"GLOBAL_window[$$PROP_setTimeout](function() {}, 0);" +
"var doc=GLOBAL_window.document;" +
"GLOBAL_window.alert(\"foo\");" +
"GLOBAL_window.eval(\"1\");" +
"GLOBAL_window.location.href=\"http://www.example.com\";" +
"function foo() {var window = \"bar\"; return window}foo();");
}
/**
* Some globals should not be aliased because they have special meaning
* within the language (like arguments).
*/
public void testUnaliasable() {
test("function foo() {" +
"var x=arguments.length;" +
"var y=arguments.length;" +
"var z=arguments.length;" +
"var w=arguments.length;" +
"return x + y + z + w" +
"};foo();",
formatPropNameDecl("length") +
"function foo() {" +
"var x=arguments[$$PROP_length];" +
"var y=arguments[$$PROP_length];" +
"var z=arguments[$$PROP_length];" +
"var w=arguments[$$PROP_length];" +
"return x + y + z + w" +
"};foo();");
test("var x=new ActiveXObject();" +
"x.foo=\"bar\";" +
"var y=new ActiveXObject();" +
"y.foo=\"bar\";" +
"var z=new ActiveXObject();" +
"z.foo=\"bar\";",
"var x=new ActiveXObject();" +
"x.foo=\"bar\";" +
"var y=new ActiveXObject();" +
"y.foo=\"bar\";" +
"var z=new ActiveXObject();" +
"z.foo=\"bar\";");
test("var _a=eval('foo'),_b=eval('foo'),_c=eval('foo'),_d=eval('foo')," +
"_e=eval('foo'),_f=eval('foo'),_g=eval('foo');",
"var _a=eval('foo'),_b=eval('foo'),_c=eval('foo'),_d=eval('foo')," +
"_e=eval('foo'),_f=eval('foo'),_g=eval('foo');");
}
/**
* Test using a whitelist to explicitly alias only specific
* identifiers.
*/
public void testAliasableGlobals() {
aliasableGlobals = "notused,length";
test("function foo() {" +
"var x=arguments.length;" +
"var y=arguments.length;" +
"var z=arguments.length;" +
"var w=arguments.length;" +
"return x + y + z + w" +
"};foo();",
formatPropNameDecl("length") +
"function foo() {" +
"var x=arguments[$$PROP_length];" +
"var y=arguments[$$PROP_length];" +
"var z=arguments[$$PROP_length];" +
"var w=arguments[$$PROP_length];" +
"return x + y + z + w" +
"};foo();");
aliasableGlobals = "notused,notlength";
test("function foo() {" +
"var x=arguments.length;" +
"var y=arguments.length;" +
"var z=arguments.length;" +
"var w=arguments.length;" +
"return x + y + z + w" +
"};foo();",
"function foo() {" +
"var x=arguments.length;" +
"var y=arguments.length;" +
"var z=arguments.length;" +
"var w=arguments.length;" +
"return x + y + z + w" +
"};foo();");
}
/**
* Test combined usage of aliasable and unaliasable global lists.
*/
public void testAliasableAndUnaliasableGlobals() {
// Only aliasable provided - OK
aliasableGlobals = "foo,bar";
unaliasableGlobals = "";
test("var x;", "var x;");
// Only unaliasable provided - OK
aliasableGlobals = "";
unaliasableGlobals = "baz,qux";
test("var x;", "var x;");
// Both provided - bad
aliasableGlobals = "foo,bar";
unaliasableGlobals = "baz,qux";
try {
test("var x;", "var x;");
fail("Expected an IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// pass
}
}
/**
* Global variables that get re-assigned should not be aliased.
*/
public void testGlobalAssigment() {
test("var x=_USER_ID+window;" +
"var y=_USER_ID+window;" +
"var z=_USER_ID+window;" +
"var w=x+y+z;" +
"_USER_ID = \"foo\";" +
"window++;",
"var x=_USER_ID+window;" +
"var y=_USER_ID+window;" +
"var z=_USER_ID+window;" +
"var w=x+y+z;" +
"_USER_ID = \"foo\";" +
"window++");
}
public void testNewOperator() {
test("var x;new x(window);window;window;window;window;window",
"var GLOBAL_window=window; var x;" +
" new x(GLOBAL_window);GLOBAL_window;GLOBAL_window;" +
" GLOBAL_window;GLOBAL_window;GLOBAL_window");
}
/**
* Test the standard replacement for GETPROP
*/
public void testGetProp() {
test("function foo(a,b){return a.length > b.length;}",
formatPropNameDecl("length") +
"function foo(a, b){return a[$$PROP_length] > b[$$PROP_length];}");
test("Foo.prototype.bar = function() { return 'foo'; }",
formatPropNameDecl("prototype") +
"Foo[$$PROP_prototype].bar = function() { return 'foo'; }");
test("Foo.notreplaced = 5", "Foo.notreplaced=5");
}
/**
* Ops that should be ignored
*/
public void testIgnoredOps() {
testSame("function foo() { this.length-- }");
testSame("function foo() { this.length++ }");
testSame("function foo() { this.length+=5 }");
testSame("function foo() { this.length-=5 }");
}
/**
* Test property setting
*/
public void testSetProp() {
test("function foo() { this.innerHTML = 'hello!'; }",
formatSetPropFn("innerHTML")
+ "function foo() { SETPROP_innerHTML(this, 'hello!'); }");
}
/**
* Test for modifying both parent and child, as all replacements
* are on a single pass and modifying both involves being careful with
* references.
*/
public void testParentChild() {
test("a.length = b.length = c.length;", formatSetPropFn("length")
+ formatPropNameDecl("length")
+ "SETPROP_length(a, SETPROP_length(b, c[$$PROP_length]))");
}
private static final String MODULE_SRC_ONE =
"a=b.length;a=b.length;a=b.length;";
private static final String MODULE_SRC_TWO = "c=d.length;";
/**
* Test that the code is placed in the first module when there are no
* dependencies.
*/
public void testModulesWithoutDependencies() {
test(createModules(MODULE_SRC_ONE, MODULE_SRC_TWO),
new String[] {
"var $$PROP_length=\"length\";a=b[$$PROP_length];" +
"a=b[$$PROP_length];a=b[$$PROP_length];",
"c=d[$$PROP_length];"});
}
/**
* Test that the code is placed in the first module when the second module
* depends on the first.
*/
public void testModulesWithDependencies() {
test(createModuleChain(MODULE_SRC_ONE, MODULE_SRC_TWO),
new String[] {
"var $$PROP_length=\"length\";a=b[$$PROP_length];" +
"a=b[$$PROP_length];a=b[$$PROP_length];",
"c=d[$$PROP_length];"});
}
public void testPropAccessorPushedDeeper1() {
test(createModuleChain("var a = \"foo\";", "var b = a.length;"),
new String[] {
"var a = \"foo\";",
formatPropNameDecl("length") + "var b = a[$$PROP_length]" });
}
public void testPropAccessorPushedDeeper2() {
test(createModuleChain(
"var a = \"foo\";", "var b = a.length;", "var c = a.length;"),
new String[] {
"var a = \"foo\";",
formatPropNameDecl("length") + "var b = a[$$PROP_length]",
"var c = a[$$PROP_length]" });
}
public void testPropAccessorPushedDeeper3() {
test(createModuleStar(
"var a = \"foo\";", "var b = a.length;", "var c = a.length;"),
new String[] {
formatPropNameDecl("length") + "var a = \"foo\";",
"var b = a[$$PROP_length]",
"var c = a[$$PROP_length]" });
}
public void testPropAccessorNotPushedDeeper() {
test(createModuleChain("var a = \"foo\"; var b = a.length;",
"var c = a.length;"),
new String[] {
formatPropNameDecl("length") +
"var a = \"foo\"; var b = a[$$PROP_length]",
"var c = a[$$PROP_length]" });
}
public void testPropMutatorPushedDeeper() {
test(createModuleChain("var a = [1];", "a.length = 0;"),
new String[] {
"var a = [1];",
formatSetPropFn("length") + "SETPROP_length(a, 0);" });
}
public void testPropMutatorNotPushedDeeper() {
test(createModuleChain(
"var a = [1]; a.length = 1;", "a.length = 0;"),
new String[] {
formatSetPropFn("length") + "var a = [1]; SETPROP_length(a, 1);",
"SETPROP_length(a, 0);" });
}
public void testGlobalAliasPushedDeeper() {
test(createModuleChain(
"var a = 1;",
"var b = window, c = window, d = window, e = window;"),
new String[] { "var a = 1;",
"var GLOBAL_window = window;" +
"var b = GLOBAL_window, c = GLOBAL_window, " +
" d = GLOBAL_window, e = GLOBAL_window;" });
}
public void testGlobalAliasNotPushedDeeper() {
test(createModuleChain(
"var a = 1, b = window;",
"var c = window, d = window, e = window;"),
new String[] { "var GLOBAL_window = window;" +
"var a = 1, b = GLOBAL_window;",
"var c = GLOBAL_window, " +
" d = GLOBAL_window, e = GLOBAL_window;" });
}
public void testNoAliasAnnotationForSingleVar() {
testSame("[RangeObject, RangeObject, RangeObject]");
}
public void testNoAliasAnnotationForMultiVarDeclaration() {
test("[RuntimeObject, RuntimeObject, RuntimeObject," +
" SelectionObject, SelectionObject, SelectionObject]",
"var GLOBAL_SelectionObject = SelectionObject;" +
"[RuntimeObject, RuntimeObject, RuntimeObject," +
" GLOBAL_SelectionObject, GLOBAL_SelectionObject," +
" GLOBAL_SelectionObject]");
}
public void testNoAliasAnnotationForFunction() {
testSame("[NoAliasFunction(), NoAliasFunction(), NoAliasFunction()]");
}
private String formatPropNameDecl(String prop) {
return "var $$PROP_" + prop + "='" + prop + "';";
}
private String formatSetPropFn(String prop) {
String mutatorName = "SETPROP_" + prop;
String arg1 = mutatorName + "$a";
String arg2 = mutatorName + "$b";
return "function " + mutatorName + "(" + arg1 + "," + arg2 + ") {" +
"return " + arg1 + "." + prop + "=" + arg2 + ";}";
}
@Override
protected CompilerPass getProcessor(Compiler compiler) {
AliasExternals ae = new AliasExternals(
compiler, compiler.getModuleGraph(),
unaliasableGlobals, aliasableGlobals);
ae.setRequiredUsage(1);
return ae;
}
}