Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(680)

Side by Side Diff: pkg/unittest/lib/src/iterable_matchers.dart

Issue 16408019: Improved error messages from unittest. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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 part of matcher; 5 part of matcher;
6 6
7 /** 7 /**
8 * Returns a matcher which matches [Iterable]s in which all elements 8 * Returns a matcher which matches [Iterable]s in which all elements
9 * match the given [matcher]. 9 * match the given [matcher].
10 */ 10 */
11 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); 11 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
12 12
13 class _EveryElement extends _IterableMatcher { 13 class _EveryElement extends _IterableMatcher {
14 Matcher _matcher; 14 Matcher _matcher;
15 15
16 _EveryElement(Matcher this._matcher); 16 _EveryElement(Matcher this._matcher);
17 17
18 bool matches(item, MatchState matchState) { 18 bool matches(item, Map matchState) {
19 if (item is! Iterable) { 19 if (item is! Iterable) {
20 return false; 20 return false;
21 } 21 }
22 var i = 0; 22 var i = 0;
23 for (var element in item) { 23 for (var element in item) {
24 if (!_matcher.matches(element, matchState)) { 24 if (!_matcher.matches(element, matchState)) {
25 matchState.state = { 25 addStateInfo(matchState, {'index': i, 'element': element});
26 'index': i,
27 'element': element,
28 'state': matchState.state
29 };
30 return false; 26 return false;
31 } 27 }
32 ++i; 28 ++i;
33 } 29 }
34 return true; 30 return true;
35 } 31 }
36 32
37 Description describe(Description description) => 33 Description describe(Description description) =>
38 description.add('every element ').addDescriptionOf(_matcher); 34 description.add('every element(').addDescriptionOf(_matcher).add(')');
39 35
40 Description describeMismatch(item, Description mismatchDescription, 36 Description describeMismatch(item, Description mismatchDescription,
41 MatchState matchState, bool verbose) { 37 Map matchState, bool verbose) {
42 if (matchState.state != null) { 38 if (matchState['index'] != null) {
43 var index = matchState.state['index']; 39 var index = matchState['index'];
44 var element = matchState.state['element']; 40 var element = matchState['element'];
45 mismatchDescription.add('position $index '); 41 mismatchDescription.add('has value ').addDescriptionOf(element).
46 return _matcher.describeMismatch(element, mismatchDescription, 42 add(' which ');
47 matchState.state['state'], verbose); 43 var subDescription = new StringDescription();
44 _matcher.describeMismatch(element, subDescription,
45 matchState['state'], verbose);
46 if (subDescription.length > 0) {
47 mismatchDescription.add(subDescription);
48 } else {
49 mismatchDescription.add("doesn't match ");
50 _matcher.describe(mismatchDescription);
51 }
52 mismatchDescription.add(' at index $index');
53 return mismatchDescription;
48 } 54 }
49 return super.describeMismatch(item, mismatchDescription, 55 return super.describeMismatch(item, mismatchDescription,
50 matchState, verbose); 56 matchState, verbose);
51 } 57 }
52 } 58 }
53 59
54 /** 60 /**
55 * Returns a matcher which matches [Iterable]s in which at least one 61 * Returns a matcher which matches [Iterable]s in which at least one
56 * element matches the given [matcher]. 62 * element matches the given [matcher].
57 */ 63 */
58 Matcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher)); 64 Matcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher));
59 65
60 class _SomeElement extends _IterableMatcher { 66 class _SomeElement extends _IterableMatcher {
61 Matcher _matcher; 67 Matcher _matcher;
62 68
63 _SomeElement(this._matcher); 69 _SomeElement(this._matcher);
64 70
65 bool matches(item, MatchState matchState) { 71 bool matches(item, Map matchState) {
66 return item.any((e) => _matcher.matches(e, matchState)); 72 return item.any((e) => _matcher.matches(e, matchState));
67 } 73 }
68 74
69 Description describe(Description description) => 75 Description describe(Description description) =>
70 description.add('some element ').addDescriptionOf(_matcher); 76 description.add('some element ').addDescriptionOf(_matcher);
71 } 77 }
72 78
73 /** 79 /**
74 * Returns a matcher which matches [Iterable]s that have the same 80 * Returns a matcher which matches [Iterable]s that have the same
75 * length and the same elements as [expected], and in the same order. 81 * length and the same elements as [expected], and in the same order.
76 * This is equivalent to equals but does not recurse. 82 * This is equivalent to equals but does not recurse.
77 */ 83 */
78 84
79 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected); 85 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
80 86
81 class _OrderedEquals extends BaseMatcher { 87 class _OrderedEquals extends BaseMatcher {
82 final Iterable _expected; 88 final Iterable _expected;
83 Matcher _matcher; 89 Matcher _matcher;
84 90
85 _OrderedEquals(this._expected) { 91 _OrderedEquals(this._expected) {
86 _matcher = equals(_expected, 1); 92 _matcher = equals(_expected, 1);
87 } 93 }
88 94
89 bool matches(item, MatchState matchState) => 95 bool matches(item, Map matchState) =>
90 (item is Iterable) && _matcher.matches(item, matchState); 96 (item is Iterable) && _matcher.matches(item, matchState);
91 97
92 Description describe(Description description) => 98 Description describe(Description description) =>
93 description.add('equals ').addDescriptionOf(_expected).add(' ordered'); 99 description.add('equals ').addDescriptionOf(_expected).add(' ordered');
94 100
95 Description describeMismatch(item, Description mismatchDescription, 101 Description describeMismatch(item, Description mismatchDescription,
96 MatchState matchState, bool verbose) { 102 Map matchState, bool verbose) {
97 if (item is !Iterable) { 103 if (item is !Iterable) {
98 return mismatchDescription.add('not an Iterable'); 104 return mismatchDescription.add('is not an Iterable');
99 } else { 105 } else {
100 return _matcher.describeMismatch(item, mismatchDescription, 106 return _matcher.describeMismatch(item, mismatchDescription,
101 matchState, verbose); 107 matchState, verbose);
102 } 108 }
103 } 109 }
104 } 110 }
105 /** 111 /**
106 * Returns a matcher which matches [Iterable]s that have the same 112 * Returns a matcher which matches [Iterable]s that have the same
107 * length and the same elements as [expected], but not necessarily in 113 * length and the same elements as [expected], but not necessarily in
108 * the same order. Note that this is O(n^2) so should only be used on 114 * the same order. Note that this is O(n^2) so should only be used on
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 matched[actualPosition] = gotMatch = true; 148 matched[actualPosition] = gotMatch = true;
143 break; 149 break;
144 } 150 }
145 } 151 }
146 ++actualPosition; 152 ++actualPosition;
147 } 153 }
148 if (!gotMatch) { 154 if (!gotMatch) {
149 Description reason = new StringDescription(); 155 Description reason = new StringDescription();
150 reason.add('has no match for element '). 156 reason.add('has no match for element ').
151 addDescriptionOf(expectedElement). 157 addDescriptionOf(expectedElement).
152 add(' at position ${expectedPosition}'); 158 add(' at index ${expectedPosition}');
153 return reason.toString(); 159 return reason.toString();
154 } 160 }
155 ++expectedPosition; 161 ++expectedPosition;
156 } 162 }
157 return null; 163 return null;
158 } 164 }
159 165
160 bool matches(item, MatchState mismatchState) => (_test(item) == null); 166 bool matches(item, Map mismatchState) => (_test(item) == null);
161 167
162 Description describe(Description description) => 168 Description describe(Description description) =>
163 description.add('equals ').addDescriptionOf(_expected).add(' unordered'); 169 description.add('equals ').addDescriptionOf(_expected).add(' unordered');
164 170
165 Description describeMismatch(item, Description mismatchDescription, 171 Description describeMismatch(item, Description mismatchDescription,
166 MatchState matchState, bool verbose) => 172 Map matchState, bool verbose) =>
167 mismatchDescription.add(_test(item)); 173 mismatchDescription.add(_test(item));
168 } 174 }
169 175
170 /** 176 /**
171 * Iterable matchers match against [Iterable]s. We add this intermediate 177 * Iterable matchers match against [Iterable]s. We add this intermediate
172 * class to give better mismatch error messages than the base Matcher class. 178 * class to give better mismatch error messages than the base Matcher class.
173 */ 179 */
174 abstract class _IterableMatcher extends BaseMatcher { 180 abstract class _IterableMatcher extends BaseMatcher {
175 const _IterableMatcher(); 181 const _IterableMatcher();
176 Description describeMismatch(item, Description mismatchDescription, 182 Description describeMismatch(item, Description mismatchDescription,
177 MatchState matchState, bool verbose) { 183 Map matchState, bool verbose) {
178 if (item is! Iterable) { 184 if (item is! Iterable) {
179 return mismatchDescription. 185 return mismatchDescription.
180 addDescriptionOf(item). 186 addDescriptionOf(item).
181 add(' not an Iterable'); 187 add(' not an Iterable');
182 } else { 188 } else {
183 return super.describeMismatch(item, mismatchDescription, matchState, 189 return super.describeMismatch(item, mismatchDescription, matchState,
184 verbose); 190 verbose);
185 } 191 }
186 } 192 }
187 } 193 }
188 194
189 /** 195 /**
190 * A pairwise matcher for iterable. You can pass an arbitrary [comparator] 196 * A pairwise matcher for iterable. You can pass an arbitrary [comparator]
191 * function that takes an expected and actual argument which will be applied 197 * function that takes an expected and actual argument which will be applied
192 * to each pair in order. [description] should be a meaningful name for 198 * to each pair in order. [description] should be a meaningful name for
193 * the comparator. 199 * the comparator.
194 */ 200 */
195 Matcher pairwiseCompare(Iterable expected, Function comparator, 201 Matcher pairwiseCompare(Iterable expected, Function comparator,
196 String description) => 202 String description) =>
197 new _PairwiseCompare(expected, comparator, description); 203 new _PairwiseCompare(expected, comparator, description);
198 204
199 class _PairwiseCompare extends _IterableMatcher { 205 class _PairwiseCompare extends _IterableMatcher {
200 Iterable _expected; 206 Iterable _expected;
201 Function _comparator; 207 Function _comparator;
202 String _description; 208 String _description;
203 209
204 _PairwiseCompare(this._expected, this._comparator, this._description); 210 _PairwiseCompare(this._expected, this._comparator, this._description);
205 211
206 bool matches(item, MatchState matchState) { 212 bool matches(item, Map matchState) {
207 if (item is! Iterable) return false; 213 if (item is! Iterable) return false;
208 if (item.length != _expected.length) return false; 214 if (item.length != _expected.length) return false;
209 var iterator = item.iterator; 215 var iterator = item.iterator;
210 var i = 0; 216 var i = 0;
211 for (var e in _expected) { 217 for (var e in _expected) {
212 iterator.moveNext(); 218 iterator.moveNext();
213 if (!_comparator(e, iterator.current)) { 219 if (!_comparator(e, iterator.current)) {
214 matchState.state = { 220 addStateInfo(matchState, {'index': i, 'expected': e, 'actual':
Siggi Cherem (dart-lang) 2013/06/14 01:20:56 nit: move the last key to the next line, so key/va
215 'index': i, 221 iterator.current});
216 'expected': e,
217 'actual' : iterator.current,
218 'state': matchState.state
219 };
220 return false; 222 return false;
221 } 223 }
222 i++; 224 i++;
223 } 225 }
224 return true; 226 return true;
225 } 227 }
226 228
227 Description describe(Description description) => 229 Description describe(Description description) =>
228 description.add('pairwise $_description ').addDescriptionOf(_expected); 230 description.add('pairwise $_description ').addDescriptionOf(_expected);
229 231
230 Description describeMismatch(item, Description mismatchDescription, 232 Description describeMismatch(item, Description mismatchDescription,
231 MatchState matchState, bool verbose) { 233 Map matchState, bool verbose) {
232 if (item is !Iterable) { 234 if (item is !Iterable) {
233 return mismatchDescription.add('not an Iterable'); 235 return mismatchDescription.add('is not an Iterable');
234 } else if (item.length != _expected.length) { 236 } else if (item.length != _expected.length) {
235 return mismatchDescription. 237 return mismatchDescription.
236 add('length was ${item.length} instead of ${_expected.length}'); 238 add('has length ${item.length} instead of ${_expected.length}');
237 } else { 239 } else {
238 return mismatchDescription. 240 return mismatchDescription.
239 addDescriptionOf(matchState.state["actual"]). 241 add('has ').
240 add(' not $_description '). 242 addDescriptionOf(matchState["actual"]).
241 addDescriptionOf(matchState.state["expected"]). 243 add(' which is not $_description ').
242 add(' at position ${matchState.state["index"]}'); 244 addDescriptionOf(matchState["expected"]).
245 add(' at index ${matchState["index"]}');
243 } 246 }
244 } 247 }
245 } 248 }
246 249
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698