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

600 lines
18 KiB
Java

/*
* Copyright 2008 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.collect.Maps;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.rhino.Node;
import java.util.Map;
/**
* Unit test for AmbiguateProperties Compiler pass.
*
*/
public class AmbiguatePropertiesTest extends CompilerTestCase {
private AmbiguateProperties lastPass;
private static final String EXTERNS =
"Function.prototype.call=function(){};" +
"Function.prototype.inherits=function(){};" +
"prop.toString;" +
"var google = { gears: { factory: {}, workerPool: {} } };";
public AmbiguatePropertiesTest() {
super(EXTERNS);
enableNormalize();
enableTypeCheck(CheckLevel.WARNING);
enableClosurePass();
}
@Override
public CompilerPass getProcessor(final Compiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
lastPass = new AmbiguateProperties(compiler, new char[]{'$'});
lastPass.process(externs, root);
}
};
}
@Override
protected int getNumRepetitions() {
return 1;
}
@Override
protected CompilerOptions getOptions() {
// no missing properties check
CompilerOptions options = new CompilerOptions();
options.setLanguageIn(LanguageMode.ECMASCRIPT5);
return options;
}
public void testOneVar1() {
test("/** @constructor */ var Foo = function(){};Foo.prototype.b = 0;",
"var Foo = function(){};Foo.prototype.a = 0;");
}
public void testOneVar2() {
testSame("/** @constructor */ var Foo = function(){};" +
"Foo.prototype = {b: 0};");
}
public void testOneVar3() {
testSame("/** @constructor */ var Foo = function(){};" +
"Foo.prototype = {get b() {return 0}};");
}
public void testOneVar4() {
testSame("/** @constructor */ var Foo = function(){};" +
"Foo.prototype = {set b(a) {}};");
}
public void testTwoVar1() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.z=0;\n"
+ "Foo.prototype.z=0;\n"
+ "Foo.prototype.x=0;";
String output = ""
+ "var Foo = function(){};\n"
+ "Foo.prototype.a=0;\n"
+ "Foo.prototype.a=0;\n"
+ "Foo.prototype.b=0;";
test(js, output);
}
public void testTwoVar2() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype={z:0, z:1, x:0};\n";
// TODO(johnlenz): It would be nice to handle this type of declaration.
testSame(js);
}
public void testTwoIndependentVar() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.b = 0;\n"
+ "/** @constructor */ var Bar = function(){};\n"
+ "Bar.prototype.c = 0;";
String output = ""
+ "var Foo = function(){};"
+ "Foo.prototype.a=0;"
+ "var Bar = function(){};"
+ "Bar.prototype.a=0;";
test(js, output);
}
public void testTwoTypesTwoVar() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.r = 0;\n"
+ "Foo.prototype.g = 0;\n"
+ "/** @constructor */ var Bar = function(){};\n"
+ "Bar.prototype.c = 0;"
+ "Bar.prototype.r = 0;";
String output = ""
+ "var Foo = function(){};"
+ "Foo.prototype.a=0;"
+ "Foo.prototype.b=0;"
+ "var Bar = function(){};"
+ "Bar.prototype.b=0;"
+ "Bar.prototype.a=0;";
test(js, output);
}
public void testUnion() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "/** @constructor */ var Bar = function(){};\n"
+ "Foo.prototype.foodoo=0;\n"
+ "Bar.prototype.bardoo=0;\n"
+ "/** @type {Foo|Bar} */\n"
+ "var U;\n"
+ "U.joint;"
+ "U.joint";
String output = ""
+ "var Foo = function(){};\n"
+ "var Bar = function(){};\n"
+ "Foo.prototype.b=0;\n"
+ "Bar.prototype.b=0;\n"
+ "var U;\n"
+ "U.a;"
+ "U.a";
test(js, output);
}
public void testUnions() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "/** @constructor */ var Bar = function(){};\n"
+ "/** @constructor */ var Baz = function(){};\n"
+ "/** @constructor */ var Bat = function(){};\n"
+ "Foo.prototype.lone1=0;\n"
+ "Bar.prototype.lone2=0;\n"
+ "Baz.prototype.lone3=0;\n"
+ "Bat.prototype.lone4=0;\n"
+ "/** @type {Foo|Bar} */\n"
+ "var U1;\n"
+ "U1.j1;"
+ "U1.j2;"
+ "/** @type {Baz|Bar} */\n"
+ "var U2;\n"
+ "U2.j3;"
+ "U2.j4;"
+ "/** @type {Baz|Bat} */\n"
+ "var U3;"
+ "U3.j5;"
+ "U3.j6";
String output = ""
+ "var Foo = function(){};\n"
+ "var Bar = function(){};\n"
+ "var Baz = function(){};\n"
+ "var Bat = function(){};\n"
+ "Foo.prototype.c=0;\n"
+ "Bar.prototype.e=0;\n"
+ "Baz.prototype.e=0;\n"
+ "Bat.prototype.c=0;\n"
+ "var U1;\n"
+ "U1.a;"
+ "U1.b;"
+ "var U2;\n"
+ "U2.c;"
+ "U2.d;"
+ "var U3;"
+ "U3.a;"
+ "U3.b";
test(js, output);
}
public void testExtends() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.x=0;\n"
+ "/** @constructor \n @extends Foo */ var Bar = function(){};\n"
+ "goog.inherits(Bar, Foo);\n"
+ "Bar.prototype.y=0;\n"
+ "Bar.prototype.z=0;\n"
+ "/** @constructor */ var Baz = function(){};\n"
+ "Baz.prototype.l=0;\n"
+ "Baz.prototype.m=0;\n"
+ "Baz.prototype.n=0;\n"
+ "(new Baz).m\n";
String output = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.a=0;\n"
+ "/** @constructor \n @extends Foo */ var Bar = function(){};\n"
+ "goog.inherits(Bar, Foo);\n"
+ "Bar.prototype.b=0;\n"
+ "Bar.prototype.c=0;\n"
+ "/** @constructor */ var Baz = function(){};\n"
+ "Baz.prototype.b=0;\n"
+ "Baz.prototype.a=0;\n"
+ "Baz.prototype.c=0;\n"
+ "(new Baz).a\n";
test(js, output);
}
public void testLotsOfVars() {
StringBuilder js = new StringBuilder();
StringBuilder output = new StringBuilder();
js.append("/** @constructor */ var Foo = function(){};\n");
js.append("/** @constructor */ var Bar = function(){};\n");
output.append(js.toString());
int vars = 10;
for (int i = 0; i < vars; i++) {
js.append("Foo.prototype.var" + i + " = 0;");
js.append("Bar.prototype.var" + (i + 10000) + " = 0;");
output.append("Foo.prototype." + (char) ('a' + i) + "=0;");
output.append("Bar.prototype." + (char) ('a' + i) + "=0;");
}
test(js.toString(), output.toString());
}
public void testLotsOfClasses() {
StringBuilder b = new StringBuilder();
int classes = 10;
for (int i = 0; i < classes; i++) {
String c = "Foo" + i;
b.append("/** @constructor */ var " + c + " = function(){};\n");
b.append(c + ".prototype.varness" + i + " = 0;");
}
String js = b.toString();
test(js, js.replaceAll("varness\\d+", "a"));
}
public void testFunctionType() {
String js = ""
+ "/** @constructor */ function Foo(){};\n"
+ "/** @return {Bar} */\n"
+ "Foo.prototype.fun = function() { return new Bar(); };\n"
+ "/** @constructor */ function Bar(){};\n"
+ "Bar.prototype.bazz;\n"
+ "(new Foo).fun().bazz();";
String output = ""
+ "function Foo(){};\n"
+ "Foo.prototype.a = function() { return new Bar(); };\n"
+ "function Bar(){};\n"
+ "Bar.prototype.a;\n"
+ "(new Foo).a().a();";
test(js, output);
}
public void testPrototypePropertiesAsObjLitKeys1() {
test("/** @constructor */ function Bar() {};" +
"Bar.prototype = {2: function(){}, getA: function(){}};",
"/** @constructor */ function Bar() {};" +
"Bar.prototype = {2: function(){}, a: function(){}};");
}
public void testPrototypePropertiesAsObjLitKeys2() {
testSame("/** @constructor */ function Bar() {};" +
"Bar.prototype = {2: function(){}, 'getA': function(){}};");
}
public void testQuotedPrototypeProperty() {
testSame("/** @constructor */ function Bar() {};" +
"Bar.prototype['getA'] = function(){};" +
"var bar = new Bar();" +
"bar['getA']();");
}
public void testOverlappingOriginalAndGeneratedNames() {
test("/** @constructor */ function Bar(){};"
+ "Bar.prototype.b = function(){};"
+ "Bar.prototype.a = function(){};"
+ "var bar = new Bar();"
+ "bar.b();",
"function Bar(){};"
+ "Bar.prototype.a = function(){};"
+ "Bar.prototype.b = function(){};"
+ "var bar = new Bar();"
+ "bar.a();");
}
public void testPropertyAddedToObject() {
testSame("var foo = {}; foo.prop = '';");
}
public void testPropertyAddedToFunction() {
test("var foo = function(){}; foo.prop = '';",
"var foo = function(){}; foo.a = '';");
}
public void testPropertyOfObjectOfUnknownType() {
testSame("var foo = x(); foo.prop = '';");
}
public void testPropertyOnParamOfUnknownType() {
testSame("/** @constructor */ function Foo(){};\n"
+ "Foo.prototype.prop = 0;"
+ "function go(aFoo){\n"
+ " aFoo.prop = 1;"
+ "}");
}
public void testSetPropertyOfGlobalThis() {
testSame("this.prop = 'bar'");
}
public void testReadPropertyOfGlobalThis() {
testSame("f(this.prop);");
}
public void testSetQuotedPropertyOfThis() {
testSame("this['prop'] = 'bar';");
}
public void testExternedPropertyName() {
test("/** @constructor */ var Bar = function(){};"
+ "/** @override */ Bar.prototype.toString = function(){};"
+ "Bar.prototype.func = function(){};"
+ "var bar = new Bar();"
+ "bar.toString();",
"var Bar = function(){};"
+ "Bar.prototype.toString = function(){};"
+ "Bar.prototype.a = function(){};"
+ "var bar = new Bar();"
+ "bar.toString();");
}
public void testExternedPropertyNameDefinedByObjectLiteral() {
testSame("/**@constructor*/function Bar(){};Bar.prototype.factory");
}
public void testStaticAndInstanceMethodWithSameName() {
test("/** @constructor */function Bar(){}; Bar.getA = function(){}; " +
"Bar.prototype.getA = function(){}; Bar.getA();" +
"var bar = new Bar(); bar.getA();",
"function Bar(){}; Bar.a = function(){};" +
"Bar.prototype.a = function(){}; Bar.a();" +
"var bar = new Bar(); bar.a();");
}
public void testStaticAndInstanceProperties() {
test("/** @constructor */function Bar(){};" +
"Bar.getA = function(){}; " +
"Bar.prototype.getB = function(){};",
"function Bar(){}; Bar.a = function(){};" +
"Bar.prototype.a = function(){};");
}
public void testStaticAndSubInstanceProperties() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.x=0;\n"
+ "/** @constructor \n @extends Foo */ var Bar = function(){};\n"
+ "goog.inherits(Bar, Foo);\n"
+ "Bar.y=0;\n"
+ "Bar.prototype.z=0;\n";
String output = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.a=0;\n"
+ "/** @constructor \n @extends Foo */ var Bar = function(){};\n"
+ "goog.inherits(Bar, Foo);\n"
+ "Bar.a=0;\n"
+ "Bar.prototype.a=0;\n";
test(js, output);
}
public void testStaticWithFunctions() {
String js = ""
+ "/** @constructor */ var Foo = function() {};\n"
+ "Foo.x = 0;"
+ "/** @param {!Function} x */ function f(x) { x.y = 1 }"
+ "f(Foo)";
String output = ""
+ "/** @constructor */ var Foo = function() {};\n"
+ "Foo.a = 0;"
+ "/** @param {!Function} x */ function f(x) { x.y = 1 }"
+ "f(Foo)";
test(js, output);
js = ""
+ "/** @constructor */ var Foo = function() {};\n"
+ "Foo.x = 0;"
+ "/** @param {!Function} x */ function f(x) { x.y = 1; x.x = 2;}"
+ "f(Foo)";
test(js, js);
js = ""
+ "/** @constructor */ var Foo = function() {};\n"
+ "Foo.x = 0;"
+ "/** @constructor */ var Bar = function() {};\n"
+ "Bar.y = 0;";
output = ""
+ "/** @constructor */ var Foo = function() {};\n"
+ "Foo.a = 0;"
+ "/** @constructor */ var Bar = function() {};\n"
+ "Bar.a = 0;";
test(js, output);
}
public void testTypeMismatch() {
testSame(EXTERNS, "/** @constructor */var Foo = function(){};\n"
+ "/** @constructor */var Bar = function(){};\n"
+ "Foo.prototype.b = 0;\n"
+ "/** @type {Foo} */\n"
+ "var F = new Bar();",
TypeValidator.TYPE_MISMATCH_WARNING,
"initializing variable\n"
+ "found : Bar\n"
+ "required: (Foo|null)");
}
public void testRenamingMap() {
String js = ""
+ "/** @constructor */ var Foo = function(){};\n"
+ "Foo.prototype.z=0;\n"
+ "Foo.prototype.z=0;\n"
+ "Foo.prototype.x=0;\n"
+ "Foo.prototype.y=0;";
String output = ""
+ "var Foo = function(){};\n"
+ "Foo.prototype.a=0;\n"
+ "Foo.prototype.a=0;\n"
+ "Foo.prototype.b=0;\n"
+ "Foo.prototype.c=0;";
test(js, output);
Map<String, String> answerMap = Maps.newHashMap();
answerMap.put("x", "b");
answerMap.put("y", "c");
answerMap.put("z", "a");
assertEquals(answerMap, lastPass.getRenamingMap());
}
public void testInline() {
String js = ""
+ "/** @interface */ function Foo(){}\n"
+ "Foo.prototype.x = function(){};\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @implements {Foo}\n"
+ " */\n"
+ "function Bar(){}\n"
+ "/** @inheritDoc */\n"
+ "Bar.prototype.x = function() { return this.y; };\n"
+ "Bar.prototype.z = function() {};\n"
// Simulates inline getters.
+ "/** @type {Foo} */ (new Bar).y;";
String output = ""
+ "function Foo(){}\n"
+ "Foo.prototype.a = function(){};\n"
+ "function Bar(){}\n"
+ "Bar.prototype.a = function() { return this.b; };\n"
+ "Bar.prototype.c = function() {};\n"
// Simulates inline getters.
+ "(new Bar).b;";
test(js, output);
}
public void testImplementsAndExtends() {
String js = ""
+ "/** @interface */ function Foo() {}\n"
+ "/**\n"
+ " * @constructor\n"
+ " */\n"
+ "function Bar(){}\n"
+ "Bar.prototype.y = function() { return 3; };\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {Bar}\n"
+ " * @implements {Foo}\n"
+ " */\n"
+ "function SubBar(){ }\n"
+ "/** @param {Foo} x */ function f(x) { x.z = 3; }\n"
+ "/** @param {SubBar} x */ function g(x) { x.z = 3; }";
String output = ""
+ "function Foo(){}\n"
+ "function Bar(){}\n"
+ "Bar.prototype.b = function() { return 3; };\n"
+ "function SubBar(){}\n"
+ "function f(x) { x.a = 3; }\n"
+ "function g(x) { x.a = 3; }";
test(js, output);
}
public void testImplementsAndExtends2() {
String js = ""
+ "/** @interface */ function A() {}\n"
+ "/**\n"
+ " * @constructor\n"
+ " */\n"
+ "function C1(){}\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {C1}\n"
+ " * @implements {A}\n"
+ " */\n"
+ "function C2(){}\n"
+ "/** @param {C1} x */ function f(x) { x.y = 3; }\n"
+ "/** @param {A} x */ function g(x) { x.z = 3; }\n";
String output = ""
+ "function A(){}\n"
+ "function C1(){}\n"
+ "function C2(){}\n"
+ "function f(x) { x.a = 3; }\n"
+ "function g(x) { x.b = 3; }\n";
test(js, output);
}
public void testExtendsInterface() {
String js = ""
+ "/** @interface */ function A() {}\n"
+ "/** @interface \n @extends {A} */ function B() {}\n"
+ "/** @param {A} x */ function f(x) { x.y = 3; }\n"
+ "/** @param {B} x */ function g(x) { x.z = 3; }\n";
String output = ""
+ "function A(){}\n"
+ "function B(){}\n"
+ "function f(x) { x.a = 3; }\n"
+ "function g(x) { x.b = 3; }\n";
test(js, output);
}
public void testFunctionSubType() {
String js = ""
+ "Function.prototype.a = 1;\n"
+ "function f() {}\n"
+ "f.y = 2;\n";
String output = ""
+ "Function.prototype.a = 1;\n"
+ "function f() {}\n"
+ "f.b = 2;\n";
test(js, output);
}
public void testFunctionSubType2() {
String js = ""
+ "Function.prototype.a = 1;\n"
+ "/** @constructor */ function F() {}\n"
+ "F.y = 2;\n";
String output = ""
+ "Function.prototype.a = 1;\n"
+ "function F() {}\n"
+ "F.b = 2;\n";
test(js, output);
}
public void testPredeclaredType() {
String js =
"goog.addDependency('zzz.js', ['goog.Foo'], []);" +
"/** @constructor */ " +
"function A() {" +
" this.x = 3;" +
"}" +
"/** @param {goog.Foo} x */" +
"function f(x) { x.y = 4; }";
String result =
"0;" +
"/** @constructor */ " +
"function A() {" +
" this.a = 3;" +
"}" +
"/** @param {goog.Foo} x */" +
"function f(x) { x.y = 4; }";
test(js, result);
}
}