| 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 |