| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
|  | 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. | 
|  | 4 | 
|  | 5 /** | 
|  | 6  * This library contains an Expect class with static methods that can be used | 
|  | 7  * for simple unit-tests. | 
|  | 8  */ | 
|  | 9 library expect; | 
|  | 10 | 
|  | 11 /** | 
|  | 12  * Expect is used for tests that do not want to make use of the | 
|  | 13  * Dart unit test library - for example, the core language tests. | 
|  | 14  * Third parties are discouraged from using this, and should use | 
|  | 15  * the expect() function in the unit test library instead for | 
|  | 16  * test assertions. | 
|  | 17  */ | 
|  | 18 class Expect { | 
|  | 19   /** | 
|  | 20    * Return a slice of a string. | 
|  | 21    * | 
|  | 22    * The slice will contain at least the substring from [start] to the lower of | 
|  | 23    * [end] and `start + length`. | 
|  | 24    * If the result is no more than `length - 10` characters long, | 
|  | 25    * context may be added by extending the range of the slice, by decreasing | 
|  | 26    * [start] and increasing [end], up to at most length characters. | 
|  | 27    * If the start or end of the slice are not matching the start or end of | 
|  | 28    * the string, ellipses are added before or after the slice. | 
|  | 29    * Control characters may be encoded as "\xhh" codes. | 
|  | 30    */ | 
|  | 31   static String _truncateString(String string, int start, int end, int length) { | 
|  | 32     if (end - start > length) { | 
|  | 33       end = start + length; | 
|  | 34     } else if (end - start < length) { | 
|  | 35       int overflow = length - (end - start); | 
|  | 36       if (overflow > 10) overflow = 10; | 
|  | 37       // Add context. | 
|  | 38       start = start - ((overflow + 1) ~/ 2); | 
|  | 39       end = end + (overflow ~/ 2); | 
|  | 40       if (start < 0) start = 0; | 
|  | 41       if (end > string.length) end = string.length; | 
|  | 42     } | 
|  | 43     if (start == 0 && end == string.length) return string; | 
|  | 44     StringBuffer buf = new StringBuffer(); | 
|  | 45     if (start > 0) buf.write("..."); | 
|  | 46     for (int i = start; i < end; i++) { | 
|  | 47       int code = string.codeUnitAt(i); | 
|  | 48       if (code < 0x20) { | 
|  | 49         buf.write(r"\x"); | 
|  | 50         buf.write("0123456789abcdef"[code ~/ 16]); | 
|  | 51         buf.write("0123456789abcdef"[code % 16]); | 
|  | 52       } else { | 
|  | 53         buf.writeCharCode(string.codeUnitAt(i)); | 
|  | 54       } | 
|  | 55     } | 
|  | 56     if (end < string.length) buf.write("..."); | 
|  | 57     return buf.toString(); | 
|  | 58   } | 
|  | 59 | 
|  | 60   /** | 
|  | 61    * Find the difference between two strings. | 
|  | 62    * | 
|  | 63    * This finds the first point where two strings differ, and returns | 
|  | 64    * a text describing the difference. | 
|  | 65    * | 
|  | 66    * For small strings (length less than 20) nothing is done, and null is | 
|  | 67    * returned. Small strings can be compared visually, but for longer strings | 
|  | 68    * only a slice containing the first difference will be shown. | 
|  | 69    */ | 
|  | 70   static String _stringDifference(String expected, String actual) { | 
|  | 71     if (expected.length < 20 && actual.length < 20) return null; | 
|  | 72     for (int i = 0; i < expected.length && i < actual.length; i++) { | 
|  | 73       if (expected.codeUnitAt(i) != actual.codeUnitAt(i)) { | 
|  | 74         int start = i; | 
|  | 75         i++; | 
|  | 76         while (i < expected.length && i < actual.length) { | 
|  | 77           if (expected.codeUnitAt(i) == actual.codeUnitAt(i)) break; | 
|  | 78           i++; | 
|  | 79         } | 
|  | 80         int end = i; | 
|  | 81         var truncExpected = _truncateString(expected, start, end, 20); | 
|  | 82         var truncActual = _truncateString(actual, start, end, 20); | 
|  | 83         return "at index $start: Expected <$truncExpected>, " | 
|  | 84                                 "Found: <$truncActual>"; | 
|  | 85       } | 
|  | 86     } | 
|  | 87     return null; | 
|  | 88   } | 
|  | 89 | 
|  | 90   /** | 
|  | 91    * Checks whether the expected and actual values are equal (using `==`). | 
|  | 92    */ | 
|  | 93   static void equals(var expected, var actual, [String reason = null]) { | 
|  | 94     if (expected == actual) return; | 
|  | 95     String msg = _getMessage(reason); | 
|  | 96     if (expected is String && actual is String) { | 
|  | 97       String stringDifference = _stringDifference(expected, actual); | 
|  | 98       if (stringDifference != null) { | 
|  | 99         _fail("Expect.equals($stringDifference$msg) fails."); | 
|  | 100       } | 
|  | 101     } | 
|  | 102     _fail("Expect.equals(expected: <$expected>, actual: <$actual>$msg) fails."); | 
|  | 103   } | 
|  | 104 | 
|  | 105   /** | 
|  | 106    * Checks whether the actual value is a bool and its value is true. | 
|  | 107    */ | 
|  | 108   static void isTrue(var actual, [String reason = null]) { | 
|  | 109     if (_identical(actual, true)) return; | 
|  | 110     String msg = _getMessage(reason); | 
|  | 111     _fail("Expect.isTrue($actual$msg) fails."); | 
|  | 112   } | 
|  | 113 | 
|  | 114   /** | 
|  | 115    * Checks whether the actual value is a bool and its value is false. | 
|  | 116    */ | 
|  | 117   static void isFalse(var actual, [String reason = null]) { | 
|  | 118     if (_identical(actual, false)) return; | 
|  | 119     String msg = _getMessage(reason); | 
|  | 120     _fail("Expect.isFalse($actual$msg) fails."); | 
|  | 121   } | 
|  | 122 | 
|  | 123   /** | 
|  | 124    * Checks whether [actual] is null. | 
|  | 125    */ | 
|  | 126   static void isNull(actual, [String reason = null]) { | 
|  | 127     if (null == actual) return; | 
|  | 128     String msg = _getMessage(reason); | 
|  | 129     _fail("Expect.isNull(actual: <$actual>$msg) fails."); | 
|  | 130   } | 
|  | 131 | 
|  | 132   /** | 
|  | 133    * Checks whether [actual] is not null. | 
|  | 134    */ | 
|  | 135   static void isNotNull(actual, [String reason = null]) { | 
|  | 136     if (null != actual) return; | 
|  | 137     String msg = _getMessage(reason); | 
|  | 138     _fail("Expect.isNotNull(actual: <$actual>$msg) fails."); | 
|  | 139   } | 
|  | 140 | 
|  | 141   /** | 
|  | 142    * Checks whether the expected and actual values are identical | 
|  | 143    * (using `identical`). | 
|  | 144    */ | 
|  | 145   static void identical(var expected, var actual, [String reason = null]) { | 
|  | 146     if (_identical(expected, actual)) return; | 
|  | 147     String msg = _getMessage(reason); | 
|  | 148     _fail("Expect.identical(expected: <$expected>, actual: <$actual>$msg) " | 
|  | 149           "fails."); | 
|  | 150   } | 
|  | 151 | 
|  | 152   // Unconditional failure. | 
|  | 153   static void fail(String msg) { | 
|  | 154     _fail("Expect.fail('$msg')"); | 
|  | 155   } | 
|  | 156 | 
|  | 157   /** | 
|  | 158    * Failure if the difference between expected and actual is greater than the | 
|  | 159    * given tolerance. If no tolerance is given, tolerance is assumed to be the | 
|  | 160    * value 4 significant digits smaller than the value given for expected. | 
|  | 161    */ | 
|  | 162   static void approxEquals(num expected, | 
|  | 163                            num actual, | 
|  | 164                            [num tolerance = null, | 
|  | 165                             String reason = null]) { | 
|  | 166     if (tolerance == null) { | 
|  | 167       tolerance = (expected / 1e4).abs(); | 
|  | 168     } | 
|  | 169     // Note: use !( <= ) rather than > so we fail on NaNs | 
|  | 170     if ((expected - actual).abs() <= tolerance) return; | 
|  | 171 | 
|  | 172     String msg = _getMessage(reason); | 
|  | 173     _fail('Expect.approxEquals(expected:<$expected>, actual:<$actual>, ' | 
|  | 174           'tolerance:<$tolerance>$msg) fails'); | 
|  | 175   } | 
|  | 176 | 
|  | 177   static void notEquals(unexpected, actual, [String reason = null]) { | 
|  | 178     if (unexpected != actual) return; | 
|  | 179     String msg = _getMessage(reason); | 
|  | 180     _fail("Expect.notEquals(unexpected: <$unexpected>, actual:<$actual>$msg) " | 
|  | 181           "fails."); | 
|  | 182   } | 
|  | 183 | 
|  | 184   /** | 
|  | 185    * Checks that all elements in [expected] and [actual] are equal `==`. | 
|  | 186    * This is different than the typical check for identity equality `identical` | 
|  | 187    * used by the standard list implementation.  It should also produce nicer | 
|  | 188    * error messages than just calling `Expect.equals(expected, actual)`. | 
|  | 189    */ | 
|  | 190   static void listEquals(List expected, List actual, [String reason = null]) { | 
|  | 191     String msg = _getMessage(reason); | 
|  | 192     int n = (expected.length < actual.length) ? expected.length : actual.length; | 
|  | 193     for (int i = 0; i < n; i++) { | 
|  | 194       if (expected[i] != actual[i]) { | 
|  | 195         _fail('Expect.listEquals(at index $i, ' | 
|  | 196               'expected: <${expected[i]}>, actual: <${actual[i]}>$msg) fails'); | 
|  | 197       } | 
|  | 198     } | 
|  | 199     // We check on length at the end in order to provide better error | 
|  | 200     // messages when an unexpected item is inserted in a list. | 
|  | 201     if (expected.length != actual.length) { | 
|  | 202       _fail('Expect.listEquals(list length, ' | 
|  | 203         'expected: <${expected.length}>, actual: <${actual.length}>$msg) ' | 
|  | 204         'fails: Next element <' | 
|  | 205         '${expected.length > n ? expected[n] : actual[n]}>'); | 
|  | 206     } | 
|  | 207   } | 
|  | 208 | 
|  | 209   /** | 
|  | 210    * Checks that all [expected] and [actual] have the same set of keys (using | 
|  | 211    * the semantics of [Map.containsKey] to determine what "same" means. For | 
|  | 212    * each key, checks that the values in both maps are equal using `==`. | 
|  | 213    */ | 
|  | 214   static void mapEquals(Map expected, Map actual, [String reason = null]) { | 
|  | 215     String msg = _getMessage(reason); | 
|  | 216 | 
|  | 217     // Make sure all of the values are present in both and match. | 
|  | 218     for (final key in expected.keys) { | 
|  | 219       if (!actual.containsKey(key)) { | 
|  | 220         _fail('Expect.mapEquals(missing expected key: <$key>$msg) fails'); | 
|  | 221       } | 
|  | 222 | 
|  | 223       Expect.equals(expected[key], actual[key]); | 
|  | 224     } | 
|  | 225 | 
|  | 226     // Make sure the actual map doesn't have any extra keys. | 
|  | 227     for (final key in actual.keys) { | 
|  | 228       if (!expected.containsKey(key)) { | 
|  | 229         _fail('Expect.mapEquals(unexpected key: <$key>$msg) fails'); | 
|  | 230       } | 
|  | 231     } | 
|  | 232   } | 
|  | 233 | 
|  | 234   /** | 
|  | 235    * Specialized equality test for strings. When the strings don't match, | 
|  | 236    * this method shows where the mismatch starts and ends. | 
|  | 237    */ | 
|  | 238   static void stringEquals(String expected, | 
|  | 239                            String actual, | 
|  | 240                            [String reason = null]) { | 
|  | 241     if (expected == actual) return; | 
|  | 242 | 
|  | 243     String msg = _getMessage(reason); | 
|  | 244     String defaultMessage = | 
|  | 245         'Expect.stringEquals(expected: <$expected>", <$actual>$msg) fails'; | 
|  | 246 | 
|  | 247     if ((expected == null) || (actual == null)) { | 
|  | 248       _fail('$defaultMessage'); | 
|  | 249     } | 
|  | 250 | 
|  | 251     // Scan from the left until we find the mismatch. | 
|  | 252     int left = 0; | 
|  | 253     int right = 0; | 
|  | 254     int eLen = expected.length; | 
|  | 255     int aLen = actual.length; | 
|  | 256 | 
|  | 257     while (true) { | 
|  | 258       if (left == eLen || left == aLen || expected[left] != actual[left]) { | 
|  | 259         break; | 
|  | 260       } | 
|  | 261       left++; | 
|  | 262     } | 
|  | 263 | 
|  | 264     // Scan from the right until we find the mismatch. | 
|  | 265     int eRem = eLen - left;  // Remaining length ignoring left match. | 
|  | 266     int aRem = aLen - left; | 
|  | 267     while (true) { | 
|  | 268       if (right == eRem || right == aRem || | 
|  | 269           expected[eLen - right - 1] != actual[aLen - right - 1]) { | 
|  | 270         break; | 
|  | 271       } | 
|  | 272       right++; | 
|  | 273     } | 
|  | 274 | 
|  | 275     // First difference is at index `left`, last at `length - right - 1` | 
|  | 276     // Make useful difference message. | 
|  | 277     // Example: | 
|  | 278     // Diff (1209..1209/1246): | 
|  | 279     // ...,{"name":"[  ]FallThroug... | 
|  | 280     // ...,{"name":"[ IndexError","kind":"class"},{"name":" ]FallThroug... | 
|  | 281     // (colors would be great!) | 
|  | 282 | 
|  | 283     // Make snippets of up to ten characters before and after differences. | 
|  | 284 | 
|  | 285     String leftSnippet = expected.substring(left < 10 ? 0 : left - 10, left); | 
|  | 286     int rightSnippetLength = right < 10 ? right : 10; | 
|  | 287     String rightSnippet = | 
|  | 288         expected.substring(eLen - right, eLen - right + rightSnippetLength); | 
|  | 289 | 
|  | 290     // Make snippets of the differences. | 
|  | 291     String eSnippet = expected.substring(left, eLen - right); | 
|  | 292     String aSnippet = actual.substring(left, aLen - right); | 
|  | 293 | 
|  | 294     // If snippets are long, elide the middle. | 
|  | 295     if (eSnippet.length > 43) { | 
|  | 296       eSnippet = eSnippet.substring(0, 20) + "..." + | 
|  | 297                  eSnippet.substring(eSnippet.length - 20); | 
|  | 298     } | 
|  | 299     if (aSnippet.length > 43) { | 
|  | 300       aSnippet = aSnippet.substring(0, 20) + "..." + | 
|  | 301                  aSnippet.substring(aSnippet.length - 20); | 
|  | 302     } | 
|  | 303     // Add "..." before and after, unless the snippets reach the end. | 
|  | 304     String leftLead = "..."; | 
|  | 305     String rightTail = "..."; | 
|  | 306     if (left <= 10) leftLead = ""; | 
|  | 307     if (right <= 10) rightTail = ""; | 
|  | 308 | 
|  | 309     String diff = '\nDiff ($left..${eLen - right}/${aLen - right}):\n' | 
|  | 310                   '$leftLead$leftSnippet[ $eSnippet ]$rightSnippet$rightTail\n' | 
|  | 311                   '$leftLead$leftSnippet[ $aSnippet ]$rightSnippet$rightTail'; | 
|  | 312     _fail("$defaultMessage$diff"); | 
|  | 313   } | 
|  | 314 | 
|  | 315   /** | 
|  | 316    * Checks that every element of [expected] is also in [actual], and that | 
|  | 317    * every element of [actual] is also in [expected]. | 
|  | 318    */ | 
|  | 319   static void setEquals(Iterable expected, | 
|  | 320                         Iterable actual, | 
|  | 321                         [String reason = null]) { | 
|  | 322     final missingSet = new Set.from(expected); | 
|  | 323     missingSet.removeAll(actual); | 
|  | 324     final extraSet = new Set.from(actual); | 
|  | 325     extraSet.removeAll(expected); | 
|  | 326 | 
|  | 327     if (extraSet.isEmpty && missingSet.isEmpty) return; | 
|  | 328     String msg = _getMessage(reason); | 
|  | 329 | 
|  | 330     StringBuffer sb = new StringBuffer("Expect.setEquals($msg) fails"); | 
|  | 331     // Report any missing items. | 
|  | 332     if (!missingSet.isEmpty) { | 
|  | 333       sb.write('\nExpected collection does not contain: '); | 
|  | 334     } | 
|  | 335 | 
|  | 336     for (final val in missingSet) { | 
|  | 337       sb.write('$val '); | 
|  | 338     } | 
|  | 339 | 
|  | 340     // Report any extra items. | 
|  | 341     if (!extraSet.isEmpty) { | 
|  | 342       sb.write('\nExpected collection should not contain: '); | 
|  | 343     } | 
|  | 344 | 
|  | 345     for (final val in extraSet) { | 
|  | 346       sb.write('$val '); | 
|  | 347     } | 
|  | 348     _fail(sb.toString()); | 
|  | 349   } | 
|  | 350 | 
|  | 351   /** | 
|  | 352    * Calls the function [f] and verifies that it throws an exception. | 
|  | 353    * The optional [check] function can provide additional validation | 
|  | 354    * that the correct exception is being thrown.  For example, to check | 
|  | 355    * the type of the exception you could write this: | 
|  | 356    * | 
|  | 357    *     Expect.throws(myThrowingFunction, (e) => e is MyException); | 
|  | 358    */ | 
|  | 359   static void throws(void f(), | 
|  | 360                      [_CheckExceptionFn check = null, | 
|  | 361                       String reason = null]) { | 
|  | 362     String msg = reason == null ? "" : "($reason)"; | 
|  | 363     if (f is! _Nullary) { | 
|  | 364       // Only throws from executing the funtion body should count as throwing. | 
|  | 365       // The failure to even call `f` should throw outside the try/catch. | 
|  | 366       _fail("Expect.throws$msg: Function f not callable with zero arguments"); | 
|  | 367     } | 
|  | 368     try { | 
|  | 369       f(); | 
|  | 370     } catch (e, s) { | 
|  | 371       if (check != null) { | 
|  | 372         if (!check(e)) { | 
|  | 373           _fail("Expect.throws$msg: Unexpected '$e'\n$s"); | 
|  | 374         } | 
|  | 375       } | 
|  | 376       return; | 
|  | 377     } | 
|  | 378     _fail('Expect.throws$msg fails: Did not throw'); | 
|  | 379   } | 
|  | 380 | 
|  | 381   static String _getMessage(String reason) | 
|  | 382       => (reason == null) ? "" : ", '$reason'"; | 
|  | 383 | 
|  | 384   static void _fail(String message) { | 
|  | 385     throw new ExpectException(message); | 
|  | 386   } | 
|  | 387 } | 
|  | 388 | 
|  | 389 bool _identical(a, b) => identical(a, b); | 
|  | 390 | 
|  | 391 typedef bool _CheckExceptionFn(exception); | 
|  | 392 typedef _Nullary();  // Expect.throws argument must be this type. | 
|  | 393 | 
|  | 394 class ExpectException implements Exception { | 
|  | 395   ExpectException(this.message); | 
|  | 396   String toString() => message; | 
|  | 397   String message; | 
|  | 398 } | 
|  | 399 | 
|  | 400 /// Annotation class for testing of dart2js. Use this as metadata on method | 
|  | 401 /// declarations to disable inlining of the annotated method. | 
|  | 402 class NoInline { | 
|  | 403   const NoInline(); | 
|  | 404 } | 
|  | 405 | 
|  | 406 /// Annotation class for testing of dart2js. Use this as metadata on method | 
|  | 407 /// declarations to make the type inferrer trust the parameter and return types, | 
|  | 408 /// effectively asserting the runtime values will (at least) be subtypes of the | 
|  | 409 /// annotated types. | 
|  | 410 /// | 
|  | 411 /// While the actually inferred type is guaranteed to be a subtype of the | 
|  | 412 /// annotation, it often is more precise. In particular, if a method is only | 
|  | 413 /// called with `null`, the inferrer will still infer null. To ensure that | 
|  | 414 /// the annotated type is also the inferred type, additionally use | 
|  | 415 /// [AssumeDynamic]. | 
|  | 416 class TrustTypeAnnotations { | 
|  | 417   const TrustTypeAnnotations(); | 
|  | 418 } | 
|  | 419 | 
|  | 420 /// Annotation class for testing of dart2js. Use this as metadata on method | 
|  | 421 /// declarations to disable closed world assumptions on parameters, effectively | 
|  | 422 /// assuming that the runtime arguments could be any value. Note that the | 
|  | 423 /// constraints due to [TrustTypeAnnotations] still apply. | 
|  | 424 class AssumeDynamic { | 
|  | 425   const AssumeDynamic(); | 
|  | 426 } | 
| OLD | NEW | 
|---|