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
17package com.google.common.testing;
18
19import static com.google.common.base.Preconditions.checkState;
20import static org.truth0.Truth.ASSERT;
21
22import com.google.common.annotations.GwtCompatible;
23import com.google.common.base.Equivalence;
24import com.google.common.base.Objects;
25import com.google.common.collect.ImmutableMap;
26import com.google.common.collect.ImmutableTable;
27
28import junit.framework.AssertionFailedError;
29import junit.framework.TestCase;
30
31/**
32 * Tests for {@link EquivalenceTester}.
33 *
34 * @author Gregory Kick
35 */
36@GwtCompatible
37public class EquivalenceTesterTest extends TestCase {
38  private EquivalenceTester<Object> tester;
39  private MockEquivalence equivalenceMock;
40
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 */
48  public void testOf_NullPointerException() {
49    try {
50      EquivalenceTester.of(null);
51      fail("Should fail on null reference");
52    } catch (NullPointerException expected) {}
53  }
54
55  public void testTest_NoData() {
56    tester.test();
57  }
58
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
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      ASSERT.that(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
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      ASSERT.that(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
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      ASSERT.that(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
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
196    TestObject(int group , int item) {
197      this.group = group;
198      this.item = item;
199    }
200
201    @Override public String toString() {
202      return Objects.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
217    void expectEquivalent(Object a, Object b) {
218      checkRecording();
219      equivalentExpectationsBuilder.put(a, b, true);
220    }
221
222    void expectDistinct(Object a, Object b) {
223      checkRecording();
224      equivalentExpectationsBuilder.put(a, b, false);
225    }
226
227    void expectHash(Object object, int hash) {
228      checkRecording();
229      hashExpectationsBuilder.put(object, hash);
230    }
231
232    void replay() {
233      checkRecording();
234      equivalentExpectations = equivalentExpectationsBuilder.build();
235      hashExpectations = hashExpectationsBuilder.build();
236    }
237
238    @Override protected boolean doEquivalent(Object a, Object b) {
239      return equivalentExpectations.get(a, b);
240    }
241
242    @Override protected int doHash(Object object) {
243      return hashExpectations.get(object);
244    }
245
246    void checkRecording() {
247      checkState(equivalentExpectations == null && hashExpectations == null);
248    }
249  }
250}
251