From 57d4998dc993631d2e9d0493106a895a3591eb8f Mon Sep 17 00:00:00 2001 From: Andreas Hufler Date: Tue, 3 Sep 2024 10:47:03 +0200 Subject: [PATCH 1/2] add custom types remove obsolete validators remove snapshots fix actions fix version fix missing steps add basic validators add PR snapshots --- .idea/encodings.xml | 6 + pom.xml | 39 +++ .../springboot/toolbox/type/EmailAddress.java | 36 +++ .../springboot/toolbox/type/Iban.java | 46 ++++ .../toolbox/type/ScaledBigDecimal.java | 233 ++++++++++++++++++ .../util/EmailAddressValidator.java | 27 ++ .../validation/util/IbanValidator.java | 27 ++ .../toolbox/type/EmailAddressTest.java | 82 ++++++ .../springboot/toolbox/type/IbanTest.java | 82 ++++++ .../util/EmailAddressValidatorTest.java | 62 +++++ .../validation/util/IbanValidatorTest.java | 62 +++++ 11 files changed, 702 insertions(+) create mode 100644 .idea/encodings.xml create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidator.java create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidator.java create mode 100644 src/test/java/it/aboutbits/springboot/toolbox/type/EmailAddressTest.java create mode 100644 src/test/java/it/aboutbits/springboot/toolbox/type/IbanTest.java create mode 100644 src/test/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidatorTest.java create mode 100644 src/test/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidatorTest.java diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63e9001 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8159baf..835c6b9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,17 +3,56 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.2 + + + it.aboutbits spring-boot-toolbox BUILD-SNAPSHOT Utility library for Spring Boot projects. + jar 21 + + org.springframework.boot + spring-boot-starter-validation + + + + + org.projectlombok + lombok + true + + + + + + commons-validator + commons-validator + 1.9.0 + + + + + org.jetbrains + annotations + 24.1.0 + + + + org.springframework.boot + spring-boot-starter-test + diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java b/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java new file mode 100644 index 0000000..5593728 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java @@ -0,0 +1,36 @@ +package it.aboutbits.springboot.toolbox.type; + +import it.aboutbits.springboot.toolbox.validation.util.EmailAddressValidator; +import org.jetbrains.annotations.NotNull; + +/** + * A record representing an email address, validated and stored in lowercase. + *

+ * The EmailAddress record ensures that the provided email address string + * is in a valid format and automatically converts it to lowercase for + * consistent internal representation. It implements the Comparable + * interface to allow comparison between different email addresses. + *

+ * + * @param value the email address string + * @throws IllegalArgumentException if the provided email address is not in a valid format + */ +public record EmailAddress(String value) implements Comparable { + public EmailAddress(String value) { + if (value == null || EmailAddressValidator.isNotValid(value)) { + throw new IllegalArgumentException("Value is not a valid email address: " + value); + } + + this.value = value.toLowerCase(); + } + + @Override + public String toString() { + return value; + } + + @Override + public int compareTo(@NotNull EmailAddress o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java b/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java new file mode 100644 index 0000000..042cd08 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java @@ -0,0 +1,46 @@ +package it.aboutbits.springboot.toolbox.type; + +import it.aboutbits.springboot.toolbox.validation.util.IbanValidator; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * The {@code Iban} class represents an International Bank Account Number (IBAN) and provides functionality for validation + * and comparison of IBANs. It ensures the valid format of the IBAN according to predefined rules. + * + * @param value the IBAN value, which must be a valid and non-null string + */ +public record Iban(String value) implements Comparable { + public Iban(String value) { + if (value == null || IbanValidator.isNotValid(value.toUpperCase())) { + throw new IllegalArgumentException("Value is not a valid IBAN: " + value); + } + + this.value = value.toUpperCase(); + } + + @Override + public String toString() { + return value; + } + + /** + * Retrieves the ABI (Bank Branch Code) if the IBAN belongs to an Italian bank. + * + * @return An {@code Optional} containing the ABI value if the IBAN is Italian, or an empty {@code Optional} otherwise. + */ + public Optional getAbiIfItalian() { + var iban = value(); + + if (!iban.startsWith("IT")) { + return Optional.empty(); + } + return Optional.of(iban.substring(5, 10)); + } + + @Override + public int compareTo(@NotNull Iban o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java b/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java new file mode 100644 index 0000000..9e47157 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java @@ -0,0 +1,233 @@ +package it.aboutbits.springboot.toolbox.type; + +import lombok.NonNull; +import org.jetbrains.annotations.NotNull; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Objects; + +/** + * A record that represents a scaled BigDecimal with a fixed MathContext. + * This class provides various constructors for creating instances with different numerical types. + * It also provides a set of arithmetic operations that return new instances with the appropriate scale and rounding. + */ +public record ScaledBigDecimal( + @NonNull BigDecimal value +) implements Comparable { + private static final MathContext MATH_CONTEXT = new MathContext(15, RoundingMode.HALF_UP); + + public static final ScaledBigDecimal ZERO = new ScaledBigDecimal(0); + public static final ScaledBigDecimal ONE = new ScaledBigDecimal(1); + public static final ScaledBigDecimal TWO = new ScaledBigDecimal(2); + public static final ScaledBigDecimal TEN = new ScaledBigDecimal(10); + + public ScaledBigDecimal(@NonNull BigDecimal value) { + this.value = value.setScale(MATH_CONTEXT.getPrecision(), MATH_CONTEXT.getRoundingMode()); + } + + public ScaledBigDecimal(int value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull Integer value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull BigInteger value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public ScaledBigDecimal(long value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull Long value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public ScaledBigDecimal(float value) { + this(new BigDecimal(String.valueOf(value), MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull Float value) { + this(new BigDecimal(String.valueOf(value), MATH_CONTEXT)); + } + + public ScaledBigDecimal(double value) { + this(new BigDecimal(String.valueOf(value), MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull Double value) { + this(new BigDecimal(String.valueOf(value), MATH_CONTEXT)); + } + + public ScaledBigDecimal(@NonNull String value) { + this(new BigDecimal(value, MATH_CONTEXT)); + } + + public static ScaledBigDecimal valueOf(int value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull Integer value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull BigInteger value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(long value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull Long value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(float value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull Float value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(double value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull Double value) { + return new ScaledBigDecimal(value); + } + + public static ScaledBigDecimal valueOf(@NonNull String value) { + return new ScaledBigDecimal(value); + } + + @NotNull + public ScaledBigDecimal add(@NonNull ScaledBigDecimal other) { + return new ScaledBigDecimal(this.value().add(other.value())); + } + + @NotNull + public ScaledBigDecimal subtract(@NonNull ScaledBigDecimal other) { + return new ScaledBigDecimal(this.value().subtract(other.value())); + } + + @NotNull + public ScaledBigDecimal multiply(@NonNull ScaledBigDecimal other) { + return new ScaledBigDecimal(this.value().multiply(other.value())); + } + + @NotNull + public ScaledBigDecimal divide(@NonNull ScaledBigDecimal other) { + return new ScaledBigDecimal(this.value().divide(other.value(), MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal add(@NonNull BigDecimal other) { + return new ScaledBigDecimal(this.value().add(other)); + } + + @NotNull + public ScaledBigDecimal subtract(@NonNull BigDecimal other) { + return new ScaledBigDecimal(this.value().subtract(other)); + } + + @NotNull + public ScaledBigDecimal multiply(@NonNull BigDecimal other) { + return new ScaledBigDecimal(this.value().multiply(other)); + } + + @NotNull + public ScaledBigDecimal divide(@NonNull BigDecimal other) { + return new ScaledBigDecimal(this.value().divide(other, MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal remainder(@NonNull ScaledBigDecimal divisor) { + return new ScaledBigDecimal(this.value().remainder(divisor.value(), MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal remainder(@NonNull BigDecimal divisor) { + return new ScaledBigDecimal(this.value().remainder(divisor, MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal sqrt() { + return new ScaledBigDecimal(this.value().sqrt(MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal pow(int n) { + return new ScaledBigDecimal(this.value().pow(n, MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal abs() { + return new ScaledBigDecimal(this.value().abs(MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal negate() { + return new ScaledBigDecimal(this.value().negate(MATH_CONTEXT)); + } + + @NotNull + public ScaledBigDecimal min(@NonNull ScaledBigDecimal val) { + return new ScaledBigDecimal(this.value().min(val.value())); + } + + @NotNull + public ScaledBigDecimal min(@NonNull BigDecimal val) { + return new ScaledBigDecimal(this.value().min(val)); + } + + @NotNull + public ScaledBigDecimal max(@NonNull ScaledBigDecimal val) { + return new ScaledBigDecimal(this.value().max(val.value())); + } + + @NotNull + public ScaledBigDecimal max(@NonNull BigDecimal val) { + return new ScaledBigDecimal(this.value().max(val)); + } + + @NotNull + public BigDecimal toBigDecimal(int scale) { + return this.value().setScale(scale, RoundingMode.HALF_UP); + } + + @NotNull + public ScaledBigDecimal roundToScale(int scale) { + return new ScaledBigDecimal(this.value().setScale(scale, RoundingMode.HALF_UP)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof ScaledBigDecimal other) { + return this.value().compareTo(other.value()) == 0; + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hash(MATH_CONTEXT, value()); + } + + @Override + public int compareTo(@NotNull ScaledBigDecimal o) { + return this.value().compareTo(o.value()); + } +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidator.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidator.java new file mode 100644 index 0000000..62ed128 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidator.java @@ -0,0 +1,27 @@ +package it.aboutbits.springboot.toolbox.validation.util; + +import org.apache.commons.validator.routines.EmailValidator; + +public final class EmailAddressValidator { + private static final EmailValidator EMAIL_VALIDATOR = EmailValidator.getInstance(); + + private EmailAddressValidator() { + } + + /** + * Validates if the provided email address is in a proper format. + * + * @param email the email address to validate + * @return true if the email address is valid, false otherwise + */ + public static boolean isValid(String email) { + if (email == null) { + return false; + } + return EMAIL_VALIDATOR.isValid(email); + } + + public static boolean isNotValid(String email) { + return !isValid(email); + } +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidator.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidator.java new file mode 100644 index 0000000..b3de1a1 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidator.java @@ -0,0 +1,27 @@ +package it.aboutbits.springboot.toolbox.validation.util; + +import org.apache.commons.validator.routines.IBANValidator; + +public final class IbanValidator { + private static final IBANValidator IBAN_VALIDATOR = new IBANValidator(); + + private IbanValidator() { + } + + /** + * Validates whether the given IBAN (International Bank Account Number) is valid according to predefined rules. + * + * @param iban the IBAN to be validated + * @return true if the IBAN is valid, false otherwise + */ + public static boolean isValid(String iban) { + if (iban == null) { + return false; + } + return IBAN_VALIDATOR.isValid(iban); + } + + public static boolean isNotValid(String iban) { + return !isValid(iban); + } +} diff --git a/src/test/java/it/aboutbits/springboot/toolbox/type/EmailAddressTest.java b/src/test/java/it/aboutbits/springboot/toolbox/type/EmailAddressTest.java new file mode 100644 index 0000000..bbed40e --- /dev/null +++ b/src/test/java/it/aboutbits/springboot/toolbox/type/EmailAddressTest.java @@ -0,0 +1,82 @@ +package it.aboutbits.springboot.toolbox.type; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class EmailAddressTest { + @Nested + class Constructor { + @ParameterizedTest + @ValueSource(strings = {"egon@aboutbits.it", "hans.mueller@aboutbits.it", "peterP_pansky@aboutbits.it"}) + void validValues_shouldSucceed(String value) { + assertThatCode( + () -> new EmailAddress(value) + ).doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", "\t", "\r", "\n", "sepp", "x@ y", "@aboutbits.it", "hans mueller@aboutbits.it", "peter@pansky@aboutbits.it"}) + void invalidValues_shouldFail(String value) { + assertThatIllegalArgumentException().isThrownBy( + () -> new EmailAddress(value) + ); + } + + @Test + void null_shouldFail() { + assertThatIllegalArgumentException().isThrownBy( + () -> new EmailAddress(null) + ); + } + } + + @Nested + class ToStringAndValue { + @Test + void shouldAlwaysReturnTheSameValue() { + var emailAddress = new EmailAddress("someValue@aboutbits.it"); + + assertThat(emailAddress.value()).isEqualTo(emailAddress.toString()); + } + + @Test + void shouldReturnLowercaseValue() { + var emailAddress = new EmailAddress("someValue@aboutbits.it"); + + assertThat(emailAddress.value()).isEqualTo("somevalue@aboutbits.it"); + } + } + + @Nested + class CompareTo { + @Test + void shouldCompareToReturnNegativeWhenInputValueIsGreater() { + var emailAddress1 = new EmailAddress("abc@aboutbits.it"); + var emailAddress2 = new EmailAddress("xyz@aboutbits.it"); + + assertThat(emailAddress1.compareTo(emailAddress2)).isNegative(); + } + + @Test + void shouldCompareToReturnPositiveWhenInputValueIsLesser() { + var emailAddress1 = new EmailAddress("xyz@aboutbits.it"); + var emailAddress2 = new EmailAddress("abc@aboutbits.it"); + + assertThat(emailAddress1.compareTo(emailAddress2)).isPositive(); + } + + @Test + void shouldCompareToReturnZeroWhenInputValuesAreEqual() { + var emailAddress1 = new EmailAddress("abc@aboutbits.it"); + var emailAddress2 = new EmailAddress("abc@aboutbits.it"); + + assertThat(emailAddress1).isEqualByComparingTo(emailAddress2); + } + } +} diff --git a/src/test/java/it/aboutbits/springboot/toolbox/type/IbanTest.java b/src/test/java/it/aboutbits/springboot/toolbox/type/IbanTest.java new file mode 100644 index 0000000..3b9fe55 --- /dev/null +++ b/src/test/java/it/aboutbits/springboot/toolbox/type/IbanTest.java @@ -0,0 +1,82 @@ +package it.aboutbits.springboot.toolbox.type; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class IbanTest { + @Nested + class Constructor { + @ParameterizedTest + @ValueSource(strings = {"NL08INGB3330533676", "HR3425000097537651489", "IT37G0300203280237914848919", "AT705400073311799347", "DE60500105175378199617"}) + void validValues_shouldSucceed(String value) { + assertThatCode( + () -> new Iban(value) + ).doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"IT60X0542811101000000123450", "some-wrong-stuff", "", " ", " ", "\t", "\r", "\n"}) + void invalidValues_shouldFail(String value) { + assertThatIllegalArgumentException().isThrownBy( + () -> new Iban(value) + ); + } + + @Test + void null_shouldFail() { + assertThatIllegalArgumentException().isThrownBy( + () -> new Iban(null) + ); + } + } + + @Nested + class ToStringAndValue { + @Test + void shouldAlwaysReturnTheSameValue() { + var emailAddress = new Iban("HR3425000097537651489"); + + assertThat(emailAddress.value()).isEqualTo(emailAddress.toString()); + } + + @Test + void shouldReturnUppercaseValue() { + var emailAddress = new Iban("hr3425000097537651489"); + + assertThat(emailAddress.value()).isEqualTo("HR3425000097537651489"); + } + } + + @Nested + class CompareTo { + @Test + void shouldCompareToReturnNegativeWhenInputValueIsGreater() { + var iban1 = new Iban("HR3425000097537651489"); + var iban2 = new Iban("NL08INGB3330533676"); + + assertThat(iban1.compareTo(iban2)).isNegative(); + } + + @Test + void shouldCompareToReturnPositiveWhenInputValueIsLesser() { + var iban1 = new Iban("NL08INGB3330533676"); + var iban2 = new Iban("HR3425000097537651489"); + + assertThat(iban1.compareTo(iban2)).isPositive(); + } + + @Test + void shouldCompareToReturnZeroWhenInputValuesAreEqual() { + var iban1 = new Iban("HR3425000097537651489"); + var iban2 = new Iban("HR3425000097537651489"); + + assertThat(iban1).isEqualByComparingTo(iban2); + } + } +} diff --git a/src/test/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidatorTest.java b/src/test/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidatorTest.java new file mode 100644 index 0000000..3e3a189 --- /dev/null +++ b/src/test/java/it/aboutbits/springboot/toolbox/validation/util/EmailAddressValidatorTest.java @@ -0,0 +1,62 @@ +package it.aboutbits.springboot.toolbox.validation.util; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class EmailAddressValidatorTest { + @Nested + class IsValid { + @ParameterizedTest + @ValueSource(strings = {"egon@aboutbits.it", "hans.mueller@aboutbits.it", "peterP_pansky@aboutbits.it"}) + void validValues_shouldSucceed(String value) { + assertThat( + EmailAddressValidator.isValid(value) + ).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", "\t", "\r", "\n", "sepp", "x@ y", "@aboutbits.it", "hans mueller@aboutbits.it", "peter@pansky@aboutbits.it"}) + void invalidValues_shouldFail(String value) { + assertThat( + EmailAddressValidator.isValid(value) + ).isFalse(); + } + + @Test + void null_shouldFail() { + assertThat( + EmailAddressValidator.isValid(null) + ).isFalse(); + } + } + + @Nested + class IsNotValid { + @ParameterizedTest + @ValueSource(strings = {"egon@aboutbits.it", "hans.mueller@aboutbits.it", "peterP_pansky@aboutbits.it"}) + void validValues_shouldSucceed(String value) { + assertThat( + EmailAddressValidator.isNotValid(value) + ).isFalse(); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", "\t", "\r", "\n", "sepp", "x@ y", "@aboutbits.it", "hans mueller@aboutbits.it", "peter@pansky@aboutbits.it"}) + void invalidValues_shouldFail(String value) { + assertThat( + EmailAddressValidator.isNotValid(value) + ).isTrue(); + } + + @Test + void null_shouldFail() { + assertThat( + EmailAddressValidator.isNotValid(null) + ).isTrue(); + } + } +} diff --git a/src/test/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidatorTest.java b/src/test/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidatorTest.java new file mode 100644 index 0000000..d70ea11 --- /dev/null +++ b/src/test/java/it/aboutbits/springboot/toolbox/validation/util/IbanValidatorTest.java @@ -0,0 +1,62 @@ +package it.aboutbits.springboot.toolbox.validation.util; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class IbanValidatorTest { + @Nested + class IsValid { + @ParameterizedTest + @ValueSource(strings = {"NL08INGB3330533676", "HR3425000097537651489", "IT37G0300203280237914848919", "AT705400073311799347", "DE60500105175378199617"}) + void validValues_shouldSucceed(String value) { + assertThat( + IbanValidator.isValid(value) + ).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = {"IT60X0542811101000000123450", "some-wrong-stuff", "", " ", " ", "\t", "\r", "\n"}) + void invalidValues_shouldFail(String value) { + assertThat( + IbanValidator.isValid(value) + ).isFalse(); + } + + @Test + void null_shouldFail() { + assertThat( + IbanValidator.isValid(null) + ).isFalse(); + } + } + + @Nested + class IsNotValid { + @ParameterizedTest + @ValueSource(strings = {"NL08INGB3330533676", "HR3425000097537651489", "IT37G0300203280237914848919", "AT705400073311799347", "DE60500105175378199617"}) + void validValues_shouldSucceed(String value) { + assertThat( + IbanValidator.isNotValid(value) + ).isFalse(); + } + + @ParameterizedTest + @ValueSource(strings = {"IT60X0542811101000000123450", "some-wrong-stuff", "", " ", " ", "\t", "\r", "\n"}) + void invalidValues_shouldFail(String value) { + assertThat( + IbanValidator.isNotValid(value) + ).isTrue(); + } + + @Test + void null_shouldFail() { + assertThat( + IbanValidator.isNotValid(null) + ).isTrue(); + } + } +} From 20d1dfe742f6aebcbc8e06fdc17b32e6cbfbfe13 Mon Sep 17 00:00:00 2001 From: Andreas Hufler Date: Wed, 4 Sep 2024 10:23:24 +0200 Subject: [PATCH 2/2] cleanup nullability annotations and relay hashcode --- pom.xml | 7 --- .../springboot/toolbox/type/EmailAddress.java | 5 +- .../springboot/toolbox/type/Iban.java | 6 ++- .../toolbox/type/ScaledBigDecimal.java | 46 +++++++++---------- 4 files changed, 29 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index 835c6b9..01001da 100644 --- a/pom.xml +++ b/pom.xml @@ -41,13 +41,6 @@ 1.9.0 - - - org.jetbrains - annotations - 24.1.0 - - org.springframework.boot diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java b/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java index 5593728..4c2869b 100644 --- a/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/EmailAddress.java @@ -1,7 +1,7 @@ package it.aboutbits.springboot.toolbox.type; import it.aboutbits.springboot.toolbox.validation.util.EmailAddressValidator; -import org.jetbrains.annotations.NotNull; +import lombok.NonNull; /** * A record representing an email address, validated and stored in lowercase. @@ -24,13 +24,14 @@ public EmailAddress(String value) { this.value = value.toLowerCase(); } + @NonNull @Override public String toString() { return value; } @Override - public int compareTo(@NotNull EmailAddress o) { + public int compareTo(@NonNull EmailAddress o) { return value().compareTo(o.value()); } } diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java b/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java index 042cd08..0098da5 100644 --- a/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/Iban.java @@ -1,7 +1,7 @@ package it.aboutbits.springboot.toolbox.type; import it.aboutbits.springboot.toolbox.validation.util.IbanValidator; -import org.jetbrains.annotations.NotNull; +import lombok.NonNull; import java.util.Optional; @@ -20,6 +20,7 @@ public Iban(String value) { this.value = value.toUpperCase(); } + @NonNull @Override public String toString() { return value; @@ -30,6 +31,7 @@ public String toString() { * * @return An {@code Optional} containing the ABI value if the IBAN is Italian, or an empty {@code Optional} otherwise. */ + @NonNull public Optional getAbiIfItalian() { var iban = value(); @@ -40,7 +42,7 @@ public Optional getAbiIfItalian() { } @Override - public int compareTo(@NotNull Iban o) { + public int compareTo(@NonNull Iban o) { return value().compareTo(o.value()); } } diff --git a/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java b/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java index 9e47157..3ffc5ec 100644 --- a/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java +++ b/src/main/java/it/aboutbits/springboot/toolbox/type/ScaledBigDecimal.java @@ -1,13 +1,11 @@ package it.aboutbits.springboot.toolbox.type; import lombok.NonNull; -import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; import java.math.RoundingMode; -import java.util.Objects; /** * A record that represents a scaled BigDecimal with a fixed MathContext. @@ -108,102 +106,102 @@ public static ScaledBigDecimal valueOf(@NonNull String value) { return new ScaledBigDecimal(value); } - @NotNull + @NonNull public ScaledBigDecimal add(@NonNull ScaledBigDecimal other) { return new ScaledBigDecimal(this.value().add(other.value())); } - @NotNull + @NonNull public ScaledBigDecimal subtract(@NonNull ScaledBigDecimal other) { return new ScaledBigDecimal(this.value().subtract(other.value())); } - @NotNull + @NonNull public ScaledBigDecimal multiply(@NonNull ScaledBigDecimal other) { return new ScaledBigDecimal(this.value().multiply(other.value())); } - @NotNull + @NonNull public ScaledBigDecimal divide(@NonNull ScaledBigDecimal other) { return new ScaledBigDecimal(this.value().divide(other.value(), MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal add(@NonNull BigDecimal other) { return new ScaledBigDecimal(this.value().add(other)); } - @NotNull + @NonNull public ScaledBigDecimal subtract(@NonNull BigDecimal other) { return new ScaledBigDecimal(this.value().subtract(other)); } - @NotNull + @NonNull public ScaledBigDecimal multiply(@NonNull BigDecimal other) { return new ScaledBigDecimal(this.value().multiply(other)); } - @NotNull + @NonNull public ScaledBigDecimal divide(@NonNull BigDecimal other) { return new ScaledBigDecimal(this.value().divide(other, MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal remainder(@NonNull ScaledBigDecimal divisor) { return new ScaledBigDecimal(this.value().remainder(divisor.value(), MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal remainder(@NonNull BigDecimal divisor) { return new ScaledBigDecimal(this.value().remainder(divisor, MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal sqrt() { return new ScaledBigDecimal(this.value().sqrt(MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal pow(int n) { return new ScaledBigDecimal(this.value().pow(n, MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal abs() { return new ScaledBigDecimal(this.value().abs(MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal negate() { return new ScaledBigDecimal(this.value().negate(MATH_CONTEXT)); } - @NotNull + @NonNull public ScaledBigDecimal min(@NonNull ScaledBigDecimal val) { return new ScaledBigDecimal(this.value().min(val.value())); } - @NotNull + @NonNull public ScaledBigDecimal min(@NonNull BigDecimal val) { return new ScaledBigDecimal(this.value().min(val)); } - @NotNull + @NonNull public ScaledBigDecimal max(@NonNull ScaledBigDecimal val) { return new ScaledBigDecimal(this.value().max(val.value())); } - @NotNull + @NonNull public ScaledBigDecimal max(@NonNull BigDecimal val) { return new ScaledBigDecimal(this.value().max(val)); } - @NotNull + @NonNull public BigDecimal toBigDecimal(int scale) { return this.value().setScale(scale, RoundingMode.HALF_UP); } - @NotNull + @NonNull public ScaledBigDecimal roundToScale(int scale) { return new ScaledBigDecimal(this.value().setScale(scale, RoundingMode.HALF_UP)); } @@ -223,11 +221,11 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(MATH_CONTEXT, value()); + return value().hashCode(); } @Override - public int compareTo(@NotNull ScaledBigDecimal o) { + public int compareTo(@NonNull ScaledBigDecimal o) { return this.value().compareTo(o.value()); } }