001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.testing; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020import static junit.framework.Assert.assertEquals; 021import static junit.framework.Assert.assertTrue; 022 023import com.google.common.annotations.GwtCompatible; 024import com.google.common.base.Equivalence; 025import com.google.common.collect.ImmutableList; 026import com.google.common.collect.Lists; 027import com.google.common.testing.RelationshipTester.ItemReporter; 028import java.util.List; 029 030/** 031 * Tester for {@link Equivalence} relationships between groups of objects. 032 * 033 * <p>To use, create a new {@link EquivalenceTester} and add equivalence groups where each group 034 * contains objects that are supposed to be equal to each other. Objects of different groups are 035 * expected to be unequal. For example: 036 * 037 * <pre>{@code 038 * EquivalenceTester.of(someStringEquivalence) 039 * .addEquivalenceGroup("hello", "h" + "ello") 040 * .addEquivalenceGroup("world", "wor" + "ld") 041 * .test(); 042 * }</pre> 043 * 044 * <p>Note that testing {@link Object#equals(Object)} is more simply done using the {@link 045 * EqualsTester}. It includes an extra test against an instance of an arbitrary class without having 046 * to explicitly add another equivalence group. 047 * 048 * @author Gregory Kick 049 * @since 10.0 050 */ 051@GwtCompatible 052public final class EquivalenceTester<T> { 053 private static final int REPETITIONS = 3; 054 055 private final Equivalence<? super T> equivalence; 056 private final RelationshipTester<T> delegate; 057 private final List<T> items = Lists.newArrayList(); 058 059 private EquivalenceTester(Equivalence<? super T> equivalence) { 060 this.equivalence = checkNotNull(equivalence); 061 this.delegate = new RelationshipTester<>(equivalence, "equivalent", "hash", new ItemReporter()); 062 } 063 064 public static <T> EquivalenceTester<T> of(Equivalence<? super T> equivalence) { 065 return new EquivalenceTester<>(equivalence); 066 } 067 068 /** 069 * Adds a group of objects that are supposed to be equivalent to each other and not equivalent to 070 * objects in any other equivalence group added to this tester. 071 */ 072 public EquivalenceTester<T> addEquivalenceGroup(T first, T... rest) { 073 addEquivalenceGroup(Lists.asList(first, rest)); 074 return this; 075 } 076 077 public EquivalenceTester<T> addEquivalenceGroup(Iterable<T> group) { 078 delegate.addRelatedGroup(group); 079 items.addAll(ImmutableList.copyOf(group)); 080 return this; 081 } 082 083 /** Run tests on equivalence methods, throwing a failure on an invalid test */ 084 public EquivalenceTester<T> test() { 085 for (int run = 0; run < REPETITIONS; run++) { 086 testItems(); 087 delegate.test(); 088 } 089 return this; 090 } 091 092 private void testItems() { 093 for (T item : items) { 094 /* 095 * TODO(cpovirk): consider no longer running these equivalent() tests on every Equivalence, 096 * since the Equivalence base type now implements this logic itself 097 */ 098 assertTrue(item + " must be inequivalent to null", !equivalence.equivalent(item, null)); 099 assertTrue("null must be inequivalent to " + item, !equivalence.equivalent(null, item)); 100 assertTrue(item + " must be equivalent to itself", equivalence.equivalent(item, item)); 101 assertEquals( 102 "the hash of " + item + " must be consistent", 103 equivalence.hash(item), 104 equivalence.hash(item)); 105 } 106 } 107}