All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.testing.RelationshipTester Maven / Gradle / Ivy

Go to download

Guava testlib is a set of java classes used for more convenient unit testing - particularly to assist the tests for Guava itself.

There is a newer version: 17.0
Show newest version
/*
 * Copyright (C) 2011 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.testing;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Equivalence;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

import junit.framework.AssertionFailedError;

import java.util.List;

/**
 * Implementation helper for {@link EqualsTester} and {@link EquivalenceTester} that tests for
 * equivalence classes.
 *
 * @author Gregory Kick
 */
@GwtCompatible
final class RelationshipTester {

  static class ItemReporter {
    String reportItem(Item item) {
      return item.toString();
    }
  }

  /**
   * A word about using {@link Equivalence}, which automatically checks for {@code null} and
   * identical inputs: This sounds like it ought to be a problem here, since the goals of this class
   * include testing that {@code equals()} is reflexive and is tolerant of {@code null}. However,
   * there's no problem. The reason: {@link EqualsTester} tests {@code null} and identical inputs
   * directly against {@code equals()} rather than through the {@code Equivalence}.
   */
  private final Equivalence equivalence;
  private final String relationshipName;
  private final String hashName;
  private final ItemReporter itemReporter;
  private final List> groups = Lists.newArrayList();

  RelationshipTester(Equivalence equivalence, String relationshipName, String hashName,
      ItemReporter itemReporter) {
    this.equivalence = checkNotNull(equivalence);
    this.relationshipName = checkNotNull(relationshipName);
    this.hashName = checkNotNull(hashName);
    this.itemReporter = checkNotNull(itemReporter);
  }

  // TODO(cpovirk): should we reject null items, since the tests already check null automatically?
  public RelationshipTester addRelatedGroup(Iterable group) {
    groups.add(ImmutableList.copyOf(group));
    return this;
  }

  public void test() {
    for (int groupNumber = 0; groupNumber < groups.size(); groupNumber++) {
      ImmutableList group = groups.get(groupNumber);
      for (int itemNumber = 0; itemNumber < group.size(); itemNumber++) {
        // check related items in same group
        for (int relatedItemNumber = 0; relatedItemNumber < group.size(); relatedItemNumber++) {
          if (itemNumber != relatedItemNumber) {
            assertRelated(groupNumber, itemNumber, relatedItemNumber);
          }
        }
        // check unrelated items in all other groups
        for (int unrelatedGroupNumber = 0; unrelatedGroupNumber < groups.size();
            unrelatedGroupNumber++) {
          if (groupNumber != unrelatedGroupNumber) {
            ImmutableList unrelatedGroup = groups.get(unrelatedGroupNumber);
            for (int unrelatedItemNumber = 0; unrelatedItemNumber < unrelatedGroup.size();
                unrelatedItemNumber++) {
              assertUnrelated(groupNumber, itemNumber, unrelatedGroupNumber, unrelatedItemNumber);
            }
          }
        }
      }
    }
  }

  private void assertRelated(int groupNumber, int itemNumber, int relatedItemNumber) {
    Item itemInfo = getItem(groupNumber, itemNumber);
    Item relatedInfo = getItem(groupNumber, relatedItemNumber);

    T item = itemInfo.value;
    T related = relatedInfo.value;
    assertWithTemplate("$ITEM must be $RELATIONSHIP to $OTHER", itemInfo, relatedInfo,
        equivalence.equivalent(item, related));
    
    int itemHash = equivalence.hash(item);
    int relatedHash = equivalence.hash(related);
    assertWithTemplate("the $HASH (" + itemHash + ") of $ITEM must be equal to the $HASH ("
        + relatedHash + ") of $OTHER", itemInfo, relatedInfo, itemHash == relatedHash);
  }

  private void assertUnrelated(int groupNumber, int itemNumber, int unrelatedGroupNumber,
      int unrelatedItemNumber) {
    Item itemInfo = getItem(groupNumber, itemNumber);
    Item unrelatedInfo = getItem(unrelatedGroupNumber, unrelatedItemNumber);

    assertWithTemplate("$ITEM must not be $RELATIONSHIP to $OTHER", itemInfo, unrelatedInfo,
        !equivalence.equivalent(itemInfo.value, unrelatedInfo.value));
  }

  private void assertWithTemplate(String template, Item item, Item other, boolean condition) {
    if (!condition) {
      throw new AssertionFailedError(template
          .replace("$RELATIONSHIP", relationshipName)
          .replace("$HASH", hashName)
          .replace("$ITEM", itemReporter.reportItem(item))
          .replace("$OTHER", itemReporter.reportItem(other)));
    }
  }

  private Item getItem(int groupNumber, int itemNumber) {
    return new Item(groups.get(groupNumber).get(itemNumber), groupNumber, itemNumber);
  }

  static final class Item {
    final T value;
    final int groupNumber;
    final int itemNumber;

    Item(T value, int groupNumber, int itemNumber) {
      this.value = value;
      this.groupNumber = groupNumber;
      this.itemNumber = itemNumber;
    }

    @Override public String toString() {
      return new StringBuilder()
          .append(value)
          .append(" [group ")
          .append(groupNumber + 1)
          .append(", item ")
          .append(itemNumber + 1)
          .append(']')
          .toString();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy