Skip to content

Commit

Permalink
Add checkOnlyOneArgumentIsNull methods to KiwiPreconditions (#1140)
Browse files Browse the repository at this point in the history
Closes #1139
  • Loading branch information
sleberknight authored May 30, 2024
1 parent 3f6fe87 commit 07f0dd5
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/main/java/org/kiwiproject/base/KiwiPreconditions.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,54 @@ public static <T> void checkArgumentNotNull(T reference, String errorMessageTemp
}
}

/**
* Ensures that only one of two given arguments is null.
* Throws {@link IllegalArgumentException} if both are null or both are non-null.
*
* @param first the first argument
* @param second the second argument
* @param <T> the object type
*/
public static <T> void checkOnlyOneArgumentIsNull(T first, T second) {
Preconditions.checkArgument(isOnlyOneNull(first, second));
}

/**
* Ensures that only one of two given arguments is null.
* Throws {@link IllegalArgumentException} if both are null or both are non-null.
*
* @param first the first argument
* @param second the second argument
* @param message the error message to use if the check fails
* @param <T> the object type
*/
public static <T> void checkOnlyOneArgumentIsNull(T first, T second, String message) {
Preconditions.checkArgument(isOnlyOneNull(first, second), message);
}

/**
* Ensures that only one of two given arguments is null.
* Throws {@link IllegalArgumentException} if both are null or both are non-null.
*
* @param first the first argument
* @param second the second argument
* @param errorMessageTemplate a template for the exception message should the check fail, according to how
* {@link KiwiStrings#format(String, Object...)} handles placeholders
* @param errorMessageArgs the arguments to be substituted into the message template. Arguments
* are converted to strings using {@link String#valueOf(Object)}.
* @param <T> the object type
*/
public static <T> void checkOnlyOneArgumentIsNull(T first,
T second,
String errorMessageTemplate,
Object... errorMessageArgs) {
Preconditions.checkArgument(isOnlyOneNull(first, second), errorMessageTemplate, errorMessageArgs);
}

private static <T> boolean isOnlyOneNull(T left, T right) {
return (nonNull(left) && isNull(right)) || (isNull(left) && nonNull(right));
}

/**
* Ensures that an object reference passed as a parameter to the calling method is null, throwing
* an {@link IllegalArgumentException} if not null.
Expand Down
73 changes: 73 additions & 0 deletions src/test/java/org/kiwiproject/base/KiwiPreconditionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.assertj.core.util.Sets.newLinkedHashSet;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.kiwiproject.base.KiwiPreconditions.MAX_PORT_NUMBER;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull;
import static org.kiwiproject.base.KiwiPreconditions.requireNotBlank;
Expand Down Expand Up @@ -212,6 +213,78 @@ void testCheckArgumentNotNull_MessageWithTemplate(SoftAssertions softly) {
softly.assertThat(catchThrowable(() -> checkArgumentNotNull(new Object(), errorMessageTemplate, errorMessageArgs))).isNull();
}

@Nested
class CheckOnlyOneArgumentIsNull {

@Test
void shouldCheckWithNoErrorMessage() {
assertAll(
() -> assertThatCode(() -> KiwiPreconditions.checkOnlyOneArgumentIsNull("a", null))
.doesNotThrowAnyException(),

() -> assertThatCode(() -> KiwiPreconditions.checkOnlyOneArgumentIsNull(null, "b"))
.doesNotThrowAnyException(),

() -> assertThatIllegalArgumentException()
.isThrownBy(() -> KiwiPreconditions.checkOnlyOneArgumentIsNull(null, null))
.withMessage(null),

() -> assertThatIllegalArgumentException()
.isThrownBy(() -> KiwiPreconditions.checkOnlyOneArgumentIsNull("a", "b"))
.withMessage(null)
);
}

@Test
void shouldCheckWithErrorMessage() {
var message = "only one can be non-null";
assertAll(
() -> assertThatCode(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull("a", null, message))
.doesNotThrowAnyException(),

() -> assertThatCode(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(null, "b", message))
.doesNotThrowAnyException(),

() -> assertThatIllegalArgumentException().isThrownBy(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(null, null, message))
.withMessage(message),

() -> assertThatIllegalArgumentException().isThrownBy(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull("a", "b", message))
.withMessage(message)
);
}

@Test
void shouldCheckWithErrorMessageTemplate() {
var errorMessageTemplate = "only %s or %s can be non-null";
var expectedMessage = "only a or b can be non-null";
assertAll(
() -> assertThatCode(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(
"a", null, errorMessageTemplate, "a", "b"))
.doesNotThrowAnyException(),

() -> assertThatCode(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(
null, "b", errorMessageTemplate, "a", "b"))
.doesNotThrowAnyException(),

() -> assertThatIllegalArgumentException().isThrownBy(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(
null, null, errorMessageTemplate, "a", "b"))
.withMessage(expectedMessage),

() -> assertThatIllegalArgumentException().isThrownBy(() ->
KiwiPreconditions.checkOnlyOneArgumentIsNull(
"a", "b", errorMessageTemplate, "a", "b"))
.withMessage(expectedMessage)
);
}
}

@Nested
class CheckArgumentIsNull {

Expand Down

0 comments on commit 07f0dd5

Please sign in to comment.