• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
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  * Unit tests for {@link EqualsTester}.
31  *
32  * @author Jim McMaster
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   private ValidTestObject notEqualObject2;
42 
43   @Override
setUp()44   public void setUp() throws Exception {
45     super.setUp();
46     reference = new ValidTestObject(1, 2);
47     equalsTester = new EqualsTester();
48     equalObject1 = new ValidTestObject(1, 2);
49     equalObject2 = new ValidTestObject(1, 2);
50     notEqualObject1 = new ValidTestObject(0, 2);
51     notEqualObject2 = new ValidTestObject(1, 0);
52   }
53 
54   /**
55    * Test null reference yields error
56    */
testAddNullReference()57   public void testAddNullReference() {
58     try {
59       equalsTester.addEqualityGroup((Object) null);
60       fail("Should fail on null reference");
61     } catch (NullPointerException e) {}
62   }
63 
64   /**
65    * Test equalObjects after adding multiple instances at once with a null
66    */
testAddTwoEqualObjectsAtOnceWithNull()67   public void testAddTwoEqualObjectsAtOnceWithNull() {
68     try {
69       equalsTester.addEqualityGroup(reference, equalObject1, null);
70       fail("Should fail on null equal object");
71     } catch (NullPointerException e) {}
72   }
73 
74   /**
75    * Test adding null equal object yields error
76    */
testAddNullEqualObject()77   public void testAddNullEqualObject() {
78     try {
79       equalsTester.addEqualityGroup(reference, (Object[]) null);
80       fail("Should fail on null equal object");
81     } catch (NullPointerException e) {}
82   }
83 
84   /**
85    * Test adding objects only by addEqualityGroup, with no reference object
86    * specified in the constructor.
87    */
testAddEqualObjectWithOArgConstructor()88   public void testAddEqualObjectWithOArgConstructor() {
89     equalsTester.addEqualityGroup(equalObject1, notEqualObject1);
90     try {
91       equalsTester.testEquals();
92     } catch (AssertionFailedError e) {
93       assertErrorMessage(
94         e,
95         equalObject1 + " [group 1, item 1] must be equal to "
96             + notEqualObject1 + " [group 1, item 2]");
97       return;
98     }
99     fail("Should get not equal to equal object error");
100   }
101 
102   /**
103    * Test EqualsTester with no equals or not equals objects.  This checks
104    * proper handling of null, incompatible class and reflexive tests
105    */
testTestEqualsEmptyLists()106   public void testTestEqualsEmptyLists() {
107     equalsTester.addEqualityGroup(reference);
108     equalsTester.testEquals();
109   }
110 
111   /**
112    * Test EqualsTester after populating equalObjects.  This checks proper
113    * handling of equality and verifies hashCode for valid objects
114    */
testTestEqualsEqualsObjects()115   public void testTestEqualsEqualsObjects() {
116     equalsTester.addEqualityGroup(reference, equalObject1, equalObject2);
117     equalsTester.testEquals();
118   }
119 
120   /**
121    * Test proper handling of case where an object is not equal to itself
122    */
testNonreflexiveEquals()123   public void testNonreflexiveEquals() {
124     Object obj = new NonReflexiveObject();
125     equalsTester.addEqualityGroup(obj);
126     try {
127       equalsTester.testEquals();
128     } catch (AssertionFailedError e) {
129       assertErrorMessage(
130           e, obj + " must be equal to itself");
131       return;
132     }
133     fail("Should get non-reflexive error");
134   }
135 
136   /**
137    * Test proper handling where an object tests equal to null
138    */
testInvalidEqualsNull()139   public void testInvalidEqualsNull() {
140     Object obj = new InvalidEqualsNullObject();
141     equalsTester.addEqualityGroup(obj);
142     try {
143       equalsTester.testEquals();
144     } catch (AssertionFailedError e) {
145       assertErrorMessage(
146           e, obj + " must be unequal to null");
147       return;
148     }
149     fail("Should get equal to null error");
150   }
151 
152   /**
153    * Test proper handling where an object incorrectly tests for an
154    * incompatible class
155    */
testInvalidEqualsIncompatibleClass()156   public void testInvalidEqualsIncompatibleClass() {
157     Object obj = new InvalidEqualsIncompatibleClassObject();
158     equalsTester.addEqualityGroup(obj);
159     try {
160       equalsTester.testEquals();
161     } catch (AssertionFailedError e) {
162       assertErrorMessage(
163           e,
164           obj
165           + " must be unequal to an arbitrary object of another class");
166       return;
167     }
168     fail("Should get equal to incompatible class error");
169   }
170 
171   /**
172    * Test proper handling where an object is not equal to one the user has
173    * said should be equal
174    */
testInvalidNotEqualsEqualObject()175   public void testInvalidNotEqualsEqualObject() {
176     equalsTester.addEqualityGroup(reference, notEqualObject1);
177     try {
178       equalsTester.testEquals();
179     } catch (AssertionFailedError e) {
180       assertErrorMessage(e, reference.toString() + " [group 1, item 1]");
181       assertErrorMessage(e, notEqualObject1.toString() + " [group 1, item 2]");
182       return;
183     }
184     fail("Should get not equal to equal object error");
185   }
186 
187   /**
188    * Test for an invalid hashCode method, i.e., one that returns different
189    * value for objects that are equal according to the equals method
190    */
testInvalidHashCode()191   public void testInvalidHashCode() {
192     Object a = new InvalidHashCodeObject(1, 2);
193     Object b = new InvalidHashCodeObject(1, 2);
194     equalsTester.addEqualityGroup(a, b);
195     try {
196       equalsTester.testEquals();
197     } catch (AssertionFailedError e) {
198       assertErrorMessage(
199           e, "the hash (" + a.hashCode() + ") of " + a
200           + " [group 1, item 1] must be equal to the hash (" + b.hashCode() + ") of " + b);
201       return;
202     }
203     fail("Should get invalid hashCode error");
204   }
205 
testNullEqualityGroup()206   public void testNullEqualityGroup() {
207     EqualsTester tester = new EqualsTester();
208     try {
209       tester.addEqualityGroup((Object[]) null);
210       fail();
211     } catch (NullPointerException e) {}
212   }
213 
testNullObjectInEqualityGroup()214   public void testNullObjectInEqualityGroup() {
215     EqualsTester tester = new EqualsTester();
216     try {
217       tester.addEqualityGroup(1, null, 3);
218       fail();
219     } catch (NullPointerException e) {
220       assertErrorMessage(e, "at index 1");
221     }
222   }
223 
testSymmetryBroken()224   public void testSymmetryBroken() {
225     EqualsTester tester = new EqualsTester()
226         .addEqualityGroup(named("foo").addPeers("bar"), named("bar"));
227     try {
228       tester.testEquals();
229     } catch (AssertionFailedError e) {
230       assertErrorMessage(
231           e,
232           "bar [group 1, item 2] must be equal to foo [group 1, item 1]");
233       return;
234     }
235     fail("should failed because symmetry is broken");
236   }
237 
testTransitivityBrokenInEqualityGroup()238   public void testTransitivityBrokenInEqualityGroup() {
239     EqualsTester tester = new EqualsTester()
240         .addEqualityGroup(
241             named("foo").addPeers("bar", "baz"),
242             named("bar").addPeers("foo"),
243             named("baz").addPeers("foo"));
244     try {
245       tester.testEquals();
246     } catch (AssertionFailedError e) {
247       assertErrorMessage(
248           e,
249           "bar [group 1, item 2] must be equal to baz [group 1, item 3]");
250       return;
251     }
252     fail("should failed because transitivity is broken");
253   }
254 
testUnequalObjectsInEqualityGroup()255   public void testUnequalObjectsInEqualityGroup() {
256     EqualsTester tester = new EqualsTester()
257         .addEqualityGroup(named("foo"), named("bar"));
258     try {
259       tester.testEquals();
260     } catch (AssertionFailedError e) {
261       assertErrorMessage(
262           e,
263           "foo [group 1, item 1] must be equal to bar [group 1, item 2]");
264       return;
265     }
266     fail("should failed because of unequal objects in the same equality group");
267   }
268 
testTransitivityBrokenAcrossEqualityGroups()269   public void testTransitivityBrokenAcrossEqualityGroups() {
270     EqualsTester tester = new EqualsTester()
271         .addEqualityGroup(
272             named("foo").addPeers("bar"),
273             named("bar").addPeers("foo", "x"))
274         .addEqualityGroup(
275             named("baz").addPeers("x"),
276             named("x").addPeers("baz", "bar"));
277     try {
278       tester.testEquals();
279     } catch (AssertionFailedError e) {
280       assertErrorMessage(
281           e,
282           "bar [group 1, item 2] must be unequal to x [group 2, item 2]");
283       return;
284     }
285     fail("should failed because transitivity is broken");
286   }
287 
testEqualityGroups()288   public void testEqualityGroups() {
289     new EqualsTester()
290         .addEqualityGroup(
291             named("foo").addPeers("bar"), named("bar").addPeers("foo"))
292         .addEqualityGroup(named("baz"), named("baz"))
293         .testEquals();
294   }
295 
assertErrorMessage(Throwable e, String message)296   private static void assertErrorMessage(Throwable e, String message) {
297     // TODO(kevinb): use a Truth assertion here
298     if (!e.getMessage().contains(message)) {
299       fail("expected <" + e.getMessage() + "> to contain <" + message + ">");
300     }
301   }
302 
303   /**
304    * Test class with valid equals and hashCode methods.  Testers created
305    * with instances of this class should always pass.
306    */
307   private static class ValidTestObject {
308     private int aspect1;
309     private int aspect2;
310 
ValidTestObject(int aspect1, int aspect2)311     ValidTestObject(int aspect1, int aspect2) {
312       this.aspect1 = aspect1;
313       this.aspect2 = aspect2;
314     }
315 
equals(Object o)316     @Override public boolean equals(Object o) {
317       if (!(o instanceof ValidTestObject)) {
318         return false;
319       }
320       ValidTestObject other = (ValidTestObject) o;
321       if (aspect1 != other.aspect1) {
322         return false;
323       }
324       if (aspect2 != other.aspect2) {
325         return false;
326       }
327       return true;
328     }
329 
hashCode()330     @Override public int hashCode() {
331       int result = 17;
332       result = 37 * result + aspect1;
333       result = 37 * result + aspect2;
334       return result;
335     }
336   }
337 
338   /** Test class with invalid hashCode method. */
339   private static class InvalidHashCodeObject {
340     private int aspect1;
341     private int aspect2;
342 
InvalidHashCodeObject(int aspect1, int aspect2)343     InvalidHashCodeObject(int aspect1, int aspect2) {
344       this.aspect1 = aspect1;
345       this.aspect2 = aspect2;
346     }
347 
equals(Object o)348     @Override public boolean equals(Object o) {
349       if (!(o instanceof InvalidHashCodeObject)) {
350         return false;
351       }
352       InvalidHashCodeObject other = (InvalidHashCodeObject) o;
353       if (aspect1 != other.aspect1) {
354         return false;
355       }
356       if (aspect2 != other.aspect2) {
357         return false;
358       }
359       return true;
360     }
361   }
362 
363   /** Test class that violates reflexitivity.  It is not equal to itself */
364   private static class NonReflexiveObject{
365 
equals(Object o)366     @Override public boolean equals(Object o) {
367       return false;
368     }
369 
hashCode()370     @Override public int hashCode() {
371       return super.hashCode();
372     }
373   }
374 
375   /** Test class that returns true if the test object is null */
376   private static class InvalidEqualsNullObject{
377 
equals(Object o)378     @Override public boolean equals(Object o) {
379       return o == this || o == null;
380     }
381 
hashCode()382     @Override public int hashCode() {
383       return 0;
384     }
385   }
386 
387   /**
388    * Test class that returns true even if the test object is of the wrong class
389    */
390   private static class InvalidEqualsIncompatibleClassObject{
391 
equals(Object o)392     @Override public boolean equals(Object o) {
393       if (o == null) {
394         return false;
395       }
396       return true;
397     }
398 
hashCode()399     @Override public int hashCode() {
400       return 0;
401     }
402   }
403 
named(String name)404   private static NamedObject named(String name) {
405     return new NamedObject(name);
406   }
407 
408   private static class NamedObject {
409     private final Set<String> peerNames = Sets.newHashSet();
410 
411     private final String name;
412 
NamedObject(String name)413     NamedObject(String name) {
414       this.name = Preconditions.checkNotNull(name);
415     }
416 
addPeers(String... names)417     NamedObject addPeers(String... names) {
418       peerNames.addAll(ImmutableList.copyOf(names));
419       return this;
420     }
421 
equals(Object obj)422     @Override public boolean equals(Object obj) {
423       if (obj instanceof NamedObject) {
424         NamedObject that = (NamedObject) obj;
425         return name.equals(that.name) || peerNames.contains(that.name);
426       }
427       return false;
428     }
429 
hashCode()430     @Override public int hashCode() {
431       return 0;
432     }
433 
toString()434     @Override public String toString() {
435       return name;
436     }
437   }
438 }
439