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

Side by Side Diff: quiver/lib/testing/src/equality/equality.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
OLDNEW
(Empty)
1 // Copyright 2014 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 part of quiver.testing.equality;
16
17 /**
18 * Matcher for == and hashCode methods of a class.
19 *
20 * To use, invoke areEqualityGroups with a list of equality groups where each
21 * group contains objects that are supposed to be equal to each other, and
22 * objects of different groups are expected to be unequal. For example:
23 *
24 * expect({
25 * 'hello': ["hello", "h" + "ello"],
26 * 'world': ["world", "wor" + "ld"],
27 * 'three': [2, 1 + 1]
28 * }, areEqualityGroups);
29 *
30 * This tests that:
31 *
32 * * comparing each object against itself returns true
33 * * comparing each object against an instance of an incompatible class
34 * returns false
35 * * comparing each pair of objects within the same equality group returns
36 * true
37 * * comparing each pair of objects from different equality groups returns
38 * false
39 * * the hash codes of any two equal objects are equal
40 * * equals implementation is idempotent
41 *
42 * The format of the Map passed to expect is such that the map keys are used in
43 * error messages to identify the group described by the map value.
44 *
45 * When a test fails, the error message labels the objects involved in
46 * the failed comparison as follows:
47 *
48 * "`[group x, item j]`" refers to the ith item in the xth equality group,
49 * where both equality groups and the items within equality groups are
50 * numbered starting from 1. When either a constructor argument or an
51 * equal object is provided, that becomes group 1.
52 *
53 */
54 const Matcher areEqualityGroups = const _EqualityGroupMatcher();
55
56 const _repetitions = 3;
57
58 class _EqualityGroupMatcher extends Matcher {
59 static const failureReason = 'failureReason';
60 const _EqualityGroupMatcher();
61
62 @override
63 Description describe(Description description) =>
64 description.add('to be equality groups');
65
66 @override
67 bool matches(Map<String, List> item, Map matchState) {
68 try {
69 _verifyEqualityGroups(item, matchState);
70 return true;
71 } on MatchError catch (e) {
72 matchState[failureReason] = e.toString();
73 return false;
74 }
75 }
76
77 Description describeMismatch(item, Description mismatchDescription,
78 Map matchState, bool verbose) =>
79 mismatchDescription.add(" ${matchState[failureReason]}");
80
81 void _verifyEqualityGroups(Map<String, List> equalityGroups, Map matchState) {
82 if (equalityGroups == null) {
83 throw new MatchError('Equality Group must not be null');
84 }
85 var equalityGroupsCopy = {};
86 equalityGroups.forEach((String groupName, List group) {
87 if (groupName == null) {
88 throw new MatchError('Group name must not be null');
89 }
90 if (group == null) {
91 throw new MatchError('Group must not be null');
92 }
93 equalityGroupsCopy[groupName] = new List.from(group);
94 });
95
96 // Run the test multiple times to ensure deterministic equals
97 for (var run in range(_repetitions)) {
98 _checkBasicIdentity(equalityGroupsCopy, matchState);
99 _checkGroupBasedEquality(equalityGroupsCopy);
100 }
101 }
102
103 void _checkBasicIdentity(Map<String, List> equalityGroups, Map matchState) {
104 var flattened = equalityGroups.values.expand((group) => group);
105 for (var item in flattened) {
106 if (item == _NotAnInstance.equalToNothing) {
107 throw new MatchError(
108 "$item must not be equal to an arbitrary object of another class");
109 }
110
111 if (item != item) {
112 throw new MatchError("$item must be equal to itself");
113 }
114
115 if (item.hashCode != item.hashCode) {
116 throw new MatchError("the implementation of hashCode of $item must "
117 "be idempotent");
118 }
119 }
120 }
121
122 void _checkGroupBasedEquality(Map<String, List> equalityGroups) {
123 equalityGroups.forEach((String groupName, List group) {
124 var groupLength = group.length;
125 for (var itemNumber = 0; itemNumber < groupLength; itemNumber++) {
126 _checkEqualToOtherGroup(
127 equalityGroups, groupLength, itemNumber, groupName);
128 _checkUnequalToOtherGroups(equalityGroups, groupName, itemNumber);
129 }
130 });
131 }
132
133 void _checkUnequalToOtherGroups(
134 Map<String, List> equalityGroups, String groupName, int itemNumber) {
135 equalityGroups.forEach((String unrelatedGroupName, List unrelatedGroup) {
136 if (groupName != unrelatedGroupName) {
137 for (var unrelatedItemNumber = 0;
138 unrelatedItemNumber < unrelatedGroup.length;
139 unrelatedItemNumber++) {
140 _expectUnrelated(equalityGroups, groupName, itemNumber,
141 unrelatedGroupName, unrelatedItemNumber);
142 }
143 }
144 });
145 }
146
147 void _checkEqualToOtherGroup(Map<String, List> equalityGroups,
148 int groupLength, int itemNumber, String groupName) {
149 for (var relatedItemNumber = 0;
150 relatedItemNumber < groupLength;
151 relatedItemNumber++) {
152 if (itemNumber != relatedItemNumber) {
153 _expectRelated(
154 equalityGroups, groupName, itemNumber, relatedItemNumber);
155 }
156 }
157 }
158
159 void _expectRelated(Map<String, List> equalityGroups, String groupName,
160 int itemNumber, int relatedItemNumber) {
161 var itemInfo = _createItem(equalityGroups, groupName, itemNumber);
162 var relatedInfo = _createItem(equalityGroups, groupName, relatedItemNumber);
163
164 if (itemInfo.value != relatedInfo.value) {
165 throw new MatchError("$itemInfo must be equal to $relatedInfo");
166 }
167
168 if (itemInfo.value.hashCode != relatedInfo.value.hashCode) {
169 throw new MatchError(
170 "the hashCode (${itemInfo.value.hashCode}) of $itemInfo must "
171 "be equal to the hashCode (${relatedInfo.value.hashCode}) of "
172 "$relatedInfo}");
173 }
174 }
175
176 void _expectUnrelated(Map<String, List> equalityGroups, String groupName,
177 int itemNumber, String unrelatedGroupName, int unrelatedItemNumber) {
178 var itemInfo = _createItem(equalityGroups, groupName, itemNumber);
179 var unrelatedInfo =
180 _createItem(equalityGroups, unrelatedGroupName, unrelatedItemNumber);
181
182 if (itemInfo.value == unrelatedInfo.value) {
183 throw new MatchError("$itemInfo must not be equal to " "$unrelatedInfo)");
184 }
185 }
186
187 _Item _createItem(
188 Map<String, List> equalityGroups, String groupName, int itemNumber) =>
189 new _Item(equalityGroups[groupName][itemNumber], groupName, itemNumber);
190 }
191
192 class _NotAnInstance {
193 static const equalToNothing = const _NotAnInstance._();
194 const _NotAnInstance._();
195 }
196
197 class _Item {
198 final Object value;
199 final String groupName;
200 final int itemNumber;
201
202 _Item(this.value, this.groupName, this.itemNumber);
203
204 @override
205 String toString() => "$value [group '$groupName', item ${itemNumber + 1}]";
206 }
207
208 class MatchError extends Error {
209 final message;
210
211 /// The [message] describes the match error.
212 MatchError([this.message]);
213
214 String toString() => message;
215 }
OLDNEW
« no previous file with comments | « quiver/lib/testing/src/async/fake_async.dart ('k') | quiver/lib/testing/src/runtime/checked_mode.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698