Home | History | Annotate | Download | only in testing
      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
     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    */
     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    */
     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    */
     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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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 
    206   public void testNullEqualityGroup() {
    207     EqualsTester tester = new EqualsTester();
    208     try {
    209       tester.addEqualityGroup((Object[]) null);
    210       fail();
    211     } catch (NullPointerException e) {}
    212   }
    213 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    311     ValidTestObject(int aspect1, int aspect2) {
    312       this.aspect1 = aspect1;
    313       this.aspect2 = aspect2;
    314     }
    315 
    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 
    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 
    343     InvalidHashCodeObject(int aspect1, int aspect2) {
    344       this.aspect1 = aspect1;
    345       this.aspect2 = aspect2;
    346     }
    347 
    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 
    366     @Override public boolean equals(Object o) {
    367       return false;
    368     }
    369 
    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 
    378     @Override public boolean equals(Object o) {
    379       return o == this || o == null;
    380     }
    381 
    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 
    392     @Override public boolean equals(Object o) {
    393       if (o == null) {
    394         return false;
    395       }
    396       return true;
    397     }
    398 
    399     @Override public int hashCode() {
    400       return 0;
    401     }
    402   }
    403 
    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 
    413     NamedObject(String name) {
    414       this.name = Preconditions.checkNotNull(name);
    415     }
    416 
    417     NamedObject addPeers(String... names) {
    418       peerNames.addAll(ImmutableList.copyOf(names));
    419       return this;
    420     }
    421 
    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 
    430     @Override public int hashCode() {
    431       return 0;
    432     }
    433 
    434     @Override public String toString() {
    435       return name;
    436     }
    437   }
    438 }
    439