OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.serialization_test_helper; | 5 library dart2js.serialization_test_helper; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'package:compiler/src/common/resolution.dart'; | 8 import 'package:compiler/src/common/resolution.dart'; |
9 import 'package:compiler/src/constants/expressions.dart'; | 9 import 'package:compiler/src/constants/expressions.dart'; |
10 import 'package:compiler/src/constants/values.dart'; | 10 import 'package:compiler/src/constants/values.dart'; |
11 import 'package:compiler/src/dart_types.dart'; | 11 import 'package:compiler/src/dart_types.dart'; |
12 import 'package:compiler/src/compiler.dart'; | 12 import 'package:compiler/src/compiler.dart'; |
13 import 'package:compiler/src/elements/elements.dart'; | 13 import 'package:compiler/src/elements/elements.dart'; |
14 import 'package:compiler/src/serialization/equivalence.dart'; | 14 import 'package:compiler/src/serialization/equivalence.dart'; |
15 import 'package:compiler/src/tree/nodes.dart'; | 15 import 'package:compiler/src/tree/nodes.dart'; |
16 import 'package:expect/expect.dart'; | 16 import 'package:expect/expect.dart'; |
17 import 'test_data.dart'; | 17 import 'test_data.dart'; |
18 | 18 |
19 Check currentCheck; | 19 Check currentCheck; |
20 | 20 |
21 class Check { | 21 class Check { |
22 final Check parent; | 22 final Check parent; |
23 final Object object1; | 23 final Object object1; |
24 final Object object2; | 24 final Object object2; |
25 final String property; | 25 final String property; |
26 final Object value1; | 26 final Object value1; |
27 final Object value2; | 27 final Object value2; |
28 | 28 |
29 Check(this.parent, this.object1, this.object2, this.property, this.value1, thi
s.value2); | 29 Check(this.parent, this.object1, this.object2, this.property, this.value1, |
| 30 this.value2); |
30 | 31 |
31 String printOn(StringBuffer sb, String indent) { | 32 String printOn(StringBuffer sb, String indent) { |
32 if (parent != null) { | 33 if (parent != null) { |
33 indent = parent.printOn(sb, indent); | 34 indent = parent.printOn(sb, indent); |
34 sb.write('\n$indent|\n'); | 35 sb.write('\n$indent|\n'); |
35 } | 36 } |
36 sb.write("${indent}property='$property'\n "); | 37 sb.write("${indent}property='$property'\n "); |
37 sb.write("${indent}object1=$object1 (${object1.runtimeType})\n "); | 38 sb.write("${indent}object1=$object1 (${object1.runtimeType})\n "); |
38 sb.write("${indent}value=${value1 == null ? "null" : "'$value1'"} "); | 39 sb.write("${indent}value=${value1 == null ? "null" : "'$value1'"} "); |
39 sb.write("(${value1.runtimeType}) vs\n "); | 40 sb.write("(${value1.runtimeType}) vs\n "); |
(...skipping 12 matching lines...) Expand all Loading... |
52 | 53 |
53 /// Strategy for checking equivalence. | 54 /// Strategy for checking equivalence. |
54 /// | 55 /// |
55 /// Use this strategy to fail early with contextual information in the event of | 56 /// Use this strategy to fail early with contextual information in the event of |
56 /// inequivalence. | 57 /// inequivalence. |
57 class CheckStrategy implements TestStrategy { | 58 class CheckStrategy implements TestStrategy { |
58 const CheckStrategy(); | 59 const CheckStrategy(); |
59 | 60 |
60 @override | 61 @override |
61 bool test(var object1, var object2, String property, var value1, var value2, | 62 bool test(var object1, var object2, String property, var value1, var value2, |
62 [bool equivalence(a, b) = equality]) { | 63 [bool equivalence(a, b) = equality]) { |
63 return check(object1, object2, property, value1, value2, equivalence); | 64 return check(object1, object2, property, value1, value2, equivalence); |
64 } | 65 } |
65 | 66 |
66 @override | 67 @override |
67 bool testLists( | 68 bool testLists( |
68 Object object1, Object object2, String property, | 69 Object object1, Object object2, String property, List list1, List list2, |
69 List list1, List list2, | |
70 [bool elementEquivalence(a, b) = equality]) { | 70 [bool elementEquivalence(a, b) = equality]) { |
71 return checkListEquivalence( | 71 return checkListEquivalence(object1, object2, property, list1, list2, |
72 object1, object2, property, list1, list2, | |
73 (o1, o2, p, v1, v2) { | 72 (o1, o2, p, v1, v2) { |
74 if (!elementEquivalence(v1, v2)) { | 73 if (!elementEquivalence(v1, v2)) { |
75 throw "$o1.$p = '${v1}' <> " | 74 throw "$o1.$p = '${v1}' <> " |
76 "$o2.$p = '${v2}'"; | 75 "$o2.$p = '${v2}'"; |
77 } | 76 } |
78 return true; | 77 return true; |
79 }); | 78 }); |
80 } | 79 } |
81 | 80 |
82 @override | 81 @override |
83 bool testSets( | 82 bool testSets( |
84 var object1, var object2, String property, | 83 var object1, var object2, String property, Iterable set1, Iterable set2, |
85 Iterable set1, Iterable set2, | |
86 [bool elementEquivalence(a, b) = equality]) { | 84 [bool elementEquivalence(a, b) = equality]) { |
87 return checkSetEquivalence( | 85 return checkSetEquivalence( |
88 object1, object2,property, set1, set2, elementEquivalence); | 86 object1, object2, property, set1, set2, elementEquivalence); |
89 } | 87 } |
90 | 88 |
91 @override | 89 @override |
92 bool testMaps( | 90 bool testMaps(var object1, var object2, String property, Map map1, Map map2, |
93 var object1, var object2, String property, Map map1, Map map2, | |
94 [bool keyEquivalence(a, b) = equality, | 91 [bool keyEquivalence(a, b) = equality, |
95 bool valueEquivalence(a, b) = equality]) { | 92 bool valueEquivalence(a, b) = equality]) { |
96 return checkMapEquivalence(object1, object2, property, | 93 return checkMapEquivalence(object1, object2, property, map1, map2, |
97 map1, map2, keyEquivalence, valueEquivalence); | 94 keyEquivalence, valueEquivalence); |
98 } | 95 } |
99 | 96 |
100 @override | 97 @override |
101 bool testElements( | 98 bool testElements(Object object1, Object object2, String property, |
102 Object object1, Object object2, String property, | |
103 Element element1, Element element2) { | 99 Element element1, Element element2) { |
104 return checkElementIdentities( | 100 return checkElementIdentities( |
105 object1, object2, property, element1, element2); | 101 object1, object2, property, element1, element2); |
106 } | 102 } |
107 | 103 |
108 @override | 104 @override |
109 bool testTypes( | 105 bool testTypes(Object object1, Object object2, String property, |
110 Object object1, Object object2, String property, | |
111 DartType type1, DartType type2) { | 106 DartType type1, DartType type2) { |
112 return checkTypes(object1, object2, property, type1, type2); | 107 return checkTypes(object1, object2, property, type1, type2); |
113 } | 108 } |
114 | 109 |
115 @override | 110 @override |
116 bool testConstants( | 111 bool testConstants(Object object1, Object object2, String property, |
117 Object object1, Object object2, String property, | |
118 ConstantExpression exp1, ConstantExpression exp2) { | 112 ConstantExpression exp1, ConstantExpression exp2) { |
119 return checkConstants(object1, object2, property, exp1, exp2); | 113 return checkConstants(object1, object2, property, exp1, exp2); |
120 } | 114 } |
121 | 115 |
122 @override | 116 @override |
123 bool testConstantValues(Object object1, Object object2, String property, | 117 bool testConstantValues(Object object1, Object object2, String property, |
124 ConstantValue value1, ConstantValue value2) { | 118 ConstantValue value1, ConstantValue value2) { |
125 return areConstantValuesEquivalent(value1, value2); | 119 return areConstantValuesEquivalent(value1, value2); |
126 } | 120 } |
127 | 121 |
128 @override | 122 @override |
129 bool testTypeLists( | 123 bool testTypeLists(Object object1, Object object2, String property, |
130 Object object1, Object object2, String property, | |
131 List<DartType> list1, List<DartType> list2) { | 124 List<DartType> list1, List<DartType> list2) { |
132 return checkTypeLists(object1, object2, property, list1, list2); | 125 return checkTypeLists(object1, object2, property, list1, list2); |
133 } | 126 } |
134 | 127 |
135 @override | 128 @override |
136 bool testConstantLists( | 129 bool testConstantLists(Object object1, Object object2, String property, |
137 Object object1, Object object2, String property, | 130 List<ConstantExpression> list1, List<ConstantExpression> list2) { |
138 List<ConstantExpression> list1, | |
139 List<ConstantExpression> list2) { | |
140 return checkConstantLists(object1, object2, property, list1, list2); | 131 return checkConstantLists(object1, object2, property, list1, list2); |
141 } | 132 } |
142 | 133 |
143 @override | 134 @override |
144 bool testConstantValueLists(Object object1, Object object2, String property, | 135 bool testConstantValueLists(Object object1, Object object2, String property, |
145 List<ConstantValue> list1, List<ConstantValue> list2) { | 136 List<ConstantValue> list1, List<ConstantValue> list2) { |
146 return checkConstantValueLists(object1, object2, property, list1, list2); | 137 return checkConstantValueLists(object1, object2, property, list1, list2); |
147 } | 138 } |
148 | 139 |
149 @override | 140 @override |
150 bool testNodes(Object object1, Object object2, String property, | 141 bool testNodes( |
151 Node node1, Node node2) { | 142 Object object1, Object object2, String property, Node node1, Node node2) { |
152 return new NodeEquivalenceVisitor(this).testNodes( | 143 return new NodeEquivalenceVisitor(this) |
153 object1, object2, property, node1, node2); | 144 .testNodes(object1, object2, property, node1, node2); |
154 } | 145 } |
155 } | 146 } |
156 | 147 |
157 /// Check that the values [property] of [object1] and [object2], [value1] and | 148 /// Check that the values [property] of [object1] and [object2], [value1] and |
158 /// [value2] respectively, are equal and throw otherwise. | 149 /// [value2] respectively, are equal and throw otherwise. |
159 bool check(var object1, var object2, String property, var value1, var value2, | 150 bool check(var object1, var object2, String property, var value1, var value2, |
160 [bool equivalence(a, b) = equality]) { | 151 [bool equivalence(a, b) = equality]) { |
161 currentCheck = new Check( | 152 currentCheck = |
162 currentCheck, object1, object2, property, value1, value2); | 153 new Check(currentCheck, object1, object2, property, value1, value2); |
163 if (!equivalence(value1, value2)) { | 154 if (!equivalence(value1, value2)) { |
164 throw currentCheck; | 155 throw currentCheck; |
165 } | 156 } |
166 currentCheck = currentCheck.parent; | 157 currentCheck = currentCheck.parent; |
167 return true; | 158 return true; |
168 } | 159 } |
169 | 160 |
170 /// Check equivalence of the two lists, [list1] and [list2], using | 161 /// Check equivalence of the two lists, [list1] and [list2], using |
171 /// [checkEquivalence] to check the pair-wise equivalence. | 162 /// [checkEquivalence] to check the pair-wise equivalence. |
172 /// | 163 /// |
173 /// Uses [object1], [object2] and [property] to provide context for failures. | 164 /// Uses [object1], [object2] and [property] to provide context for failures. |
174 bool checkListEquivalence( | 165 bool checkListEquivalence( |
175 Object object1, Object object2, String property, | 166 Object object1, |
176 Iterable list1, Iterable list2, | 167 Object object2, |
| 168 String property, |
| 169 Iterable list1, |
| 170 Iterable list2, |
177 void checkEquivalence(o1, o2, property, a, b)) { | 171 void checkEquivalence(o1, o2, property, a, b)) { |
178 currentCheck = | 172 currentCheck = |
179 new Check(currentCheck, object1, object2, property, list1, list2); | 173 new Check(currentCheck, object1, object2, property, list1, list2); |
180 for (int i = 0; i < list1.length && i < list2.length; i++) { | 174 for (int i = 0; i < list1.length && i < list2.length; i++) { |
181 checkEquivalence( | 175 checkEquivalence( |
182 object1, object2, property, | 176 object1, object2, property, list1.elementAt(i), list2.elementAt(i)); |
183 list1.elementAt(i), list2.elementAt(i)); | |
184 } | 177 } |
185 for (int i = list1.length; i < list2.length; i++) { | 178 for (int i = list1.length; i < list2.length; i++) { |
186 throw | 179 throw 'Missing equivalent for element ' |
187 'Missing equivalent for element ' | |
188 '#$i ${list2.elementAt(i)} in `${property}` on $object2.\n' | 180 '#$i ${list2.elementAt(i)} in `${property}` on $object2.\n' |
189 '`${property}` on $object1:\n ${list1.join('\n ')}\n' | 181 '`${property}` on $object1:\n ${list1.join('\n ')}\n' |
190 '`${property}` on $object2:\n ${list2.join('\n ')}'; | 182 '`${property}` on $object2:\n ${list2.join('\n ')}'; |
191 } | 183 } |
192 for (int i = list2.length; i < list1.length; i++) { | 184 for (int i = list2.length; i < list1.length; i++) { |
193 throw | 185 throw 'Missing equivalent for element ' |
194 'Missing equivalent for element ' | |
195 '#$i ${list1.elementAt(i)} in `${property}` on $object1.\n' | 186 '#$i ${list1.elementAt(i)} in `${property}` on $object1.\n' |
196 '`${property}` on $object1:\n ${list1.join('\n ')}\n' | 187 '`${property}` on $object1:\n ${list1.join('\n ')}\n' |
197 '`${property}` on $object2:\n ${list2.join('\n ')}'; | 188 '`${property}` on $object2:\n ${list2.join('\n ')}'; |
198 } | 189 } |
199 currentCheck = currentCheck.parent; | 190 currentCheck = currentCheck.parent; |
200 return true; | 191 return true; |
201 } | 192 } |
202 | 193 |
203 /// Computes the set difference between [set1] and [set2] using | 194 /// Computes the set difference between [set1] and [set2] using |
204 /// [elementEquivalence] to determine element equivalence. | 195 /// [elementEquivalence] to determine element equivalence. |
205 /// | 196 /// |
206 /// Elements both in [set1] and [set2] are added to [common], elements in [set1] | 197 /// Elements both in [set1] and [set2] are added to [common], elements in [set1] |
207 /// but not in [set2] are added to [unfound], and the set of elements in [set2] | 198 /// but not in [set2] are added to [unfound], and the set of elements in [set2] |
208 /// but not in [set1] are returned. | 199 /// but not in [set1] are returned. |
209 Set computeSetDifference( | 200 Set computeSetDifference( |
210 Iterable set1, | 201 Iterable set1, Iterable set2, List<List> common, List unfound, |
211 Iterable set2, | 202 {bool sameElement(a, b): equality, void checkElements(a, b)}) { |
212 List<List> common, | |
213 List unfound, | |
214 {bool sameElement(a, b): equality, | |
215 void checkElements(a, b)}) { | |
216 // TODO(johnniwinther): Avoid the quadratic cost here. Some ideas: | 203 // TODO(johnniwinther): Avoid the quadratic cost here. Some ideas: |
217 // - convert each set to a list and sort it first, then compare by walking | 204 // - convert each set to a list and sort it first, then compare by walking |
218 // both lists in parallel | 205 // both lists in parallel |
219 // - map each element to a canonical object, create a map containing those | 206 // - map each element to a canonical object, create a map containing those |
220 // mappings, use the mapped sets to compare (then operations like | 207 // mappings, use the mapped sets to compare (then operations like |
221 // set.difference would work) | 208 // set.difference would work) |
222 Set remaining = set2.toSet(); | 209 Set remaining = set2.toSet(); |
223 for (var element1 in set1) { | 210 for (var element1 in set1) { |
224 var correspondingElement; | 211 var correspondingElement; |
225 for (var element2 in remaining) { | 212 for (var element2 in remaining) { |
(...skipping 12 matching lines...) Expand all Loading... |
238 unfound.add(element1); | 225 unfound.add(element1); |
239 } | 226 } |
240 } | 227 } |
241 return remaining; | 228 return remaining; |
242 } | 229 } |
243 | 230 |
244 /// Check equivalence of the two iterables, [set1] and [set1], as sets using | 231 /// Check equivalence of the two iterables, [set1] and [set1], as sets using |
245 /// [elementEquivalence] to compute the pair-wise equivalence. | 232 /// [elementEquivalence] to compute the pair-wise equivalence. |
246 /// | 233 /// |
247 /// Uses [object1], [object2] and [property] to provide context for failures. | 234 /// Uses [object1], [object2] and [property] to provide context for failures. |
248 bool checkSetEquivalence( | 235 bool checkSetEquivalence(var object1, var object2, String property, |
249 var object1, | 236 Iterable set1, Iterable set2, bool sameElement(a, b), |
250 var object2, | |
251 String property, | |
252 Iterable set1, | |
253 Iterable set2, | |
254 bool sameElement(a, b), | |
255 {void onSameElement(a, b)}) { | 237 {void onSameElement(a, b)}) { |
256 List<List> common = <List>[]; | 238 List<List> common = <List>[]; |
257 List unfound = []; | 239 List unfound = []; |
258 Set remaining = | 240 Set remaining = computeSetDifference(set1, set2, common, unfound, |
259 computeSetDifference(set1, set2, common, unfound, | 241 sameElement: sameElement, checkElements: onSameElement); |
260 sameElement: sameElement, checkElements: onSameElement); | |
261 if (unfound.isNotEmpty || remaining.isNotEmpty) { | 242 if (unfound.isNotEmpty || remaining.isNotEmpty) { |
262 String message = | 243 String message = "Set mismatch for `$property` on $object1 vs $object2: \n" |
263 "Set mismatch for `$property` on $object1 vs $object2: \n" | |
264 "Common:\n ${common.join('\n ')}\n" | 244 "Common:\n ${common.join('\n ')}\n" |
265 "Unfound:\n ${unfound.join('\n ')}\n" | 245 "Unfound:\n ${unfound.join('\n ')}\n" |
266 "Extra: \n ${remaining.join('\n ')}"; | 246 "Extra: \n ${remaining.join('\n ')}"; |
267 throw message; | 247 throw message; |
268 } | 248 } |
269 return true; | 249 return true; |
270 } | 250 } |
271 | 251 |
272 /// Check equivalence of the two iterables, [set1] and [set1], as sets using | 252 /// Check equivalence of the two iterables, [set1] and [set1], as sets using |
273 /// [elementEquivalence] to compute the pair-wise equivalence. | 253 /// [elementEquivalence] to compute the pair-wise equivalence. |
274 /// | 254 /// |
275 /// Uses [object1], [object2] and [property] to provide context for failures. | 255 /// Uses [object1], [object2] and [property] to provide context for failures. |
276 bool checkMapEquivalence( | 256 bool checkMapEquivalence(var object1, var object2, String property, Map map1, |
277 var object1, | 257 Map map2, bool sameKey(a, b), bool sameValue(a, b)) { |
278 var object2, | |
279 String property, | |
280 Map map1, | |
281 Map map2, | |
282 bool sameKey(a, b), | |
283 bool sameValue(a, b)) { | |
284 List<List> common = <List>[]; | 258 List<List> common = <List>[]; |
285 List unfound = []; | 259 List unfound = []; |
286 Set remaining = | 260 Set remaining = computeSetDifference(map1.keys, map2.keys, common, unfound, |
287 computeSetDifference(map1.keys, map2.keys, common, unfound, | 261 sameElement: sameKey); |
288 sameElement: sameKey); | |
289 if (unfound.isNotEmpty || remaining.isNotEmpty) { | 262 if (unfound.isNotEmpty || remaining.isNotEmpty) { |
290 String message = | 263 String message = |
291 "Map key mismatch for `$property` on $object1 vs $object2: \n" | 264 "Map key mismatch for `$property` on $object1 vs $object2: \n" |
292 "Common:\n ${common.join('\n ')}\n" | 265 "Common:\n ${common.join('\n ')}\n" |
293 "Unfound:\n ${unfound.join('\n ')}\n" | 266 "Unfound:\n ${unfound.join('\n ')}\n" |
294 "Extra: \n ${remaining.join('\n ')}"; | 267 "Extra: \n ${remaining.join('\n ')}"; |
295 throw message; | 268 throw message; |
296 } | 269 } |
297 for (List pair in common) { | 270 for (List pair in common) { |
298 check(object1, object2, 'Map value for `$property`', | 271 check(object1, object2, 'Map value for `$property`', map1[pair[0]], |
299 map1[pair[0]], map2[pair[1]], sameValue); | 272 map2[pair[1]], sameValue); |
300 } | 273 } |
301 return true; | 274 return true; |
302 } | 275 } |
303 | 276 |
304 /// Checks the equivalence of the identity (but not properties) of [element1] | 277 /// Checks the equivalence of the identity (but not properties) of [element1] |
305 /// and [element2]. | 278 /// and [element2]. |
306 /// | 279 /// |
307 /// Uses [object1], [object2] and [property] to provide context for failures. | 280 /// Uses [object1], [object2] and [property] to provide context for failures. |
308 bool checkElementIdentities( | 281 bool checkElementIdentities(Object object1, Object object2, String property, |
309 Object object1, Object object2, String property, | |
310 Element element1, Element element2) { | 282 Element element1, Element element2) { |
311 if (identical(element1, element2)) return true; | 283 if (identical(element1, element2)) return true; |
312 return check(object1, object2, | 284 return check( |
313 property, element1, element2, areElementsEquivalent); | 285 object1, object2, property, element1, element2, areElementsEquivalent); |
314 } | 286 } |
315 | 287 |
316 /// Checks the pair-wise equivalence of the identity (but not properties) of the | 288 /// Checks the pair-wise equivalence of the identity (but not properties) of the |
317 /// elements in [list] and [list2]. | 289 /// elements in [list] and [list2]. |
318 /// | 290 /// |
319 /// Uses [object1], [object2] and [property] to provide context for failures. | 291 /// Uses [object1], [object2] and [property] to provide context for failures. |
320 bool checkElementListIdentities( | 292 bool checkElementListIdentities(Object object1, Object object2, String property, |
321 Object object1, Object object2, String property, | |
322 Iterable<Element> list1, Iterable<Element> list2) { | 293 Iterable<Element> list1, Iterable<Element> list2) { |
323 return checkListEquivalence( | 294 return checkListEquivalence( |
324 object1, object2, property, | 295 object1, object2, property, list1, list2, checkElementIdentities); |
325 list1, list2, checkElementIdentities); | |
326 } | 296 } |
327 | 297 |
328 /// Checks the equivalence of [type1] and [type2]. | 298 /// Checks the equivalence of [type1] and [type2]. |
329 /// | 299 /// |
330 /// Uses [object1], [object2] and [property] to provide context for failures. | 300 /// Uses [object1], [object2] and [property] to provide context for failures. |
331 bool checkTypes( | 301 bool checkTypes(Object object1, Object object2, String property, DartType type1, |
332 Object object1, Object object2, String property, | 302 DartType type2) { |
333 DartType type1, DartType type2) { | |
334 if (identical(type1, type2)) return true; | 303 if (identical(type1, type2)) return true; |
335 if (type1 == null || type2 == null) { | 304 if (type1 == null || type2 == null) { |
336 return check(object1, object2, property, type1, type2); | 305 return check(object1, object2, property, type1, type2); |
337 } else { | 306 } else { |
338 return check(object1, object2, property, type1, type2, | 307 return check(object1, object2, property, type1, type2, |
339 (a, b) => const TypeEquivalence(const CheckStrategy()).visit(a, b)); | 308 (a, b) => const TypeEquivalence(const CheckStrategy()).visit(a, b)); |
340 } | 309 } |
341 } | 310 } |
342 | 311 |
343 /// Checks the pair-wise equivalence of the types in [list1] and [list2]. | 312 /// Checks the pair-wise equivalence of the types in [list1] and [list2]. |
344 /// | 313 /// |
345 /// Uses [object1], [object2] and [property] to provide context for failures. | 314 /// Uses [object1], [object2] and [property] to provide context for failures. |
346 bool checkTypeLists( | 315 bool checkTypeLists(Object object1, Object object2, String property, |
347 Object object1, Object object2, String property, | |
348 List<DartType> list1, List<DartType> list2) { | 316 List<DartType> list1, List<DartType> list2) { |
349 return checkListEquivalence( | 317 return checkListEquivalence( |
350 object1, object2, property, list1, list2, checkTypes); | 318 object1, object2, property, list1, list2, checkTypes); |
351 } | 319 } |
352 | 320 |
353 /// Checks the equivalence of [exp1] and [exp2]. | 321 /// Checks the equivalence of [exp1] and [exp2]. |
354 /// | 322 /// |
355 /// Uses [object1], [object2] and [property] to provide context for failures. | 323 /// Uses [object1], [object2] and [property] to provide context for failures. |
356 bool checkConstants( | 324 bool checkConstants(Object object1, Object object2, String property, |
357 Object object1, Object object2, String property, | |
358 ConstantExpression exp1, ConstantExpression exp2) { | 325 ConstantExpression exp1, ConstantExpression exp2) { |
359 if (identical(exp1, exp2)) return true; | 326 if (identical(exp1, exp2)) return true; |
360 if (exp1 == null || exp2 == null) { | 327 if (exp1 == null || exp2 == null) { |
361 return check(object1, object2, property, exp1, exp2); | 328 return check(object1, object2, property, exp1, exp2); |
362 } else { | 329 } else { |
363 return check(object1, object2, property, exp1, exp2, | 330 return check(object1, object2, property, exp1, exp2, |
364 (a, b) => const ConstantEquivalence(const CheckStrategy()).visit(a, b)); | 331 (a, b) => const ConstantEquivalence(const CheckStrategy()).visit(a, b)); |
365 } | 332 } |
366 } | 333 } |
367 | 334 |
368 /// Checks the equivalence of [value1] and [value2]. | 335 /// Checks the equivalence of [value1] and [value2]. |
369 /// | 336 /// |
370 /// Uses [object1], [object2] and [property] to provide context for failures. | 337 /// Uses [object1], [object2] and [property] to provide context for failures. |
371 bool checkConstantValues( | 338 bool checkConstantValues(Object object1, Object object2, String property, |
372 Object object1, Object object2, String property, | |
373 ConstantValue value1, ConstantValue value2) { | 339 ConstantValue value1, ConstantValue value2) { |
374 if (identical(value1, value2)) return true; | 340 if (identical(value1, value2)) return true; |
375 if (value1 == null || value2 == null) { | 341 if (value1 == null || value2 == null) { |
376 return check(object1, object2, property, value1, value2); | 342 return check(object1, object2, property, value1, value2); |
377 } else { | 343 } else { |
378 return check(object1, object2, property, value1, value2, | 344 return check( |
379 (a, b) => const ConstantValueEquivalence( | 345 object1, |
380 const CheckStrategy()).visit(a, b)); | 346 object2, |
| 347 property, |
| 348 value1, |
| 349 value2, |
| 350 (a, b) => |
| 351 const ConstantValueEquivalence(const CheckStrategy()).visit(a, b)); |
381 } | 352 } |
382 } | 353 } |
383 | 354 |
384 /// Checks the pair-wise equivalence of the constants in [list1] and [list2]. | 355 /// Checks the pair-wise equivalence of the constants in [list1] and [list2]. |
385 /// | 356 /// |
386 /// Uses [object1], [object2] and [property] to provide context for failures. | 357 /// Uses [object1], [object2] and [property] to provide context for failures. |
387 bool checkConstantLists( | 358 bool checkConstantLists(Object object1, Object object2, String property, |
388 Object object1, Object object2, String property, | 359 List<ConstantExpression> list1, List<ConstantExpression> list2) { |
389 List<ConstantExpression> list1, | |
390 List<ConstantExpression> list2) { | |
391 return checkListEquivalence( | 360 return checkListEquivalence( |
392 object1, object2, property, | 361 object1, object2, property, list1, list2, checkConstants); |
393 list1, list2, checkConstants); | |
394 } | 362 } |
395 | 363 |
396 /// Checks the pair-wise equivalence of the constants values in [list1] and | 364 /// Checks the pair-wise equivalence of the constants values in [list1] and |
397 /// [list2]. | 365 /// [list2]. |
398 /// | 366 /// |
399 /// Uses [object1], [object2] and [property] to provide context for failures. | 367 /// Uses [object1], [object2] and [property] to provide context for failures. |
400 bool checkConstantValueLists( | 368 bool checkConstantValueLists(Object object1, Object object2, String property, |
401 Object object1, Object object2, String property, | 369 List<ConstantValue> list1, List<ConstantValue> list2) { |
402 List<ConstantValue> list1, | |
403 List<ConstantValue> list2) { | |
404 return checkListEquivalence( | 370 return checkListEquivalence( |
405 object1, object2, property, | 371 object1, object2, property, list1, list2, checkConstantValues); |
406 list1, list2, checkConstantValues); | |
407 } | 372 } |
408 | 373 |
409 /// Check member property equivalence between all members common to [compiler1] | 374 /// Check member property equivalence between all members common to [compiler1] |
410 /// and [compiler2]. | 375 /// and [compiler2]. |
411 void checkLoadedLibraryMembers( | 376 void checkLoadedLibraryMembers( |
412 Compiler compiler1, | 377 Compiler compiler1, |
413 Compiler compiler2, | 378 Compiler compiler2, |
414 bool hasProperty(Element member1), | 379 bool hasProperty(Element member1), |
415 void checkMemberProperties(Compiler compiler1, Element member1, | 380 void checkMemberProperties(Compiler compiler1, Element member1, |
416 Compiler compiler2, Element member2, | 381 Compiler compiler2, Element member2, |
417 {bool verbose}), | 382 {bool verbose}), |
418 {bool verbose: false}) { | 383 {bool verbose: false}) { |
419 | |
420 void checkMembers(Element member1, Element member2) { | 384 void checkMembers(Element member1, Element member2) { |
421 if (member1.isClass && member2.isClass) { | 385 if (member1.isClass && member2.isClass) { |
422 ClassElement class1 = member1; | 386 ClassElement class1 = member1; |
423 ClassElement class2 = member2; | 387 ClassElement class2 = member2; |
424 if (!class1.isResolved) return; | 388 if (!class1.isResolved) return; |
425 | 389 |
426 if (hasProperty(member1)) { | 390 if (hasProperty(member1)) { |
427 if (areElementsEquivalent(member1, member2)) { | 391 if (areElementsEquivalent(member1, member2)) { |
428 checkMemberProperties( | 392 checkMemberProperties(compiler1, member1, compiler2, member2, |
429 compiler1, member1, | |
430 compiler2, member2, | |
431 verbose: verbose); | 393 verbose: verbose); |
432 } | 394 } |
433 } | 395 } |
434 | 396 |
435 class1.forEachLocalMember((m1) { | 397 class1.forEachLocalMember((m1) { |
436 checkMembers(m1, class2.localLookup(m1.name)); | 398 checkMembers(m1, class2.localLookup(m1.name)); |
437 }); | 399 }); |
438 ClassElement superclass1 = class1.superclass; | 400 ClassElement superclass1 = class1.superclass; |
439 ClassElement superclass2 = class2.superclass; | 401 ClassElement superclass2 = class2.superclass; |
440 while (superclass1 != null && superclass1.isUnnamedMixinApplication) { | 402 while (superclass1 != null && superclass1.isUnnamedMixinApplication) { |
441 for (ConstructorElement c1 in superclass1.constructors) { | 403 for (ConstructorElement c1 in superclass1.constructors) { |
442 checkMembers(c1, superclass2.lookupConstructor(c1.name)); | 404 checkMembers(c1, superclass2.lookupConstructor(c1.name)); |
443 } | 405 } |
444 superclass1 = superclass1.superclass; | 406 superclass1 = superclass1.superclass; |
445 superclass2 = superclass2.superclass; | 407 superclass2 = superclass2.superclass; |
446 } | 408 } |
447 return; | 409 return; |
448 } | 410 } |
449 | 411 |
450 if (!hasProperty(member1)) { | 412 if (!hasProperty(member1)) { |
451 return; | 413 return; |
452 } | 414 } |
453 | 415 |
454 if (member2 == null) { | 416 if (member2 == null) { |
455 throw 'Missing member for ${member1}'; | 417 throw 'Missing member for ${member1}'; |
456 } | 418 } |
457 | 419 |
458 if (areElementsEquivalent(member1, member2)) { | 420 if (areElementsEquivalent(member1, member2)) { |
459 checkMemberProperties( | 421 checkMemberProperties(compiler1, member1, compiler2, member2, |
460 compiler1, member1, | |
461 compiler2, member2, | |
462 verbose: verbose); | 422 verbose: verbose); |
463 } | 423 } |
464 } | 424 } |
465 | 425 |
466 for (LibraryElement library1 in compiler1.libraryLoader.libraries) { | 426 for (LibraryElement library1 in compiler1.libraryLoader.libraries) { |
467 LibraryElement library2 = | 427 LibraryElement library2 = |
468 compiler2.libraryLoader.lookupLibrary(library1.canonicalUri); | 428 compiler2.libraryLoader.lookupLibrary(library1.canonicalUri); |
469 if (library2 != null) { | 429 if (library2 != null) { |
470 library1.forEachLocalMember((Element member1) { | 430 library1.forEachLocalMember((Element member1) { |
471 checkMembers(member1, library2.localLookup(member1.name)); | 431 checkMembers(member1, library2.localLookup(member1.name)); |
472 }); | 432 }); |
473 | |
474 } | 433 } |
475 } | 434 } |
476 } | 435 } |
477 | 436 |
478 /// Check equivalence of all resolution impacts. | 437 /// Check equivalence of all resolution impacts. |
479 void checkAllImpacts( | 438 void checkAllImpacts(Compiler compiler1, Compiler compiler2, |
480 Compiler compiler1, | |
481 Compiler compiler2, | |
482 {bool verbose: false}) { | 439 {bool verbose: false}) { |
483 checkLoadedLibraryMembers( | 440 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) { |
484 compiler1, | 441 return compiler1.resolution.hasResolutionImpact(member1); |
485 compiler2, | 442 }, checkImpacts, verbose: verbose); |
486 (Element member1) { | |
487 return compiler1.resolution.hasResolutionImpact(member1); | |
488 }, | |
489 checkImpacts, | |
490 verbose: verbose); | |
491 } | 443 } |
492 | 444 |
493 /// Check equivalence of resolution impact for [member1] and [member2]. | 445 /// Check equivalence of resolution impact for [member1] and [member2]. |
494 void checkImpacts(Compiler compiler1, Element member1, | 446 void checkImpacts( |
495 Compiler compiler2, Element member2, | 447 Compiler compiler1, Element member1, Compiler compiler2, Element member2, |
496 {bool verbose: false}) { | 448 {bool verbose: false}) { |
497 ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1); | 449 ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1); |
498 ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2); | 450 ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2); |
499 | 451 |
500 if (impact1 == null && impact2 == null) return; | 452 if (impact1 == null && impact2 == null) return; |
501 | 453 |
502 if (verbose) { | 454 if (verbose) { |
503 print('Checking impacts for $member1 vs $member2'); | 455 print('Checking impacts for $member1 vs $member2'); |
504 } | 456 } |
505 | 457 |
506 if (impact1 == null) { | 458 if (impact1 == null) { |
507 throw 'Missing impact for $member1. $member2 has $impact2'; | 459 throw 'Missing impact for $member1. $member2 has $impact2'; |
508 } | 460 } |
509 if (impact2 == null) { | 461 if (impact2 == null) { |
510 throw 'Missing impact for $member2. $member1 has $impact1'; | 462 throw 'Missing impact for $member2. $member1 has $impact1'; |
511 } | 463 } |
512 | 464 |
513 testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy()); | 465 testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy()); |
514 } | 466 } |
515 | 467 |
516 void checkSets( | 468 void checkSets( |
517 Iterable set1, | 469 Iterable set1, Iterable set2, String messagePrefix, bool sameElement(a, b), |
518 Iterable set2, | |
519 String messagePrefix, | |
520 bool sameElement(a, b), | |
521 {bool failOnUnfound: true, | 470 {bool failOnUnfound: true, |
522 bool failOnExtra: true, | 471 bool failOnExtra: true, |
523 bool verbose: false, | 472 bool verbose: false, |
524 void onSameElement(a, b), | 473 void onSameElement(a, b), |
525 void onUnfoundElement(a), | 474 void onUnfoundElement(a), |
526 void onExtraElement(b), | 475 void onExtraElement(b), |
527 String elementToString(key): defaultToString}) { | 476 String elementToString(key): defaultToString}) { |
528 List<List> common = <List>[]; | 477 List<List> common = <List>[]; |
529 List unfound = []; | 478 List unfound = []; |
530 Set remaining = computeSetDifference( | 479 Set remaining = computeSetDifference(set1, set2, common, unfound, |
531 set1, set2, common, unfound, | 480 sameElement: sameElement, checkElements: onSameElement); |
532 sameElement: sameElement, | |
533 checkElements: onSameElement); | |
534 if (onUnfoundElement != null) { | 481 if (onUnfoundElement != null) { |
535 unfound.forEach(onUnfoundElement); | 482 unfound.forEach(onUnfoundElement); |
536 } | 483 } |
537 if (onExtraElement != null) { | 484 if (onExtraElement != null) { |
538 remaining.forEach(onExtraElement); | 485 remaining.forEach(onExtraElement); |
539 } | 486 } |
540 StringBuffer sb = new StringBuffer(); | 487 StringBuffer sb = new StringBuffer(); |
541 sb.write("$messagePrefix:"); | 488 sb.write("$messagePrefix:"); |
542 if (verbose) { | 489 if (verbose) { |
543 sb.write("\n Common: \n"); | 490 sb.write("\n Common: \n"); |
(...skipping 18 matching lines...) Expand all Loading... |
562 } else { | 509 } else { |
563 print(message); | 510 print(message); |
564 } | 511 } |
565 } else if (verbose) { | 512 } else if (verbose) { |
566 print(message); | 513 print(message); |
567 } | 514 } |
568 } | 515 } |
569 | 516 |
570 String defaultToString(obj) => '$obj'; | 517 String defaultToString(obj) => '$obj'; |
571 | 518 |
572 void checkMaps( | 519 void checkMaps(Map map1, Map map2, String messagePrefix, bool sameKey(a, b), |
573 Map map1, | |
574 Map map2, | |
575 String messagePrefix, | |
576 bool sameKey(a, b), | |
577 bool sameValue(a, b), | 520 bool sameValue(a, b), |
578 {bool failOnUnfound: true, | 521 {bool failOnUnfound: true, |
579 bool failOnMismatch: true, | 522 bool failOnMismatch: true, |
580 bool verbose: false, | 523 bool verbose: false, |
581 String keyToString(key): defaultToString, | 524 String keyToString(key): defaultToString, |
582 String valueToString(key): defaultToString}) { | 525 String valueToString(key): defaultToString}) { |
583 List<List> common = <List>[]; | 526 List<List> common = <List>[]; |
584 List unfound = []; | 527 List unfound = []; |
585 List<List> mismatch = <List>[]; | 528 List<List> mismatch = <List>[]; |
586 Set remaining = computeSetDifference( | 529 Set remaining = computeSetDifference(map1.keys, map2.keys, common, unfound, |
587 map1.keys, map2.keys, common, unfound, | 530 sameElement: sameKey, checkElements: (k1, k2) { |
588 sameElement: sameKey, | 531 var v1 = map1[k1]; |
589 checkElements: (k1, k2) { | 532 var v2 = map2[k2]; |
590 var v1 = map1[k1]; | 533 if (!sameValue(v1, v2)) { |
591 var v2 = map2[k2]; | 534 mismatch.add([k1, k2]); |
592 if (!sameValue(v1, v2)) { | 535 } |
593 mismatch.add([k1, k2]); | 536 }); |
594 } | |
595 }); | |
596 StringBuffer sb = new StringBuffer(); | 537 StringBuffer sb = new StringBuffer(); |
597 sb.write("$messagePrefix:"); | 538 sb.write("$messagePrefix:"); |
598 if (verbose) { | 539 if (verbose) { |
599 sb.write("\n Common: \n"); | 540 sb.write("\n Common: \n"); |
600 for (List pair in common) { | 541 for (List pair in common) { |
601 var k1 = pair[0]; | 542 var k1 = pair[0]; |
602 var k2 = pair[1]; | 543 var k2 = pair[1]; |
603 var v1 = map1[k1]; | 544 var v1 = map1[k1]; |
604 var v2 = map2[k2]; | 545 var v2 = map2[k2]; |
605 sb.write(" key1 =${keyToString(k1)}\n"); | 546 sb.write(" key1 =${keyToString(k1)}\n"); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 remaining.isNotEmpty) { | 585 remaining.isNotEmpty) { |
645 Expect.fail(message); | 586 Expect.fail(message); |
646 } else { | 587 } else { |
647 print(message); | 588 print(message); |
648 } | 589 } |
649 } else if (verbose) { | 590 } else if (verbose) { |
650 print(message); | 591 print(message); |
651 } | 592 } |
652 } | 593 } |
653 | 594 |
654 void checkAllResolvedAsts( | 595 void checkAllResolvedAsts(Compiler compiler1, Compiler compiler2, |
655 Compiler compiler1, | |
656 Compiler compiler2, | |
657 {bool verbose: false}) { | 596 {bool verbose: false}) { |
658 checkLoadedLibraryMembers( | 597 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) { |
659 compiler1, | 598 return member1 is ExecutableElement && |
660 compiler2, | 599 compiler1.resolution.hasResolvedAst(member1); |
661 (Element member1) { | 600 }, checkResolvedAsts, verbose: verbose); |
662 return member1 is ExecutableElement && | |
663 compiler1.resolution.hasResolvedAst(member1); | |
664 }, | |
665 checkResolvedAsts, | |
666 verbose: verbose); | |
667 } | 601 } |
668 | 602 |
669 | |
670 /// Check equivalence of [impact1] and [impact2]. | 603 /// Check equivalence of [impact1] and [impact2]. |
671 void checkResolvedAsts(Compiler compiler1, Element member1, | 604 void checkResolvedAsts( |
672 Compiler compiler2, Element member2, | 605 Compiler compiler1, Element member1, Compiler compiler2, Element member2, |
673 {bool verbose: false}) { | 606 {bool verbose: false}) { |
674 if (!compiler2.serialization.isDeserialized(member2)) { | 607 if (!compiler2.serialization.isDeserialized(member2)) { |
675 return; | 608 return; |
676 } | 609 } |
677 ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1); | 610 ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1); |
678 ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2); | 611 ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2); |
679 | 612 |
680 if (resolvedAst1 == null || resolvedAst2 == null) return; | 613 if (resolvedAst1 == null || resolvedAst2 == null) return; |
681 | 614 |
682 if (verbose) { | 615 if (verbose) { |
683 print('Checking resolved asts for $member1 vs $member2'); | 616 print('Checking resolved asts for $member1 vs $member2'); |
684 } | 617 } |
685 | 618 |
686 testResolvedAstEquivalence( | 619 testResolvedAstEquivalence(resolvedAst1, resolvedAst2, const CheckStrategy()); |
687 resolvedAst1, resolvedAst2, const CheckStrategy()); | |
688 } | 620 } |
689 | 621 |
690 /// Returns the test arguments for testing the [index]th skipped test. The | 622 /// Returns the test arguments for testing the [index]th skipped test. The |
691 /// [skip] count is used to check that [index] is a valid index. | 623 /// [skip] count is used to check that [index] is a valid index. |
692 List<String> testSkipped(int index, int skip) { | 624 List<String> testSkipped(int index, int skip) { |
693 if (index < 0 || index >= skip) { | 625 if (index < 0 || index >= skip) { |
694 throw new ArgumentError('Invalid skip index $index'); | 626 throw new ArgumentError('Invalid skip index $index'); |
695 } | 627 } |
696 return ['${index}', '${index + 1}']; | 628 return ['${index}', '${index + 1}']; |
697 } | 629 } |
698 | 630 |
699 /// Return the test arguments for testing the [index]th segment (1-based) of | 631 /// Return the test arguments for testing the [index]th segment (1-based) of |
700 /// the [TESTS] split into [count] groups. The first [skip] tests are excluded | 632 /// the [TESTS] split into [count] groups. The first [skip] tests are excluded |
701 /// from the automatic grouping. | 633 /// from the automatic grouping. |
702 List<String> testSegment(int index, int count, int skip) { | 634 List<String> testSegment(int index, int count, int skip) { |
703 if (index < 0 || index > count) { | 635 if (index < 0 || index > count) { |
704 throw new ArgumentError('Invalid segment index $index'); | 636 throw new ArgumentError('Invalid segment index $index'); |
705 } | 637 } |
706 | 638 |
707 String segmentNumber(int i) { | 639 String segmentNumber(int i) { |
708 return '${skip + i * (TESTS.length - skip) ~/ count}'; | 640 return '${skip + i * (TESTS.length - skip) ~/ count}'; |
709 } | 641 } |
710 | 642 |
711 if (index == 1 && skip != 0) { | 643 if (index == 1 && skip != 0) { |
712 return ['${skip}', segmentNumber(index)]; | 644 return ['${skip}', segmentNumber(index)]; |
713 } else if (index == count) { | 645 } else if (index == count) { |
714 return [segmentNumber(index - 1)]; | 646 return [segmentNumber(index - 1)]; |
715 } else { | 647 } else { |
716 return [segmentNumber(index - 1), segmentNumber(index)]; | 648 return [segmentNumber(index - 1), segmentNumber(index)]; |
717 } | 649 } |
718 } | 650 } |
OLD | NEW |