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 * Returns a matcher which matches collections in which all elements | |
7 * match the given [matcher]. | |
8 */ | |
9 IMatcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); | |
10 | |
11 class _EveryElement extends _CollectionMatcher { | |
12 Matcher _matcher; | |
13 | |
14 _EveryElement(Matcher this._matcher); | |
15 | |
16 bool matches(item) { | |
17 try { | |
18 return item.every((e) => _matcher.matches(e)); | |
19 } catch (var e) { | |
20 return false; | |
21 } | |
22 } | |
23 | |
24 IDescription describe(IDescription description) => | |
25 description.add('every element ').addDescriptionOf(_matcher); | |
26 } | |
27 | |
28 /** | |
29 * Returns a matcher which matches collections in which at least one | |
30 * element matches the given [matcher]. | |
31 */ | |
32 IMatcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher)); | |
33 | |
34 class _SomeElement extends _CollectionMatcher { | |
35 Matcher _matcher; | |
36 | |
37 _SomeElement(this._matcher); | |
38 | |
39 bool matches(item) { | |
40 try { | |
41 return item.some( (e) => _matcher.matches(e) ); | |
42 } catch (var e) { | |
43 return false; | |
44 } | |
45 } | |
46 | |
47 IDescription describe(IDescription description) => | |
48 description.add('some element ').addDescriptionOf(_matcher); | |
49 } | |
50 | |
51 /** | |
52 * Returns a matcher which matches Iterables that have the same | |
53 * length and the same elements as [expected], and in the same order. | |
54 */ | |
55 IMatcher orderedEquals(Iterable expected) => new _OrderedEquals(expected); | |
56 | |
57 class _OrderedEquals extends Matcher { | |
58 Iterable _expected; | |
59 | |
60 _OrderedEquals(this._expected); | |
61 | |
62 String _test(item) { | |
63 if (item is !Iterable) { | |
64 return 'is not Iterable'; | |
65 } | |
66 var expectedIterator = _expected.iterator(); | |
67 var actualIterator = item.iterator(); | |
68 var position = 0; | |
69 while (true) { | |
70 if (expectedIterator.hasNext()) { | |
71 if (actualIterator.hasNext()) { | |
72 if (expectedIterator.next() != actualIterator.next()) { | |
73 return 'mismatch at position ${position}'; | |
74 } else { | |
75 ++position; | |
76 } | |
77 } else { | |
78 return 'shorter than expected'; | |
79 } | |
80 } else if (actualIterator.hasNext()) { | |
81 return 'longer than expected'; | |
82 } else { | |
83 return null; | |
84 } | |
85 } | |
86 } | |
87 | |
88 bool matches(item) => (_test(item) == null); | |
89 | |
90 IDescription describe(IDescription description) => | |
91 description.add('equals ').addDescriptionOf(_expected).add(' ordered'); | |
92 | |
93 IDescription describeMismatch(item, IDescription mismatchDescription) => | |
94 mismatchDescription.add(_test(item)); | |
95 } | |
96 | |
97 /** | |
98 * Returns a matcher which matches Iterables that have the same | |
99 * length and the same elements as [expected], but not necessarily in | |
100 * the same order. Note that this is O(n^2) so should only be used on | |
101 * small objects. | |
102 */ | |
103 IMatcher unorderedEquals(Iterable expected) => | |
104 new _UnorderedEquals(expected); | |
105 | |
106 class _UnorderedEquals extends Matcher { | |
107 Iterable _expected; | |
108 | |
109 _UnorderedEquals(Iterable this._expected); | |
110 | |
111 String _test(item) { | |
112 if (item is !Iterable) { | |
113 return 'not iterable'; | |
114 } | |
Bob Nystrom
2012/06/01 18:22:23
If you like, you can make this a single line:
if
gram
2012/06/01 22:22:00
I think I prefer it split, especially as it has a
| |
115 // Check the lengths are the same. | |
116 var expectedLength = 0; | |
117 if (_expected is Collection) { | |
118 Collection cast = _expected; // "_expected as Collection" | |
119 expectedLength = cast.length; | |
120 } else { | |
121 for (var element in _expected) { | |
122 ++expectedLength; | |
123 } | |
124 } | |
125 var actualLength = 0; | |
126 if (item is Collection) { | |
127 actualLength = item.length; | |
128 } else { | |
129 for (var element in item) { | |
130 ++actualLength; | |
131 } | |
132 } | |
133 if (expectedLength > actualLength) { | |
134 return 'has too few elements (${actualLength} < ${expectedLength})'; | |
135 } else if (expectedLength < actualLength) { | |
136 return 'has too many elements (${actualLength} > ${expectedLength})'; | |
137 } | |
138 var mask = 0; | |
139 var expectedPosition = 0; | |
140 for (var expectedElement in _expected) { | |
141 var actualPosition = 0; | |
142 var matched = false; | |
143 for (var actualElement in item) { | |
144 if ((mask & (1 << actualPosition)) == 0) { // not matched yet? | |
145 if (expectedElement == actualElement) { | |
146 matched = true; | |
147 mask |= (1 << actualPosition); | |
Bob Nystrom
2012/06/01 18:22:23
This may be the first Dart code I've seen that rel
gram
2012/06/01 22:22:00
I was concerned about that. In one respect I want
Bob Nystrom
2012/06/01 22:29:01
Maybe leave a TODO: use int when all Dart implemen
| |
148 break; | |
149 } | |
150 } | |
151 ++actualPosition; | |
152 } | |
153 if (!matched) { | |
154 return 'has no match for element ${expectedElement} ' | |
155 'at position ${expectedPosition}'; | |
156 } | |
157 ++expectedPosition; | |
158 } | |
159 return null; | |
160 } | |
161 | |
162 bool matches(item) => (_test(item) == null); | |
163 | |
164 IDescription describe(IDescription description) => | |
165 description.add('equals ').addDescriptionOf(_expected).add(' unordered'); | |
166 | |
167 IDescription describeMismatch(item, IDescription mismatchDescription) => | |
168 mismatchDescription.add(_test(item)); | |
169 } | |
170 | |
171 /** | |
172 * Collection matchers match against a collection. We add this intermediate | |
173 * class to give better mismatch error messages than the base Matcher class. | |
174 */ | |
175 | |
176 /*abstract*/ class _CollectionMatcher extends Matcher { | |
Bob Nystrom
2012/06/01 18:22:23
I think Dart does actually allow abstract here (wh
gram
2012/06/01 22:22:00
frog barfs when generating docs.
Bob Nystrom
2012/06/01 22:29:01
Ah. Please leave a TODO then saying "uncomment thi
| |
177 const _CollectionMatcher(); | |
178 IDescription describeMismatch(item, IDescription mismatchDescription) { | |
179 if (item is !Collection) { | |
180 return mismatchDescription. | |
181 addDescriptionOf(item). | |
182 add(' not a collection'); | |
183 } else { | |
184 return super.describeMismatch(item, mismatchDescription); | |
185 } | |
186 } | |
187 } | |
OLD | NEW |