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/dart_types.dart'; | 10 import 'package:compiler/src/dart_types.dart'; |
11 import 'package:compiler/src/compiler.dart'; | 11 import 'package:compiler/src/compiler.dart'; |
12 import 'package:compiler/src/elements/elements.dart'; | 12 import 'package:compiler/src/elements/elements.dart'; |
13 import 'package:compiler/src/serialization/equivalence.dart'; | 13 import 'package:compiler/src/serialization/equivalence.dart'; |
14 import 'package:compiler/src/tree/nodes.dart'; | 14 import 'package:compiler/src/tree/nodes.dart'; |
| 15 import 'package:expect/expect.dart'; |
15 | 16 |
16 Check currentCheck; | 17 Check currentCheck; |
17 | 18 |
18 class Check { | 19 class Check { |
19 final Check parent; | 20 final Check parent; |
20 final Object object1; | 21 final Object object1; |
21 final Object object2; | 22 final Object object2; |
22 final String property; | 23 final String property; |
23 final Object value1; | 24 final Object value1; |
24 final Object value2; | 25 final Object value2; |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 | 179 |
179 /// Computes the set difference between [set1] and [set2] using | 180 /// Computes the set difference between [set1] and [set2] using |
180 /// [elementEquivalence] to determine element equivalence. | 181 /// [elementEquivalence] to determine element equivalence. |
181 /// | 182 /// |
182 /// Elements both in [set1] and [set2] are added to [common], elements in [set1] | 183 /// Elements both in [set1] and [set2] are added to [common], elements in [set1] |
183 /// but not in [set2] are added to [unfound], and the set of elements in [set2] | 184 /// but not in [set2] are added to [unfound], and the set of elements in [set2] |
184 /// but not in [set1] are returned. | 185 /// but not in [set1] are returned. |
185 Set computeSetDifference( | 186 Set computeSetDifference( |
186 Iterable set1, | 187 Iterable set1, |
187 Iterable set2, | 188 Iterable set2, |
188 List common, | 189 List<List> common, |
189 List unfound, | 190 List unfound, |
190 {bool sameElement(a, b): equality, | 191 {bool sameElement(a, b): equality, |
191 void checkElements(a, b)}) { | 192 void checkElements(a, b)}) { |
192 // TODO(johnniwinther): Avoid the quadratic cost here. Some ideas: | 193 // TODO(johnniwinther): Avoid the quadratic cost here. Some ideas: |
193 // - convert each set to a list and sort it first, then compare by walking | 194 // - convert each set to a list and sort it first, then compare by walking |
194 // both lists in parallel | 195 // both lists in parallel |
195 // - map each element to a canonical object, create a map containing those | 196 // - map each element to a canonical object, create a map containing those |
196 // mappings, use the mapped sets to compare (then operations like | 197 // mappings, use the mapped sets to compare (then operations like |
197 // set.difference would work) | 198 // set.difference would work) |
198 Set remaining = set2.toSet(); | 199 Set remaining = set2.toSet(); |
199 for (var element1 in set1) { | 200 for (var element1 in set1) { |
200 bool found = false; | 201 var correspondingElement; |
201 for (var element2 in remaining) { | 202 for (var element2 in remaining) { |
202 if (sameElement(element1, element2)) { | 203 if (sameElement(element1, element2)) { |
203 if (checkElements != null) { | 204 if (checkElements != null) { |
204 checkElements(element1, element2); | 205 checkElements(element1, element2); |
205 } | 206 } |
206 found = true; | 207 correspondingElement = element2; |
207 remaining.remove(element2); | 208 remaining.remove(element2); |
208 break; | 209 break; |
209 } | 210 } |
210 } | 211 } |
211 if (found) { | 212 if (correspondingElement != null) { |
212 common.add(element1); | 213 common.add([element1, correspondingElement]); |
213 } else { | 214 } else { |
214 unfound.add(element1); | 215 unfound.add(element1); |
215 } | 216 } |
216 } | 217 } |
217 return remaining; | 218 return remaining; |
218 } | 219 } |
219 | 220 |
220 /// Check equivalence of the two iterables, [set1] and [set1], as sets using | 221 /// Check equivalence of the two iterables, [set1] and [set1], as sets using |
221 /// [elementEquivalence] to compute the pair-wise equivalence. | 222 /// [elementEquivalence] to compute the pair-wise equivalence. |
222 /// | 223 /// |
223 /// Uses [object1], [object2] and [property] to provide context for failures. | 224 /// Uses [object1], [object2] and [property] to provide context for failures. |
224 bool checkSetEquivalence( | 225 bool checkSetEquivalence( |
225 var object1, | 226 var object1, |
226 var object2, | 227 var object2, |
227 String property, | 228 String property, |
228 Iterable set1, | 229 Iterable set1, |
229 Iterable set2, | 230 Iterable set2, |
230 bool sameElement(a, b), | 231 bool sameElement(a, b), |
231 {void onSameElement(a, b)}) { | 232 {void onSameElement(a, b)}) { |
232 List common = []; | 233 List<List> common = <List>[]; |
233 List unfound = []; | 234 List unfound = []; |
234 Set remaining = | 235 Set remaining = |
235 computeSetDifference(set1, set2, common, unfound, | 236 computeSetDifference(set1, set2, common, unfound, |
236 sameElement: sameElement, checkElements: onSameElement); | 237 sameElement: sameElement, checkElements: onSameElement); |
237 if (unfound.isNotEmpty || remaining.isNotEmpty) { | 238 if (unfound.isNotEmpty || remaining.isNotEmpty) { |
238 String message = | 239 String message = |
239 "Set mismatch for `$property` on $object1 vs $object2: \n" | 240 "Set mismatch for `$property` on $object1 vs $object2: \n" |
240 "Common:\n ${common.join('\n ')}\n" | 241 "Common:\n ${common.join('\n ')}\n" |
241 "Unfound:\n ${unfound.join('\n ')}\n" | 242 "Unfound:\n ${unfound.join('\n ')}\n" |
242 "Extra: \n ${remaining.join('\n ')}"; | 243 "Extra: \n ${remaining.join('\n ')}"; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 | 422 |
422 if (impact1 == null) { | 423 if (impact1 == null) { |
423 throw 'Missing impact for $member1. $member2 has $impact2'; | 424 throw 'Missing impact for $member1. $member2 has $impact2'; |
424 } | 425 } |
425 if (impact2 == null) { | 426 if (impact2 == null) { |
426 throw 'Missing impact for $member2. $member1 has $impact1'; | 427 throw 'Missing impact for $member2. $member1 has $impact1'; |
427 } | 428 } |
428 | 429 |
429 testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy()); | 430 testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy()); |
430 } | 431 } |
| 432 |
| 433 void checkSets( |
| 434 Iterable set1, |
| 435 Iterable set2, |
| 436 String messagePrefix, |
| 437 bool sameElement(a, b), |
| 438 {bool failOnUnfound: true, |
| 439 bool verbose: false, |
| 440 void onSameElement(a, b)}) { |
| 441 List<List> common = <List>[]; |
| 442 List unfound = []; |
| 443 Set remaining = computeSetDifference( |
| 444 set1, set2, common, unfound, |
| 445 sameElement: sameElement, |
| 446 checkElements: onSameElement); |
| 447 StringBuffer sb = new StringBuffer(); |
| 448 sb.write("$messagePrefix:"); |
| 449 if (verbose) { |
| 450 sb.write("\n Common:\n ${common.join('\n ')}"); |
| 451 } |
| 452 if (unfound.isNotEmpty || verbose) { |
| 453 sb.write("\n Unfound:\n ${unfound.join('\n ')}"); |
| 454 } |
| 455 if (remaining.isNotEmpty || verbose) { |
| 456 sb.write("\n Extra: \n ${remaining.join('\n ')}"); |
| 457 } |
| 458 String message = sb.toString(); |
| 459 if (unfound.isNotEmpty || remaining.isNotEmpty) { |
| 460 |
| 461 if (failOnUnfound || remaining.isNotEmpty) { |
| 462 Expect.fail(message); |
| 463 } else { |
| 464 print(message); |
| 465 } |
| 466 } else if (verbose) { |
| 467 print(message); |
| 468 } |
| 469 } |
| 470 |
| 471 String defaultToString(obj) => '$obj'; |
| 472 |
| 473 void checkMaps( |
| 474 Map map1, |
| 475 Map map2, |
| 476 String messagePrefix, |
| 477 bool sameKey(a, b), |
| 478 bool sameValue(a, b), |
| 479 {bool failOnUnfound: true, |
| 480 bool failOnMismatch: true, |
| 481 bool verbose: false, |
| 482 String keyToString(key): defaultToString, |
| 483 String valueToString(key): defaultToString}) { |
| 484 List<List> common = <List>[]; |
| 485 List unfound = []; |
| 486 List<List> mismatch = <List>[]; |
| 487 Set remaining = computeSetDifference( |
| 488 map1.keys, map2.keys, common, unfound, |
| 489 sameElement: sameKey, |
| 490 checkElements: (k1, k2) { |
| 491 var v1 = map1[k1]; |
| 492 var v2 = map2[k2]; |
| 493 if (!sameValue(v1, v2)) { |
| 494 mismatch.add([k1, k2]); |
| 495 } |
| 496 }); |
| 497 StringBuffer sb = new StringBuffer(); |
| 498 sb.write("$messagePrefix:"); |
| 499 if (verbose) { |
| 500 sb.write("\n Common: \n"); |
| 501 for (List pair in common) { |
| 502 var k1 = pair[0]; |
| 503 var k2 = pair[1]; |
| 504 var v1 = map1[k1]; |
| 505 var v2 = map2[k2]; |
| 506 sb.write(" key1 =${keyToString(k1)}\n"); |
| 507 sb.write(" key2 =${keyToString(k2)}\n"); |
| 508 sb.write(" value1=${valueToString(v1)}\n"); |
| 509 sb.write(" value2=${valueToString(v2)}\n"); |
| 510 } |
| 511 } |
| 512 if (unfound.isNotEmpty || verbose) { |
| 513 sb.write("\n Unfound: \n"); |
| 514 for (var k1 in unfound) { |
| 515 var v1 = map1[k1]; |
| 516 sb.write(" key1 =${keyToString(k1)}\n"); |
| 517 sb.write(" value1=${valueToString(v1)}\n"); |
| 518 } |
| 519 } |
| 520 if (remaining.isNotEmpty || verbose) { |
| 521 sb.write("\n Extra: \n"); |
| 522 for (var k2 in remaining) { |
| 523 var v2 = map2[k2]; |
| 524 sb.write(" key2 =${keyToString(k2)}\n"); |
| 525 sb.write(" value2=${valueToString(v2)}\n"); |
| 526 } |
| 527 } |
| 528 if (mismatch.isNotEmpty || verbose) { |
| 529 sb.write("\n Mismatch: \n"); |
| 530 for (List pair in mismatch) { |
| 531 var k1 = pair[0]; |
| 532 var k2 = pair[1]; |
| 533 var v1 = map1[k1]; |
| 534 var v2 = map2[k2]; |
| 535 sb.write(" key1 =${keyToString(k1)}\n"); |
| 536 sb.write(" key2 =${keyToString(k2)}\n"); |
| 537 sb.write(" value1=${valueToString(v1)}\n"); |
| 538 sb.write(" value2=${valueToString(v2)}\n"); |
| 539 } |
| 540 } |
| 541 String message = sb.toString(); |
| 542 if (unfound.isNotEmpty || mismatch.isNotEmpty || remaining.isNotEmpty) { |
| 543 if ((unfound.isNotEmpty && failOnUnfound) || |
| 544 (mismatch.isNotEmpty && failOnMismatch) || |
| 545 remaining.isNotEmpty) { |
| 546 Expect.fail(message); |
| 547 } else { |
| 548 print(message); |
| 549 } |
| 550 } else if (verbose) { |
| 551 print(message); |
| 552 } |
| 553 } |
OLD | NEW |