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

Side by Side Diff: lib/src/matcher/iterable_matchers.dart

Issue 1135653004: pkg/(unit)test: include a copy of old matcher (Closed) Base URL: https://github.com/dart-lang/test.git@stable
Patch Set: another nit Created 5 years, 7 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
« no previous file with comments | « lib/src/matcher/interfaces.dart ('k') | lib/src/matcher/map_matchers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 library unittest.matcher.iterable_matchers;
6
7 import 'core_matchers.dart';
8 import 'description.dart';
9 import 'interfaces.dart';
10 import 'util.dart';
11
12 /// Returns a matcher which matches [Iterable]s in which all elements
13 /// match the given [matcher].
14 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
15
16 class _EveryElement extends _IterableMatcher {
17 final Matcher _matcher;
18
19 _EveryElement(Matcher this._matcher);
20
21 bool matches(item, Map matchState) {
22 if (item is! Iterable) {
23 return false;
24 }
25 var i = 0;
26 for (var element in item) {
27 if (!_matcher.matches(element, matchState)) {
28 addStateInfo(matchState, {'index': i, 'element': element});
29 return false;
30 }
31 ++i;
32 }
33 return true;
34 }
35
36 Description describe(Description description) =>
37 description.add('every element(').addDescriptionOf(_matcher).add(')');
38
39 Description describeMismatch(
40 item, Description mismatchDescription, Map matchState, bool verbose) {
41 if (matchState['index'] != null) {
42 var index = matchState['index'];
43 var element = matchState['element'];
44 mismatchDescription
45 .add('has value ')
46 .addDescriptionOf(element)
47 .add(' which ');
48 var subDescription = new StringDescription();
49 _matcher.describeMismatch(
50 element, subDescription, matchState['state'], verbose);
51 if (subDescription.length > 0) {
52 mismatchDescription.add(subDescription.toString());
53 } else {
54 mismatchDescription.add("doesn't match ");
55 _matcher.describe(mismatchDescription);
56 }
57 mismatchDescription.add(' at index $index');
58 return mismatchDescription;
59 }
60 return super.describeMismatch(
61 item, mismatchDescription, matchState, verbose);
62 }
63 }
64
65 /// Returns a matcher which matches [Iterable]s in which at least one
66 /// element matches the given [matcher].
67 Matcher anyElement(matcher) => new _AnyElement(wrapMatcher(matcher));
68
69 class _AnyElement extends _IterableMatcher {
70 final Matcher _matcher;
71
72 _AnyElement(this._matcher);
73
74 bool matches(item, Map matchState) {
75 return item.any((e) => _matcher.matches(e, matchState));
76 }
77
78 Description describe(Description description) =>
79 description.add('some element ').addDescriptionOf(_matcher);
80 }
81
82 /// Returns a matcher which matches [Iterable]s that have the same
83 /// length and the same elements as [expected], in the same order.
84 ///
85 /// This is equivalent to [equals] but does not recurse.
86 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
87
88 class _OrderedEquals extends Matcher {
89 final Iterable _expected;
90 Matcher _matcher;
91
92 _OrderedEquals(this._expected) {
93 _matcher = equals(_expected, 1);
94 }
95
96 bool matches(item, Map matchState) =>
97 (item is Iterable) && _matcher.matches(item, matchState);
98
99 Description describe(Description description) =>
100 description.add('equals ').addDescriptionOf(_expected).add(' ordered');
101
102 Description describeMismatch(
103 item, Description mismatchDescription, Map matchState, bool verbose) {
104 if (item is! Iterable) {
105 return mismatchDescription.add('is not an Iterable');
106 } else {
107 return _matcher.describeMismatch(
108 item, mismatchDescription, matchState, verbose);
109 }
110 }
111 }
112
113 /// Returns a matcher which matches [Iterable]s that have the same length and
114 /// the same elements as [expected], but not necessarily in the same order.
115 ///
116 /// Note that this is O(n^2) so should only be used on small objects.
117 Matcher unorderedEquals(Iterable expected) => new _UnorderedEquals(expected);
118
119 class _UnorderedEquals extends _UnorderedMatches {
120 final List _expectedValues;
121
122 _UnorderedEquals(Iterable expected)
123 : super(expected.map(equals)),
124 _expectedValues = expected.toList();
125
126 Description describe(Description description) => description
127 .add('equals ')
128 .addDescriptionOf(_expectedValues)
129 .add(' unordered');
130 }
131
132 /// Iterable matchers match against [Iterable]s. We add this intermediate
133 /// class to give better mismatch error messages than the base Matcher class.
134 abstract class _IterableMatcher extends Matcher {
135 const _IterableMatcher();
136 Description describeMismatch(
137 item, Description mismatchDescription, Map matchState, bool verbose) {
138 if (item is! Iterable) {
139 return mismatchDescription.addDescriptionOf(item).add(' not an Iterable');
140 } else {
141 return super.describeMismatch(
142 item, mismatchDescription, matchState, verbose);
143 }
144 }
145 }
146
147 /// Returns a matcher which matches [Iterable]s whose elements match the
148 /// matchers in [expected], but not necessarily in the same order.
149 ///
150 /// Note that this is `O(n^2)` and so should only be used on small objects.
151 Matcher unorderedMatches(Iterable expected) => new _UnorderedMatches(expected);
152
153 class _UnorderedMatches extends Matcher {
154 final List<Matcher> _expected;
155
156 _UnorderedMatches(Iterable expected)
157 : _expected = expected.map(wrapMatcher).toList();
158
159 String _test(item) {
160 if (item is! Iterable) return 'not iterable';
161 item = item.toList();
162
163 // Check the lengths are the same.
164 if (_expected.length > item.length) {
165 return 'has too few elements (${item.length} < ${_expected.length})';
166 } else if (_expected.length < item.length) {
167 return 'has too many elements (${item.length} > ${_expected.length})';
168 }
169
170 var matched = new List<bool>.filled(item.length, false);
171 var expectedPosition = 0;
172 for (var expectedMatcher in _expected) {
173 var actualPosition = 0;
174 var gotMatch = false;
175 for (var actualElement in item) {
176 if (!matched[actualPosition]) {
177 if (expectedMatcher.matches(actualElement, {})) {
178 matched[actualPosition] = gotMatch = true;
179 break;
180 }
181 }
182 ++actualPosition;
183 }
184
185 if (!gotMatch) {
186 return new StringDescription()
187 .add('has no match for ')
188 .addDescriptionOf(expectedMatcher)
189 .add(' at index ${expectedPosition}')
190 .toString();
191 }
192
193 ++expectedPosition;
194 }
195 return null;
196 }
197
198 bool matches(item, Map mismatchState) => _test(item) == null;
199
200 Description describe(Description description) => description
201 .add('matches ')
202 .addAll('[', ', ', ']', _expected)
203 .add(' unordered');
204
205 Description describeMismatch(
206 item, Description mismatchDescription, Map matchState, bool verbose) =>
207 mismatchDescription.add(_test(item));
208 }
209
210 /// A pairwise matcher for [Iterable]s.
211 ///
212 /// The [comparator] function, taking an expected and an actual argument, and
213 /// returning whether they match, will be applied to each pair in order.
214 /// [description] should be a meaningful name for the comparator.
215 Matcher pairwiseCompare(
216 Iterable expected, bool comparator(a, b), String description) =>
217 new _PairwiseCompare(expected, comparator, description);
218
219 typedef bool _Comparator(a, b);
220
221 class _PairwiseCompare extends _IterableMatcher {
222 final Iterable _expected;
223 final _Comparator _comparator;
224 final String _description;
225
226 _PairwiseCompare(this._expected, this._comparator, this._description);
227
228 bool matches(item, Map matchState) {
229 if (item is! Iterable) return false;
230 if (item.length != _expected.length) return false;
231 var iterator = item.iterator;
232 var i = 0;
233 for (var e in _expected) {
234 iterator.moveNext();
235 if (!_comparator(e, iterator.current)) {
236 addStateInfo(matchState, {
237 'index': i,
238 'expected': e,
239 'actual': iterator.current
240 });
241 return false;
242 }
243 i++;
244 }
245 return true;
246 }
247
248 Description describe(Description description) =>
249 description.add('pairwise $_description ').addDescriptionOf(_expected);
250
251 Description describeMismatch(
252 item, Description mismatchDescription, Map matchState, bool verbose) {
253 if (item is! Iterable) {
254 return mismatchDescription.add('is not an Iterable');
255 } else if (item.length != _expected.length) {
256 return mismatchDescription
257 .add('has length ${item.length} instead of ${_expected.length}');
258 } else {
259 return mismatchDescription
260 .add('has ')
261 .addDescriptionOf(matchState["actual"])
262 .add(' which is not $_description ')
263 .addDescriptionOf(matchState["expected"])
264 .add(' at index ${matchState["index"]}');
265 }
266 }
267 }
OLDNEW
« no previous file with comments | « lib/src/matcher/interfaces.dart ('k') | lib/src/matcher/map_matchers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698