/* * 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.javascript.jscomp.ExtractPrototypeMemberDeclarations.Pattern; /** * Tests for {@link ExtractPrototypeMemberDeclarations}. * */ public final class ExtractPrototypeMemberDeclarationsTest extends CompilerTestCase { private static final String TMP = "JSCompiler_prototypeAlias"; private Pattern pattern = Pattern.USE_GLOBAL_TEMP; @Override protected void setUp() { enableNormalize(); pattern = Pattern.USE_GLOBAL_TEMP; } @Override protected CompilerPass getProcessor(Compiler compiler) { return new ExtractPrototypeMemberDeclarations(compiler, pattern); } public void testNotEnoughPrototypeToExtract() { // switch statement with stuff after "return" for (int i = 0; i < 7; i++) { testSame(generatePrototypeDeclarations("x", i)); } } public void testExtractingSingleClassPrototype() { extract(generatePrototypeDeclarations("x", 7), loadPrototype("x") + generateExtractedDeclarations(7)); } public void testExtractingTwoClassPrototype() { extract( generatePrototypeDeclarations("x", 6) + generatePrototypeDeclarations("y", 6), loadPrototype("x") + generateExtractedDeclarations(6) + loadPrototype("y") + generateExtractedDeclarations(6)); } public void testExtractingTwoClassPrototypeInDifferentBlocks() { extract( generatePrototypeDeclarations("x", 6) + "if (foo()) {" + generatePrototypeDeclarations("y", 6) + "}", loadPrototype("x") + generateExtractedDeclarations(6) + "if (foo()) {" + loadPrototype("y") + generateExtractedDeclarations(6) + "}"); } public void testNoMemberDeclarations() { testSame( "x.prototype = {}; x.prototype = {}; x.prototype = {};" + "x.prototype = {}; x.prototype = {}; x.prototype = {};" + "x.prototype = {}; x.prototype = {}; x.prototype = {};"); } public void testExtractingPrototypeWithQName() { extract( generatePrototypeDeclarations("com.google.javascript.jscomp.x", 7), loadPrototype("com.google.javascript.jscomp.x") + generateExtractedDeclarations(7)); } public void testInterweaved() { testSame( "x.prototype.a=1; y.prototype.a=1;" + "x.prototype.b=1; y.prototype.b=1;" + "x.prototype.c=1; y.prototype.c=1;" + "x.prototype.d=1; y.prototype.d=1;" + "x.prototype.e=1; y.prototype.e=1;" + "x.prototype.f=1; y.prototype.f=1;"); } public void testExtractingPrototypeWithNestedMembers() { extract( "x.prototype.y.a = 1;" + "x.prototype.y.b = 1;" + "x.prototype.y.c = 1;" + "x.prototype.y.d = 1;" + "x.prototype.y.e = 1;" + "x.prototype.y.f = 1;" + "x.prototype.y.g = 1;", loadPrototype("x") + TMP + ".y.a = 1;" + TMP + ".y.b = 1;" + TMP + ".y.c = 1;" + TMP + ".y.d = 1;" + TMP + ".y.e = 1;" + TMP + ".y.f = 1;" + TMP + ".y.g = 1;"); } public void testWithDevirtualization() { extract( "x.prototype.a = 1;" + "x.prototype.b = 1;" + "function devirtualize1() { }" + "x.prototype.c = 1;" + "x.prototype.d = 1;" + "x.prototype.e = 1;" + "x.prototype.f = 1;" + "x.prototype.g = 1;", loadPrototype("x") + TMP + ".a = 1;" + TMP + ".b = 1;" + "function devirtualize1() { }" + TMP + ".c = 1;" + TMP + ".d = 1;" + TMP + ".e = 1;" + TMP + ".f = 1;" + TMP + ".g = 1;"); extract( "x.prototype.a = 1;" + "x.prototype.b = 1;" + "function devirtualize1() { }" + "x.prototype.c = 1;" + "x.prototype.d = 1;" + "function devirtualize2() { }" + "x.prototype.e = 1;" + "x.prototype.f = 1;" + "function devirtualize3() { }" + "x.prototype.g = 1;", loadPrototype("x") + TMP + ".a = 1;" + TMP + ".b = 1;" + "function devirtualize1() { }" + TMP + ".c = 1;" + TMP + ".d = 1;" + "function devirtualize2() { }" + TMP + ".e = 1;" + TMP + ".f = 1;" + "function devirtualize3() { }" + TMP + ".g = 1;"); } public void testAnonSimple() { pattern = Pattern.USE_IIFE; extract( generatePrototypeDeclarations("x", 3), generateExtractedDeclarations(3) + loadPrototype("x")); testSame(generatePrototypeDeclarations("x", 1)); testSame(generatePrototypeDeclarations("x", 2)); extract( generatePrototypeDeclarations("x", 7), generateExtractedDeclarations(7) + loadPrototype("x")); } public void testAnonWithDevirtualization() { pattern = Pattern.USE_IIFE; extract( "x.prototype.a = 1;" + "x.prototype.b = 1;" + "function devirtualize() { }" + "x.prototype.c = 1;", "(function(" + TMP + "){" + TMP + ".a = 1;" + TMP + ".b = 1;" + TMP + ".c = 1;" + loadPrototype("x") + "function devirtualize() { }"); extract( "x.prototype.a = 1;" + "function devirtualize1() { }" + "x.prototype.b = 1;" + "function devirtualize2() { }" + "x.prototype.c = 1;" + "function devirtualize3() { }", "(function(" + TMP + "){" + TMP + ".a = 1;" + TMP + ".b = 1;" + TMP + ".c = 1;" + loadPrototype("x") + "function devirtualize1() { }" + "function devirtualize2() { }" + "function devirtualize3() { }"); } public void testAnonWithSideFx() { pattern = Pattern.USE_IIFE; testSame( "function foo() {};" + "foo.prototype.a1 = 1;" + "bar();;" + "foo.prototype.a2 = 2;" + "bar();;" + "foo.prototype.a3 = 3;" + "bar();;" + "foo.prototype.a4 = 4;" + "bar();;" + "foo.prototype.a5 = 5;" + "bar();;" + "foo.prototype.a6 = 6;" + "bar();;" + "foo.prototype.a7 = 7;" + "bar();"); } public String loadPrototype(String qName) { if (pattern == Pattern.USE_GLOBAL_TEMP) { return TMP + " = " + qName + ".prototype;"; } else { return "})(" + qName + ".prototype);"; } } public void extract(String src, String expected) { if (pattern == Pattern.USE_GLOBAL_TEMP) { test(src, "var " + TMP + ";" + expected); } else { test(src, expected); } } public String generatePrototypeDeclarations(String className, int num) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < num; i++) { char member = (char) ('a' + i); builder.append(generatePrototypeDeclaration( className, "" + member, "" + member)); } return builder.toString(); } public String generatePrototypeDeclaration(String className, String member, String value) { return className + ".prototype." + member + " = " + value + ";"; } public String generateExtractedDeclarations(int num) { StringBuilder builder = new StringBuilder(); if (pattern == Pattern.USE_IIFE) { builder.append("(function(").append(TMP).append("){"); } for (int i = 0; i < num; i++) { char member = (char) ('a' + i); builder.append(generateExtractedDeclaration("" + member, "" + member)); } return builder.toString(); } public String generateExtractedDeclaration(String member, String value) { return TMP + "." + member + " = " + value + ";"; } }