Chromium Code Reviews| 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 /** Returns a matcher that matches any null value. */ | |
| 6 IMatcher isNull() => new _IsNull(); | |
|
Bob Nystrom
2012/05/30 23:23:51
Make it a var:
final isNull = const _IsNull();
P
gram
2012/06/01 17:33:15
Done.
| |
| 7 | |
| 8 /** Returns a matcher that matches any non-null value. */ | |
| 9 IMatcher isNotNull() => isNot(isNull()); | |
| 10 | |
| 11 class _IsNull extends Matcher { | |
| 12 bool matches(item) => (item == null); | |
|
Bob Nystrom
2012/05/30 23:23:51
Remove parens:
bool matches(item) => item == nul
gram
2012/06/01 17:33:15
Done.
| |
| 13 IDescription describe(IDescription description) => description.append('null'); | |
| 14 } | |
| 15 | |
| 16 /** Returns a matcher that matches the Boolean value true. */ | |
| 17 IMatcher isTrue() => new _IsTrue(); | |
| 18 | |
| 19 /** Returns a matcher that matches anything except the Boolean value true. */ | |
| 20 IMatcher isFalse() => isNot(isTrue()); | |
| 21 | |
| 22 class _IsTrue extends Matcher { | |
| 23 | |
|
Bob Nystrom
2012/05/30 23:23:51
Delete this blank line.
gram
2012/06/01 17:33:15
Done.
| |
| 24 bool matches(item) => (item == true); | |
|
Bob Nystrom
2012/05/30 23:23:51
Remove unneeded parens.
gram
2012/06/01 17:33:15
Done.
| |
| 25 | |
| 26 IDescription describe(IDescription description) => description.append('true'); | |
| 27 } | |
| 28 | |
| 29 /** Returns a matches that matches if the value is the same instance | |
|
Bob Nystrom
2012/05/30 23:23:51
Can you format this with the text on the next line
gram
2012/06/01 17:33:15
Done.
| |
| 30 * as [object] (===). | |
|
Bob Nystrom
2012/05/30 23:23:51
Put === in backticks to code format it: as [object
gram
2012/06/01 17:33:15
Done.
| |
| 31 */ | |
| 32 IMatcher same(object) => new _IsSame(object); | |
|
Bob Nystrom
2012/05/30 23:23:51
"isSameAs"?
gram
2012/06/01 17:33:15
Done.
| |
| 33 | |
| 34 class _IsSame extends Matcher { | |
| 35 | |
| 36 var _object; | |
|
Bob Nystrom
2012/05/30 23:23:51
Other matcher classes use "_val" for this. Should
gram
2012/06/01 17:33:15
Done.
| |
| 37 | |
| 38 _IsSame(this._object); | |
| 39 | |
| 40 bool matches(item) => (item === _object); | |
|
Bob Nystrom
2012/05/30 23:23:51
Unnecessary ().
gram
2012/06/01 17:33:15
Done.
| |
| 41 | |
| 42 // If all types were hashable we could show a hash here | |
|
Bob Nystrom
2012/05/30 23:23:51
True. :(
Add a "." at the end of the sentence.
gram
2012/06/01 17:33:15
Done.
| |
| 43 IDescription describe(IDescription description) => | |
| 44 description.append('same instance as ').appendDescriptionOf(_object); | |
| 45 } | |
| 46 | |
| 47 /** Returns a matcher that matches if two objects are equal (==). */ | |
| 48 IMatcher equals(obj) => new _IsEqual(obj); | |
| 49 | |
| 50 class _IsEqual extends Matcher { | |
| 51 var _object; | |
| 52 | |
| 53 _IsEqual(this._object); | |
| 54 | |
| 55 bool matches(item) => (item == _object); | |
| 56 | |
| 57 IDescription describe(IDescription description) { | |
| 58 //if (_object is IMatcher) { | |
|
Bob Nystrom
2012/05/30 23:23:51
Remove commented out code.
gram
2012/06/01 17:33:15
Done.
| |
| 59 // return description.append('<'). | |
| 60 // appendDescriptionOf(_object). | |
| 61 // append('>'); | |
| 62 //} else { | |
| 63 return description.appendDescriptionOf(_object); | |
| 64 //} | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 /** Returns a matcher that matches any value. */ | |
| 69 IMatcher anything([description = 'anything']) => new _IsAnything(description); | |
|
Bob Nystrom
2012/05/30 23:23:51
Can we get rid of description and make this a cons
gram
2012/06/01 17:33:15
Done.
| |
| 70 | |
| 71 class _IsAnything extends Matcher { | |
| 72 var _description; | |
| 73 | |
| 74 _IsAnything([this._description = 'anything']); | |
| 75 | |
| 76 bool matches(item) => true; | |
| 77 | |
| 78 IDescription describe(IDescription description) => | |
| 79 description.append(_description); | |
| 80 } | |
| 81 | |
| 82 /** | |
| 83 * Returns a matcher that matches functions that throw exceptions when called. | |
| 84 * The value passed to expect() should be a reference to the function. | |
| 85 * Note that the function cannot take arguments; to handle this | |
| 86 * a wrapper will have to be created. | |
| 87 * The function will be called once. | |
| 88 */ | |
| 89 IMatcher throwsException() => new _Throws(); | |
|
Bob Nystrom
2012/05/30 23:23:51
"throwsException" -> "throws"?
gram
2012/06/01 17:33:15
Done.
| |
| 90 | |
| 91 /** | |
| 92 * Returns a matcher that matches a function call against an exception, | |
| 93 * which is in turn constrained by a [matcher]. | |
| 94 * The value passed to expect() should be a reference to the function. | |
| 95 * Note that the function cannot take arguments; to handle this | |
| 96 * a wrapper will have to be created. | |
| 97 * The function will be called once upon success, or twice upon failure | |
| 98 * (the second time to get the failure description). | |
| 99 */ | |
| 100 IMatcher throwsExceptionWhich(IMatcher matcher) => new _Throws(matcher); | |
| 101 /** | |
|
Bob Nystrom
2012/05/30 23:23:51
Add blank line above comment.
gram
2012/06/01 17:33:15
Done.
| |
| 102 * Returns a matcher that matches a function call against no exception. | |
| 103 * The function will be called once. Any exceptions will be silently swallowed. | |
| 104 * The value passed to expect() should be a reference to the function. | |
| 105 * Note that the function cannot take arguments; to handle this | |
| 106 * a wrapper will have to be created. | |
| 107 */ | |
| 108 IMatcher returnsNormally() => new _ReturnsNormally(); | |
|
Bob Nystrom
2012/05/30 23:23:51
Maybe I don't the intent here, but it seems to me
gram
2012/06/01 17:33:15
Yes - this will catch an exception and return fals
Bob Nystrom
2012/06/01 18:22:22
What happens when exceptions are thrown outside of
| |
| 109 | |
| 110 class _Throws extends Matcher { | |
| 111 IMatcher _matcher; | |
| 112 | |
| 113 _Throws([IMatcher this._matcher = null]) { | |
| 114 if (_matcher != null && !(_matcher is Matcher)) { | |
|
Bob Nystrom
2012/05/30 23:23:51
You can delete this. Dart will validate this for y
gram
2012/06/01 17:33:15
Done.
gram
2012/06/01 17:33:15
Done.
| |
| 115 throw new IllegalArgumentException('Throws parameter must be matcher'); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 bool matches(item) { | |
| 120 try { | |
| 121 item(); | |
| 122 return false; | |
| 123 } catch (final e) { | |
| 124 return _matcher == null || _matcher.matches(e); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 IDescription describe(IDescription description) { | |
| 129 if (_matcher == null) { | |
| 130 return description.append("throws an exception"); | |
| 131 } else { | |
| 132 return description.append('throws an exception which needs to match '). | |
|
Bob Nystrom
2012/05/30 23:23:51
"which needs to match" -> "which matches"?
gram
2012/06/01 17:33:15
Done.
| |
| 133 appendDescriptionOf(_matcher); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 IDescription describeMismatch(item, IDescription mismatchDescription) { | |
| 138 try { | |
| 139 item(); | |
| 140 return mismatchDescription.append(' no exception'); | |
| 141 } catch (final e) { | |
| 142 return mismatchDescription.append(' exception does not match '). | |
| 143 appendDescriptionOf(_matcher); | |
| 144 } | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 class _ReturnsNormally extends Matcher { | |
| 149 bool matches(f) { | |
| 150 try { | |
| 151 f(); | |
| 152 return true; | |
| 153 } catch (final e) { | |
| 154 return false; | |
| 155 } | |
| 156 } | |
| 157 IDescription describe(IDescription description) => | |
| 158 description.append("return normally"); | |
| 159 IDescription describeMismatch(item, IDescription mismatchDescription) { | |
| 160 return mismatchDescription.append(' threw exception'); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 /** | |
| 165 * Returns a matcher that matches if an object is an instance | |
| 166 * of a (super)[type]. | |
|
Bob Nystrom
2012/05/30 23:23:51
This is worded a bit confusingly. Maybe:
"if an o
gram
2012/06/01 17:33:15
Done.
| |
| 167 * | |
| 168 * As types are not first class objects in Dart we can only | |
| 169 * approximate this test, by using a generic wrapper named Type. | |
|
Bob Nystrom
2012/05/30 23:23:51
Delete ","
gram
2012/06/01 17:33:15
Done.
| |
| 170 * | |
| 171 * For example, to test whether 'bar' is an instance of type | |
| 172 * 'Foo', we would write: | |
| 173 * | |
| 174 * expect(bar, instanceOf(new Type<Foo>())); | |
| 175 * | |
| 176 * To get better error message, supply a name when creating the | |
| 177 * Type wrapper; e.g.: | |
| 178 * | |
| 179 * expect(bar, instanceOf(new Type<Foo>('Foo'))); | |
| 180 */ | |
| 181 IMatcher isInstanceOf(Type type) => new _IsInstanceOf(type); | |
| 182 | |
| 183 class Type<T> { | |
|
Bob Nystrom
2012/05/30 23:23:51
How about making this implement IMatcher directly
gram
2012/06/01 17:33:15
Done.
| |
| 184 String _name; | |
| 185 Type([this._name = 'specified type']); | |
| 186 bool isInstance(obj) => obj is T; | |
| 187 String toString() => _name; | |
| 188 } | |
| 189 | |
| 190 class _IsInstanceOf extends Matcher { | |
| 191 | |
| 192 Type _expected_type; | |
|
Bob Nystrom
2012/05/30 23:23:51
"_expectedType"
gram
2012/06/01 17:33:15
No longer applicable.
| |
| 193 | |
| 194 _IsInstanceOf(Type this._expected_type) { | |
| 195 if (!(_expected_type is Type)) { | |
| 196 throw new IllegalArgumentException('IsInstanceOf requires type'); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 bool matches(item) => _expected_type.isInstance(item); | |
| 201 | |
| 202 // The description here is lame :-( | |
|
Bob Nystrom
2012/05/30 23:23:51
Why?
gram
2012/06/01 17:33:15
Because we don't have the type name unless it is e
| |
| 203 IDescription describe(IDescription description) => | |
| 204 description.append('an instance of ${_expected_type.toString()}'); | |
|
Bob Nystrom
2012/05/30 23:23:51
You don't need .toString() here. Interpolation doe
gram
2012/06/01 17:33:15
Done.
| |
| 205 } | |
| 206 | |
| 207 /** | |
| 208 * Returns a matcher that matches if an object has a length property | |
| 209 * that matches [matcher]. | |
|
Bob Nystrom
2012/05/30 23:23:51
This doesn't seem to add a lot of value. Why not j
gram
2012/06/01 17:33:15
You can make this a bit shorter, with:
expect(foo
Bob Nystrom
2012/06/01 18:22:22
I like terseness, but I also like simplicity and m
| |
| 210 */ | |
| 211 IMatcher hasLength([matcher = null]) => | |
| 212 new _HasLength(matcher == null ? anything() : wrapMatcher(matcher)); | |
| 213 | |
| 214 // TODO(gram) - this is intended to fail if the value | |
| 215 // does not have a length property but it doesn't. See if this | |
| 216 // can be fixed. | |
| 217 class _HasLength extends Matcher { | |
| 218 | |
| 219 var _len_matcher; | |
|
Bob Nystrom
2012/05/30 23:23:51
"_lenMatcher"
gram
2012/06/01 17:33:15
Done.
| |
| 220 | |
| 221 _HasLength(Matcher this._len_matcher) { } | |
| 222 bool matches(item) { | |
| 223 try { | |
| 224 // TODO(gram): this hack to throw if no length property is not | |
| 225 // working | |
| 226 if ((item.length * item.length) >= 0) { | |
| 227 return _len_matcher.matches(item.length); | |
| 228 } | |
| 229 } catch(var e) { | |
| 230 return false; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 IDescription describeMismatch(item, IDescription mismatchDescription) { | |
| 235 super.describeMismatch(item, mismatchDescription); | |
| 236 try { | |
| 237 // TODO(gram): this hack to throw if no length property is not | |
| 238 // working | |
| 239 if ((item.length * item.length) >= 0) { | |
| 240 return mismatchDescription.append(' with length of '). | |
| 241 appendDescriptionOf(item.length); | |
| 242 } | |
| 243 } catch (var e) { | |
| 244 return mismatchDescription.append(' has no length property'); | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 IDescription describe(IDescription description) => | |
| 249 description.append('an object with length of '). | |
| 250 appendDescriptionOf(_len_matcher); | |
| 251 } | |
| 252 | |
| 253 /** Returns a matcher that matches if value.toString() matches [matcher] */ | |
| 254 IMatcher hasString(matcher) => new _HasString(wrapMatcher(matcher)); | |
|
Bob Nystrom
2012/05/30 23:23:51
This name is confusing to me, and it doesn't seem
gram
2012/06/01 17:33:15
Done.
| |
| 255 | |
| 256 class _HasString extends Matcher { | |
| 257 var _str_matcher; | |
| 258 | |
| 259 _HasString(this._str_matcher); | |
| 260 | |
| 261 bool matches(item) => _str_matcher.matches(item.toString()); | |
| 262 | |
| 263 IDescription describe(IDescription description) => | |
| 264 description.append('with toString() value '). | |
| 265 appendDescriptionOf(_str_matcher); | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * Returns a matcher that does a deep recursive match. This only works | |
| 270 * with built-in types. Note that cyclic structures will never terminate! | |
|
Bob Nystrom
2012/05/30 23:23:51
Wouldn't this also work with user-defined types th
gram
2012/06/01 17:33:15
I made it a bit more general, and added an item co
| |
| 271 */ | |
| 272 IMatcher recursivelyMatches(obj) => new _DeepMatcher(obj); | |
| 273 | |
| 274 class _DeepMatcher extends Matcher { | |
| 275 var _obj; | |
| 276 | |
| 277 _DeepMatcher(this._obj) {} | |
| 278 | |
| 279 String _recursiveMatch(expected, actual, String location) { | |
| 280 String reason = null; | |
| 281 if (expected is Collection) { | |
| 282 if (!(actual is Collection)) { | |
| 283 reason = 'expected a collection'; | |
| 284 } else if (expected.length != actual.length) { | |
| 285 reason = 'different collection lengths'; | |
| 286 } else { | |
| 287 for (var i = 0; i < expected.length; i++) { | |
| 288 reason = _recursiveMatch(expected[i], actual[i], | |
| 289 'at position ${i} ${location}'); | |
|
Bob Nystrom
2012/05/30 23:23:51
Indent another 2 spaces. Continued lines are inden
gram
2012/06/01 17:33:15
Done.
| |
| 290 if (reason != null) { | |
| 291 break; | |
| 292 } | |
| 293 } | |
| 294 } | |
| 295 } else if (expected is Map) { | |
| 296 if (!(actual is Map)) { | |
|
Bob Nystrom
2012/05/30 23:23:51
actual is !Map
gram
2012/06/01 17:33:15
Done.
| |
| 297 reason = 'expected a map'; | |
| 298 } else if (expected.length != actual.length) { | |
| 299 reason = 'different map lengths'; | |
| 300 } else { | |
| 301 for (var key in expected.getKeys()) { | |
| 302 if (!actual.containsKey(key)) { | |
| 303 reason = 'missing map key ${key}'; | |
| 304 break; | |
| 305 } | |
| 306 reason = _recursiveMatch(expected[key], actual[key], | |
| 307 'with key ${key} ${location}'); | |
| 308 if (reason != null) { | |
| 309 break; | |
| 310 } | |
| 311 } | |
| 312 } | |
| 313 } else { | |
| 314 if (expected != actual) { | |
| 315 reason = 'expected ${expected} but got ${actual}'; | |
| 316 } | |
| 317 } | |
| 318 if (reason == null) { | |
| 319 return null; | |
| 320 } else { | |
| 321 return '${reason} ${location}'; | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 bool matches(item) => (_recursiveMatch(_obj, item, '') == null); | |
| 326 | |
| 327 IDescription describe(IDescription description) => | |
| 328 description.append('recursively matches '). | |
| 329 appendDescriptionOf(_obj); | |
| 330 | |
| 331 | |
| 332 IDescription describeMismatch(item, IDescription mismatchDescription) => | |
| 333 mismatchDescription.append(_recursiveMatch(_obj, item, '')); | |
| 334 } | |
| 335 | |
| 336 | |
| 337 | |
| OLD | NEW |