Skip to content

Commit

Permalink
[Breaking change] Introduce first class Iterator assertions without r…
Browse files Browse the repository at this point in the history
…emoving previous supported assertions that were for Iterable. Fixes #414.
  • Loading branch information
windmueller authored and joel-costigliola committed Sep 30, 2018
1 parent b68e95c commit acafa14
Show file tree
Hide file tree
Showing 48 changed files with 712 additions and 636 deletions.
Expand Up @@ -48,7 +48,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.assertj.core.api.IterableAssert.LazyIterable;
import org.assertj.core.api.filter.FilterOperator;
import org.assertj.core.api.filter.Filters;
import org.assertj.core.api.iterable.Extractor;
Expand Down Expand Up @@ -120,13 +119,6 @@ public AbstractIterableAssert(ACTUAL actual, Class<?> selfType) {
super(actual, selfType);
}

protected static <T> Iterable<T> toLazyIterable(Iterator<T> actual) {
if (actual == null) {
return null;
}
return new LazyIterable<>(actual);
}

/**
* {@inheritDoc}
*/
Expand Down
96 changes: 96 additions & 0 deletions src/main/java/org/assertj/core/api/AbstractIteratorAssert.java
@@ -0,0 +1,96 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2018 the original author or authors.
*/
package org.assertj.core.api;

import java.util.Iterator;

import org.assertj.core.internal.Iterators;
import org.assertj.core.util.VisibleForTesting;

/**
* <p>Base class for all implementations of assertions for {@link Iterator}s.</p>
* <p>Note that none of the assertions modify the actual iterator, i.e. they do not consume any elements.
* In order to use consuming assertions, use {@link #toIterable()}.</p>
*
* @param <SELF> the "self" type of this assertion class.
* @param <ELEMENT> the type of elements.
*
* @author Stephan Windmüller
* @since 3.12.0
*/
public abstract class AbstractIteratorAssert<SELF extends AbstractIteratorAssert<SELF, ELEMENT>, ELEMENT>
extends AbstractAssert<SELF, Iterator<? extends ELEMENT>> {

@VisibleForTesting
Iterators iterators = Iterators.instance();

/**
* Creates a new <code>{@link org.assertj.core.api.AbstractIteratorAssert}</code>.
*
* @param actual the actual value to verify
* @param selfType the "self type"
*/
public AbstractIteratorAssert(Iterator<? extends ELEMENT> actual, Class<?> selfType) {
super(actual, selfType);
}

/**
* <p>Verifies that the actual {@code Iterator} has at least one more element.</p>
*
* Example:
* <pre><code class='java'> Iterator&lt;TolkienCharacter&gt; elvesRingBearers = list(galadriel, elrond, gandalf).iterator();
*
* assertThat(elvesRingBearers).hasNext();</code></pre>
*
* @throws AssertionError if the actual {@code Iterator} is {@code null} or does not have another element.
* @return this assertion object.
* @since 3.12.0
*/
public SELF hasNext() {
iterators.assertHasNext(info, actual);
return myself;
}

/**
* <p>Verifies that the actual {@code Iterator} has no more elements.</p>
*
* Example:
* <pre><code class='java'> Iterator&lt;String&gt; result = Collections.emptyList().iterator();
*
* assertThat(result).isExhausted();</code></pre>
*
* @throws AssertionError if the actual {@code Iterator} is {@code null} or has another element.
* @return this assertion object.
* @since 3.12.0
*/
public SELF isExhausted() {
iterators.assertIsExhausted(info, actual);
return myself;
}

/**
* <p>Creates a new {@link IterableAssert} from this {@link IteratorAssert} which allows for
* using any Iterable assertions like {@link IterableAssert#contains(Object[])}.</p>
* Example:
* <pre><code class='java'> Iterator&lt;String&gt; bestBasketBallPlayers = getBestBasketBallPlayers();
*
* assertThat(bestBasketBallPlayers).toIterable().contains("Jordan", "Magic", "Lebron");</code></pre>
*
* @return the new {@link IterableAssert}.
* @since 3.12.0
*/
public IterableAssert<ELEMENT> toIterable() {
return new IterableAssert<>(IterableAssert.toIterable(actual));
}

}
18 changes: 13 additions & 5 deletions src/main/java/org/assertj/core/api/Assertions.java
Expand Up @@ -2635,18 +2635,26 @@ public static <ELEMENT> IterableAssert<ELEMENT> assertThat(Iterable<? extends EL
}

/**
* Creates a new instance of <code>{@link IterableAssert}</code>.
* Creates a new instance of <code>{@link IteratorAssert}</code>.
* <p>
* <b>Breaking change in version 3.12.0:</b> this method does not return anymore an {@link IterableAssert} but an {@link IteratorAssert}.<br>
* In order to access assertions from {@link IterableAssert}, use {@link IteratorAssert#toIterable()}.
* <p>
* <b>Be aware that calls to most methods on returned IterableAssert will consume Iterator so it won't be possible to
* iterate over it again.</b> Calling multiple methods on returned IterableAssert is safe as Iterator's elements are
* cached by IterableAssert first time Iterator is consumed.
* {@link IteratorAssert} instances have limited assertions because it does not consume iterator's elements.
* <p>
* Examples:
* <pre><code class='java'> Iterator&lt;String&gt; bestBasketBallPlayers = getBestBasketBallPlayers();
*
* assertThat(bestBasketBallPlayers).hasNext() // Iterator assertion
* .toIterable() // switch to Iterable assertions
* .contains("Jordan", "Magic", "Lebron"); // Iterable assertion </code></pre>
*
* @param <ELEMENT> the type of elements.
* @param actual the actual value.
* @return the created assertion object.
*/
@CheckReturnValue
public static <ELEMENT> IterableAssert<ELEMENT> assertThat(Iterator<? extends ELEMENT> actual) {
public static <ELEMENT> IteratorAssert<ELEMENT> assertThat(Iterator<? extends ELEMENT> actual) {
return AssertionsForInterfaceTypes.assertThat(actual);
}

Expand Down
Expand Up @@ -107,19 +107,15 @@ public static <ELEMENT> IterableAssert<ELEMENT> assertThat(Iterable<? extends EL
}

/**
* Creates a new instance of <code>{@link IterableAssert}</code>.
* <p>
* <b>Be aware that calls to most methods on returned IterableAssert will consume Iterator so it won't be possible to
* iterate over it again.</b> Calling multiple methods on returned IterableAssert is safe as Iterator's elements are
* cached by IterableAssert first time Iterator is consumed.
* Creates a new instance of <code>{@link IteratorAssert}</code>.
*
* @param <ELEMENT> the type of elements.
* @param actual the actual value.
* @return the created assertion object.
*/
@CheckReturnValue
public static <ELEMENT> IterableAssert<ELEMENT> assertThat(Iterator<? extends ELEMENT> actual) {
return new IterableAssert<>(actual);
public static <ELEMENT> IteratorAssert<ELEMENT> assertThat(Iterator<? extends ELEMENT> actual) {
return new IteratorAssert<>(actual);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/org/assertj/core/api/Assumptions.java
Expand Up @@ -763,7 +763,9 @@ public static <ELEMENT> ProxyableIterableAssert<ELEMENT> assumeThat(Iterable<? e
}

/**
* Creates a new instance of <code>{@link IterableAssert}</code> assumption.
* Creates a new instance of <code>{@link IteratorAssert}</code> assumption.
* <p>
* <b>Breaking change in version 3.12.0:</b> this method does not return anymore an {@link ProxyableIterableAssert} but an {@link IteratorAssert}.<br>
*
* @param <ELEMENT> the type of elements.
* @param actual the actual value.
Expand All @@ -772,8 +774,8 @@ public static <ELEMENT> ProxyableIterableAssert<ELEMENT> assumeThat(Iterable<? e
*/
@CheckReturnValue
@SuppressWarnings("unchecked")
public static <ELEMENT> ProxyableIterableAssert<ELEMENT> assumeThat(Iterator<? extends ELEMENT> actual) {
return asAssumption(ProxyableIterableAssert.class, Iterator.class, actual);
public static <ELEMENT> IteratorAssert<ELEMENT> assumeThat(Iterator<? extends ELEMENT> actual) {
return asAssumption(IteratorAssert.class, Iterator.class, actual);
}

/**
Expand Down
20 changes: 15 additions & 5 deletions src/main/java/org/assertj/core/api/BDDAssertions.java
Expand Up @@ -356,17 +356,27 @@ public static <T> IterableAssert<T> then(Iterable<? extends T> actual) {
}

/**
* Creates a new instance of <code>{@link org.assertj.core.api.IterableAssert}</code>. The <code>{@link
* java.util.Iterator}</code> is first
* converted
* into an <code>{@link Iterable}</code>
* Creates a new instance of <code>{@link IteratorAssert}</code>.
* <p>
* <b>Breaking change in version 3.12.0:</b> this method does not return anymore an {@link IterableAssert} but an {@link IteratorAssert}.<br>
* In order to access assertions from {@link IterableAssert}, use {@link IteratorAssert#toIterable()}.
* <p>
* {@link IteratorAssert} instances have limited assertions because it does not consume iterator's elements.
* <p>
* Examples:
* <pre><code class='java'> Iterator&lt;String&gt; bestBasketBallPlayers = getBestBasketBallPlayers();
*
* then(bestBasketBallPlayers).hasNext() // Iterator assertion
* .toIterable() // switch to Iterable assertions
* .contains("Jordan", "Magic", "Lebron"); // Iterable assertion </code></pre>
*
*
* @param <T> the actual elements type
* @param actual the actual value.
* @return the created assertion object.
*/
@CheckReturnValue
public static <T> IterableAssert<T> then(Iterator<? extends T> actual) {
public static <T> IteratorAssert<T> then(Iterator<? extends T> actual) {
return assertThat(actual);
}

Expand Down

0 comments on commit acafa14

Please sign in to comment.