Skip to content

Commit 79fd0e6

Browse files
Add AbstractRichIterableAssert scaffold and first concrete types (SetIterable and Bag) (#16)
1 parent 065e00f commit 79fd0e6

12 files changed

Lines changed: 536 additions & 4 deletions
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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.error.ShouldHaveSize.shouldHaveSize;
19+
import static org.assertj.core.util.Preconditions.checkArgument;
20+
21+
import java.util.Objects;
22+
import java.util.function.Function;
23+
import java.util.function.Predicate;
24+
25+
import org.assertj.core.api.AbstractAssert;
26+
import org.assertj.core.api.AbstractIterableAssert;
27+
import org.eclipse.collections.api.RichIterable;
28+
29+
/**
30+
* Base class for implementations of Eclipse Collections {@link RichIterable} assertions.
31+
*
32+
* @param <SELF> the "self" type of this assertion class. Please read &quot;<a href="https://bit.ly/1IZIRcY"
33+
* target="_blank">Emulating 'self types' using Java Generics to simplify fluent API implementation</a>&quot;
34+
* for more details.
35+
* @param <ACTUAL> the type of the "actual" value.
36+
* @param <ELEMENT> the type of elements of the "actual" value.
37+
* @param <ELEMENT_ASSERT> used for navigational assertions to return the right assert type.
38+
*/
39+
//@format:off
40+
public abstract class AbstractRichIterableAssert<SELF extends AbstractRichIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT>,
41+
ACTUAL extends RichIterable<? extends ELEMENT>,
42+
ELEMENT,
43+
ELEMENT_ASSERT extends AbstractAssert<? extends ELEMENT_ASSERT, ELEMENT>>
44+
extends AbstractIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT> {
45+
//@format:on
46+
47+
protected AbstractRichIterableAssert(ACTUAL actual, Class<?> selfType) {
48+
super(actual, selfType);
49+
}
50+
51+
@Override
52+
public <T> SELF filteredOn(Function<? super ELEMENT, T> function, T expectedValue) {
53+
checkArgument(function != null, "The filter function should not be null");
54+
return internalFilteredOn(element -> Objects.equals(function.apply(element), expectedValue));
55+
}
56+
57+
/**
58+
* Filters the iterable under test keeping only elements matching the given {@link Predicate}.
59+
* <p>
60+
* Example: check old employees whose age &gt; 100:
61+
*
62+
* <pre><code class='java'> Employee yoda = new Employee(1L, new Name("Yoda"), 800);
63+
* Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
64+
* Employee luke = new Employee(3L, new Name("Luke", "Skywalker"), 26);
65+
*
66+
* List&lt;Employee&gt; employees = List.of(yoda, luke, obiwan);
67+
*
68+
* assertThat(employees).filteredOn(employee -&gt; employee.getAge() &gt; 100)
69+
* .containsOnly(yoda, obiwan);</code></pre>
70+
*
71+
* @param predicate the filter predicate
72+
* @return a new assertion object with the filtered iterable under test
73+
* @throws IllegalArgumentException if the given predicate is {@code null}.
74+
*/
75+
@Override
76+
public SELF filteredOn(Predicate<? super ELEMENT> predicate) {
77+
checkArgument(predicate != null, "The filter predicate should not be null");
78+
return internalFilteredOn(predicate::test);
79+
}
80+
81+
/**
82+
* Verifies that the number of values in the actual RichIterable is equal to the given one.
83+
* <p>
84+
* Example:
85+
* <pre>{@code
86+
* // assertions will pass
87+
* assertThat(Sets.immutable.of("TNG", "DS9")).hasSize(2);
88+
* assertThat(Bags.immutable.of(1, 2, 3)).hasSize(3);
89+
*
90+
* // assertions will fail
91+
* assertThat(Sets.immutable.empty()).hasSize(1);
92+
* assertThat(Bags.immutable.of(1, 2, 3)).hasSize(2);
93+
* }</pre>
94+
*
95+
* @param expected the expected number of values in the actual collection.
96+
* @return {@code this} assertion object.
97+
* @throws AssertionError if the number of values of the actual collection is not equal to the given one.
98+
*/
99+
@Override
100+
public SELF hasSize(int expected) {
101+
isNotNull();
102+
103+
int actualSize = actual.size();
104+
if (actualSize == expected) {
105+
return myself;
106+
}
107+
108+
throw assertionError(shouldHaveSize(actual, actualSize, expected));
109+
}
110+
111+
/**
112+
* Helper method that filters via Eclipse Collections to avoid creating any JCL collections.
113+
*
114+
* @param predicate The predicate to filter on.
115+
* @return A new {@link AbstractRichIterableAssert} with the filtered values.
116+
*/
117+
private SELF internalFilteredOn(org.eclipse.collections.api.block.predicate.Predicate<? super ELEMENT> predicate) {
118+
checkArgument(predicate != null, "The filter predicate should not be null");
119+
// TODO: In AbstractIterableAssert the withAssertionState method is package-private. Need to find out how to handle
120+
// this method or if we need to use it
121+
return newAbstractIterableAssert(actual.select(predicate));//.withAssertionState(myself);
122+
}
123+
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package org.assertj.eclipse.collections.api;
1717

18-
import org.assertj.core.util.CheckReturnValue;
18+
import org.assertj.core.annotation.CheckReturnValue;
19+
import org.eclipse.collections.api.bag.Bag;
1920
import org.eclipse.collections.api.multimap.Multimap;
21+
import org.eclipse.collections.api.set.SetIterable;
2022

2123
/**
2224
* Entry point for assertion methods for the Eclipse Collections library. Each method in this class is a static factory
@@ -31,6 +33,17 @@ protected Assertions() {
3133
// Do nothing
3234
}
3335

36+
/**
37+
* Creates a new instance of {@link BagAssert}.
38+
*
39+
* @param actual the actual value.
40+
* @return the created assertion object.
41+
* @param <T> The type of the elements in the bag
42+
*/
43+
public static <T> BagAssert<T> assertThat(Bag<T> actual) {
44+
return new BagAssert<>(actual);
45+
}
46+
3447
/**
3548
* Creates a new instance of {@link MultimapAssert}.
3649
*
@@ -42,4 +55,15 @@ protected Assertions() {
4255
public static <KEY, VALUE> MultimapAssert<KEY, VALUE> assertThat(Multimap<KEY, VALUE> actual) {
4356
return new MultimapAssert<>(actual);
4457
}
58+
59+
/**
60+
* Creates a new instance of {@link SetIterableAssert}.
61+
*
62+
* @param actual the actual value.
63+
* @return the created assertion object.
64+
* @param <T> The type of the elements in the set
65+
*/
66+
public static <T>SetIterableAssert<T> assertThat(SetIterable<T> actual) {
67+
return new SetIterableAssert<>(actual);
68+
}
4569
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package org.assertj.eclipse.collections.api;
1717

18-
import org.assertj.core.util.CheckReturnValue;
18+
import org.assertj.core.annotation.CheckReturnValue;
19+
import org.eclipse.collections.api.bag.Bag;
1920
import org.eclipse.collections.api.multimap.Multimap;
21+
import org.eclipse.collections.api.set.SetIterable;
2022

2123
/**
2224
* Behavior-driven development style entry point for assertion methods for the Eclipse Collections library. Each method
@@ -31,6 +33,17 @@ protected BDDAssertions() {
3133
// Do nothing
3234
}
3335

36+
/**
37+
* Creates a new instance of {@link BagAssert}.
38+
*
39+
* @param actual the actual value.
40+
* @return thre created assertion object.
41+
* @param <T> THe type of the elements in the bag
42+
*/
43+
public static <T> BagAssert<T> then(Bag<T> actual) {
44+
return assertThat(actual);
45+
}
46+
3447
/**
3548
* Creates a new instance of {@link MultimapAssert}.
3649
*
@@ -42,4 +55,15 @@ protected BDDAssertions() {
4255
public static <KEY, VALUE> MultimapAssert<KEY, VALUE> then(Multimap<KEY, VALUE> actual) {
4356
return assertThat(actual);
4457
}
58+
59+
/**
60+
* Creates a new instance of {@link SetIterableAssert}.
61+
*
62+
* @param actual the actual value.
63+
* @return the created assertion object.
64+
* @param <T> The type of the elements in the set
65+
*/
66+
public static <T> SetIterableAssert<T> then(SetIterable<T> actual) {
67+
return assertThat(actual);
68+
}
4569
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.ObjectAssert;
19+
import org.eclipse.collections.api.bag.Bag;
20+
import org.eclipse.collections.api.bag.ImmutableBag;
21+
import org.eclipse.collections.api.factory.Bags;
22+
23+
/**
24+
* Assertion methods for the {@link Bag} interface.
25+
*
26+
* @param <ELEMENT> the type of elements stored in {@link Bag}.
27+
*/
28+
public class BagAssert<ELEMENT> extends AbstractRichIterableAssert<BagAssert<ELEMENT>, Bag<? extends ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>> {
29+
public BagAssert(Bag<? extends ELEMENT> elements) {
30+
super(elements, BagAssert.class);
31+
}
32+
33+
@Override
34+
protected ObjectAssert<ELEMENT> toAssert(ELEMENT value) {
35+
return new ObjectAssert<>(value);
36+
}
37+
38+
@Override
39+
protected BagAssert<ELEMENT> newAbstractIterableAssert(Iterable<? extends ELEMENT> iterable) {
40+
ImmutableBag<? extends ELEMENT> elements = Bags.immutable.ofAll(iterable);
41+
return new BagAssert<>(elements);
42+
}
43+
}

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,30 @@
1515
*/
1616
package org.assertj.eclipse.collections.api;
1717

18+
import org.assertj.core.annotation.CheckReturnValue;
1819
import org.assertj.core.api.SoftAssertionsProvider;
19-
import org.assertj.core.util.CheckReturnValue;
20+
import org.eclipse.collections.api.bag.Bag;
2021
import org.eclipse.collections.api.multimap.Multimap;
22+
import org.eclipse.collections.api.set.SetIterable;
2123

2224
/**
2325
* Soft assertions implementations for Eclipse Collections types.
2426
*/
2527
@CheckReturnValue
2628
public interface EclipseCollectionsSoftAssertionsProvider extends SoftAssertionsProvider {
29+
30+
/**
31+
* Create a new, proxied instance of a {@link BagAssert}
32+
*
33+
* @param actual the actual value
34+
* @return the created assertion object
35+
* @param <T> The type of the elements in the bag
36+
*/
37+
@SuppressWarnings("unchecked")
38+
default <T> BagAssert<T> assertThat(Bag<T> actual) {
39+
return this.proxy(BagAssert.class, Bag.class, actual);
40+
}
41+
2742
/**
2843
* Creates a new, proxied instance of a {@link MultimapAssert}
2944
*
@@ -36,4 +51,16 @@ public interface EclipseCollectionsSoftAssertionsProvider extends SoftAssertions
3651
default <KEY, VALUE> MultimapAssert<KEY, VALUE> assertThat(Multimap<KEY, VALUE> actual) {
3752
return this.proxy(MultimapAssert.class, Multimap.class, actual);
3853
}
54+
55+
/**
56+
* Creates a new, proxied instance of a {@link SetIterableAssert}
57+
*
58+
* @param actual the actual value
59+
* @return the created assertion object
60+
* @param <T> The type of the elements in the set
61+
*/
62+
@SuppressWarnings("unchecked")
63+
default <T> SetIterableAssert<T> assertThat(SetIterable<T> actual) {
64+
return this.proxy(SetIterableAssert.class, SetIterable.class, actual);
65+
}
3966
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.ObjectAssert;
19+
import org.eclipse.collections.api.factory.Sets;
20+
import org.eclipse.collections.api.set.ImmutableSet;
21+
import org.eclipse.collections.api.set.SetIterable;
22+
23+
/**
24+
* Assertion methods for {@link SetIterable} interface.
25+
*
26+
* @param <ELEMENT> the type of elements stored in {@link SetIterable}.
27+
*/
28+
public class SetIterableAssert<ELEMENT> extends AbstractRichIterableAssert<SetIterableAssert<ELEMENT>, SetIterable<? extends ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>> {
29+
public SetIterableAssert(SetIterable<? extends ELEMENT> elements) {
30+
super(elements, SetIterableAssert.class);
31+
}
32+
33+
@Override
34+
protected ObjectAssert<ELEMENT> toAssert(ELEMENT value) {
35+
return new ObjectAssert<>(value);
36+
}
37+
38+
@Override
39+
protected SetIterableAssert<ELEMENT> newAbstractIterableAssert(Iterable<? extends ELEMENT> iterable) {
40+
ImmutableSet<? extends ELEMENT> elements = Sets.immutable.ofAll(iterable);
41+
return new SetIterableAssert<>(elements);
42+
}
43+
}

src/test/java/module-info.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
* Test module for AssertJ Eclipse Collections
1818
*/
1919
open module org.assertj.eclipse.collections.test {
20+
exports org.assertj.eclipse.collections.api.bag;
2021
exports org.assertj.eclipse.collections.api.multimap;
22+
exports org.assertj.eclipse.collections.api.set;
2123

2224
requires org.assertj.eclipse.collections;
2325
requires org.assertj.core;

0 commit comments

Comments
 (0)