-
-
Notifications
You must be signed in to change notification settings - Fork 682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
anyOf
and allOf
variants for multiple ThrowingConsumer
parameters
#2764
Comments
|
If I understood it correctly, we want to transform this: assertThat(some)
.isNotEmpty()
.extracting(Some::getOther)
.allSatisfy(o -> {
assertThat(o).satisfiesAnyOf(
o1 -> assertThat(o1).isNull(),
o1 -> assertThat(o1).isNotNull().extracting(Other::getId).isEqualTo(x)
)
}); into this: assertThat(some)
.isNotEmpty()
.extracting(Some::getOther)
.allSatisfyAnyOf(
o -> assertThat(o).isNull(),
o -> assertThat(o).isNotNull().extracting(Other::getId).isEqualTo(x);
); which is indeed easier to read. However, this would open the door to other combinations:
Adding Are we willing to add all of these? With some formatting adjustments, the original example could look like this: assertThat(some)
.isNotEmpty()
.extracting(Some::getOther)
.allSatisfy(o -> assertThat(o).satisfiesAnyOf(
o1 -> assertThat(o1).isNull(),
o1 -> assertThat(o1).isNotNull().extracting(Other::getId).isEqualTo(x)
)); which I personally consider a good compromise. |
Fair point, we don't want to have so many combinations |
If I may, I want to contribute to the project by sharing my solution. I have an abstract base class for my entity classes. public abstract class _Mapped<T extends _Mapped<T, U>, U> {
@Transient
protected @Nullable U _getId() {
return ...;
}
} An here comes one of entities. @Entity
@Table(name = ...)
public class Some extends _Mapped<Some, Long> {
public void setOther(final Other other) {
this.other = other;
setOtherId(
Optional.ofNullable(this.other)
.map(Other::getId)
.orElse(null)
);
}
@Column(name = COLUMN_NAME_OTHER_ID, nullable = false)
private Long otherId;
@Valid
@NotFound(action = NotFoundAction.IGNORE) // -> EAGER!
@ManyToOne(optional = /*false*/true, fetch = FetchType.LAZY)
@JoinColumn(name = COLUMN_NAME_OTEHR_ID, nullable = false, insertable = false, updatable = false,
foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Other other; // either null or has its `id` equal to `otherId`
} Now, with a list of selected As an already applicable solution, I can do this. List<Some> list = selectSome();
list.forEach(s -> {
assertThat(s.getOther()).satisfiesAnyOf(
o -> assertThat(o).isNull(),
o -> assertThat(o).isNotNull().extracting(Other::getId).isEqualTo(s.getOtherId());
);
}); Nothing's wrong, as already mentioned, yet the public final class _MappedConditions {
public static <T extends _Mapped<T, U>, U> Condition<T> id(final U id) {
return new Condition<>(
t -> {
assert t != null;
return Objects.equals(t._getId(), id);
},
String.format("should has id of %1$s", id)
);
}
} Now the expression may look like this. list.forEach(s -> {
assertThat(s.getOther()).satisfiesAnyOf(
o -> assertThat(o).isNull(),
o -> assertThat(o).isNotNull().has(id(r.getOtherId()))
);
}); And another public static <T extends _Mapped<T, U>, U> Condition<T> nullOrHasId(final U id) {
final Condition<T> hasId = id(id);
return new Condition<>(
t -> t == null || hasId.matches(t),
"should be null or " + hasId.description().value()
);
} Which leads the statements look like this. list.forEach(s -> {
assertThat(s.getOther()).is(nullOrHasId(r.getOtherId()));
});
// or
assertThat(list).allSatisfy(s -> {
assertThat(s.getOther()).is(nullOrHasId(r.getOtherId()));
}); |
Reopening to discuss a potential improvement for this use case. We could transform my example: assertThat(some)
.isNotEmpty()
.extracting(Some::getOther)
.allSatisfy(o -> assertThat(o).satisfiesAnyOf(
o1 -> assertThat(o1).isNull(),
o1 -> assertThat(o1).isNotNull().extracting(Other::getId).isEqualTo(x)
)); into: assertThat(some)
.isNotEmpty()
.extracting(Some::getOther)
.allSatisfy(anyOf( // anyOf(ThrowingConsumer...) in Assertions?
o1 -> assertThat(o1).isNull(),
o1 -> assertThat(o1).isNotNull().extracting(Other::getId).isEqualTo(x)
)); where public static <T> ThrowingConsumer<T> anyOf(ThrowingConsumer<? super T>... assertions) {
return e -> new ObjectAssert<>(e).satisfiesAnyOf(assertions);
} Also, an We already have other @joel-costigliola @onacit thoughts? |
LGTM |
@scordio What an elegant syntax/idiom you suggested! Thanks! |
There is one aspect where I see a potential issue. If we would put public static <T> ThrowingConsumer<T> anyOf(ThrowingConsumer<? super T>... assertions) {
...
} This means they would "steal" the |
anyOf
and allOf
variants for multiple ThrowingConsumer
s
anyOf
and allOf
variants for multiple ThrowingConsumer
sanyOf
and allOf
variants for multiple ThrowingConsumer
parameters
anyOf
and allOf
variants for multiple ThrowingConsumer
parametersanyOf
and allOf
variants for multiple ThrowingConsumer
parameters
Feature summary
I need to assert with
satisfiesAnyOf
for each element in an iterable.This may be a collection version of #1304 .
Example
The text was updated successfully, but these errors were encountered: