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