Skip to content

Commit b988c4d

Browse files
Add assertThatExceptionOfType/thenExceptionOfType to Soft/BDDSoft assertions.
Improve tests verifying that Assertions - BDDAssertions - WithAssertions and their soft counterparts are in sync. Fix assertj#2499
1 parent 711ceea commit b988c4d

9 files changed

+695
-70
lines changed

src/main/java/org/assertj/core/api/Java6BDDSoftAssertionsProvider.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static org.assertj.core.api.Assertions.catchThrowable;
1616

1717
import java.io.File;
18+
import java.io.IOException;
1819
import java.io.InputStream;
1920
import java.math.BigDecimal;
2021
import java.math.BigInteger;
@@ -945,4 +946,112 @@ default AbstractUrlAssert<?> then(URL actual) {
945946
return proxy(UrlAssert.class, URL.class, actual);
946947
}
947948

949+
/**
950+
* Entry point to check that an exception of type T is thrown by a given {@code throwingCallable}
951+
* which allows to chain assertions on the thrown exception.
952+
* <p>
953+
* Example:
954+
* <pre><code class='java'> softly.thenExceptionOfType(IOException.class)
955+
* .isThrownBy(() -&gt; { throw new IOException("boom!"); })
956+
* .withMessage("boom!"); </code></pre>
957+
*
958+
* This method is more or less the same of {@link #thenThrownBy(ThrowingCallable)} but in a more natural way.
959+
*
960+
* @param <T> the Throwable type.
961+
* @param throwableType the Throwable type class.
962+
* @return the created {@link ThrowableTypeAssert}.
963+
* @since 3.23.0.
964+
*/
965+
default <T extends Throwable> ThrowableTypeAssert<T> thenExceptionOfType(final Class<T> throwableType) {
966+
return new SoftThrowableTypeAssert<>(throwableType, this);
967+
}
968+
969+
/**
970+
* Alias for {@link #thenExceptionOfType(Class)} for {@link RuntimeException}.
971+
*
972+
* @return the created {@link ThrowableTypeAssert}.
973+
*
974+
* @since 3.23.0
975+
*/
976+
default ThrowableTypeAssert<RuntimeException> thenRuntimeException() {
977+
return thenExceptionOfType(RuntimeException.class);
978+
}
979+
980+
/**
981+
* Alias for {@link #thenExceptionOfType(Class)} for {@link NullPointerException}.
982+
*
983+
* @return the created {@link ThrowableTypeAssert}.
984+
*
985+
* @since 3.23.0
986+
*/
987+
default ThrowableTypeAssert<NullPointerException> thenNullPointerException() {
988+
return thenExceptionOfType(NullPointerException.class);
989+
}
990+
991+
/**
992+
* Alias for {@link #thenExceptionOfType(Class)} for {@link IllegalArgumentException}.
993+
*
994+
* @return the created {@link ThrowableTypeAssert}.
995+
*
996+
* @since 3.23.0
997+
*/
998+
default ThrowableTypeAssert<IllegalArgumentException> thenIllegalArgumentException() {
999+
return thenExceptionOfType(IllegalArgumentException.class);
1000+
}
1001+
1002+
/**
1003+
* Alias for {@link #thenExceptionOfType(Class)} for {@link IOException}.
1004+
*
1005+
* @return the created {@link ThrowableTypeAssert}.
1006+
*
1007+
* @since 3.23.0
1008+
*/
1009+
default ThrowableTypeAssert<IOException> thenIOException() {
1010+
return thenExceptionOfType(IOException.class);
1011+
}
1012+
1013+
/**
1014+
* Alias for {@link #thenExceptionOfType(Class)} for {@link IllegalStateException}.
1015+
*
1016+
* @return the created {@link ThrowableTypeAssert}.
1017+
*
1018+
* @since 3.23.0
1019+
*/
1020+
default ThrowableTypeAssert<IllegalStateException> thenIllegalStateException() {
1021+
return thenExceptionOfType(IllegalStateException.class);
1022+
}
1023+
1024+
/**
1025+
* Alias for {@link #thenExceptionOfType(Class)} for {@link Exception}.
1026+
*
1027+
* @return the created {@link ThrowableTypeAssert}.
1028+
*
1029+
* @since 3.23.0
1030+
*/
1031+
default ThrowableTypeAssert<Exception> thenException() {
1032+
return thenExceptionOfType(Exception.class);
1033+
}
1034+
1035+
/**
1036+
* Alias for {@link #thenExceptionOfType(Class)} for {@link ReflectiveOperationException}.
1037+
*
1038+
* @return the created {@link ThrowableTypeAssert}.
1039+
*
1040+
* @since 3.23.0
1041+
*/
1042+
default ThrowableTypeAssert<ReflectiveOperationException> thenReflectiveOperationException() {
1043+
return thenExceptionOfType(ReflectiveOperationException.class);
1044+
}
1045+
1046+
/**
1047+
* Alias for {@link #thenExceptionOfType(Class)} for {@link IndexOutOfBoundsException}.
1048+
*
1049+
* @return the created {@link ThrowableTypeAssert}.
1050+
*
1051+
* @since 3.23.0
1052+
*/
1053+
default ThrowableTypeAssert<IndexOutOfBoundsException> thenIndexOutOfBoundsException() {
1054+
return thenExceptionOfType(IndexOutOfBoundsException.class);
1055+
}
1056+
9481057
}

src/main/java/org/assertj/core/api/Java6StandardSoftAssertionsProvider.java

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static org.assertj.core.api.Assertions.catchThrowable;
1616

1717
import java.io.File;
18+
import java.io.IOException;
1819
import java.io.InputStream;
1920
import java.math.BigDecimal;
2021
import java.math.BigInteger;
@@ -928,4 +929,113 @@ default UriAssert assertThat(URI actual) {
928929
default AbstractUrlAssert<?> assertThat(URL actual) {
929930
return proxy(UrlAssert.class, URL.class, actual);
930931
}
932+
933+
/**
934+
* Entry point to check that an exception of type T is thrown by a given {@code throwingCallable}
935+
* which allows to chain assertions on the thrown exception.
936+
* <p>
937+
* Example:
938+
* <pre><code class='java'> softly.assertThatExceptionOfType(IOException.class)
939+
* .isThrownBy(() -&gt; { throw new IOException("boom!"); })
940+
* .withMessage("boom!"); </code></pre>
941+
*
942+
* This method is more or less the same of {@link #assertThatThrownBy(ThrowingCallable)} but in a more natural way.
943+
*
944+
* @param <T> the Throwable type.
945+
* @param throwableType the Throwable type class.
946+
* @return the created {@link ThrowableTypeAssert}.
947+
* @since 3.23.0.
948+
*/
949+
default <T extends Throwable> ThrowableTypeAssert<T> assertThatExceptionOfType(final Class<T> throwableType) {
950+
return new SoftThrowableTypeAssert<>(throwableType, this);
951+
}
952+
953+
/**
954+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link RuntimeException}.
955+
*
956+
* @return the created {@link ThrowableTypeAssert}.
957+
*
958+
* @since 3.23.0
959+
*/
960+
default ThrowableTypeAssert<RuntimeException> assertThatRuntimeException() {
961+
return assertThatExceptionOfType(RuntimeException.class);
962+
}
963+
964+
/**
965+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link NullPointerException}.
966+
*
967+
* @return the created {@link ThrowableTypeAssert}.
968+
*
969+
* @since 3.23.0
970+
*/
971+
default ThrowableTypeAssert<NullPointerException> assertThatNullPointerException() {
972+
return assertThatExceptionOfType(NullPointerException.class);
973+
}
974+
975+
/**
976+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link IllegalArgumentException}.
977+
*
978+
* @return the created {@link ThrowableTypeAssert}.
979+
*
980+
* @since 3.23.0
981+
*/
982+
default ThrowableTypeAssert<IllegalArgumentException> assertThatIllegalArgumentException() {
983+
return assertThatExceptionOfType(IllegalArgumentException.class);
984+
}
985+
986+
/**
987+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link IOException}.
988+
*
989+
* @return the created {@link ThrowableTypeAssert}.
990+
*
991+
* @since 3.23.0
992+
*/
993+
default ThrowableTypeAssert<IOException> assertThatIOException() {
994+
return assertThatExceptionOfType(IOException.class);
995+
}
996+
997+
/**
998+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link IllegalStateException}.
999+
*
1000+
* @return the created {@link ThrowableTypeAssert}.
1001+
*
1002+
* @since 3.23.0
1003+
*/
1004+
default ThrowableTypeAssert<IllegalStateException> assertThatIllegalStateException() {
1005+
return assertThatExceptionOfType(IllegalStateException.class);
1006+
}
1007+
1008+
/**
1009+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link Exception}.
1010+
*
1011+
* @return the created {@link ThrowableTypeAssert}.
1012+
*
1013+
* @since 3.23.0
1014+
*/
1015+
default ThrowableTypeAssert<Exception> assertThatException() {
1016+
return assertThatExceptionOfType(Exception.class);
1017+
}
1018+
1019+
/**
1020+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link ReflectiveOperationException}.
1021+
*
1022+
* @return the created {@link ThrowableTypeAssert}.
1023+
*
1024+
* @since 3.23.0
1025+
*/
1026+
default ThrowableTypeAssert<ReflectiveOperationException> assertThatReflectiveOperationException() {
1027+
return assertThatExceptionOfType(ReflectiveOperationException.class);
1028+
}
1029+
1030+
/**
1031+
* Alias for {@link #assertThatExceptionOfType(Class)} for {@link IndexOutOfBoundsException}.
1032+
*
1033+
* @return the created {@link ThrowableTypeAssert}.
1034+
*
1035+
* @since 3.23.0
1036+
*/
1037+
default ThrowableTypeAssert<IndexOutOfBoundsException> assertThatIndexOutOfBoundsException() {
1038+
return assertThatExceptionOfType(IndexOutOfBoundsException.class);
1039+
}
1040+
9311041
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2022 the original author or authors.
12+
*/
13+
package org.assertj.core.api;
14+
15+
import org.assertj.core.description.Description;
16+
17+
/**
18+
* {@link ThrowableAssertAlternative} subclass used in soft assertions.
19+
* <p>
20+
* Assertion methods for {@link java.lang.Throwable} similar to {@link ThrowableAssert} but with assertions methods named
21+
* differently to make testing code fluent (ex : <code>withMessage</code> instead of <code>hasMessage</code>.
22+
* <pre><code class='java'> SoftAssertions softly = new SoftAssertions();
23+
*
24+
* softly.assertThatExceptionOfType(IOException.class)
25+
* .isThrownBy(() -&gt; { throw new IOException("boom! tcha!"); });
26+
* .withMessage("boom! %s", "tcha!"); </code></pre>
27+
*
28+
* This class is linked with the {@link ThrowableTypeAssert} and allow to check that an exception type is thrown by a lambda.
29+
*
30+
* @since 3.23.0
31+
*/
32+
public class SoftThrowableAssertAlternative<ACTUAL extends Throwable> extends ThrowableAssertAlternative<ACTUAL> {
33+
34+
private final ThrowableAssert<ACTUAL> proxyedThrowableAssert;
35+
36+
@SuppressWarnings("unchecked")
37+
public SoftThrowableAssertAlternative(final ACTUAL actual, SoftAssertionsProvider softAssertionsProvider) {
38+
super(actual);
39+
proxyedThrowableAssert = softAssertionsProvider.proxy(ThrowableAssert.class, Throwable.class, actual);
40+
}
41+
42+
@Override
43+
public SoftThrowableAssertAlternative<ACTUAL> as(Description description) {
44+
super.as(description);
45+
return this;
46+
}
47+
48+
@Override
49+
protected ThrowableAssert<ACTUAL> getDelegate() {
50+
return proxyedThrowableAssert;
51+
}
52+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2022 the original author or authors.
12+
*/
13+
package org.assertj.core.api;
14+
15+
import org.assertj.core.description.Description;
16+
import org.assertj.core.util.CheckReturnValue;
17+
18+
/**
19+
* ThrowableTypeAssert for soft assertions.
20+
*
21+
* @since 3.23.0
22+
*/
23+
public class SoftThrowableTypeAssert<T extends Throwable> extends ThrowableTypeAssert<T> {
24+
25+
private SoftAssertionsProvider softAssertionsProvider;
26+
27+
/**
28+
* Default constructor.
29+
*
30+
* @param throwableType class representing the target (expected) exception
31+
* @param softAssertionsProvider the soft assertion instance used later on to proxy {@link ThrowableAssert}
32+
*/
33+
public SoftThrowableTypeAssert(final Class<? extends T> throwableType, SoftAssertionsProvider softAssertionsProvider) {
34+
super(throwableType);
35+
this.softAssertionsProvider = softAssertionsProvider;
36+
}
37+
38+
@Override
39+
protected ThrowableAssertAlternative<T> buildThrowableTypeAssert(T throwable) {
40+
return new SoftThrowableAssertAlternative<>(throwable, softAssertionsProvider);
41+
}
42+
43+
@Override
44+
@CheckReturnValue
45+
public SoftThrowableTypeAssert<T> describedAs(Description description) {
46+
this.description = description;
47+
return this;
48+
}
49+
}

0 commit comments

Comments
 (0)