com.google.testing.util.MoreAsserts.java Source code

Java tutorial

Introduction

Here is the source code for com.google.testing.util.MoreAsserts.java

Source

/*
 * Copyright 2011 Google Inc.
 *
 * 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.testing.util;

import static java.util.Arrays.asList;

import com.google.common.base.Objects;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.Comparator;

import junit.framework.Assert;

import java.util.Iterator;
import java.util.List;

public final class MoreAsserts {

    private MoreAsserts() {
    }

    /**
     * Asserts that {@code actual} contains precisely the elements
     * {@code expected}, in any order.  Both collections may contain
     * duplicates, and this method will only pass if the quantities are
     * exactly the same.
     */
    public static void assertContentsAnyOrder(String message, Iterable<?> actual, Object... expected) {
        assertEqualsImpl(message, HashMultiset.create(asList(expected)), HashMultiset.create(actual));
    }

    /**
     * Variant of {@link #assertContentsAnyOrder(String,Iterable,Object...)}
     * using a generic message.
     */
    public static void assertContentsAnyOrder(Iterable<?> actual, Object... expected) {
        assertContentsAnyOrder((String) null, actual, expected);
    }

    /**
     * Asserts that {@code actual} contains precisely the elements
     * {@code expected}, in any order.  Both collections may contain
     * duplicates, and this method will only pass if the quantities are
     * exactly the same.  This method uses the user-provided Comparator
     * object for doing the object comparison, instead of relying on the
     * contents' implementation of {@link Object#equals(Object)}. It also takes
     * in the expected set of objects as an Iterable.
     * <p>
     * Note the different order of expected and actual from the other
     * {@link #assertContentsAnyOrder(String,Iterable,Object...)}
     */
    public static <T> void assertContentsAnyOrder(String message, Iterable<? extends T> expected,
            Iterable<? extends T> actual, Comparator<? super T> comparator) {
        // We should not iterate over an Iterable more than once. There's
        // no guarentees that Iterable.iterator() returns an iterator over the
        // entire collection every time.
        //
        // Why don't we use TreeMultiset? Unfortunately, TreeMultiset.toString()
        // produces really odd output for duplicates. In addition, our contract
        // states that we use the comparator to compare equality, not to order
        // items.
        ImmutableList<T> actualList = ImmutableList.copyOf(actual);
        ImmutableList<T> expectedList = ImmutableList.copyOf(expected);

        // First compare sizes to save ourselves on N X M operation.
        // This also handles the case where "expected" is a subset of "actual".
        if (actualList.size() != expectedList.size()) {
            failNotEqual(message, expectedList, actualList);
        }

        // Now for each expected value, iterate through actuals and delete entry
        // if found. We need to make another copy of the "actual" items because
        // we will be removing items from this list, and we need to keep the original
        // for the failure message.
        List<T> unfoundItems = Lists.newLinkedList(actualList);
        for (T ex : expectedList) {
            boolean found = false;
            Iterator<T> iter = unfoundItems.iterator();
            while (iter.hasNext()) {
                T ac = iter.next();
                if (comparator.compare(ex, ac) == 0) {
                    iter.remove();
                    found = true;
                    break;
                }
            }
            if (!found) {
                failNotEqual(message, expectedList, actualList);
            }
        }
    }

    /**
     * Variant of {@link #assertContentsAnyOrder(String,Iterable,Object...)}
     * using a generic message.
     */
    public static <T> void assertContentsAnyOrder(Iterable<? extends T> expected, Iterable<? extends T> actual,
            Comparator<? super T> comparator) {
        assertContentsAnyOrder((String) null, expected, actual, comparator);
    }

    private static void failNotEqual(String message, Object expected, Object actual) {
        if ((expected != null) && (actual != null) && expected.toString().equals(actual.toString())) {
            failWithMessage(message, "expected:<(" + expected.getClass().getName() + ") " + expected
                    + "> but was:<(" + actual.getClass().getName() + ") " + actual + ">");
        } else {
            failWithMessage(message, "expected:<" + expected + "> but was:<" + actual + ">");
        }
    }

    /**
     * Replacement of {@link Assert#assertEquals} which provides the same error
     * message in GWT and java.
     */
    private static void assertEqualsImpl(String message, Object expected, Object actual) {
        if (!Objects.equal(expected, actual)) {
            failWithMessage(message, "expected:<" + expected + "> but was:<" + actual + ">");
        }
    }

    private static void failWithMessage(String userMessage, String ourMessage) {
        Assert.fail((userMessage == null) ? ourMessage : userMessage + ' ' + ourMessage);
    }
}