From 2dcd754888892c4ff769ee171ea0824aaa1e3832 Mon Sep 17 00:00:00 2001 From: Seol_JY Date: Mon, 23 Dec 2024 15:22:39 +0900 Subject: [PATCH 1/5] Introduce repeatable annotation value collection for fields --- .../generator/ArbitraryGeneratorContext.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java index 69ae5f7ce..df7781a9e 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java @@ -18,12 +18,15 @@ package com.navercorp.fixturemonkey.api.generator; -import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.*; import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -107,6 +110,30 @@ public Optional findAnnotation(Class annotationClas return this.getResolvedProperty().getAnnotation(annotationClass); } + public List findAnnotations(Class annotationClass) { + List results = this.getResolvedProperty().getAnnotations().stream() + .filter(it -> annotationClass.isAssignableFrom(it.annotationType())) + .map(annotationClass::cast).collect(toList()); + + Repeatable repeatable = annotationClass.getAnnotation(Repeatable.class); + if (repeatable != null) { + Class containerClass = repeatable.value(); + this.getResolvedProperty().getAnnotations().stream() + .filter(it -> containerClass.isAssignableFrom(it.annotationType())) + .findFirst() + .ifPresent(container -> { + try { + Method valueMethod = container.annotationType().getDeclaredMethod("value"); + T[] values = (T[])valueMethod.invoke(container); + results.addAll(Arrays.asList(values)); + } catch (Exception ignored) { + } + }); + } + + return results; + } + public List getChildren() { return Collections.unmodifiableList(this.children); } From 396ef8f163f30ea3de5c9b14df534775cf89f0ff Mon Sep 17 00:00:00 2001 From: Seol_JY Date: Mon, 23 Dec 2024 15:23:25 +0900 Subject: [PATCH 2/5] Enhance decimal validation constraints handling with accurate behavior --- .../JakartaValidationConstraintGenerator.java | 220 +++++++----------- .../JakartaValidationFixtureMonkeyTest.java | 6 +- .../spec/BigDecimalIntrospectorSpec.java | 8 + .../JavaxValidationConstraintGenerator.java | 220 +++++++----------- .../JavaxValidationFixtureMonkeyTest.java | 6 +- .../spec/BigDecimalIntrospectorSpec.java | 8 + 6 files changed, 190 insertions(+), 278 deletions(-) diff --git a/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java b/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java index cdbc76a86..d46ad91b2 100644 --- a/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java +++ b/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java @@ -292,178 +292,126 @@ public JavaIntegerConstraint generateIntegerConstraint(ArbitraryGeneratorContext @Override @Nullable public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext context) { - BigDecimal positiveMin = null; - Boolean positiveMinInclusive = null; - BigDecimal positiveMax = null; - Boolean positiveMaxInclusive = null; - BigDecimal negativeMin = null; - Boolean negativeMinInclusive = null; - BigDecimal negativeMax = null; - boolean negativeMaxInclusive = false; + BigDecimal min = null; + Boolean minInclusive = null; + BigDecimal max = null; + Boolean maxInclusive = null; Integer scale = null; - Optional digits = context.findAnnotation(Digits.class); - if (digits.isPresent()) { - BigDecimal value = BigDecimal.ONE; - int integer = digits.get().integer(); - if (integer > 1) { - value = BigDecimal.TEN.pow(integer - 1); + for (Min minAnn : context.findAnnotations(Min.class)) { + BigDecimal newMin = BigDecimal.valueOf(minAnn.value()); + if (min == null || newMin.compareTo(min) > 0) { + min = newMin; + minInclusive = true; } - positiveMax = value.multiply(BigDecimal.TEN).subtract(BigDecimal.ONE); - positiveMin = value; - negativeMax = positiveMin.negate(); - negativeMin = positiveMax.negate(); - positiveMinInclusive = false; - negativeMinInclusive = false; - scale = digits.get().fraction(); } - Optional minAnnotation = context.findAnnotation(Min.class); - if (minAnnotation.isPresent()) { - BigDecimal minValue = minAnnotation.map(Min::value).map(BigDecimal::valueOf).get(); - if (minValue.compareTo(BigDecimal.ZERO) >= 0) { - if (positiveMin == null) { - positiveMin = minValue; - } else { - positiveMin = positiveMin.min(minValue); - } - negativeMax = null; - negativeMin = null; - } else { - if (negativeMin == null) { - negativeMin = minValue; - } else { - negativeMin = negativeMin.min(minValue); - } - negativeMinInclusive = true; + for (DecimalMin decimalMin : context.findAnnotations(DecimalMin.class)) { + BigDecimal newMin = new BigDecimal(decimalMin.value()); + if (min == null || newMin.compareTo(min) > 0 || + (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { + min = newMin; + minInclusive = decimalMin.inclusive(); } } - Optional decimalMinAnnotation = context.findAnnotation(DecimalMin.class); - if (decimalMinAnnotation.isPresent()) { - BigDecimal decimalMin = new BigDecimal( - decimalMinAnnotation - .get() - .value() - ); - - if (decimalMin.compareTo(BigDecimal.ZERO) >= 0) { - if (positiveMin == null) { - positiveMin = decimalMin; - } else { - positiveMin = positiveMin.min(decimalMin); - } - if (!decimalMinAnnotation.map(DecimalMin::inclusive).get()) { - positiveMinInclusive = false; - } - negativeMax = null; - negativeMin = null; - } else { - if (negativeMin == null) { - negativeMin = decimalMin; - } else { - negativeMin = negativeMin.min(negativeMin); - } - if (!decimalMinAnnotation.map(DecimalMin::inclusive).get()) { - negativeMinInclusive = false; - } + for (Max maxAnn : context.findAnnotations(Max.class)) { + BigDecimal newMax = BigDecimal.valueOf(maxAnn.value()); + if (max == null || newMax.compareTo(max) < 0) { + max = newMax; + maxInclusive = true; } } - Optional maxAnnotation = context.findAnnotation(Max.class); - if (maxAnnotation.isPresent()) { - BigDecimal maxValue = maxAnnotation.map(Max::value).map(BigDecimal::valueOf).get(); - if (maxValue.compareTo(BigDecimal.ZERO) > 0) { - if (positiveMax == null) { - positiveMax = maxValue; - } else { - positiveMax = positiveMax.max(maxValue); - } - } else { - if (negativeMax == null) { - negativeMax = maxValue; - } else { - negativeMax = negativeMax.max(maxValue); - } + for (DecimalMax decimalMax : context.findAnnotations(DecimalMax.class)) { + BigDecimal newMax = new BigDecimal(decimalMax.value()); + if (max == null || newMax.compareTo(max) < 0 || + (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { + max = newMax; + maxInclusive = decimalMax.inclusive(); } } - Optional decimalMaxAnnotation = context.findAnnotation(DecimalMax.class); - if (decimalMaxAnnotation.isPresent()) { - BigDecimal decimalMax = new BigDecimal( - decimalMaxAnnotation - .get() - .value() - ); - - if (decimalMax.compareTo(BigDecimal.ZERO) > 0) { - if (positiveMax == null) { - positiveMax = decimalMax; - } else { - positiveMax = positiveMax.max(decimalMax); - } - positiveMaxInclusive = decimalMaxAnnotation.map(DecimalMax::inclusive).get(); - } else { - if (negativeMax == null) { - negativeMax = decimalMax; - } else { - negativeMax = negativeMax.max(decimalMax); - } - negativeMaxInclusive = decimalMaxAnnotation.map(DecimalMax::inclusive).get(); - } - - if (!decimalMaxAnnotation.map(DecimalMax::inclusive).get()) { - positiveMaxInclusive = false; + if (context.findAnnotation(Positive.class).isPresent()) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0 || + (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { + min = BigDecimal.ZERO; + minInclusive = false; } + } - if (positiveMax == null) { - positiveMax = decimalMax; - } else if (positiveMax.compareTo(decimalMax) > 0) { - positiveMax = decimalMax; + if (context.findAnnotation(PositiveOrZero.class).isPresent()) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0) { + min = BigDecimal.ZERO; + minInclusive = true; } } if (context.findAnnotation(Negative.class).isPresent()) { - if (negativeMax == null || negativeMax.compareTo(BigDecimal.ZERO) > 0) { - negativeMax = BigDecimal.ZERO; - negativeMaxInclusive = false; + if (max == null || BigDecimal.ZERO.compareTo(max) < 0 || + (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { + max = BigDecimal.ZERO; + maxInclusive = false; } } if (context.findAnnotation(NegativeOrZero.class).isPresent()) { - if (negativeMax == null || negativeMax.compareTo(BigDecimal.ZERO) > 0) { - negativeMax = BigDecimal.ZERO; - negativeMaxInclusive = true; + if (max == null || BigDecimal.ZERO.compareTo(max) < 0) { + max = BigDecimal.ZERO; + maxInclusive = true; } } - if (context.findAnnotation(Positive.class).isPresent()) { - if (positiveMin == null || positiveMin.compareTo(BigDecimal.ZERO) < 0) { - positiveMin = BigDecimal.ZERO; - positiveMinInclusive = false; + Optional digitsAnn = context.findAnnotation(Digits.class); + if (digitsAnn.isPresent()) { + Digits digits = digitsAnn.get(); + int integerDigits = digits.integer(); + int fractionDigits = digits.fraction(); + + StringBuilder maxBuilder = new StringBuilder(); + for (int i = 0; i < integerDigits; i++) { + maxBuilder.append('9'); } - } + if (fractionDigits > 0) { + maxBuilder.append('.'); + for (int i = 0; i < fractionDigits; i++) { + maxBuilder.append('9'); + } + } + BigDecimal digitsMax = new BigDecimal(maxBuilder.toString()); + BigDecimal digitsMin = digitsMax.negate(); - if (context.findAnnotation(PositiveOrZero.class).isPresent()) { - if (positiveMin == null || positiveMin.compareTo(BigDecimal.ZERO) < 0) { - positiveMin = BigDecimal.ZERO; - positiveMinInclusive = true; + if (max == null || digitsMax.compareTo(max) < 0) { + max = digitsMax; + maxInclusive = true; + } + if (min == null || digitsMin.compareTo(min) > 0) { + min = digitsMin; + minInclusive = true; } + + scale = digits.fraction(); } - if (positiveMin == null && positiveMax == null && negativeMin == null && negativeMax == null && scale == null) { + if (min == null && max == null) { return null; } + boolean isPositiveMin = min != null && min.compareTo(BigDecimal.ZERO) >= 0; + boolean isPositiveMax = max != null && max.compareTo(BigDecimal.ZERO) >= 0; + boolean isNegativeMin = min != null && min.compareTo(BigDecimal.ZERO) < 0; + boolean isNegativeMax = max != null && max.compareTo(BigDecimal.ZERO) < 0; + return new JavaDecimalConstraint( - positiveMin, - positiveMinInclusive, - positiveMax, - positiveMaxInclusive, - negativeMin, - negativeMinInclusive, - negativeMax, - negativeMaxInclusive, + isPositiveMin ? min : null, + isPositiveMin ? minInclusive : null, + isPositiveMax ? max : null, + isPositiveMax ? maxInclusive : null, + + isNegativeMin ? min : null, + isNegativeMin ? minInclusive : null, + isNegativeMax ? max : null, + isNegativeMax ? maxInclusive : null, scale ); } diff --git a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java index c5697c96a..1a0e26552 100644 --- a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java +++ b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java @@ -18,9 +18,7 @@ package com.navercorp.fixturemonkey.jakarta.validation; -import static org.assertj.core.api.BDDAssertions.then; -import static org.assertj.core.api.BDDAssertions.thenNoException; -import static org.assertj.core.api.BDDAssertions.thenThrownBy; +import static org.assertj.core.api.BDDAssertions.*; import java.math.BigDecimal; import java.math.BigInteger; @@ -81,6 +79,8 @@ void sampleBigDecimal() { then(actual.getNegativeOrZero()).isLessThanOrEqualTo(BigDecimal.ZERO); then(actual.getPositive()).isPositive(); then(actual.getPositiveOrZero()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + then(actual.getDecimalEqual()).isEqualByComparingTo(BigDecimal.valueOf(100.1)); + then(actual.getIntegerEqual()).isEqualByComparingTo(BigDecimal.valueOf(100)); } @Property(tries = 100) diff --git a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/spec/BigDecimalIntrospectorSpec.java b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/spec/BigDecimalIntrospectorSpec.java index 496be13fc..3827edfc3 100644 --- a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/spec/BigDecimalIntrospectorSpec.java +++ b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/spec/BigDecimalIntrospectorSpec.java @@ -51,4 +51,12 @@ public class BigDecimalIntrospectorSpec { @PositiveOrZero private BigDecimal positiveOrZero; + + @DecimalMin(value = "100.1") + @DecimalMax(value = "100.1") + private BigDecimal decimalEqual; + + @Max(value = 100) + @Min(value = 100) + private BigDecimal integerEqual; } diff --git a/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java b/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java index 289267ad7..cfd5c4284 100644 --- a/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java +++ b/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java @@ -291,178 +291,126 @@ public JavaIntegerConstraint generateIntegerConstraint(ArbitraryGeneratorContext @Override @Nullable public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext context) { - BigDecimal positiveMin = null; - Boolean positiveMinInclusive = null; - BigDecimal positiveMax = null; - Boolean positiveMaxInclusive = null; - BigDecimal negativeMin = null; - Boolean negativeMinInclusive = null; - BigDecimal negativeMax = null; - boolean negativeMaxInclusive = false; + BigDecimal min = null; + Boolean minInclusive = null; + BigDecimal max = null; + Boolean maxInclusive = null; Integer scale = null; - Optional digits = context.findAnnotation(Digits.class); - if (digits.isPresent()) { - BigDecimal value = BigDecimal.ONE; - int integer = digits.get().integer(); - if (integer > 1) { - value = BigDecimal.TEN.pow(integer - 1); + for (Min minAnn : context.findAnnotations(Min.class)) { + BigDecimal newMin = BigDecimal.valueOf(minAnn.value()); + if (min == null || newMin.compareTo(min) > 0) { + min = newMin; + minInclusive = true; } - positiveMax = value.multiply(BigDecimal.TEN).subtract(BigDecimal.ONE); - positiveMin = value; - negativeMax = positiveMin.negate(); - negativeMin = positiveMax.negate(); - positiveMinInclusive = false; - negativeMinInclusive = false; - scale = digits.get().fraction(); } - Optional minAnnotation = context.findAnnotation(Min.class); - if (minAnnotation.isPresent()) { - BigDecimal minValue = minAnnotation.map(Min::value).map(BigDecimal::valueOf).get(); - if (minValue.compareTo(BigDecimal.ZERO) >= 0) { - if (positiveMin == null) { - positiveMin = minValue; - } else { - positiveMin = positiveMin.min(minValue); - } - negativeMax = null; - negativeMin = null; - } else { - if (negativeMin == null) { - negativeMin = minValue; - } else { - negativeMin = negativeMin.min(minValue); - } - negativeMinInclusive = true; + for (DecimalMin decimalMin : context.findAnnotations(DecimalMin.class)) { + BigDecimal newMin = new BigDecimal(decimalMin.value()); + if (min == null || newMin.compareTo(min) > 0 || + (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { + min = newMin; + minInclusive = decimalMin.inclusive(); } } - Optional decimalMinAnnotation = context.findAnnotation(DecimalMin.class); - if (decimalMinAnnotation.isPresent()) { - BigDecimal decimalMin = new BigDecimal( - decimalMinAnnotation - .get() - .value() - ); - - if (decimalMin.compareTo(BigDecimal.ZERO) >= 0) { - if (positiveMin == null) { - positiveMin = decimalMin; - } else { - positiveMin = positiveMin.min(decimalMin); - } - if (!decimalMinAnnotation.map(DecimalMin::inclusive).get()) { - positiveMinInclusive = false; - } - negativeMax = null; - negativeMin = null; - } else { - if (negativeMin == null) { - negativeMin = decimalMin; - } else { - negativeMin = negativeMin.min(negativeMin); - } - if (!decimalMinAnnotation.map(DecimalMin::inclusive).get()) { - negativeMinInclusive = false; - } + for (Max maxAnn : context.findAnnotations(Max.class)) { + BigDecimal newMax = BigDecimal.valueOf(maxAnn.value()); + if (max == null || newMax.compareTo(max) < 0) { + max = newMax; + maxInclusive = true; } } - Optional maxAnnotation = context.findAnnotation(Max.class); - if (maxAnnotation.isPresent()) { - BigDecimal maxValue = maxAnnotation.map(Max::value).map(BigDecimal::valueOf).get(); - if (maxValue.compareTo(BigDecimal.ZERO) > 0) { - if (positiveMax == null) { - positiveMax = maxValue; - } else { - positiveMax = positiveMax.max(maxValue); - } - } else { - if (negativeMax == null) { - negativeMax = maxValue; - } else { - negativeMax = negativeMax.max(maxValue); - } + for (DecimalMax decimalMax : context.findAnnotations(DecimalMax.class)) { + BigDecimal newMax = new BigDecimal(decimalMax.value()); + if (max == null || newMax.compareTo(max) < 0 || + (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { + max = newMax; + maxInclusive = decimalMax.inclusive(); } } - Optional decimalMaxAnnotation = context.findAnnotation(DecimalMax.class); - if (decimalMaxAnnotation.isPresent()) { - BigDecimal decimalMax = new BigDecimal( - decimalMaxAnnotation - .get() - .value() - ); - - if (decimalMax.compareTo(BigDecimal.ZERO) > 0) { - if (positiveMax == null) { - positiveMax = decimalMax; - } else { - positiveMax = positiveMax.max(decimalMax); - } - positiveMaxInclusive = decimalMaxAnnotation.map(DecimalMax::inclusive).get(); - } else { - if (negativeMax == null) { - negativeMax = decimalMax; - } else { - negativeMax = negativeMax.max(decimalMax); - } - negativeMaxInclusive = decimalMaxAnnotation.map(DecimalMax::inclusive).get(); - } - - if (!decimalMaxAnnotation.map(DecimalMax::inclusive).get()) { - positiveMaxInclusive = false; + if (context.findAnnotation(Positive.class).isPresent()) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0 || + (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { + min = BigDecimal.ZERO; + minInclusive = false; } + } - if (positiveMax == null) { - positiveMax = decimalMax; - } else if (positiveMax.compareTo(decimalMax) > 0) { - positiveMax = decimalMax; + if (context.findAnnotation(PositiveOrZero.class).isPresent()) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0) { + min = BigDecimal.ZERO; + minInclusive = true; } } if (context.findAnnotation(Negative.class).isPresent()) { - if (negativeMax == null || negativeMax.compareTo(BigDecimal.ZERO) > 0) { - negativeMax = BigDecimal.ZERO; - negativeMaxInclusive = false; + if (max == null || BigDecimal.ZERO.compareTo(max) < 0 || + (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { + max = BigDecimal.ZERO; + maxInclusive = false; } } if (context.findAnnotation(NegativeOrZero.class).isPresent()) { - if (negativeMax == null || negativeMax.compareTo(BigDecimal.ZERO) > 0) { - negativeMax = BigDecimal.ZERO; - negativeMaxInclusive = true; + if (max == null || BigDecimal.ZERO.compareTo(max) < 0) { + max = BigDecimal.ZERO; + maxInclusive = true; } } - if (context.findAnnotation(Positive.class).isPresent()) { - if (positiveMin == null || positiveMin.compareTo(BigDecimal.ZERO) < 0) { - positiveMin = BigDecimal.ZERO; - positiveMinInclusive = false; + Optional digitsAnn = context.findAnnotation(Digits.class); + if (digitsAnn.isPresent()) { + Digits digits = digitsAnn.get(); + int integerDigits = digits.integer(); + int fractionDigits = digits.fraction(); + + StringBuilder maxBuilder = new StringBuilder(); + for (int i = 0; i < integerDigits; i++) { + maxBuilder.append('9'); } - } + if (fractionDigits > 0) { + maxBuilder.append('.'); + for (int i = 0; i < fractionDigits; i++) { + maxBuilder.append('9'); + } + } + BigDecimal digitsMax = new BigDecimal(maxBuilder.toString()); + BigDecimal digitsMin = digitsMax.negate(); - if (context.findAnnotation(PositiveOrZero.class).isPresent()) { - if (positiveMin == null || positiveMin.compareTo(BigDecimal.ZERO) < 0) { - positiveMin = BigDecimal.ZERO; - positiveMinInclusive = true; + if (max == null || digitsMax.compareTo(max) < 0) { + max = digitsMax; + maxInclusive = true; + } + if (min == null || digitsMin.compareTo(min) > 0) { + min = digitsMin; + minInclusive = true; } + + scale = digits.fraction(); } - if (positiveMin == null && positiveMax == null && negativeMin == null && negativeMax == null && scale == null) { + if (min == null && max == null) { return null; } + boolean isPositiveMin = min != null && min.compareTo(BigDecimal.ZERO) >= 0; + boolean isPositiveMax = max != null && max.compareTo(BigDecimal.ZERO) >= 0; + boolean isNegativeMin = min != null && min.compareTo(BigDecimal.ZERO) < 0; + boolean isNegativeMax = max != null && max.compareTo(BigDecimal.ZERO) < 0; + return new JavaDecimalConstraint( - positiveMin, - positiveMinInclusive, - positiveMax, - positiveMaxInclusive, - negativeMin, - negativeMinInclusive, - negativeMax, - negativeMaxInclusive, + isPositiveMin ? min : null, + isPositiveMin ? minInclusive : null, + isPositiveMax ? max : null, + isPositiveMax ? maxInclusive : null, + + isNegativeMin ? min : null, + isNegativeMin ? minInclusive : null, + isNegativeMax ? max : null, + isNegativeMax ? maxInclusive : null, scale ); } diff --git a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java index 8e3cb7124..028ccd32f 100644 --- a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java +++ b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java @@ -18,9 +18,7 @@ package com.navercorp.fixturemonkey.javax.validation; -import static org.assertj.core.api.BDDAssertions.then; -import static org.assertj.core.api.BDDAssertions.thenNoException; -import static org.assertj.core.api.BDDAssertions.thenThrownBy; +import static org.assertj.core.api.BDDAssertions.*; import java.math.BigDecimal; import java.math.BigInteger; @@ -81,6 +79,8 @@ void sampleBigDecimal() { then(actual.getNegativeOrZero()).isLessThanOrEqualTo(BigDecimal.ZERO); then(actual.getPositive()).isPositive(); then(actual.getPositiveOrZero()).isGreaterThanOrEqualTo(BigDecimal.ZERO); + then(actual.getDecimalEqual()).isEqualByComparingTo(BigDecimal.valueOf(100.1)); + then(actual.getIntegerEqual()).isEqualByComparingTo(BigDecimal.valueOf(100)); } @Property(tries = 100) diff --git a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/spec/BigDecimalIntrospectorSpec.java b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/spec/BigDecimalIntrospectorSpec.java index aeefc7d06..bc714cade 100644 --- a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/spec/BigDecimalIntrospectorSpec.java +++ b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/spec/BigDecimalIntrospectorSpec.java @@ -52,4 +52,12 @@ public class BigDecimalIntrospectorSpec { @PositiveOrZero private BigDecimal positiveOrZero; + + @DecimalMax(value = "100.1") + @DecimalMin(value = "100.1") + private BigDecimal decimalEqual; + + @Max(value = 100) + @Min(value = 100) + private BigDecimal integerEqual; } From 9598de3a50f71453b3eb3459c43cb2c63b042fa8 Mon Sep 17 00:00:00 2001 From: Seol_JY Date: Mon, 23 Dec 2024 15:52:23 +0900 Subject: [PATCH 3/5] Fix operator line wrapping in validation constraint generators --- .../JakartaValidationConstraintGenerator.java | 16 ++++++++-------- .../JavaxValidationConstraintGenerator.java | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java b/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java index d46ad91b2..df8589ec7 100644 --- a/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java +++ b/fixture-monkey-jakarta-validation/src/main/java/com/navercorp/fixturemonkey/jakarta/validation/introspector/JakartaValidationConstraintGenerator.java @@ -308,8 +308,8 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext for (DecimalMin decimalMin : context.findAnnotations(DecimalMin.class)) { BigDecimal newMin = new BigDecimal(decimalMin.value()); - if (min == null || newMin.compareTo(min) > 0 || - (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { + if (min == null || newMin.compareTo(min) > 0 + || (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { min = newMin; minInclusive = decimalMin.inclusive(); } @@ -325,16 +325,16 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext for (DecimalMax decimalMax : context.findAnnotations(DecimalMax.class)) { BigDecimal newMax = new BigDecimal(decimalMax.value()); - if (max == null || newMax.compareTo(max) < 0 || - (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { + if (max == null || newMax.compareTo(max) < 0 + || (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { max = newMax; maxInclusive = decimalMax.inclusive(); } } if (context.findAnnotation(Positive.class).isPresent()) { - if (min == null || BigDecimal.ZERO.compareTo(min) > 0 || - (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0 + || (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { min = BigDecimal.ZERO; minInclusive = false; } @@ -348,8 +348,8 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext } if (context.findAnnotation(Negative.class).isPresent()) { - if (max == null || BigDecimal.ZERO.compareTo(max) < 0 || - (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { + if (max == null || BigDecimal.ZERO.compareTo(max) < 0 + || (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { max = BigDecimal.ZERO; maxInclusive = false; } diff --git a/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java b/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java index cfd5c4284..972774b3e 100644 --- a/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java +++ b/fixture-monkey-javax-validation/src/main/java/com/navercorp/fixturemonkey/javax/validation/introspector/JavaxValidationConstraintGenerator.java @@ -307,8 +307,8 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext for (DecimalMin decimalMin : context.findAnnotations(DecimalMin.class)) { BigDecimal newMin = new BigDecimal(decimalMin.value()); - if (min == null || newMin.compareTo(min) > 0 || - (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { + if (min == null || newMin.compareTo(min) > 0 + || (newMin.compareTo(min) == 0 && !decimalMin.inclusive() && minInclusive)) { min = newMin; minInclusive = decimalMin.inclusive(); } @@ -324,16 +324,16 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext for (DecimalMax decimalMax : context.findAnnotations(DecimalMax.class)) { BigDecimal newMax = new BigDecimal(decimalMax.value()); - if (max == null || newMax.compareTo(max) < 0 || - (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { + if (max == null || newMax.compareTo(max) < 0 + || (newMax.compareTo(max) == 0 && !decimalMax.inclusive() && maxInclusive)) { max = newMax; maxInclusive = decimalMax.inclusive(); } } if (context.findAnnotation(Positive.class).isPresent()) { - if (min == null || BigDecimal.ZERO.compareTo(min) > 0 || - (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { + if (min == null || BigDecimal.ZERO.compareTo(min) > 0 + || (BigDecimal.ZERO.compareTo(min) == 0 && minInclusive)) { min = BigDecimal.ZERO; minInclusive = false; } @@ -347,8 +347,8 @@ public JavaDecimalConstraint generateDecimalConstraint(ArbitraryGeneratorContext } if (context.findAnnotation(Negative.class).isPresent()) { - if (max == null || BigDecimal.ZERO.compareTo(max) < 0 || - (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { + if (max == null || BigDecimal.ZERO.compareTo(max) < 0 + || (BigDecimal.ZERO.compareTo(max) == 0 && maxInclusive)) { max = BigDecimal.ZERO; maxInclusive = false; } From 952364b4fa839b2f4f1814e4f16f8345566ec775 Mon Sep 17 00:00:00 2001 From: Seol_JY Date: Mon, 23 Dec 2024 16:05:51 +0900 Subject: [PATCH 4/5] Fix wildcard import in ArbitraryGeneratorContext --- .../fixturemonkey/api/generator/ArbitraryGeneratorContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java index df7781a9e..577baf228 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryGeneratorContext.java @@ -18,7 +18,8 @@ package com.navercorp.fixturemonkey.api.generator; -import static java.util.stream.Collectors.*; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; From eb987a5612c3d7564e59c36d27abb3403e495e3e Mon Sep 17 00:00:00 2001 From: Seol_JY Date: Mon, 23 Dec 2024 16:11:31 +0900 Subject: [PATCH 5/5] Fix wildcard import in ValidationFixtureMonkeyTest --- .../validation/JakartaValidationFixtureMonkeyTest.java | 4 +++- .../javax/validation/JavaxValidationFixtureMonkeyTest.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java index 1a0e26552..865f680d4 100644 --- a/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java +++ b/fixture-monkey-jakarta-validation/src/test/java/com/navercorp/fixturemonkey/jakarta/validation/JakartaValidationFixtureMonkeyTest.java @@ -18,7 +18,9 @@ package com.navercorp.fixturemonkey.jakarta.validation; -import static org.assertj.core.api.BDDAssertions.*; +import static org.assertj.core.api.BDDAssertions.then; +import static org.assertj.core.api.BDDAssertions.thenNoException; +import static org.assertj.core.api.BDDAssertions.thenThrownBy; import java.math.BigDecimal; import java.math.BigInteger; diff --git a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java index 028ccd32f..93f4fd08c 100644 --- a/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java +++ b/fixture-monkey-javax-validation/src/test/java/com/navercorp/fixturemonkey/javax/validation/JavaxValidationFixtureMonkeyTest.java @@ -18,7 +18,9 @@ package com.navercorp.fixturemonkey.javax.validation; -import static org.assertj.core.api.BDDAssertions.*; +import static org.assertj.core.api.BDDAssertions.then; +import static org.assertj.core.api.BDDAssertions.thenNoException; +import static org.assertj.core.api.BDDAssertions.thenThrownBy; import java.math.BigDecimal; import java.math.BigInteger;