1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.testing;
18
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Preconditions;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.Sets;
23
24 import junit.framework.AssertionFailedError;
25 import junit.framework.TestCase;
26
27 import java.util.Set;
28
29
30
31
32
33
34 @GwtCompatible
35 public class EqualsTesterTest extends TestCase {
36 private ValidTestObject reference;
37 private EqualsTester equalsTester;
38 private ValidTestObject equalObject1;
39 private ValidTestObject equalObject2;
40 private ValidTestObject notEqualObject1;
41
42 @Override
43 public void setUp() throws Exception {
44 super.setUp();
45 reference = new ValidTestObject(1, 2);
46 equalsTester = new EqualsTester();
47 equalObject1 = new ValidTestObject(1, 2);
48 equalObject2 = new ValidTestObject(1, 2);
49 notEqualObject1 = new ValidTestObject(0, 2);
50 }
51
52
53
54
55 public void testAddNullReference() {
56 try {
57 equalsTester.addEqualityGroup((Object) null);
58 fail("Should fail on null reference");
59 } catch (NullPointerException e) {}
60 }
61
62
63
64
65 public void testAddTwoEqualObjectsAtOnceWithNull() {
66 try {
67 equalsTester.addEqualityGroup(reference, equalObject1, null);
68 fail("Should fail on null equal object");
69 } catch (NullPointerException e) {}
70 }
71
72
73
74
75 public void testAddNullEqualObject() {
76 try {
77 equalsTester.addEqualityGroup(reference, (Object[]) null);
78 fail("Should fail on null equal object");
79 } catch (NullPointerException e) {}
80 }
81
82
83
84
85
86 public void testAddEqualObjectWithOArgConstructor() {
87 equalsTester.addEqualityGroup(equalObject1, notEqualObject1);
88 try {
89 equalsTester.testEquals();
90 } catch (AssertionFailedError e) {
91 assertErrorMessage(
92 e,
93 equalObject1 + " [group 1, item 1] must be Object#equals to "
94 + notEqualObject1 + " [group 1, item 2]");
95 return;
96 }
97 fail("Should get not equal to equal object error");
98 }
99
100
101
102
103
104 public void testTestEqualsEmptyLists() {
105 equalsTester.addEqualityGroup(reference);
106 equalsTester.testEquals();
107 }
108
109
110
111
112
113 public void testTestEqualsEqualsObjects() {
114 equalsTester.addEqualityGroup(reference, equalObject1, equalObject2);
115 equalsTester.testEquals();
116 }
117
118
119
120
121 public void testNonreflexiveEquals() {
122 Object obj = new NonReflexiveObject();
123 equalsTester.addEqualityGroup(obj);
124 try {
125 equalsTester.testEquals();
126 } catch (AssertionFailedError e) {
127 assertErrorMessage(
128 e, obj + " must be Object#equals to itself");
129 return;
130 }
131 fail("Should get non-reflexive error");
132 }
133
134
135
136
137 public void testInvalidEqualsNull() {
138 Object obj = new InvalidEqualsNullObject();
139 equalsTester.addEqualityGroup(obj);
140 try {
141 equalsTester.testEquals();
142 } catch (AssertionFailedError e) {
143 assertErrorMessage(
144 e, obj + " must not be Object#equals to null");
145 return;
146 }
147 fail("Should get equal to null error");
148 }
149
150
151
152
153
154 public void testInvalidEqualsIncompatibleClass() {
155 Object obj = new InvalidEqualsIncompatibleClassObject();
156 equalsTester.addEqualityGroup(obj);
157 try {
158 equalsTester.testEquals();
159 } catch (AssertionFailedError e) {
160 assertErrorMessage(
161 e,
162 obj
163 + " must not be Object#equals to an arbitrary object of another class");
164 return;
165 }
166 fail("Should get equal to incompatible class error");
167 }
168
169
170
171
172
173 public void testInvalidNotEqualsEqualObject() {
174 equalsTester.addEqualityGroup(reference, notEqualObject1);
175 try {
176 equalsTester.testEquals();
177 } catch (AssertionFailedError e) {
178 assertErrorMessage(e, reference + " [group 1, item 1]");
179 assertErrorMessage(e, notEqualObject1 + " [group 1, item 2]");
180 return;
181 }
182 fail("Should get not equal to equal object error");
183 }
184
185
186
187
188
189 public void testInvalidHashCode() {
190 Object a = new InvalidHashCodeObject(1, 2);
191 Object b = new InvalidHashCodeObject(1, 2);
192 equalsTester.addEqualityGroup(a, b);
193 try {
194 equalsTester.testEquals();
195 } catch (AssertionFailedError e) {
196 assertErrorMessage(
197 e, "the Object#hashCode (" + a.hashCode() + ") of " + a
198 + " [group 1, item 1] must be equal to the Object#hashCode ("
199 + b.hashCode() + ") of " + b);
200 return;
201 }
202 fail("Should get invalid hashCode error");
203 }
204
205 public void testNullEqualityGroup() {
206 EqualsTester tester = new EqualsTester();
207 try {
208 tester.addEqualityGroup((Object[]) null);
209 fail();
210 } catch (NullPointerException e) {}
211 }
212
213 public void testNullObjectInEqualityGroup() {
214 EqualsTester tester = new EqualsTester();
215 try {
216 tester.addEqualityGroup(1, null, 3);
217 fail();
218 } catch (NullPointerException e) {
219 assertErrorMessage(e, "at index 1");
220 }
221 }
222
223 public void testSymmetryBroken() {
224 EqualsTester tester = new EqualsTester()
225 .addEqualityGroup(named("foo").addPeers("bar"), named("bar"));
226 try {
227 tester.testEquals();
228 } catch (AssertionFailedError e) {
229 assertErrorMessage(
230 e,
231 "bar [group 1, item 2] must be Object#equals to foo [group 1, item 1]");
232 return;
233 }
234 fail("should failed because symmetry is broken");
235 }
236
237 public void testTransitivityBrokenInEqualityGroup() {
238 EqualsTester tester = new EqualsTester()
239 .addEqualityGroup(
240 named("foo").addPeers("bar", "baz"),
241 named("bar").addPeers("foo"),
242 named("baz").addPeers("foo"));
243 try {
244 tester.testEquals();
245 } catch (AssertionFailedError e) {
246 assertErrorMessage(
247 e,
248 "bar [group 1, item 2] must be Object#equals to baz [group 1, item 3]");
249 return;
250 }
251 fail("should failed because transitivity is broken");
252 }
253
254 public void testUnequalObjectsInEqualityGroup() {
255 EqualsTester tester = new EqualsTester()
256 .addEqualityGroup(named("foo"), named("bar"));
257 try {
258 tester.testEquals();
259 } catch (AssertionFailedError e) {
260 assertErrorMessage(
261 e,
262 "foo [group 1, item 1] must be Object#equals to bar [group 1, item 2]");
263 return;
264 }
265 fail("should failed because of unequal objects in the same equality group");
266 }
267
268 public void testTransitivityBrokenAcrossEqualityGroups() {
269 EqualsTester tester = new EqualsTester()
270 .addEqualityGroup(
271 named("foo").addPeers("bar"),
272 named("bar").addPeers("foo", "x"))
273 .addEqualityGroup(
274 named("baz").addPeers("x"),
275 named("x").addPeers("baz", "bar"));
276 try {
277 tester.testEquals();
278 } catch (AssertionFailedError e) {
279 assertErrorMessage(
280 e,
281 "bar [group 1, item 2] must not be Object#equals to x [group 2, item 2]");
282 return;
283 }
284 fail("should failed because transitivity is broken");
285 }
286
287 public void testEqualityGroups() {
288 new EqualsTester()
289 .addEqualityGroup(
290 named("foo").addPeers("bar"), named("bar").addPeers("foo"))
291 .addEqualityGroup(named("baz"), named("baz"))
292 .testEquals();
293 }
294
295 private static void assertErrorMessage(Throwable e, String message) {
296
297 if (!e.getMessage().contains(message)) {
298 fail("expected <" + e.getMessage() + "> to contain <" + message + ">");
299 }
300 }
301
302
303
304
305
306 private static class ValidTestObject {
307 private int aspect1;
308 private int aspect2;
309
310 ValidTestObject(int aspect1, int aspect2) {
311 this.aspect1 = aspect1;
312 this.aspect2 = aspect2;
313 }
314
315 @Override public boolean equals(Object o) {
316 if (!(o instanceof ValidTestObject)) {
317 return false;
318 }
319 ValidTestObject other = (ValidTestObject) o;
320 if (aspect1 != other.aspect1) {
321 return false;
322 }
323 if (aspect2 != other.aspect2) {
324 return false;
325 }
326 return true;
327 }
328
329 @Override public int hashCode() {
330 int result = 17;
331 result = 37 * result + aspect1;
332 result = 37 * result + aspect2;
333 return result;
334 }
335 }
336
337
338 private static class InvalidHashCodeObject {
339 private int aspect1;
340 private int aspect2;
341
342 InvalidHashCodeObject(int aspect1, int aspect2) {
343 this.aspect1 = aspect1;
344 this.aspect2 = aspect2;
345 }
346
347 @Override public boolean equals(Object o) {
348 if (!(o instanceof InvalidHashCodeObject)) {
349 return false;
350 }
351 InvalidHashCodeObject other = (InvalidHashCodeObject) o;
352 if (aspect1 != other.aspect1) {
353 return false;
354 }
355 if (aspect2 != other.aspect2) {
356 return false;
357 }
358 return true;
359 }
360 }
361
362
363 private static class NonReflexiveObject {
364
365 @Override public boolean equals(Object o) {
366 return false;
367 }
368
369 @Override public int hashCode() {
370 return super.hashCode();
371 }
372 }
373
374
375 private static class InvalidEqualsNullObject {
376
377 @Override public boolean equals(Object o) {
378 return o == this || o == null;
379 }
380
381 @Override public int hashCode() {
382 return 0;
383 }
384 }
385
386
387
388
389 private static class InvalidEqualsIncompatibleClassObject {
390
391 @Override public boolean equals(Object o) {
392 if (o == null) {
393 return false;
394 }
395 return true;
396 }
397
398 @Override public int hashCode() {
399 return 0;
400 }
401 }
402
403 private static NamedObject named(String name) {
404 return new NamedObject(name);
405 }
406
407 private static class NamedObject {
408 private final Set<String> peerNames = Sets.newHashSet();
409
410 private final String name;
411
412 NamedObject(String name) {
413 this.name = Preconditions.checkNotNull(name);
414 }
415
416 NamedObject addPeers(String... names) {
417 peerNames.addAll(ImmutableList.copyOf(names));
418 return this;
419 }
420
421 @Override public boolean equals(Object obj) {
422 if (obj instanceof NamedObject) {
423 NamedObject that = (NamedObject) obj;
424 return name.equals(that.name) || peerNames.contains(that.name);
425 }
426 return false;
427 }
428
429 @Override public int hashCode() {
430 return 0;
431 }
432
433 @Override public String toString() {
434 return name;
435 }
436 }
437 }