Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package it.aboutbits.springboot.testing.validation.core;

import it.aboutbits.springboot.toolbox.type.CustomType;
import jakarta.validation.Valid;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.apache.logging.log4j.util.TriConsumer;
import org.springframework.validation.annotation.Validated;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import static org.assertj.core.api.Assertions.assertThat;

@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class BaseValidationAssert<R extends BaseRuleBuilder<?>> {
@Getter(AccessLevel.PROTECTED)
Expand Down Expand Up @@ -46,6 +51,43 @@ public <P> CallBuilder<R, P> of(@NonNull P parameterUnderTest) {
return new CallBuilder<>(this);
}

@SuppressWarnings("unused")
public AnnotationChecker calling(
@NonNull Class<?> classUnderTest,
@NonNull String methodName,
@NonNull Class<?>... methodParameterTypes
) {
return new AnnotationChecker(classUnderTest, methodName, methodParameterTypes);
}

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static final class AnnotationChecker {
private final Class<?> classUnderTest;
private final String methodName;
private final Class<?>[] methodParameterTypes;

public void isEnabled() {
assertThat(classUnderTest.isAnnotationPresent(Validated.class)).isTrue();

try {
var method = classUnderTest.getMethod(methodName, methodParameterTypes);
var parameter = method.getParameters()[method.getParameterCount() - 1];
assertThat(parameter.isAnnotationPresent(Valid.class)).isTrue();
} catch (NoSuchMethodException e) {
throw new AssertionError(
"Method \"%s(%s)\" not found in class \"%s\"".formatted(
methodName,
String.join(
", ",
Arrays.stream(methodParameterTypes).map(Class::getCanonicalName).toList()
),
classUnderTest.getCanonicalName()
), e
);
}
}
}

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static final class CallBuilder<R extends BaseRuleBuilder<?>, P> {
private final BaseValidationAssert<R> parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.With;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.lang.Nullable;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand All @@ -32,6 +34,7 @@
import java.time.temporal.ChronoUnit;

import static it.aboutbits.springboot.testing.validation.ValidationAssertTest.TestValidationAssert.assertThatValidation;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

class ValidationAssertTest {
Expand Down Expand Up @@ -524,6 +527,97 @@ void propertyMissingRule_shouldFail() {
.isCompliant());
}

@Nested
@SuppressWarnings("java:S5778") // Suppress the warning for lambdas with more than one exception cause
class AnnotationChecking {
@Test
void givenValidatedClass_andValidParameter_shouldSucceed() {
assertThatCode(
() -> assertThatValidation().calling(
ClassWithValidated.class,
"someMethodWithValidParameter",
String.class
).isEnabled()
).doesNotThrowAnyException();

assertThatCode(
() -> assertThatValidation().calling(
ClassWithValidated.class,
"someMethodWithValidParameter",
Long.class,
String.class
).isEnabled()
).doesNotThrowAnyException();

assertThatCode(
() -> assertThatValidation().calling(
ClassWithValidated.class,
"someMethodWithValidParameter",
Long.class,
Integer.class,
String.class
).isEnabled()
).doesNotThrowAnyException();
}

@Test
void givenNotValidatedClass_shouldAlwaysFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithValidParameter",
String.class
).isEnabled()
);

assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithValidParameter",
Long.class,
String.class
).isEnabled()
);

assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithValidParameter",
Long.class,
Integer.class,
String.class
).isEnabled()
);

assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithoutValidParameter",
String.class
).isEnabled()
);

assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithoutValidParameter",
Long.class,
String.class
).isEnabled()
);

assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThatValidation().calling(
ClassWithoutValidated.class,
"someMethodWithoutValidParameter",
Long.class,
Integer.class,
String.class
).isEnabled()
);
}
}

private static SomeValidParameter getSomeValidParameter() {
return new SomeValidParameter(
// NotNull
Expand Down Expand Up @@ -654,4 +748,47 @@ public static TestValidationAssert assertThatValidation() {
public static final class TestRuleBuilder extends BaseRuleBuilder<TestRuleBuilder> {
}
}

@SuppressWarnings({"java:S1186", "unused"}) // Suppress the "empty method body" warning
@Validated
public static class ClassWithValidated {
public void someMethodWithValidParameter(@Valid String last) {
}

public void someMethodWithValidParameter(Long first, @Valid String last) {
}

public void someMethodWithValidParameter(Long first, Integer second, @Valid String last) {
}

public void someMethodWithoutValidParameter(String last) {
}

public void someMethodWithoutValidParameter(Long first, String last) {
}

public void someMethodWithoutValidParameter(Long first, Integer second, String last) {
}
}

@SuppressWarnings({"java:S1186", "unused"}) // Suppress the "empty method body" warning
public static class ClassWithoutValidated {
public void someMethodWithValidParameter(@Valid String last) {
}

public void someMethodWithValidParameter(Long first, @Valid String last) {
}

public void someMethodWithValidParameter(Long first, Integer second, @Valid String last) {
}

public void someMethodWithoutValidParameter(String last) {
}

public void someMethodWithoutValidParameter(Long first, String last) {
}

public void someMethodWithoutValidParameter(Long first, Integer second, String last) {
}
}
}