1 /*
2  * Copyright (C) 2011 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 static com.google.common.base.Preconditions.checkState;
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.base.Equivalence;
24 import com.google.common.base.MoreObjects;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableTable;
27 
28 import junit.framework.AssertionFailedError;
29 import junit.framework.TestCase;
30 
31 /**
32  * Tests for {@link EquivalenceTester}.
33  *
34  * @author Gregory Kick
35  */
36 @GwtCompatible
37 public class EquivalenceTesterTest extends TestCase {
38   private EquivalenceTester<Object> tester;
39   private MockEquivalence equivalenceMock;
40 
setUp()41   @Override public void setUp() throws Exception {
42     super.setUp();
43     this.equivalenceMock = new MockEquivalence();
44     this.tester = EquivalenceTester.of(equivalenceMock);
45   }
46 
47   /** Test null reference yields error */
testOf_NullPointerException()48   public void testOf_NullPointerException() {
49     try {
50       EquivalenceTester.of(null);
51       fail("Should fail on null reference");
52     } catch (NullPointerException expected) {}
53   }
54 
testTest_NoData()55   public void testTest_NoData() {
56     tester.test();
57   }
58 
testTest()59   public void testTest() {
60     Object group1Item1 = new TestObject(1, 1);
61     Object group1Item2 = new TestObject(1, 2);
62     Object group2Item1 = new TestObject(2, 1);
63     Object group2Item2 = new TestObject(2, 2);
64 
65     equivalenceMock.expectEquivalent(group1Item1, group1Item2);
66     equivalenceMock.expectDistinct(group1Item1, group2Item1);
67     equivalenceMock.expectDistinct(group1Item1, group2Item2);
68     equivalenceMock.expectEquivalent(group1Item2, group1Item1);
69     equivalenceMock.expectDistinct(group1Item2, group2Item1);
70     equivalenceMock.expectDistinct(group1Item2, group2Item2);
71     equivalenceMock.expectDistinct(group2Item1, group1Item1);
72     equivalenceMock.expectDistinct(group2Item1, group1Item2);
73     equivalenceMock.expectEquivalent(group2Item1, group2Item2);
74     equivalenceMock.expectDistinct(group2Item2, group1Item1);
75     equivalenceMock.expectDistinct(group2Item2, group1Item2);
76     equivalenceMock.expectEquivalent(group2Item2, group2Item1);
77 
78     equivalenceMock.expectHash(group1Item1, 1);
79     equivalenceMock.expectHash(group1Item2, 1);
80     equivalenceMock.expectHash(group2Item1, 2);
81     equivalenceMock.expectHash(group2Item2, 2);
82 
83     equivalenceMock.replay();
84 
85     tester.addEquivalenceGroup(group1Item1, group1Item2)
86         .addEquivalenceGroup(group2Item1, group2Item2)
87         .test();
88   }
89 
testTest_symmetric()90   public void testTest_symmetric() {
91     Object group1Item1 = new TestObject(1, 1);
92     Object group1Item2 = new TestObject(1, 2);
93 
94     equivalenceMock.expectEquivalent(group1Item1, group1Item2);
95     equivalenceMock.expectDistinct(group1Item2, group1Item1);
96 
97     equivalenceMock.expectHash(group1Item1, 1);
98     equivalenceMock.expectHash(group1Item2, 1);
99 
100     equivalenceMock.replay();
101 
102     try {
103       tester.addEquivalenceGroup(group1Item1, group1Item2).test();
104     } catch (AssertionFailedError expected) {
105       assertThat(expected.getMessage()).contains(
106           "TestObject{group=1, item=2} [group 1, item 2] must be equivalent to "
107           + "TestObject{group=1, item=1} [group 1, item 1]");
108       return;
109     }
110     fail();
111   }
112 
testTest_trasitive()113   public void testTest_trasitive() {
114     Object group1Item1 = new TestObject(1, 1);
115     Object group1Item2 = new TestObject(1, 2);
116     Object group1Item3 = new TestObject(1, 3);
117 
118     equivalenceMock.expectEquivalent(group1Item1, group1Item2);
119     equivalenceMock.expectEquivalent(group1Item1, group1Item3);
120     equivalenceMock.expectEquivalent(group1Item2, group1Item1);
121     equivalenceMock.expectDistinct(group1Item2, group1Item3);
122     equivalenceMock.expectEquivalent(group1Item3, group1Item1);
123     equivalenceMock.expectEquivalent(group1Item3, group1Item2);
124 
125     equivalenceMock.expectHash(group1Item1, 1);
126     equivalenceMock.expectHash(group1Item2, 1);
127     equivalenceMock.expectHash(group1Item3, 1);
128 
129     equivalenceMock.replay();
130 
131     try {
132       tester.addEquivalenceGroup(group1Item1, group1Item2, group1Item3).test();
133     } catch (AssertionFailedError expected) {
134       assertThat(expected.getMessage()).contains(
135           "TestObject{group=1, item=2} [group 1, item 2] must be equivalent to "
136           + "TestObject{group=1, item=3} [group 1, item 3]");
137       return;
138     }
139     fail();
140   }
141 
testTest_inequivalence()142   public void testTest_inequivalence() {
143     Object group1Item1 = new TestObject(1, 1);
144     Object group2Item1 = new TestObject(2, 1);
145 
146     equivalenceMock.expectEquivalent(group1Item1, group2Item1);
147     equivalenceMock.expectDistinct(group2Item1, group1Item1);
148 
149     equivalenceMock.expectHash(group1Item1, 1);
150     equivalenceMock.expectHash(group2Item1, 2);
151 
152     equivalenceMock.replay();
153 
154     try {
155       tester.addEquivalenceGroup(group1Item1).addEquivalenceGroup(group2Item1).test();
156     } catch (AssertionFailedError expected) {
157       assertThat(expected.getMessage()).contains(
158           "TestObject{group=1, item=1} [group 1, item 1] must not be equivalent to "
159           + "TestObject{group=2, item=1} [group 2, item 1]");
160       return;
161     }
162     fail();
163   }
164 
testTest_hash()165   public void testTest_hash() {
166     Object group1Item1 = new TestObject(1, 1);
167     Object group1Item2 = new TestObject(1, 2);
168 
169     equivalenceMock.expectEquivalent(group1Item1, group1Item2);
170     equivalenceMock.expectEquivalent(group1Item2, group1Item1);
171 
172     equivalenceMock.expectHash(group1Item1, 1);
173     equivalenceMock.expectHash(group1Item2, 2);
174 
175     equivalenceMock.replay();
176 
177     try {
178       tester.addEquivalenceGroup(group1Item1, group1Item2).test();
179     } catch (AssertionFailedError expected) {
180       String expectedMessage =
181           "the hash (1) of TestObject{group=1, item=1} [group 1, item 1] must be "
182           + "equal to the hash (2) of TestObject{group=1, item=2} [group 1, item 2]";
183       if (!expected.getMessage().contains(expectedMessage)) {
184         fail("<" + expected.getMessage() + "> expected to contain <" + expectedMessage + ">");
185       }
186       return;
187     }
188     fail();
189   }
190 
191   /** An object with a friendly {@link #toString()}. */
192   private static final class TestObject {
193     final int group;
194     final int item;
195 
TestObject(int group , int item)196     TestObject(int group , int item) {
197       this.group = group;
198       this.item = item;
199     }
200 
toString()201     @Override public String toString() {
202       return MoreObjects.toStringHelper("TestObject")
203           .add("group", group)
204           .add("item", item)
205           .toString();
206     }
207   }
208 
209   private static final class MockEquivalence extends Equivalence<Object> {
210     final ImmutableTable.Builder<Object, Object, Boolean> equivalentExpectationsBuilder =
211         ImmutableTable.builder();
212     final ImmutableMap.Builder<Object, Integer> hashExpectationsBuilder =
213         ImmutableMap.builder();
214     ImmutableTable<Object, Object, Boolean> equivalentExpectations;
215     ImmutableMap<Object, Integer> hashExpectations;
216 
expectEquivalent(Object a, Object b)217     void expectEquivalent(Object a, Object b) {
218       checkRecording();
219       equivalentExpectationsBuilder.put(a, b, true);
220     }
221 
expectDistinct(Object a, Object b)222     void expectDistinct(Object a, Object b) {
223       checkRecording();
224       equivalentExpectationsBuilder.put(a, b, false);
225     }
226 
expectHash(Object object, int hash)227     void expectHash(Object object, int hash) {
228       checkRecording();
229       hashExpectationsBuilder.put(object, hash);
230     }
231 
replay()232     void replay() {
233       checkRecording();
234       equivalentExpectations = equivalentExpectationsBuilder.build();
235       hashExpectations = hashExpectationsBuilder.build();
236     }
237 
doEquivalent(Object a, Object b)238     @Override protected boolean doEquivalent(Object a, Object b) {
239       return equivalentExpectations.get(a, b);
240     }
241 
doHash(Object object)242     @Override protected int doHash(Object object) {
243       return hashExpectations.get(object);
244     }
245 
checkRecording()246     void checkRecording() {
247       checkState(equivalentExpectations == null && hashExpectations == null);
248     }
249   }
250 }
251