Skip to content

Commit

Permalink
Implement non strict validation
Browse files Browse the repository at this point in the history
Issue: #285
  • Loading branch information
muehmar committed Oct 9, 2024
1 parent a7c6f26 commit 224d67c
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private static Generator<DiscriminatableJavaComposition, PojoSettings> methodCon
(comp, s, w) ->
w.println(
"if (%s() %s) {",
getValidCountMethodName(comp.getType()), getCountCondition(comp.getType())))
getValidCountMethodName(comp.getType()), getCountCondition(comp, s)))
.append(constant("return null;"), 1)
.append(constant("}"))
.append(
Expand All @@ -66,8 +66,9 @@ private static Generator<DiscriminatableJavaComposition, PojoSettings> methodCon
additionalFoldArguments(composition.getType())));
}

private static String getCountCondition(DiscriminatableJavaComposition.Type type) {
return type.equals(ONE_OF) ? "!= 1" : "== 0";
private static String getCountCondition(
DiscriminatableJavaComposition composition, PojoSettings settings) {
return composition.validateExactlyOneMatch(settings) ? "!= 1" : "== 0";
}

private static String additionalFoldArguments(DiscriminatableJavaComposition.Type type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,22 @@ private static Generator<CompositionContainer, PojoSettings> addInvalidSingleRes
return Generator.<CompositionContainer, PojoSettings>emptyGen()
.append(
(container, s, w) ->
w.println("if(%s) {", invalidCondition(container.getComposition())))
w.println("if(%s) {", invalidCondition(container.getComposition(), s)))
.appendOptional(
singleResultDiscriminatorHandling().indent(1),
DiscriminatorAndMemberPojo::fromCompositionContainer)
.appendList(putSingleInvalidDto(), CompositionContainer::getPojos)
.append(constant("}"));
}

private static String invalidCondition(DiscriminatableJavaComposition composition) {
private static String invalidCondition(
DiscriminatableJavaComposition composition, PojoSettings settings) {
final DiscriminatableJavaComposition.Type type = composition.getType();
final String validCountCondition =
String.format(
"%s() %s",
getCompositionValidCountMethodName(type), type.equals(ONE_OF) ? "!= 1" : "== 0");
getCompositionValidCountMethodName(type),
composition.validateExactlyOneMatch(settings) ? "!= 1" : "== 0");
final String discriminatorCondition =
String.format("!%s()", isValidAgainstTheCorrectSchemaMethodName(type));
return PList.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Generator<T, PojoSettings> isValidAgainstMoreThanOneSchema() {
.append(annotation)
.append(JacksonAnnotationGenerator.jsonIgnore())
.append(method)
.prependNewLine();
.prependNewLine()
.filter(DiscriminatableJavaComposition::validateExactlyOneMatch);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import io.github.muehmar.codegenerator.writer.Writer;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;

Expand Down Expand Up @@ -131,7 +132,11 @@ private static PList<Condition> createAllOfDtoValidationConditions(JavaObjectPoj

private static Condition methodContentOneOfCondition() {
return Condition.constant("getOneOfValidCount() == 1")
.filter(JavaObjectPojo::hasOneOfComposition);
.filter(
(pojo, settings) ->
pojo.getOneOfComposition()
.map(comp -> comp.validateExactlyOneMatch(settings))
.orElse(false));
}

private static Condition methodContentOneOfDiscriminatorCondition() {
Expand Down Expand Up @@ -206,5 +211,11 @@ default Condition filter(Predicate<JavaObjectPojo> predicate) {
final Generator<JavaObjectPojo, PojoSettings> self = this;
return (p, s, w) -> predicate.test(p) ? self.generate(p, s, w) : w;
}

@Override
default Condition filter(BiPredicate<JavaObjectPojo, PojoSettings> predicate) {
final Generator<JavaObjectPojo, PojoSettings> self = this;
return (p, s, w) -> predicate.test(p, s) ? self.generate(p, s, w) : w;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.github.muehmar.gradle.openapi.generator.java.model.composition;

import static com.github.muehmar.gradle.openapi.util.Booleans.not;

import ch.bluecare.commons.data.NonEmptyList;
import ch.bluecare.commons.data.PList;
import com.github.muehmar.gradle.openapi.generator.java.model.member.TechnicalPojoMember;
import com.github.muehmar.gradle.openapi.generator.java.model.name.JavaName;
import com.github.muehmar.gradle.openapi.generator.java.model.pojo.JavaObjectPojo;
import com.github.muehmar.gradle.openapi.generator.settings.PojoSettings;
import java.util.Optional;

public interface DiscriminatableJavaComposition {
Expand All @@ -17,6 +20,11 @@ public interface DiscriminatableJavaComposition {

Type getType();

default boolean validateExactlyOneMatch(PojoSettings settings) {
return getType() == Type.ONE_OF
&& not(settings.isNonStrictOneOfValidation() && hasDiscriminator());
}

default boolean hasDiscriminator() {
return getDiscriminator().isPresent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ void generate_when_oneOfPojo_then_correctOutput() {
expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("oneOfWithDiscriminatorAndNonStrictValidation")
void generate_when_oneOfWithDiscriminatorAndNonStrictValidation_then_correctOutput() {
final Generator<JavaObjectPojo, PojoSettings> generator = foldValidationGenerator();

final Writer writer =
generator.generate(
JavaPojos.oneOfPojoWithEnumDiscriminator(),
defaultTestSettings().withNonStrictOneOfValidation(true),
javaWriter());

expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("oneOfProtectedAndDeprecatedSettings")
void generate_when_protectedAndDeprecatedSettings_then_correctOutput() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ void generate_when_oneOfPojo_then_correctOutput() {
expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("oneOfPojoWithDiscriminatorAndNonStrictValidation")
void generate_when_oneOfPojoWithDiscriminatorAndNonStrictValidation_then_correctOutput() {
final Generator<JavaObjectPojo, PojoSettings> generator =
invalidCompositionDtoGetterGenerator();

final Writer writer =
generator.generate(
JavaPojos.oneOfPojoWithEnumDiscriminator(),
defaultTestSettings().withNonStrictOneOfValidation(true),
javaWriter());

expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("oneOfPojoWithPublicDeprecatedValidationMethods")
void generate_when_oneOfPojoWithPublicDeprecatedValidationMethods_then_correctOutput() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ void generate_when_oneOfPojo_then_correctOutput() {
expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("oneOfPojoWithDiscriminatorAndNonStrictValidation")
void generate_when_oneOfPojoWithDiscriminatorAndNonStrictValidation_then_correctOutput() {
final Generator<JavaObjectPojo, PojoSettings> generator =
ValidCountValidationMethod.validCountValidationMethodGenerator();

final JavaObjectPojo javaPojo = JavaPojos.oneOfPojoWithEnumDiscriminator();
final Writer writer =
generator.generate(
javaPojo, defaultTestSettings().withNonStrictOneOfValidation(true), javaWriter());

expect.toMatchSnapshot(writerSnapshot(writer));
}

@Test
@SnapshotName("anyOf")
void generate_when_anyOfPojo_then_correctOutput() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,19 @@ protected Object getOneOf() {
}
return foldOneOf(dto -> dto, dto -> dto, () -> null);
}
]


oneOfWithDiscriminatorAndNonStrictValidation=[
com.fasterxml.jackson.annotation.JsonIgnore
javax.validation.Valid

@Valid
@JsonIgnore
private Object getOneOf() {
if (getOneOfValidCount() == 0) {
return null;
}
return foldOneOf(dto -> dto, dto -> dto, () -> null);
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,35 @@ private Map<String, Object> getInvalidOneOf() {
]


oneOfPojoWithDiscriminatorAndNonStrictValidation=[
com.fasterxml.jackson.annotation.JsonIgnore
java.util.HashMap
java.util.Map
javax.validation.Valid

@Valid
@JsonIgnore
private Map<String, Object> getInvalidOneOf() {
final Map<String, Object> dtos = new HashMap<>();
if(getOneOfValidCount() == 0 || !isValidAgainstTheCorrectOneOfSchema()) {
if(color != null) {
switch(color.getValue()) {
case "yellow":
dtos.put("Yellow", asYellowDto());
return dtos;
case "orange":
dtos.put("Orange", asOrangeDto());
return dtos;
}
}
dtos.put("Yellow", asYellowDto());
dtos.put("Orange", asOrangeDto());
}
return dtos;
}
]


oneOfPojoWithEnumDiscriminator=[
com.fasterxml.jackson.annotation.JsonIgnore
java.util.HashMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,16 @@ private boolean isValidAgainstNoOneOfSchema() {
private boolean isValidAgainstMoreThanOneSchema() {
return getOneOfValidCount() > 1;
}
]


oneOfPojoWithDiscriminatorAndNonStrictValidation=[
com.fasterxml.jackson.annotation.JsonIgnore
javax.validation.constraints.AssertFalse

@AssertFalse(message = "Is not valid against one of the schemas [Yellow, Orange]")
@JsonIgnore
private boolean isValidAgainstNoOneOfSchema() {
return getOneOfValidCount() == 0;
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ void generate_when_oneOfPojoWithDiscriminator_then_correctOutput() {
expect.toMatchSnapshot(writer.asString());
}

@Test
@SnapshotName("oneOfPojoWithDiscriminatorAndNonStrictOneOfValidation")
void generate_when_oneOfPojoWithDiscriminatorAndNonStrictOneOfValidation_then_correctOutput() {
final Generator<JavaObjectPojo, PojoSettings> generator = validationClassGenerator();

final JavaOneOfComposition javaOneOfComposition =
JavaOneOfCompositions.fromPojosAndDiscriminator(
NonEmptyList.of(sampleObjectPojo1(), sampleObjectPojo2()),
UntypedDiscriminator.fromPropertyName(Name.ofString("type")));

final JavaObjectPojo pojo = JavaPojos.oneOfPojo(javaOneOfComposition);

final Writer writer =
generator.generate(
pojo, defaultTestSettings().withNonStrictOneOfValidation(true), javaWriter());

expect.toMatchSnapshot(writer.asString());
}

@Test
@SnapshotName("anyOfPojoWithMembers")
void generate_when_anyOfPojoWithMembers_then_correctOutput() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,29 @@ private class Validator {
]


oneOfPojoWithDiscriminatorAndNonStrictOneOfValidation=[
private class Validator {

private boolean isAdditionalPropertiesValid() {
if(getAdditionalProperties_() != null) {
return getAdditionalProperties_().values().stream().allMatch(this::isAdditionalPropertiesValueValid);
}

return false;
}

private boolean isAdditionalPropertiesValueValid(Object additionalPropertiesValue) {
return true;
}

private boolean isValid() {
return isValidAgainstTheCorrectOneOfSchema()
&& isAdditionalPropertiesValid();
}
}
]


oneOfPojoWithMembers=[
private class Validator {
private boolean isColorValid() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.github.muehmar.gradle.openapi.generator.java.model.composition;

import static com.github.muehmar.gradle.openapi.generator.java.model.pojo.JavaPojos.sampleObjectPojo1;
import static com.github.muehmar.gradle.openapi.generator.java.model.pojo.JavaPojos.sampleObjectPojo2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import com.github.muehmar.gradle.openapi.generator.java.model.pojo.JavaPojos;
import com.github.muehmar.gradle.openapi.generator.settings.PojoSettings;
import com.github.muehmar.gradle.openapi.generator.settings.TestPojoSettings;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class DiscriminatableJavaCompositionTest {

@ParameterizedTest
@MethodSource("compositionAndSettingsCombinations")
void validateExactlyOneMatch_when_compositionAndSettingsCombinations_then_matchExpected(
DiscriminatableJavaComposition composition, PojoSettings settings, boolean expected) {

assertEquals(expected, composition.validateExactlyOneMatch(settings));
}

public static Stream<Arguments> compositionAndSettingsCombinations() {
final DiscriminatableJavaComposition oneOfCompositionWithDiscriminator =
JavaPojos.oneOfPojoWithEnumDiscriminator().getOneOfComposition().get();
final DiscriminatableJavaComposition oneOfComposition =
JavaPojos.oneOfPojo(sampleObjectPojo1(), sampleObjectPojo2()).getOneOfComposition().get();
final DiscriminatableJavaComposition anyOfPojoWithDiscriminator =
JavaPojos.anyOfPojoWithDiscriminator().getAnyOfComposition().get();
final DiscriminatableJavaComposition anyOfComposition =
JavaPojos.anyOfPojo(sampleObjectPojo1(), sampleObjectPojo2()).getAnyOfComposition().get();

final PojoSettings defaultSettings = TestPojoSettings.defaultTestSettings();
final PojoSettings nonStrictSettings = defaultSettings.withNonStrictOneOfValidation(true);

return Stream.of(
arguments(oneOfComposition, defaultSettings, true),
arguments(oneOfComposition, nonStrictSettings, true),
arguments(oneOfCompositionWithDiscriminator, defaultSettings, true),
arguments(oneOfCompositionWithDiscriminator, nonStrictSettings, false),
arguments(anyOfComposition, defaultSettings, false),
arguments(anyOfComposition, nonStrictSettings, false),
arguments(anyOfPojoWithDiscriminator, defaultSettings, false),
arguments(anyOfPojoWithDiscriminator, nonStrictSettings, false));
}
}

0 comments on commit 224d67c

Please sign in to comment.