Home | History | Annotate | Download | only in testing
      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.checkNotNull;
     20 
     21 import com.google.common.annotations.GwtCompatible;
     22 import com.google.common.collect.ImmutableList;
     23 import com.google.common.collect.Lists;
     24 
     25 import junit.framework.AssertionFailedError;
     26 
     27 import java.util.List;
     28 
     29 /**
     30  * Tests a collection of objects according to the rules specified in a
     31  * {@link RelationshipAssertion}.
     32  *
     33  * @author Gregory Kick
     34  */
     35 @GwtCompatible
     36 final class RelationshipTester<T> {
     37   private final List<ImmutableList<T>> groups = Lists.newArrayList();
     38   private final RelationshipAssertion<T> assertion;
     39 
     40   RelationshipTester(RelationshipAssertion<T> assertion) {
     41     this.assertion = checkNotNull(assertion);
     42   }
     43 
     44   public RelationshipTester<T> addRelatedGroup(Iterable<? extends T> group) {
     45     groups.add(ImmutableList.copyOf(group));
     46     return this;
     47   }
     48 
     49   public void test() {
     50     for (int groupNumber = 0; groupNumber < groups.size(); groupNumber++) {
     51       ImmutableList<T> group = groups.get(groupNumber);
     52       for (int itemNumber = 0; itemNumber < group.size(); itemNumber++) {
     53         // check related items in same group
     54         for (int relatedItemNumber = 0; relatedItemNumber < group.size(); relatedItemNumber++) {
     55           if (itemNumber != relatedItemNumber) {
     56             assertRelated(groupNumber, itemNumber, relatedItemNumber);
     57           }
     58         }
     59         // check unrelated items in all other groups
     60         for (int unrelatedGroupNumber = 0; unrelatedGroupNumber < groups.size();
     61             unrelatedGroupNumber++) {
     62           if (groupNumber != unrelatedGroupNumber) {
     63             ImmutableList<T> unrelatedGroup = groups.get(unrelatedGroupNumber);
     64             for (int unrelatedItemNumber = 0; unrelatedItemNumber < unrelatedGroup.size();
     65                 unrelatedItemNumber++) {
     66               assertUnrelated(groupNumber, itemNumber, unrelatedGroupNumber, unrelatedItemNumber);
     67             }
     68           }
     69         }
     70       }
     71     }
     72   }
     73 
     74   private void assertRelated(int groupNumber, int itemNumber, int relatedItemNumber) {
     75     ImmutableList<T> group = groups.get(groupNumber);
     76     T item = group.get(itemNumber);
     77     T related = group.get(relatedItemNumber);
     78     try {
     79       assertion.assertRelated(item, related);
     80     } catch (AssertionFailedError e) {
     81       // TODO(gak): special handling for ComparisonFailure?
     82       throw new AssertionFailedError(e.getMessage()
     83           .replace("$ITEM", itemString(item, groupNumber, itemNumber))
     84           .replace("$RELATED", itemString(related, groupNumber, relatedItemNumber)));
     85     }
     86   }
     87 
     88   private void assertUnrelated(int groupNumber, int itemNumber, int unrelatedGroupNumber,
     89       int unrelatedItemNumber) {
     90     T item = groups.get(groupNumber).get(itemNumber);
     91     T unrelated = groups.get(unrelatedGroupNumber).get(unrelatedItemNumber);
     92     try {
     93       assertion.assertUnrelated(item, unrelated);
     94     } catch (AssertionFailedError e) {
     95       // TODO(gak): special handling for ComparisonFailure?
     96       throw new AssertionFailedError(e.getMessage()
     97           .replace("$ITEM", itemString(item, groupNumber, itemNumber))
     98           .replace("$UNRELATED", itemString(unrelated, unrelatedGroupNumber, unrelatedItemNumber)));
     99     }
    100   }
    101 
    102   private static String itemString(Object item, int groupNumber, int itemNumber) {
    103     return new StringBuilder()
    104         .append(item)
    105         .append(" [group ")
    106         .append(groupNumber + 1)
    107         .append(", item ")
    108         .append(itemNumber + 1)
    109         .append(']')
    110         .toString();
    111   }
    112 
    113   /**
    114    * A strategy for testing the relationship between objects.  Methods are expected to throw
    115    * {@link AssertionFailedError} whenever the relationship is violated.
    116    *
    117    * <p>As a convenience, any occurrence of {@code $ITEM}, {@code $RELATED} or {@code $UNRELATED} in
    118    * the error message will be replaced with a string that combines the {@link Object#toString()},
    119    * item number and group number of the respective item.
    120    *
    121    */
    122   interface RelationshipAssertion<T> {
    123     void assertRelated(T item, T related);
    124 
    125     void assertUnrelated(T item, T unrelated);
    126   }
    127 }
    128