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 }