001    /*
002     * Created on Mar 29, 2009
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with 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
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2009 the original author or authors.
015     */
016    package org.fest.assertions;
017    
018    import static org.fest.assertions.Collections.found;
019    import static org.fest.assertions.Collections.notFound;
020    import static org.fest.assertions.Formatting.inBrackets;
021    import static org.fest.util.Collections.duplicatesFrom;
022    import static org.fest.util.Collections.list;
023    import static org.fest.util.Objects.areEqual;
024    import static org.fest.util.Strings.concat;
025    
026    import java.util.ArrayList;
027    import java.util.Collection;
028    import java.util.List;
029    
030    import org.fest.util.Collections;
031    
032    /**
033     * Understands assertions for <code>{@link List}</code>s. To create a new instance of this class use the
034     * method <code>{@link Assertions#assertThat(List)}</code>.
035     * @since 1.1
036     *
037     * @author Alex Ruiz
038     */
039    public class ListAssert extends GroupAssert<List<?>> {
040    
041      /**
042       * Creates a new </code>{@link ListAssert}</code>.
043       * @param actual the target to verify.
044       */
045      protected ListAssert(List<?> actual) {
046        super(actual);
047      }
048    
049      /**
050       * Verifies that the actual <code>{@link List}</code> contains the given object at the given index.
051       * @param o the object to look for.
052       * @param index the index where the object should be stored in the actual <code>List</code>.
053       * @return this assertion object.
054       * @throws NullPointerException if the given <code>Index</code> is <code>null</code>.
055       * @throws IndexOutOfBoundsException if the value of the given <code>Index</code> is negative, or equal to or greater
056       * than the size of the actual <code>List</code>.
057       * @throws AssertionError if the given <code>List</code> does not contain the given object at the given index.
058       */
059      public ListAssert contains(Object o, Index index) {
060        if (index == null) throw new NullPointerException(formattedErrorMessage("The given index should not be null"));
061        isNotNull().isNotEmpty();
062        int indexValue = index.value();
063        int listSize = actualGroupSize();
064        if (indexValue < 0 || indexValue >= listSize) failIndexOutOfBounds(indexValue);
065        Object actualElement = actual.get(indexValue);
066        if (!areEqual(actualElement, o)) failElementNotFound(o, actualElement, indexValue);
067        return this;
068      }
069    
070      private void failElementNotFound(Object e, Object a, int index) {
071        failIfCustomMessageIsSet();
072        fail(concat("expecting ", inBrackets(e), " at index ", inBrackets(index), " but found ", inBrackets(a)));
073      }
074    
075      private void failIndexOutOfBounds(int index) {
076        throw new IndexOutOfBoundsException(
077            formattedErrorMessage(concat(
078            "The index ", inBrackets(index), " should be greater than or equal to zero and less than ", actualGroupSize())));
079      }
080    
081      /**
082       * Verifies that the actual <code>{@link List}</code> contains the given sequence of objects, without any other
083       * objects between them.
084       * @param sequence the sequence of objects to look for.
085       * @return this assertion object.
086       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
087       * @throws AssertionError if the given array is <code>null</code>.
088       * @throws AssertionError if the actual <code>List</code> does not contain the given sequence of objects.
089       */
090      public ListAssert containsSequence(Object...sequence) {
091        isNotNull();
092        validateIsNotNull(sequence);
093        int sequenceSize = sequence.length;
094        if (sequenceSize == 0) return this;
095        int indexOfFirst = actual.indexOf(sequence[0]);
096        if (indexOfFirst == -1) failIfSequenceNotFound(sequence);
097        int listSize = actualGroupSize();
098        for (int i = 0; i < sequenceSize; i++) {
099          int actualIndex = indexOfFirst + i;
100          if (actualIndex > listSize - 1) failIfSequenceNotFound(sequence);
101          if (!areEqual(sequence[i], actual.get(actualIndex))) failIfSequenceNotFound(sequence);
102        }
103        return this;
104      }
105    
106      private void failIfSequenceNotFound(Object[] notFound) {
107        failIfCustomMessageIsSet();
108        fail(concat("list:", inBrackets(actual), " does not contain the sequence:", inBrackets(notFound)));
109      }
110    
111      /**
112       * Verifies that the actual <code>{@link List}</code> starts with the given sequence of objects, without any other
113       * objects between them. Same as <code>{@link #containsSequence}</code>, but verifies also that first given object is
114       * also first element of <code>List</code>.
115       * @param sequence the sequence of objects to look for.
116       * @return this assertion object.
117       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
118       * @throws AssertionError if the given array is <code>null</code>.
119       * @throws AssertionError if the actual <code>List</code> is not empty and with the given sequence of objects is
120       * empty.
121       * @throws AssertionError if the actual <code>List</code> does not start with the given sequence of objects.
122       */
123      public ListAssert startsWith(Object...sequence) {
124        isNotNull();
125        validateIsNotNull(sequence);
126        int sequenceSize = sequence.length;
127        int listSize = actualGroupSize();
128        if (sequenceSize == 0 && listSize == 0) return this;
129        if (sequenceSize == 0 && listSize != 0) failIfNotStartingWithSequence(sequence);
130        if (listSize < sequenceSize) failIfNotStartingWithSequence(sequence);
131        for (int i = 0; i < sequenceSize; i++)
132          if (!areEqual(sequence[i], actual.get(i))) failIfNotStartingWithSequence(sequence);
133        return this;
134      }
135    
136      private void failIfNotStartingWithSequence(Object[] notFound) {
137        failIfCustomMessageIsSet();
138        fail(concat("list:", inBrackets(actual), " does not start with the sequence:", inBrackets(notFound)));
139      }
140    
141      /**
142       * Verifies that the actual <code>{@link List}</code> ends with the given sequence of objects, without any other
143       * objects between them. Same as <code>{@link #containsSequence}</code>, but verifies also that last given object is
144       * also last element of <code>List</code>.
145       * @param sequence the sequence of objects to look for.
146       * @return this assertion object.
147       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
148       * @throws AssertionError if the given array is <code>null</code>.
149       * @throws AssertionError if the actual <code>List</code> is not empty and with the given sequence of objects is
150       * empty.
151       * @throws AssertionError if the actual <code>List</code> does not end with the given sequence of objects.
152       */
153      public ListAssert endsWith(Object...sequence) {
154        isNotNull();
155        validateIsNotNull(sequence);
156        int sequenceSize = sequence.length;
157        int listSize = actualGroupSize();
158        if (sequenceSize == 0 && listSize == 0) return this;
159        if (sequenceSize == 0 && listSize != 0) failIfNotEndingWithSequence(sequence);
160        if (listSize < sequenceSize) failIfNotEndingWithSequence(sequence);
161        for (int i = 0; i < sequenceSize; i++) {
162          int sequenceIndex = sequenceSize - 1 - i;
163          int listIndex = listSize - 1 - i;
164          if (!areEqual(sequence[sequenceIndex], actual.get(listIndex))) failIfNotEndingWithSequence(sequence);
165        }
166        return this;
167      }
168    
169      private void failIfNotEndingWithSequence(Object[] notFound) {
170        failIfCustomMessageIsSet();
171        fail(concat("list:", inBrackets(actual), " does not end with the sequence:", inBrackets(notFound)));
172      }
173    
174      /**
175       * Verifies that the actual <code>{@link List}</code> contains the given objects, in any order.
176       * @param objects the objects to look for.
177       * @return this assertion object.
178       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
179       * @throws NullPointerException if the given array is <code>null</code>.
180       * @throws AssertionError if the actual <code>List</code> does not contain the given objects.
181       */
182      public ListAssert contains(Object...objects) {
183        isNotNull();
184        validateIsNotNull(objects);
185        Collection<Object> notFound = notFoundInActual(objects);
186        if (notFound.isEmpty()) return this;
187        throw failureIfExpectedElementsNotFound(notFound);
188      }
189    
190      private Collection<Object> notFoundInActual(Object... objects) {
191        return notFound(actual, objects);
192      }
193    
194      /**
195       * Verifies that the actual <code>{@link List}</code> contains the given objects <strong>only</strong>, in any order.
196       * @param objects the objects to look for.
197       * @return this assertion object.
198       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
199       * @throws NullPointerException if the given array is <code>null</code>.
200       * @throws AssertionError if the actual <code>List</code> does not contain the given objects, or if the actual
201       * <code>List</code> contains elements other than the ones specified.
202       */
203      public ListAssert containsOnly(Object...objects) {
204        isNotNull();
205        validateIsNotNull(objects);
206        List<Object> copy = new ArrayList<Object>(actual);
207        List<Object> notFound = notFoundInCopy(copy, objects);
208        if (!notFound.isEmpty()) throw failureIfExpectedElementsNotFound(notFound);
209        if (copy.isEmpty()) return this;
210        throw failureIfUnexpectedElementsFound(copy);
211      }
212    
213      private List<Object> notFoundInCopy(List<Object> copy, Object... objects) {
214        List<Object> notFound = new ArrayList<Object>();
215        for (Object o : objects) {
216          if (!copy.contains(o)) {
217            notFound.add(o);
218            continue;
219          }
220          copy.remove(o);
221        }
222        return notFound;
223      }
224    
225      private AssertionError failureIfExpectedElementsNotFound(Collection<Object> notFound) {
226        failIfCustomMessageIsSet();
227        return failure(concat("list:", inBrackets(actual), " does not contain element(s):", inBrackets(notFound)));
228      }
229    
230      private AssertionError failureIfUnexpectedElementsFound(List<Object> unexpected) {
231        failIfCustomMessageIsSet();
232        return failure(concat("unexpected element(s):", inBrackets(unexpected), " in list:", inBrackets(actual)));
233      }
234    
235      /**
236       * Verifies that the actual <code>{@link List}</code> does not contain the given objects.
237       * @param objects the objects that the <code>List</code> should exclude.
238       * @return this assertion object.
239       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
240       * @throws NullPointerException if the given array is <code>null</code>.
241       * @throws AssertionError if the actual <code>List</code> contains any of the given objects.
242       */
243      public ListAssert excludes(Object...objects) {
244        isNotNull();
245        validateIsNotNull(objects);
246        Collection<Object> found = found(actual, objects);
247        if (found.isEmpty()) return this;
248        failIfCustomMessageIsSet();
249        throw failure(concat("list:", inBrackets(actual), " does not exclude element(s):", inBrackets(found)));
250      }
251    
252      private void validateIsNotNull(Object[] objects) {
253        if (objects == null)
254          throw new NullPointerException(formattedErrorMessage("the given array of objects should not be null"));
255      }
256    
257      /**
258       * Verifies that the actual <code>{@link List}</code> does not have duplicates.
259       * @return this assertion object.
260       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
261       * @throws AssertionError if the actual <code>List</code> has duplicates.
262       */
263      public ListAssert doesNotHaveDuplicates() {
264        isNotNull();
265        Collection<?> duplicates = duplicatesFrom(actual);
266        if (duplicates.isEmpty()) return this;
267        failIfCustomMessageIsSet();
268        throw failure(concat("list:", inBrackets(actual), " contains duplicate(s):", inBrackets(duplicates)));
269      }
270    
271      /** {@inheritDoc} */
272      public ListAssert as(String description) {
273        description(description);
274        return this;
275      }
276    
277      /** {@inheritDoc} */
278      public ListAssert describedAs(String description) {
279        return as(description);
280      }
281    
282      /** {@inheritDoc} */
283      public ListAssert as(Description description) {
284        description(description);
285        return this;
286      }
287    
288      /** {@inheritDoc} */
289      public ListAssert describedAs(Description description) {
290        return as(description);
291      }
292    
293      /**
294       * Verifies that the actual <code>{@link List}</code> satisfies the given condition.
295       * @param condition the given condition.
296       * @return this assertion object.
297       * @throws NullPointerException if the given condition is <code>null</code>.
298       * @throws AssertionError if the actual <code>List</code> does not satisfy the given condition.
299       * @see #is(Condition)
300       */
301      public ListAssert satisfies(Condition<List<?>> condition) {
302        assertSatisfies(condition);
303        return this;
304      }
305    
306      /**
307       * Verifies that the actual <code>{@link List}</code> does not satisfy the given condition.
308       * @param condition the given condition.
309       * @return this assertion object.
310       * @throws NullPointerException if the given condition is <code>null</code>.
311       * @throws AssertionError if the actual <code>List</code> satisfies the given condition.
312       * @see #isNot(Condition)
313       */
314      public ListAssert doesNotSatisfy(Condition<List<?>> condition) {
315        assertDoesNotSatisfy(condition);
316        return this;
317      }
318    
319      /**
320       * Alias for <code>{@link #satisfies(Condition)}</code>.
321       * @param condition the given condition.
322       * @return this assertion object.
323       * @throws NullPointerException if the given condition is <code>null</code>.
324       * @throws AssertionError if the actual <code>List</code> does not satisfy the given condition.
325       * @since 1.2
326       */
327      public ListAssert is(Condition<List<?>> condition) {
328        assertIs(condition);
329        return this;
330      }
331    
332      /**
333       * Alias for <code>{@link #doesNotSatisfy(Condition)}</code>.
334       * @param condition the given condition.
335       * @return this assertion object.
336       * @throws NullPointerException if the given condition is <code>null</code>.
337       * @throws AssertionError if the actual <code>List</code> satisfies the given condition.
338       * @since 1.2
339       */
340      public ListAssert isNot(Condition<List<?>> condition) {
341        assertIsNot(condition);
342        return this;
343      }
344    
345      /**
346       * Verifies that the number of elements in the actual <code>{@link List}</code> is equal to the given one.
347       * @param expected the expected number of elements in the actual <code>List</code>.
348       * @return this assertion object.
349       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
350       * @throws AssertionError if the number of elements of the actual <code>List</code> is not equal to the given one.
351       */
352      public ListAssert hasSize(int expected) {
353        int actualSize = actualGroupSize();
354        if (actualSize == expected) return this;
355        failIfCustomMessageIsSet();
356        throw failure(concat(
357              "expected size:", inBrackets(expected)," but was:", inBrackets(actualSize), " for list:", inBrackets(actual)));
358      }
359    
360      /**
361       * Returns the number of elements in the actual <code>{@link List}</code>.
362       * @return the number of elements in the actual <code>List</code>.
363       */
364      protected int actualGroupSize() {
365        isNotNull();
366        return actual.size();
367      }
368    
369      /**
370       * Verifies that the actual <code>{@link List}</code> is empty (not <code>null</code> with zero elements.)
371       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
372       * @throws AssertionError if the actual <code>List</code> is not empty.
373       */
374      public void isEmpty() {
375        isNotNull();
376        if (Collections.isEmpty(actual)) return;
377        failIfCustomMessageIsSet();
378        fail(concat("expecting empty list, but was:", inBrackets(actual)));
379      }
380    
381      /**
382       * Verifies that the actual <code>{@link List}</code> contains at least on element.
383       * @return this assertion object.
384       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
385       * @throws AssertionError if the actual <code>List</code> is empty.
386       */
387      public ListAssert isNotEmpty() {
388        isNotNull();
389        if (!actual.isEmpty()) return this;
390        failIfCustomMessageIsSet();
391        throw failure("expecting a non-empty list, but it was empty");
392      }
393    
394      /**
395       * Verifies that the actual <code>{@link List}</code> is <code>null</code> or empty.
396       * @throws AssertionError if the actual <code>List</code> is not <code>null</code> or not empty.
397       */
398      public void isNullOrEmpty() {
399        if (Collections.isEmpty(actual)) return;
400        failIfCustomMessageIsSet();
401        fail(concat("expecting a null or empty list, but was:", inBrackets(actual)));
402      }
403    
404      /**
405       * Verifies that the actual <code>{@link List}</code> is not <code>null</code>.
406       * @return this assertion object.
407       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
408       */
409      public ListAssert isNotNull() {
410        if (actual != null) return this;
411        failIfCustomMessageIsSet();
412        throw failure("expecting a non-null list, but it was null");
413      }
414    
415      /**
416       * Verifies that the actual <code>{@link List}</code> contains the given objects, in the same order. This method works
417       * just like <code>{@link #isEqualTo(List)}</code>, with the difference that internally the given array is
418       * converted to a <code>List</code>.
419       * @param objects the objects to look for.
420       * @return this assertion object.
421       * @throws AssertionError if the actual <code>List</code> is <code>null</code>.
422       * @throws NullPointerException if the given array is <code>null</code>.
423       * @throws AssertionError if the actual <code>List</code> does not contain the given objects.
424       */
425      public ListAssert containsExactly(Object... objects) {
426        validateIsNotNull(objects);
427        return isNotNull().isEqualTo(list(objects));
428      }
429    
430      /**
431       * Verifies that the actual <code>{@link List}</code> is equal to the given one.
432       * @param expected the given <code>List</code> to compare the actual <code>List</code> to.
433       * @return this assertion object.
434       * @throws AssertionError if the actual <code>List</code> is not equal to the given one.
435       */
436      public ListAssert isEqualTo(List<?> expected) {
437        assertEqualTo(expected);
438        return this;
439      }
440    
441      /**
442       * Verifies that the actual <code>{@link List}</code> is not equal to the given one.
443       * @param other the given <code>List</code> to compare the actual <code>List</code> to.
444       * @return this assertion object.
445       * @throws AssertionError if the actual <code>List</code> is equal to the given one.
446       */
447      public ListAssert isNotEqualTo(List<?> other) {
448        assertNotEqualTo(other);
449        return this;
450      }
451    
452      /**
453       * Verifies that the actual <code>{@link List}</code> is the same as the given one.
454       * @param expected the given <code>List</code> to compare the actual <code>List</code> to.
455       * @return this assertion object.
456       * @throws AssertionError if the actual <code>List</code> is not the same as the given one.
457       */
458      public ListAssert isSameAs(List<?> expected) {
459        assertSameAs(expected);
460        return this;
461      }
462    
463      /**
464       * Verifies that the actual <code>{@link List}</code> is not the same as the given one.
465       * @param other the given <code>List</code> to compare the actual <code>List</code> to.
466       * @return this assertion object.
467       * @throws AssertionError if the actual <code>List</code> is the same as the given one.
468       */
469      public ListAssert isNotSameAs(List<?> other) {
470        assertNotSameAs(other);
471        return this;
472      }
473    
474      /** {@inheritDoc} */
475      public ListAssert overridingErrorMessage(String message) {
476        replaceDefaultErrorMessagesWith(message);
477        return this;
478      }
479    }