OLD | NEW |
| (Empty) |
1 // Copyright 2011 Google Inc. All Rights Reserved. | |
2 | |
3 package com.google.dart.compiler.backend.js.analysis; | |
4 | |
5 import com.google.common.collect.Maps; | |
6 | |
7 import junit.framework.TestCase; | |
8 | |
9 import org.mozilla.javascript.Parser; | |
10 import org.mozilla.javascript.ast.AstNode; | |
11 import org.mozilla.javascript.ast.AstRoot; | |
12 | |
13 import java.util.ArrayList; | |
14 import java.util.List; | |
15 import java.util.Map; | |
16 | |
17 | |
18 /** | |
19 * Tests that the dependency computer class reports dependencies correctly. | |
20 */ | |
21 public class DependencyComputerTest extends TestCase { | |
22 private Parser parser = new Parser(); | |
23 private Map<String, List<JavascriptElement>> namesToElements = Maps.newHashMap
(); | |
24 private List<AstNode> globals = new ArrayList<AstNode>(); | |
25 private TopLevelElementIndexer topLevelElementIndexer = new TopLevelElementInd
exer( | |
26 namesToElements, globals); | |
27 private DependencyComputer dependencyComputer = new DependencyComputer(namesTo
Elements); | |
28 | |
29 /** | |
30 * Tests that we don't add virtual dependencies for names that are shadowed by | |
31 * local variables. | |
32 */ | |
33 public void testLocalVariableShadowingOfMemberOfUninstantiatedClass() { | |
34 StringBuilder sb = new StringBuilder(); | |
35 sb.append("function A() {}\n"); | |
36 sb.append("A.prototype.foo = function() {}\n"); | |
37 sb.append("function B() {}\n"); | |
38 sb.append("B.prototype.foo = function() {}\n"); | |
39 sb.append("function execute() { var foo = 1; foo(); }"); | |
40 | |
41 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
42 astRoot.visit(topLevelElementIndexer); | |
43 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
44 List<JavascriptElement> computedDependencies = | |
45 dependencyComputer.computeDependencies(executeFunction); | |
46 assertNotNull(computedDependencies); | |
47 | |
48 /* | |
49 * The foo inside of execute method should lexically resolve to the local | |
50 * variable hence foo() does not introduce a dependency on A.prototype.foo | |
51 * or B.prototype.foo. | |
52 */ | |
53 assertEquals(0, computedDependencies.size()); | |
54 } | |
55 | |
56 /** | |
57 * Tests that we can find dependencies to methods added to the prototype chain
of native objects. | |
58 */ | |
59 public void testNativeDependencies() { | |
60 StringBuilder sb = new StringBuilder(); | |
61 sb.append("function A() {}\n"); | |
62 sb.append("A.prototype.foo = function() {}\n"); | |
63 sb.append("Array.prototype.foo = function() {}\n"); | |
64 sb.append("function execute() { Array.prototype.foo.call(); }"); | |
65 | |
66 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
67 astRoot.visit(topLevelElementIndexer); | |
68 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
69 List<JavascriptElement> computedDependencies = | |
70 dependencyComputer.computeDependencies(executeFunction); | |
71 assertNotNull(computedDependencies); | |
72 | |
73 /* | |
74 * The foo method is added to the native Array object's prototype directly,
ensure that we found | |
75 * it. | |
76 */ | |
77 assertEquals(1, computedDependencies.size()); | |
78 } | |
79 | |
80 /** | |
81 * Tests that we do add a virtual dependency to a member of an instantiated | |
82 * class even though its name is shadowed by a local variable. | |
83 */ | |
84 public void testLocalVariableShadowingOfMemberOfInstantiatedClass() { | |
85 StringBuilder sb = new StringBuilder(); | |
86 sb.append("function A() {}\n"); | |
87 sb.append("A.prototype.foo = function() {}\n"); | |
88 sb.append("function B() {}\n"); | |
89 sb.append("B.prototype.foo = function() {}\n"); | |
90 sb.append("function execute() { var foo = 1; new A(); this.foo(); }"); | |
91 | |
92 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
93 astRoot.visit(topLevelElementIndexer); | |
94 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
95 List<JavascriptElement> computedDependencies = | |
96 dependencyComputer.computeDependencies(executeFunction); | |
97 assertNotNull(computedDependencies); | |
98 | |
99 /* | |
100 * The foo inside of execute method should lexically resolve to the local | |
101 * variable foo, but this.foo() introduces a dependency on A.prototype.foo s
ince A is | |
102 * instantiated and foo is qualified. | |
103 */ | |
104 assertEquals(2, computedDependencies.size()); | |
105 } | |
106 | |
107 /** | |
108 * Tests that referencing a static method through only pulls in the static | |
109 * method and the enclosing function. | |
110 */ | |
111 public void testStaticReferencesToStaticMethods() { | |
112 StringBuilder sb = new StringBuilder(); | |
113 sb.append("function A() {}\n"); | |
114 sb.append("A.prototype.foo = function() {}\n"); | |
115 sb.append("function B() {}\n"); | |
116 sb.append("B.foo = function() {}\n"); | |
117 sb.append("function execute() { B.foo(); }"); | |
118 | |
119 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
120 astRoot.visit(topLevelElementIndexer); | |
121 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
122 List<JavascriptElement> computedDependencies = | |
123 dependencyComputer.computeDependencies(executeFunction); | |
124 assertNotNull(computedDependencies); | |
125 | |
126 // Computed dependencies should be B and B.foo | |
127 assertEquals(2, computedDependencies.size()); | |
128 List<JavascriptElement> list = new ArrayList<JavascriptElement>(namesToEleme
nts.get("B")); | |
129 list.addAll(namesToElements.get("B.foo")); | |
130 assertEquals(list, computedDependencies); | |
131 } | |
132 | |
133 /** | |
134 * Tests that referencing a virtual method through a static reference doesn't | |
135 * introduce a virtual reference to the method. | |
136 */ | |
137 public void testStaticReferencesToVirtualMethods() { | |
138 StringBuilder sb = new StringBuilder(); | |
139 sb.append("function A() {}\n"); | |
140 sb.append("A.prototype.foo = function() {}\n"); | |
141 sb.append("function execute() { A.prototype.foo.call(this); }"); | |
142 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
143 astRoot.visit(topLevelElementIndexer); | |
144 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
145 List<JavascriptElement> computedDependencies = | |
146 dependencyComputer.computeDependencies(executeFunction); | |
147 assertNotNull(computedDependencies); | |
148 assertEquals(1, computedDependencies.size()); | |
149 | |
150 // Static reference to A.prototype.foo | |
151 assertEquals(namesToElements.get("A.prototype.foo"), computedDependencies); | |
152 } | |
153 | |
154 /** | |
155 * Tests that referencing a virtual method only pulls in similarly named | |
156 * virtual methods on classes that have been instantiated.d | |
157 */ | |
158 public void testVirtualReferences() { | |
159 StringBuilder sb = new StringBuilder(); | |
160 sb.append("function A() {}\n"); | |
161 sb.append("A.prototype.foo = function() {}\n"); | |
162 sb.append("function B() {}\n"); | |
163 sb.append("B.prototype.foo = function() {}\n"); | |
164 sb.append("function execute() { new A(); foo(); }"); | |
165 | |
166 AstRoot astRoot = parser.parse(sb.toString(), "", 1); | |
167 astRoot.visit(topLevelElementIndexer); | |
168 AstNode executeFunction = (AstNode) astRoot.getLastChild(); | |
169 List<JavascriptElement> computedDependencies = | |
170 dependencyComputer.computeDependencies(executeFunction); | |
171 assertNotNull(computedDependencies); | |
172 | |
173 /* | |
174 * Expect a dependency on A and A.prototype.foo, B was not instantiated so | |
175 * B.prototype.foo does not qualify | |
176 */ | |
177 assertEquals(2, computedDependencies.size()); | |
178 List<JavascriptElement> list = new ArrayList<JavascriptElement>(namesToEleme
nts.get("A")); | |
179 list.addAll(namesToElements.get("A.prototype.foo")); | |
180 assertEquals(list, computedDependencies); | |
181 } | |
182 } | |
OLD | NEW |