1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright (C) 2011 The Guava Authors 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * you may not use this file except in compliance with the License. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * You may obtain a copy of the License at 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * http://www.apache.org/licenses/LICENSE-2.0 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Unless required by applicable law or agreed to in writing, software 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * distributed under the License is distributed on an "AS IS" BASIS, 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * See the License for the specific language governing permissions and 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * limitations under the License. 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compackage com.google.common.testing; 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport static com.google.common.base.Preconditions.checkNotNull; 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport static junit.framework.Assert.assertEquals; 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport static junit.framework.Assert.assertTrue; 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.annotations.Beta; 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.annotations.GwtCompatible; 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.base.Equivalence; 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.collect.ImmutableList; 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.collect.Lists; 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport com.google.common.testing.RelationshipTester.ItemReporter; 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comimport java.util.List; 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Tester for {@link Equivalence} relationships between groups of objects. 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * <p> 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * To use, create a new {@link EquivalenceTester} and add equivalence groups 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * where each group contains objects that are supposed to be equal to each 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * other. Objects of different groups are expected to be unequal. For example: 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * <pre> 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * {@code 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * EquivalenceTester.of(someStringEquivalence) 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * .addEquivalenceGroup("hello", "h" + "ello") 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * .addEquivalenceGroup("world", "wor" + "ld") 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * .test(); 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * } 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * </pre> 482880df2609eba09b555ca37be04b6ad89290c765Tom Hudson * 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * <p> 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Note that testing {@link Object#equals(Object)} is more simply done using 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * the {@link EqualsTester}. It includes an extra test against an instance of an 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * arbitrary class without having to explicitly add another equivalence group. 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * @author Gregory Kick 551d3c411f5e4d2ad31bc92b3a85957004329ac00dtfarina@chromium.org * @since 10.0 56d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com * 57d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com * TODO(gak): turn this into a test suite so that each test can fail 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * independently 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com@Beta 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com@GwtCompatible public final class EquivalenceTester<T> { 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private static final int REPETITIONS = 3; 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private final Equivalence<? super T> equivalence; 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private final RelationshipTester<T> delegate; 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private final List<T> items = Lists.newArrayList(); 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private EquivalenceTester(Equivalence<? super T> equivalence) { 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this.equivalence = checkNotNull(equivalence); 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this.delegate = new RelationshipTester<T>( 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com equivalence, "equivalent", "hash", new ItemReporter()); 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 742880df2609eba09b555ca37be04b6ad89290c765Tom Hudson public static <T> EquivalenceTester<T> of(Equivalence<? super T> equivalence) { 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return new EquivalenceTester<T>(equivalence); 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /** 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Adds a group of objects that are supposed to be equivalent to each other 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * and not equivalent to objects in any other equivalence group added to this 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * tester. 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public EquivalenceTester<T> addEquivalenceGroup(T first, T... rest) { 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com addEquivalenceGroup(Lists.asList(first, rest)); 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this; 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public EquivalenceTester<T> addEquivalenceGroup(Iterable<T> group) { 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com delegate.addRelatedGroup(group); 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com items.addAll(ImmutableList.copyOf(group)); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this; 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /** Run tests on equivalence methods, throwing a failure on an invalid test */ 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public EquivalenceTester<T> test() { 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int run = 0; run < REPETITIONS; run++) { 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com testItems(); 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com delegate.test(); 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this; 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1032880df2609eba09b555ca37be04b6ad89290c765Tom Hudson private void testItems() { 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (T item : items) { 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * TODO(cpovirk): consider no longer running these equivalent() tests on every Equivalence, 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * since the Equivalence base type now implements this logic itself 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com assertTrue(item + " must be inequivalent to null", !equivalence.equivalent(item, null)); 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com assertTrue("null must be inequivalent to " + item, !equivalence.equivalent(null, item)); 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com assertTrue(item + " must be equivalent to itself", equivalence.equivalent(item, item)); 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com assertEquals("the hash of " + item + " must be consistent", equivalence.hash(item), 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com equivalence.hash(item)); 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 115d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com } 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com