Skip to content

Commit 6fe498d

Browse files
Introduce AbstractOrderedIterableAssert (#17)
Introduce AbstractOrderedIterableAssert and the corresponding ListIterable and StackIterable assertion types. Overhauling how RichIterable tests are parameterized.
1 parent 79fd0e6 commit 6fe498d

19 files changed

Lines changed: 734 additions & 180 deletions
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2025-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.assertj.eclipse.collections.api;
17+
18+
import org.assertj.core.api.AbstractAssert;
19+
import org.assertj.core.api.InstanceOfAssertFactory;
20+
import org.eclipse.collections.api.ordered.OrderedIterable;
21+
22+
//@format:off
23+
public abstract class AbstractOrderedIterableAssert<SELF extends AbstractOrderedIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT>,
24+
ACTUAL extends OrderedIterable<? extends ELEMENT>,
25+
ELEMENT,
26+
ELEMENT_ASSERT extends AbstractAssert<? extends ELEMENT_ASSERT, ELEMENT>>
27+
extends AbstractRichIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT> {
28+
//@format:on
29+
30+
protected AbstractOrderedIterableAssert(ACTUAL actual, Class<?> selfType) {
31+
super(actual, selfType);
32+
}
33+
34+
@Override
35+
public ELEMENT_ASSERT first() {
36+
return executeAssertionNavigation(this::internalFirst, () -> nullElementNavigationAssert("check first element"));
37+
}
38+
39+
@Override
40+
public <ASSERT extends AbstractAssert<?, ?>> ASSERT first(InstanceOfAssertFactory<?, ASSERT> assertFactory) {
41+
return executeAssertionNavigation(() -> internalFirst().asInstanceOf(assertFactory),
42+
() -> nullValueAssert(assertFactory));
43+
}
44+
45+
@Override
46+
public ELEMENT_ASSERT last() {
47+
return executeAssertionNavigation(this::internalLast, () -> nullElementNavigationAssert("check last element"));
48+
}
49+
50+
@Override
51+
public <ASSERT extends AbstractAssert<?, ?>> ASSERT last(InstanceOfAssertFactory<?, ASSERT> assertFactory) {
52+
return executeAssertionNavigation(() -> internalLast().asInstanceOf(assertFactory),
53+
() -> nullValueAssert(assertFactory));
54+
}
55+
56+
private ELEMENT_ASSERT internalFirst() {
57+
isNotEmpty();
58+
return toAssert(actual.getFirst(), navigationDescription("check first element"));
59+
}
60+
61+
private ELEMENT_ASSERT internalLast() {
62+
isNotEmpty();
63+
return toAssert(actual.getLast(), navigationDescription("check last element"));
64+
}
65+
66+
// TODO: Decide where this method should live: here, in AbstractRichIterableAssert, or somewhere else
67+
protected ELEMENT_ASSERT nullElementNavigationAssert(String description) {
68+
return toAssert(null, navigationDescription(description));
69+
}
70+
}

src/main/java/org/assertj/eclipse/collections/api/Assertions.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
import org.assertj.core.annotation.CheckReturnValue;
1919
import org.eclipse.collections.api.bag.Bag;
20+
import org.eclipse.collections.api.list.ListIterable;
2021
import org.eclipse.collections.api.multimap.Multimap;
2122
import org.eclipse.collections.api.set.SetIterable;
23+
import org.eclipse.collections.api.stack.StackIterable;
2224

2325
/**
2426
* Entry point for assertion methods for the Eclipse Collections library. Each method in this class is a static factory
@@ -44,6 +46,10 @@ public static <T> BagAssert<T> assertThat(Bag<T> actual) {
4446
return new BagAssert<>(actual);
4547
}
4648

49+
public static <T> ListIterableAssert<T> assertThat(ListIterable<T> actual) {
50+
return new ListIterableAssert<>(actual);
51+
}
52+
4753
/**
4854
* Creates a new instance of {@link MultimapAssert}.
4955
*
@@ -63,7 +69,11 @@ public static <KEY, VALUE> MultimapAssert<KEY, VALUE> assertThat(Multimap<KEY, V
6369
* @return the created assertion object.
6470
* @param <T> The type of the elements in the set
6571
*/
66-
public static <T>SetIterableAssert<T> assertThat(SetIterable<T> actual) {
72+
public static <T> SetIterableAssert<T> assertThat(SetIterable<T> actual) {
6773
return new SetIterableAssert<>(actual);
6874
}
75+
76+
public static <T> StackIterableAssert<T> assertThat(StackIterable<T> actual) {
77+
return new StackIterableAssert<>(actual);
78+
}
6979
}

src/main/java/org/assertj/eclipse/collections/api/BDDAssertions.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
import org.assertj.core.annotation.CheckReturnValue;
1919
import org.eclipse.collections.api.bag.Bag;
20+
import org.eclipse.collections.api.list.ListIterable;
2021
import org.eclipse.collections.api.multimap.Multimap;
2122
import org.eclipse.collections.api.set.SetIterable;
23+
import org.eclipse.collections.api.stack.StackIterable;
2224

2325
/**
2426
* Behavior-driven development style entry point for assertion methods for the Eclipse Collections library. Each method
@@ -37,13 +39,24 @@ protected BDDAssertions() {
3739
* Creates a new instance of {@link BagAssert}.
3840
*
3941
* @param actual the actual value.
40-
* @return thre created assertion object.
41-
* @param <T> THe type of the elements in the bag
42+
* @return the created assertion object.
43+
* @param <T> The type of the elements in the bag
4244
*/
4345
public static <T> BagAssert<T> then(Bag<T> actual) {
4446
return assertThat(actual);
4547
}
4648

49+
/**
50+
* Creates a new instance of {@link ListIterableAssert}.
51+
*
52+
* @param actual the actual value.
53+
* @return the created assertion object.
54+
* @param <T> The type of the elements in the list
55+
*/
56+
public static <T> ListIterableAssert<T> then(ListIterable<T> actual) {
57+
return assertThat(actual);
58+
}
59+
4760
/**
4861
* Creates a new instance of {@link MultimapAssert}.
4962
*
@@ -66,4 +79,15 @@ public static <KEY, VALUE> MultimapAssert<KEY, VALUE> then(Multimap<KEY, VALUE>
6679
public static <T> SetIterableAssert<T> then(SetIterable<T> actual) {
6780
return assertThat(actual);
6881
}
82+
83+
/**
84+
* Creates a new instance of {@link StackIterableAssert}.
85+
*
86+
* @param actual the actual value.
87+
* @return the created assertion object.
88+
* @param <T> The type of the elements in the stack
89+
*/
90+
public static <T> StackIterableAssert<T> then(StackIterable<T> actual) {
91+
return assertThat(actual);
92+
}
6993
}

src/main/java/org/assertj/eclipse/collections/api/EclipseCollectionsSoftAssertionsProvider.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import org.assertj.core.annotation.CheckReturnValue;
1919
import org.assertj.core.api.SoftAssertionsProvider;
2020
import org.eclipse.collections.api.bag.Bag;
21+
import org.eclipse.collections.api.list.ListIterable;
2122
import org.eclipse.collections.api.multimap.Multimap;
2223
import org.eclipse.collections.api.set.SetIterable;
24+
import org.eclipse.collections.api.stack.StackIterable;
2325

2426
/**
2527
* Soft assertions implementations for Eclipse Collections types.
@@ -39,6 +41,18 @@ default <T> BagAssert<T> assertThat(Bag<T> actual) {
3941
return this.proxy(BagAssert.class, Bag.class, actual);
4042
}
4143

44+
/**
45+
* Creates a new, proxied instance of a {@link ListIterableAssert}
46+
*
47+
* @param actual the actual value
48+
* @return the created assertion object
49+
* @param <T> The type of the elements in the list
50+
*/
51+
@SuppressWarnings("unchecked")
52+
default <T> ListIterableAssert<T> assertThat(ListIterable<T> actual) {
53+
return this.proxy(ListIterableAssert.class, ListIterable.class, actual);
54+
}
55+
4256
/**
4357
* Creates a new, proxied instance of a {@link MultimapAssert}
4458
*
@@ -63,4 +77,16 @@ default <KEY, VALUE> MultimapAssert<KEY, VALUE> assertThat(Multimap<KEY, VALUE>
6377
default <T> SetIterableAssert<T> assertThat(SetIterable<T> actual) {
6478
return this.proxy(SetIterableAssert.class, SetIterable.class, actual);
6579
}
80+
81+
/**
82+
* Creates a new, proxied instance of a {@link StackIterableAssert}
83+
*
84+
* @param actual the actual value
85+
* @return the created assertion object
86+
* @param <T> The type of the elements in the stack
87+
*/
88+
@SuppressWarnings("unchecked")
89+
default <T> StackIterableAssert<T> assertThat(StackIterable<T> actual) {
90+
return this.proxy(StackIterableAssert.class, StackIterable.class, actual);
91+
}
6692
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2025-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.assertj.eclipse.collections.api;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import org.assertj.core.api.AbstractAssert;
21+
import org.assertj.core.api.InstanceOfAssertFactory;
22+
import org.assertj.core.api.ObjectAssert;
23+
import org.eclipse.collections.api.factory.Lists;
24+
import org.eclipse.collections.api.list.ImmutableList;
25+
import org.eclipse.collections.api.list.ListIterable;
26+
27+
/**
28+
* Assertion methods for {@link ListIterable} interface.
29+
*
30+
* @param <ELEMENT> the type of elements stored in {@link ListIterable}.
31+
*/
32+
public class ListIterableAssert<ELEMENT> extends AbstractOrderedIterableAssert<ListIterableAssert<ELEMENT>, ListIterable<? extends ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>> {
33+
public ListIterableAssert(ListIterable<? extends ELEMENT> actual) {
34+
super(actual, ListIterableAssert.class);
35+
}
36+
37+
@Override
38+
protected ObjectAssert<ELEMENT> toAssert(ELEMENT value) {
39+
return new ObjectAssert<>(value);
40+
}
41+
42+
@Override
43+
protected ListIterableAssert<ELEMENT> newAbstractIterableAssert(Iterable<? extends ELEMENT> iterable) {
44+
ImmutableList<? extends ELEMENT> elements = Lists.immutable.ofAll(iterable);
45+
return new ListIterableAssert<>(elements);
46+
}
47+
48+
@Override
49+
public ObjectAssert<ELEMENT> element(int index) {
50+
return executeAssertionNavigation(() -> internalElement(index),
51+
() -> nullElementNavigationAssert("element at index " + index));
52+
}
53+
54+
@Override
55+
public <ASSERT extends AbstractAssert<?, ?>> ASSERT element(int index, InstanceOfAssertFactory<?, ASSERT> assertFactory) {
56+
return executeAssertionNavigation(() -> internalElement(index).asInstanceOf(assertFactory),
57+
() -> nullValueAssert(assertFactory));
58+
}
59+
60+
private ObjectAssert<ELEMENT> internalElement(int index) {
61+
isNotEmpty();
62+
assertThat(index).describedAs(navigationDescription("check index validity"))
63+
.isBetween(0, actual.size() - 1);
64+
ELEMENT elementAtIndex = actual.get(index);
65+
66+
return toAssert(elementAtIndex, navigationDescription("element at index " + index));
67+
}
68+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2025-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.assertj.eclipse.collections.api;
17+
18+
import org.assertj.core.annotation.CheckReturnValue;
19+
import org.assertj.core.api.ObjectAssert;
20+
import org.eclipse.collections.api.factory.Stacks;
21+
import org.eclipse.collections.api.stack.ImmutableStack;
22+
import org.eclipse.collections.api.stack.StackIterable;
23+
24+
/**
25+
* Assertion methods for {@link StackIterable} interface.
26+
*
27+
* @param <ELEMENT> the type of elements stored in {@link StackIterable}.
28+
*/
29+
@CheckReturnValue
30+
public class StackIterableAssert<ELEMENT> extends AbstractOrderedIterableAssert<StackIterableAssert<ELEMENT>, StackIterable<? extends ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>> {
31+
public StackIterableAssert(StackIterable<? extends ELEMENT> actual) {
32+
super(actual, StackIterableAssert.class);
33+
}
34+
35+
@Override
36+
protected ObjectAssert<ELEMENT> toAssert(ELEMENT value) {
37+
return new ObjectAssert<>(value);
38+
}
39+
40+
@Override
41+
protected StackIterableAssert<ELEMENT> newAbstractIterableAssert(Iterable<? extends ELEMENT> iterable) {
42+
ImmutableStack<? extends ELEMENT> elements = Stacks.immutable.ofAll(iterable);
43+
return new StackIterableAssert<>(elements);
44+
}
45+
}

src/test/java/module-info.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
* Test module for AssertJ Eclipse Collections
1818
*/
1919
open module org.assertj.eclipse.collections.test {
20-
exports org.assertj.eclipse.collections.api.bag;
20+
exports org.assertj.eclipse.collections.api.list;
2121
exports org.assertj.eclipse.collections.api.multimap;
22-
exports org.assertj.eclipse.collections.api.set;
22+
exports org.assertj.eclipse.collections.api.richiterable;
23+
exports org.assertj.eclipse.collections.api.stack;
2324

2425
requires org.assertj.eclipse.collections;
2526
requires org.assertj.core;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2025-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.assertj.eclipse.collections.api.list;
17+
18+
import static org.assertj.core.api.Assertions.assertThatNoException;
19+
20+
import org.assertj.eclipse.collections.api.ListIterableAssert;
21+
import org.eclipse.collections.api.factory.Lists;
22+
import org.eclipse.collections.api.list.ImmutableList;
23+
import org.junit.jupiter.api.Test;
24+
25+
class ListIterableAssert_Element_Test {
26+
@Test
27+
void passes() {
28+
assertThatNoException().isThrownBy(() -> {
29+
ImmutableList<String> list = Lists.immutable.of("TOS", "TNG", "DS9", "VOY", "ENT");
30+
new ListIterableAssert<>(list).element(2).isEqualTo("DS9");
31+
});
32+
}
33+
}

0 commit comments

Comments
 (0)