• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
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.testing.util;
18 
19 import static java.util.Arrays.asList;
20 
21 import com.google.common.base.Objects;
22 import com.google.common.collect.HashMultiset;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.Lists;
25 import java.util.Comparator;
26 
27 import junit.framework.Assert;
28 
29 import java.util.Iterator;
30 import java.util.List;
31 
32 public final class MoreAsserts {
33 
MoreAsserts()34   private MoreAsserts() { }
35 
36   /**
37    * Asserts that {@code actual} contains precisely the elements
38    * {@code expected}, in any order.  Both collections may contain
39    * duplicates, and this method will only pass if the quantities are
40    * exactly the same.
41    */
assertContentsAnyOrder( String message, Iterable<?> actual, Object... expected)42   public static void assertContentsAnyOrder(
43       String message, Iterable<?> actual, Object... expected) {
44     assertEqualsImpl(message,
45         HashMultiset.create(asList(expected)), HashMultiset.create(actual));
46   }
47 
48   /**
49    * Variant of {@link #assertContentsAnyOrder(String,Iterable,Object...)}
50    * using a generic message.
51    */
assertContentsAnyOrder( Iterable<?> actual, Object... expected)52   public static void assertContentsAnyOrder(
53       Iterable<?> actual, Object... expected) {
54     assertContentsAnyOrder((String) null, actual, expected);
55   }
56 
57   /**
58    * Asserts that {@code actual} contains precisely the elements
59    * {@code expected}, in any order.  Both collections may contain
60    * duplicates, and this method will only pass if the quantities are
61    * exactly the same.  This method uses the user-provided Comparator
62    * object for doing the object comparison, instead of relying on the
63    * contents' implementation of {@link Object#equals(Object)}. It also takes
64    * in the expected set of objects as an Iterable.
65    * <p>
66    * Note the different order of expected and actual from the other
67    * {@link #assertContentsAnyOrder(String,Iterable,Object...)}
68    */
assertContentsAnyOrder(String message, Iterable<? extends T> expected, Iterable<? extends T> actual, Comparator<? super T> comparator)69   public static <T> void assertContentsAnyOrder(String message,
70       Iterable<? extends T> expected, Iterable<? extends T> actual,
71       Comparator<? super T> comparator) {
72     // We should not iterate over an Iterable more than once. There's
73     // no guarentees that Iterable.iterator() returns an iterator over the
74     // entire collection every time.
75     //
76     // Why don't we use TreeMultiset? Unfortunately, TreeMultiset.toString()
77     // produces really odd output for duplicates. In addition, our contract
78     // states that we use the comparator to compare equality, not to order
79     // items.
80     ImmutableList<T> actualList = ImmutableList.copyOf(actual);
81     ImmutableList<T> expectedList = ImmutableList.copyOf(expected);
82 
83     // First compare sizes to save ourselves on N X M operation.
84     // This also handles the case where "expected" is a subset of "actual".
85     if (actualList.size() != expectedList.size()) {
86       failNotEqual(message, expectedList, actualList);
87     }
88 
89     // Now for each expected value, iterate through actuals and delete entry
90     // if found. We need to make another copy of the "actual" items because
91     // we will be removing items from this list, and we need to keep the original
92     // for the failure message.
93     List<T> unfoundItems = Lists.newLinkedList(actualList);
94     for (T ex : expectedList) {
95       boolean found = false;
96       Iterator<T> iter = unfoundItems.iterator();
97       while (iter.hasNext()) {
98         T ac = iter.next();
99         if (comparator.compare(ex, ac) == 0) {
100           iter.remove();
101           found = true;
102           break;
103         }
104       }
105       if (!found) {
106         failNotEqual(message, expectedList, actualList);
107       }
108     }
109   }
110 
111   /**
112    * Variant of {@link #assertContentsAnyOrder(String,Iterable,Object...)}
113    * using a generic message.
114    */
assertContentsAnyOrder( Iterable<? extends T> expected, Iterable<? extends T> actual, Comparator<? super T> comparator)115   public static <T> void assertContentsAnyOrder(
116       Iterable<? extends T> expected, Iterable<? extends T> actual,
117       Comparator<? super T> comparator) {
118     assertContentsAnyOrder((String) null, expected, actual, comparator);
119   }
120 
failNotEqual(String message, Object expected, Object actual)121   private static void failNotEqual(String message, Object expected,
122       Object actual) {
123     if ((expected != null) && (actual != null)
124         && expected.toString().equals(actual.toString())) {
125       failWithMessage(message, "expected:<("
126           + expected.getClass().getName() + ") " + expected + "> but was:<("
127           + actual.getClass().getName() + ") " + actual + ">");
128     } else {
129       failWithMessage(message, "expected:<" + expected + "> but was:<" + actual
130           + ">");
131     }
132   }
133 
134   /**
135    * Replacement of {@link Assert#assertEquals} which provides the same error
136    * message in GWT and java.
137    */
assertEqualsImpl( String message, Object expected, Object actual)138   private static void assertEqualsImpl(
139       String message, Object expected, Object actual) {
140     if (!Objects.equal(expected, actual)) {
141       failWithMessage(
142           message, "expected:<" + expected + "> but was:<" + actual + ">");
143     }
144   }
145 
failWithMessage(String userMessage, String ourMessage)146   private static void failWithMessage(String userMessage, String ourMessage) {
147     Assert.fail((userMessage == null)
148         ? ourMessage
149         : userMessage + ' ' + ourMessage);
150   }
151 }
152