001 /*
002 * Created on Jul 1, 2010
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005 * the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011 * specific language governing permissions and limitations under the License.
012 *
013 * Copyright @2010-2011 the original author or authors.
014 */
015 package org.fest.assertions;
016
017 import static org.fest.assertions.Collections.*;
018 import static org.fest.assertions.Formatting.format;
019 import static org.fest.util.Collections.*;
020
021 import java.util.*;
022
023 /**
024 * Template for assertions for groups of items (e.g. collections or arrays.)
025 * @param <S> used to simulate "self types." For more information please read "<a
026 * href="http://passion.forco.de/content/emulating-self-types-using-java-generics-simplify-fluent-api-implementation"
027 * target="_blank">Emulating 'self types' using Java Generics to simplify fluent API implementation</a>."
028 * @param <A> the type the "actual" value.
029 *
030 * @author Yvonne Wang
031 *
032 * @since 1.3
033 */
034 public abstract class ItemGroupAssert<S, A> extends GroupAssert<S, A> {
035
036 /**
037 * Creates a new </code>{@link ItemGroupAssert}</code>.
038 * @param selfType the "self type."
039 * @param actual the actual group.
040 */
041 public ItemGroupAssert(Class<S> selfType, A actual) {
042 super(selfType, actual);
043 }
044
045 /**
046 * Verifies that the actual actual group of objects contains the given objects, in any order.
047 * @param objects the objects to look for.
048 * @throws AssertionError if the actual actual group of objects is {@code null}.
049 * @throws NullPointerException if the given array is {@code null}.
050 * @throws AssertionError if the actual actual group of objects does not contain the given objects.
051 */
052 protected final void assertContains(Object... objects) {
053 isNotNull();
054 validateIsNotNull(objects);
055 Collection<Object> notFound = notFoundInActual(objects);
056 if (notFound.isEmpty()) return;
057 throw failureIfExpectedElementsNotFound(notFound);
058 }
059
060 private Collection<Object> notFoundInActual(Object... objects) {
061 return notFound(actualAsSet(), objects);
062 }
063
064 /**
065 * Verifies that the actual group of objects contains the given objects <strong>only</strong>, in any order.
066 * @param objects the objects to look for.
067 * @throws AssertionError if the actual group of objects is {@code null}.
068 * @throws NullPointerException if the given group of objects is {@code null}.
069 * @throws AssertionError if the actual group of objects does not contain the given objects, or if the actual
070 * group of objects contains elements other than the ones specified.
071 */
072 protected final void assertContainsOnly(Object... objects) {
073 isNotNull();
074 validateIsNotNull(objects);
075 Set<Object> copy = actualAsSet();
076 List<Object> notFound = notFoundInCopy(copy, set(objects));
077 if (!notFound.isEmpty()) throw failureIfExpectedElementsNotFound(notFound);
078 if (copy.isEmpty()) return;
079 throw failureIfUnexpectedElementsFound(copy);
080 }
081
082 /**
083 * Returns the actual value as a {@code Set}.
084 * @return the actual value as a {@code Set}.
085 */
086 protected abstract Set<Object> actualAsSet();
087
088 private List<Object> notFoundInCopy(Set<Object> copy, Set<Object> objects) {
089 List<Object> notFound = new ArrayList<Object>();
090 for (Object o : objects) {
091 if (!copy.contains(o)) {
092 notFound.add(o);
093 continue;
094 }
095 copy.remove(o);
096 }
097 return notFound;
098 }
099
100 private AssertionError failureIfExpectedElementsNotFound(Collection<Object> notFound) {
101 failIfCustomMessageIsSet();
102 return failure(format("<%s> does not contain element(s):<%s>", actual, notFound));
103 }
104
105 private AssertionError failureIfUnexpectedElementsFound(Collection<Object> unexpected) {
106 failIfCustomMessageIsSet();
107 return failure(format("unexpected element(s):<%s> in <%s>", unexpected, actual));
108 }
109
110 /**
111 * Verifies that the actual group of objects does not contain the given objects.
112 * @param objects the objects that the group of objects should exclude.
113 * @throws AssertionError if the actual group of objects is {@code null}.
114 * @throws NullPointerException if the given array is {@code null}.
115 * @throws AssertionError if the actual group of objects contains any of the given objects.
116 */
117 protected final void assertExcludes(Object... objects) {
118 isNotNull();
119 validateIsNotNull(objects);
120 Collection<Object> found = found(actualAsSet(), objects);
121 if (found.isEmpty()) return;
122 failIfCustomMessageIsSet();
123 throw failure(format("<%s> does not exclude element(s):<%s>", actual, found));
124 }
125
126 /**
127 * Validates that the given array of objects is not {@code null}.
128 * @param objects the array of objects to verify.
129 * @throws NullPointerException if the given array of objects is {@code null}.
130 */
131 protected final void validateIsNotNull(Object[] objects) {
132 if (objects == null)
133 throw new NullPointerException(formattedErrorMessage("The given array should not be null"));
134 }
135
136 /**
137 * Verifies that the actual group of objects does not have duplicates.
138 * @throws AssertionError if the actual group of objects is {@code null}.
139 * @throws AssertionError if the actual group of objects has duplicates.
140 */
141 protected final void assertDoesNotHaveDuplicates() {
142 isNotNull();
143 Collection<?> duplicates = duplicatesFrom(actualAsList());
144 if (duplicates.isEmpty()) return;
145 failIfCustomMessageIsSet();
146 throw failure(format("<%s> contains duplicate(s):<%s>", actual, duplicates));
147 }
148
149 /**
150 * Returns the actual value as a {@code List}.
151 * @return the actual value as a {@code List}.
152 */
153 protected abstract List<Object> actualAsList();
154
155 }