001 /*
002 * Created on Jan 23, 2008
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 @2008-2009 the original author or authors.
014 */
015 package org.fest.assertions;
016
017 import static org.fest.assertions.Formatting.inBrackets;
018 import static org.fest.util.Strings.concat;
019 import static org.fest.util.Strings.quote;
020
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.List;
024 import java.util.Map;
025
026 import org.fest.util.Maps;
027
028 /**
029 * Understands assertions for <code>{@link Map}</code>s. To create a new instance of this class use the method
030 * <code>{@link Assertions#assertThat(Map)}</code>.
031 *
032 * @author David DIDIER
033 * @author Yvonne Wang
034 * @author Alex Ruiz
035 */
036 public class MapAssert extends GroupAssert<Map<?, ?>> {
037
038 private static final String ENTRY = "entry";
039 private static final String ENTRIES= "entries";
040
041 /**
042 * Creates a new </code>{@link MapAssert}</code>.
043 * @param actual the target to verify.
044 */
045 protected MapAssert(Map<?, ?> actual) {
046 super(actual);
047 }
048
049 /** {@inheritDoc} */
050 public MapAssert as(String description) {
051 description(description);
052 return this;
053 }
054
055 /** {@inheritDoc} */
056 public MapAssert describedAs(String description) {
057 return as(description);
058 }
059
060 /** {@inheritDoc} */
061 public MapAssert as(Description description) {
062 description(description);
063 return this;
064 }
065
066 /** {@inheritDoc} */
067 public MapAssert describedAs(Description description) {
068 return as(description);
069 }
070
071
072 /**
073 * Verifies that the actual <code>{@link Map}</code> contains the given entries.
074 * <p>
075 * Example:
076 * <pre>
077 * // static import org.fest.assertions.Assertions.*;
078 * // static import org.fest.assertions.MapAssert.*;
079 *
080 * assertThat(myMap).{@link #includes(org.fest.assertions.MapAssert.Entry...) includes}({@link #entry(Object, Object) entry}("jedi", yoda), {@link #entry(Object, Object) entry}("sith", anakin));
081 * </pre>
082 * </p>
083 * @param entries the given entries.
084 * @return this assertion error.
085 * @throws AssertionError if the actual map is <code>null</code>.
086 * @throws AssertionError if the actual <code>Map</code> does not contain any of the given entries.
087 * @throws NullPointerException if the given array of entries is <code>null</code>.
088 * @throws NullPointerException if any of the entries in the given array is <code>null</code>.
089 */
090 public MapAssert includes(Entry...entries) {
091 isNotNull();
092 validate(ENTRIES, entries);
093 List<Entry> notFound = new ArrayList<Entry>();
094 for (Entry e : entries) if (!containsEntry(e)) notFound.add(e);
095 if (!notFound.isEmpty()) failIfNotFound(entryOrEntries(notFound), notFound);
096 return this;
097 }
098
099 /**
100 * Verifies that the actual <code>{@link Map}</code> does not contain the given entries.
101 * <p>
102 * Example:
103 * <pre>
104 * // static import org.fest.assertions.Assertions.*;
105 * // static import org.fest.assertions.MapAssert.*;
106 *
107 * assertThat(myMap).{@link #excludes(org.fest.assertions.MapAssert.Entry...) excludes}({@link #entry(Object, Object) entry}("jedi", yoda), {@link #entry(Object, Object) entry}("sith", anakin));
108 * </pre>
109 * </p>
110 * @param entries the given entries.
111 * @return this assertion error.
112 * @throws AssertionError if the actual map is <code>null</code>.
113 * @throws AssertionError if the actual <code>Map</code> contains any of the given entries.
114 * @throws NullPointerException if the given array of entries is <code>null</code>.
115 * @throws NullPointerException if any of the entries in the given array is <code>null</code>.
116 */
117 public MapAssert excludes(Entry...entries) {
118 isNotNull();
119 validate(ENTRIES, entries);
120 List<Entry> found = new ArrayList<Entry>();
121 for (Entry e : entries) if (containsEntry(e)) found.add(e);
122 if (!found.isEmpty()) failIfFound(entryOrEntries(found), found);
123 return this;
124 }
125
126 private boolean containsEntry(Entry e) {
127 if (e == null)
128 throw new NullPointerException(formattedErrorMessage("Entries to check should not contain null"));
129 if (!actual.containsKey(e.key)) return false;
130 return actual.containsValue(e.value);
131 }
132
133 private String entryOrEntries(List<Entry> found) {
134 return found.size() == 1 ? ENTRY : ENTRIES;
135 }
136
137 /**
138 * Creates a new map entry.
139 * @param key the key of the entry.
140 * @param value the value of the entry.
141 * @return the created entry.
142 * @see #includes(org.fest.assertions.MapAssert.Entry...)
143 */
144 public static Entry entry(Object key, Object value) {
145 return new Entry(key, value);
146 }
147
148 /**
149 * Understands an entry in a <code>{@link Map}</code>.
150 *
151 * @author Yvonne Wang
152 */
153 public static class Entry {
154 final Object key;
155 final Object value;
156
157 Entry(Object key, Object value) {
158 this.key = key;
159 this.value = value;
160 }
161
162 /** @see java.lang.Object#toString() */
163 @Override public String toString() {
164 return concat(quote(key), "=", quote(value));
165 }
166 }
167
168 private void failIfNotFound(String description, Collection<?> notFound) {
169 failIfCustomMessageIsSet();
170 fail(concat("the map:", formattedActual(), " does not contain the ", description, ":", inBrackets(notFound)));
171 }
172
173 private void validate(String description, Object[] objects) {
174 if (objects == null)
175 throw new NullPointerException(
176 formattedErrorMessage(concat("The given array of ", description, " should not be null")));
177 }
178
179 private void failIfFound(String description, Collection<?> found) {
180 failIfCustomMessageIsSet();
181 fail(concat("the map:", formattedActual(), " contains the ", description, ":", inBrackets(found)));
182 }
183
184 /**
185 * Verifies that the number of elements in the actual <code>{@link Map}</code> is equal to the given one.
186 * @param expected the expected number of elements in the actual <code>Map</code>.
187 * @return this assertion object.
188 * @throws AssertionError if the actual map is <code>null</code>.
189 * @throws AssertionError if the number of elements of the actual <code>Map</code> is not equal to the given one.
190 */
191 public MapAssert hasSize(int expected) {
192 isNotNull();
193 int actualSize = actualGroupSize();
194 if (actualSize == expected) return this;
195 failIfCustomMessageIsSet();
196 throw failure(concat(
197 "expected size:", inBrackets(expected)," but was:", inBrackets(actualSize), " for map:", inBrackets(actual)));
198 }
199
200 /**
201 * Verifies that the actual <code>{@link Map}</code> is <code>null</code> or empty.
202 * @throws AssertionError if the actual <code>Map</code> is not <code>null</code> or not empty.
203 */
204 public final void isNullOrEmpty() {
205 if (Maps.isEmpty(actual)) return;
206 failIfCustomMessageIsSet();
207 fail(concat("expecting a null or empty map, but was:", formattedActual()));
208 }
209
210 /**
211 * Verifies that the actual <code>{@link Map}</code> is empty.
212 * @throws AssertionError if the actual <code>Map</code> is <code>null</code> or not empty.
213 */
214 public void isEmpty() {
215 isNotNull();
216 if (actual.isEmpty()) return;
217 failIfCustomMessageIsSet();
218 fail(concat("expecting empty map, but was:", formattedActual()));
219 }
220
221 private String formattedActual() {
222 return inBrackets(actual);
223 }
224
225 /**
226 * Verifies that the actual <code>{@link Map}</code> is equal to the given one.
227 * @param expected the given map to compare the actual <code>Map</code> to.
228 * @return this assertion object.
229 * @throws AssertionError if the actual <code>Map</code> is not equal to the given one.
230 */
231 public MapAssert isEqualTo(Map<?, ?> expected) {
232 assertEqualTo(expected);
233 return this;
234 }
235
236 /**
237 * Verifies that the actual <code>{@link Map}</code> contains at least on element.
238 * @return this assertion object.
239 * @throws AssertionError if the actual <code>Map</code> is empty.
240 */
241 public MapAssert isNotEmpty() {
242 isNotNull();
243 if (!actual.isEmpty()) return this;
244 failIfCustomMessageIsSet();
245 throw failure("expecting non-empty map, but it was empty");
246 }
247
248 /**
249 * Verifies that the actual <code>{@link Map}</code> is not equal to the given one.
250 * @param other the given map to compare the actual <code>Map</code> to.
251 * @return this assertion object.
252 * @throws AssertionError if the actual <code>Map</code> is equal to the given one.
253 */
254 public MapAssert isNotEqualTo(Map<?, ?> other) {
255 assertNotEqualTo(other);
256 return this;
257 }
258
259 /**
260 * Verifies that the actual <code>{@link Map}</code> is not <code>null</code>.
261 * @return this assertion object.
262 * @throws AssertionError if the actual <code>Map</code> is <code>null</code>.
263 */
264 public MapAssert isNotNull() {
265 if (actual == null) fail("expecting a non-null map, but it was null");
266 return this;
267 }
268
269 /**
270 * Verifies that the actual <code>{@link Map}</code> is not the same as the given one.
271 * @param other the given map to compare the actual <code>Map</code> to.
272 * @return this assertion object.
273 * @throws AssertionError if the actual <code>Map</code> is the same as the given one.
274 */
275 public MapAssert isNotSameAs(Map<?, ?> other) {
276 assertNotSameAs(other);
277 return this;
278 }
279
280 /**
281 * Verifies that the actual <code>{@link Map}</code> is the same as the given one.
282 * @param expected the given map to compare the actual <code>Map</code> to.
283 * @return this assertion object.
284 * @throws AssertionError if the actual <code>Map</code> is not the same as the given one.
285 */
286 public MapAssert isSameAs(Map<?, ?> expected) {
287 assertSameAs(expected);
288 return this;
289 }
290
291 /**
292 * Verifies that the actual <code>{@link Map}</code> satisfies the given condition.
293 * @param condition the given condition.
294 * @return this assertion object.
295 * @throws NullPointerException if the given condition is <code>null</code>.
296 * @throws AssertionError if the actual <code>Map</code> does not satisfy the given condition.
297 * @see #is(Condition)
298 */
299 public MapAssert satisfies(Condition<Map<?, ?>> condition) {
300 assertSatisfies(condition);
301 return this;
302 }
303
304 /**
305 * Verifies that the actual <code>{@link Map}</code> does not satisfy the given condition.
306 * @param condition the given condition.
307 * @return this assertion object.
308 * @throws NullPointerException if the given condition is <code>null</code>.
309 * @throws AssertionError if the actual <code>Map</code> satisfies the given condition.
310 * @see #isNot(Condition)
311 */
312 public MapAssert doesNotSatisfy(Condition<Map<?, ?>> condition) {
313 assertDoesNotSatisfy(condition);
314 return this;
315 }
316
317 /**
318 * Alias for <code>{@link #satisfies(Condition)}</code>.
319 * @param condition the given condition.
320 * @return this assertion object.
321 * @throws NullPointerException if the given condition is <code>null</code>.
322 * @throws AssertionError if the actual <code>Map</code> does not satisfy the given condition.
323 * @since 1.2
324 */
325 public MapAssert is(Condition<Map<?, ?>> condition) {
326 assertIs(condition);
327 return this;
328 }
329
330 /**
331 * Alias for <code>{@link #doesNotSatisfy(Condition)}</code>.
332 * @param condition the given condition.
333 * @return this assertion object.
334 * @throws NullPointerException if the given condition is <code>null</code>.
335 * @throws AssertionError if the actual <code>Map</code> satisfies the given condition.
336 * @since 1.2
337 */
338 public MapAssert isNot(Condition<Map<?, ?>> condition) {
339 assertIsNot(condition);
340 return this;
341 }
342
343 /**
344 * Returns the number of elements in the actual <code>{@link Map}</code>.
345 * @return the number of elements in the actual <code>{@link Map}</code>.
346 */
347 protected int actualGroupSize() {
348 isNotNull();
349 return actual.size();
350 }
351
352 /** {@inheritDoc} */
353 public MapAssert overridingErrorMessage(String message) {
354 replaceDefaultErrorMessagesWith(message);
355 return this;
356 }
357 }