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