Skip to content

Commit

Permalink
Consumer-driven validation of all properties of schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
Felipe444 committed Aug 14, 2019
1 parent 00c6094 commit aaedfcd
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,35 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
ArraySchema consumerIntegerSchema = consumerSchema.asArraySchema();
ArraySchema providerIntegerSchema = providerSchema.asArraySchema();

if (!equals(consumerIntegerSchema.getAdditionalItems(), providerIntegerSchema.getAdditionalItems())) {
if (!isValid(consumerIntegerSchema.getAdditionalItems(), providerIntegerSchema.getAdditionalItems())) {
errors.add(String.format(ERROR_FORMAT_SHORT,
consumerIntegerSchema.getId(),
"additionalItems"));
}

if (!equals(consumerIntegerSchema.getItems(), providerIntegerSchema.getItems())) {
if (!isValid(consumerIntegerSchema.getItems(), providerIntegerSchema.getItems())) {
errors.add(String.format(ERROR_FORMAT_SHORT,
consumerIntegerSchema.getId(),
"items"));
}

if (!equals(consumerIntegerSchema.getMaxItems(), providerIntegerSchema.getMaxItems())) {
if (!isValid(consumerIntegerSchema.getMaxItems(), providerIntegerSchema.getMaxItems())) {
errors.add(String.format(ERROR_FORMAT,
consumerIntegerSchema.getId(),
"maxItems",
consumerIntegerSchema.getMaxItems(),
providerIntegerSchema.getMaxItems()));
}

if (!equals(consumerIntegerSchema.getMinItems(), providerIntegerSchema.getMinItems())) {
if (!isValid(consumerIntegerSchema.getMinItems(), providerIntegerSchema.getMinItems())) {
errors.add(String.format(ERROR_FORMAT,
consumerIntegerSchema.getId(),
"minItems",
consumerIntegerSchema.getMinItems(),
providerIntegerSchema.getMinItems()));
}

if (!equals(consumerIntegerSchema.getUniqueItems(), providerIntegerSchema.getUniqueItems())) {
if (!isValid(consumerIntegerSchema.getUniqueItems(), providerIntegerSchema.getUniqueItems())) {
errors.add(String.format(ERROR_FORMAT,
consumerIntegerSchema.getId(),
"uniqueItems",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
providerContainerTypeSchema.getEnums()));
}

if (!equals(consumerContainerTypeSchema.getOneOf(), providerContainerTypeSchema.getOneOf())) {
if (!isEnumValid(consumerContainerTypeSchema.getOneOf(), providerContainerTypeSchema.getOneOf())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"oneOf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
IntegerSchema consumerIntegerSchema = consumerSchema.asIntegerSchema();
IntegerSchema providerIntegerSchema = providerSchema.asIntegerSchema();

if (!equals(consumerIntegerSchema.getDivisibleBy(), providerIntegerSchema.getDivisibleBy())) {
if (!isValid(consumerIntegerSchema.getDivisibleBy(), providerIntegerSchema.getDivisibleBy())) {
errors.add(String.format(ERROR_FORMAT,
consumerIntegerSchema.getId(),
"divisibleBy",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiPredicate;
Expand All @@ -20,31 +21,31 @@ public abstract class JsonSchemaValidator {
public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchema) {
List<String> errors = new ArrayList<>();

if (!equals(consumerSchema.get$ref(), providerSchema.get$ref())) {
if (!isValid(consumerSchema.get$ref(), providerSchema.get$ref())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"$ref",
consumerSchema.get$ref(),
providerSchema.get$ref()));
}

if (!equals(consumerSchema.get$schema(), providerSchema.get$schema())) {
if (!isValid(consumerSchema.get$schema(), providerSchema.get$schema())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"$schema",
consumerSchema.get$schema(),
providerSchema.get$schema()));
}

if (!arraysEquals(consumerSchema.getDisallow(), providerSchema.getDisallow(), Object::equals)) {
if (!isArrayValid(consumerSchema.getDisallow(), providerSchema.getDisallow(), Object::equals)) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"disallow",
jsonArrayToString(consumerSchema.getDisallow()),
jsonArrayToString(providerSchema.getDisallow())));
}

if (!arraysEquals(consumerSchema.getExtends(), providerSchema.getExtends(), Object::equals)) {
if (!isArrayValid(consumerSchema.getExtends(), providerSchema.getExtends(), Object::equals)) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"extends",
Expand All @@ -60,15 +61,15 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
providerSchema.getRequired()));
}

if (!equals(consumerSchema.getReadonly(), providerSchema.getReadonly())) {
if (!isValid(consumerSchema.getReadonly(), providerSchema.getReadonly())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"readonly",
consumerSchema.getReadonly(),
providerSchema.getReadonly()));
}

if (!equals(consumerSchema.getDescription(), providerSchema.getDescription())) {
if (!isValid(consumerSchema.getDescription(), providerSchema.getDescription())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"description",
Expand All @@ -83,20 +84,21 @@ private boolean isRequired(JsonSchema schema) {
return schema.getRequired() != null && schema.getRequired();
}

boolean equals(Object object1, Object object2) {
return Objects.equals(object1, object2);
boolean isValid(Object consumerObject, Object providerObject) {
return consumerObject == null || Objects.equals(consumerObject, providerObject);
}

<T> boolean arraysEquals(T[] array1, T[] array2, BiPredicate<T, T> checker) {
if (array1 == null) {
return array2 == null;
<T> boolean isArrayValid(T[] consumerArray, T[] providerArray, BiPredicate<T, T> checker) {
if (consumerArray == null) {
return true;
}
if (array2 == null) {

if (providerArray == null) {
return false;
}

return array1.length == array2.length && IntStream.range(0, array1.length)
.allMatch(i -> checker.test(array1[i], array2[i]));
return consumerArray.length == providerArray.length && IntStream.range(0, consumerArray.length)
.allMatch(i -> checker.test(consumerArray[i], providerArray[i]));
}

private String jsonArrayToString(JsonSchema[] array) {
Expand All @@ -111,7 +113,7 @@ String jsonToString(JsonSchema object) {
return "JsonSchema(id=" + object.getId() + ")";
}

boolean isEnumValid(Set<String> consumerEnums, Set<String> providerEnums) {
<T> boolean isEnumValid(Set<T> consumerEnums, Set<T> providerEnums) {
if (representsString(consumerEnums) && representsEnum(providerEnums)) {
return false;
}
Expand All @@ -123,11 +125,23 @@ boolean isEnumValid(Set<String> consumerEnums, Set<String> providerEnums) {
return true;
}

private boolean representsEnum(Set<String> enums) {
<T, S> boolean isMapValid(Map<T, S> consumerMap, Map<T, S> providerMap) {
if (consumerMap.size() == 0) {
return true;
}

if (providerMap.size() == 0) {
return false;
}

return consumerMap.equals(providerMap);
}

private <T> boolean representsEnum(Set<T> enums) {
return enums.size() > 0;
}

private boolean representsString(Set<String> enums) {
private <T> boolean representsString(Set<T> enums) {
return enums.size() == 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,39 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
NumberSchema consumerNumberSchema = consumerSchema.asNumberSchema();
NumberSchema providerNumberSchema = providerSchema.asNumberSchema();

if (!equals(consumerNumberSchema.getExclusiveMaximum(), providerNumberSchema.getExclusiveMaximum())) {
if (!isValid(consumerNumberSchema.getExclusiveMaximum(), providerNumberSchema.getExclusiveMaximum())) {
errors.add(String.format(ERROR_FORMAT,
consumerNumberSchema.getId(),
"exclusiveMaximum",
consumerNumberSchema.getExclusiveMaximum(),
providerNumberSchema.getExclusiveMaximum()));
}

if (!equals(consumerNumberSchema.getExclusiveMinimum(), providerNumberSchema.getExclusiveMinimum())) {
if (!isValid(consumerNumberSchema.getExclusiveMinimum(), providerNumberSchema.getExclusiveMinimum())) {
errors.add(String.format(ERROR_FORMAT,
consumerNumberSchema.getId(),
"exclusiveMinimum",
consumerNumberSchema.getExclusiveMinimum(),
providerNumberSchema.getExclusiveMinimum()));
}

if (!equals(consumerNumberSchema.getMaximum(), providerNumberSchema.getMaximum())) {
if (!isValid(consumerNumberSchema.getMaximum(), providerNumberSchema.getMaximum())) {
errors.add(String.format(ERROR_FORMAT,
consumerNumberSchema.getId(),
"maximum",
consumerNumberSchema.getMaximum(),
providerNumberSchema.getMaximum()));
}

if (!equals(consumerNumberSchema.getMinimum(), providerNumberSchema.getMinimum())) {
if (!isValid(consumerNumberSchema.getMinimum(), providerNumberSchema.getMinimum())) {
errors.add(String.format(ERROR_FORMAT,
consumerNumberSchema.getId(),
"minimum",
consumerNumberSchema.getMinimum(),
providerNumberSchema.getMinimum()));
}

if (!equals(consumerNumberSchema.getMultipleOf(), providerNumberSchema.getMultipleOf())) {
if (!isValid(consumerNumberSchema.getMultipleOf(), providerNumberSchema.getMultipleOf())) {
errors.add(String.format(ERROR_FORMAT,
consumerNumberSchema.getId(),
"multipleOf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
ObjectSchema consumerObjectSchema = consumerSchema.asObjectSchema();
ObjectSchema providerObjectSchema = providerSchema.asObjectSchema();

if (!equals(consumerObjectSchema.getAdditionalProperties(), providerObjectSchema.getAdditionalProperties())) {
if (!isValid(consumerObjectSchema.getAdditionalProperties(), providerObjectSchema.getAdditionalProperties())) {
errors.add(String.format(ERROR_FORMAT_SHORT,
consumerSchema.getId(),
"additionalProperties"));
}

if (!equals(consumerObjectSchema.getDependencies(), providerObjectSchema.getDependencies())) {
if (!isMapValid(consumerObjectSchema.getDependencies(), providerObjectSchema.getDependencies())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"dependencies",
consumerObjectSchema.getDependencies(),
providerObjectSchema.getDependencies()));
}

if (!equals(consumerObjectSchema.getPatternProperties(), providerObjectSchema.getPatternProperties())) {
if (!isMapValid(consumerObjectSchema.getPatternProperties(), providerObjectSchema.getPatternProperties())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"patternProperties",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
SimpleTypeSchema consumerSimpleTypeSchema = consumerSchema.asSimpleTypeSchema();
SimpleTypeSchema providerSimpleTypeSchema = providerSchema.asSimpleTypeSchema();

if (!equals(consumerSimpleTypeSchema.getDefault(), providerSimpleTypeSchema.getDefault())) {
if (!isValid(consumerSimpleTypeSchema.getDefault(), providerSimpleTypeSchema.getDefault())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"default",
consumerSimpleTypeSchema.getDefault(),
providerSimpleTypeSchema.getDefault()));
}

if (!arraysEquals(consumerSimpleTypeSchema.getLinks(),
if (!isArrayValid(consumerSimpleTypeSchema.getLinks(),
providerSimpleTypeSchema.getLinks(),
SimpleTypeSchemaValidator::equalsLinkDescriptionObject)) {

Expand All @@ -33,15 +33,15 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
"links"));
}

if (!equals(consumerSimpleTypeSchema.getPathStart(), providerSimpleTypeSchema.getPathStart())) {
if (!isValid(consumerSimpleTypeSchema.getPathStart(), providerSimpleTypeSchema.getPathStart())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"pathStart",
consumerSimpleTypeSchema.getPathStart(),
providerSimpleTypeSchema.getPathStart()));
}

if (!equals(consumerSimpleTypeSchema.getTitle(), providerSimpleTypeSchema.getTitle())) {
if (!isValid(consumerSimpleTypeSchema.getTitle(), providerSimpleTypeSchema.getTitle())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"title",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
StringSchema consumerStringSchema = consumerSchema.asStringSchema();
StringSchema providerStringSchema = providerSchema.asStringSchema();

if (!equals(consumerStringSchema.getMinLength(), providerStringSchema.getMinLength())) {
if (!isValid(consumerStringSchema.getMinLength(), providerStringSchema.getMinLength())) {
errors.add(String.format(ERROR_FORMAT,
consumerStringSchema.getId(),
"minLength",
consumerStringSchema.getMinLength(),
providerStringSchema.getMinLength()));
}

if (!equals(consumerStringSchema.getMaxLength(), providerStringSchema.getMaxLength())) {
if (!isValid(consumerStringSchema.getMaxLength(), providerStringSchema.getMaxLength())) {
errors.add(String.format(ERROR_FORMAT,
consumerStringSchema.getId(),
"maxLength",
consumerStringSchema.getMaxLength(),
providerStringSchema.getMaxLength()));
}

if (!equals(consumerStringSchema.getPattern(), providerStringSchema.getPattern())) {
if (!isValid(consumerStringSchema.getPattern(), providerStringSchema.getPattern())) {
errors.add(String.format(ERROR_FORMAT,
consumerStringSchema.getId(),
"pattern",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public List<String> validate(JsonSchema consumerSchema, JsonSchema providerSchem
providerValueTypeSchema.getEnums()));
}

if (!equals(consumerValueTypeSchema.getFormat(), providerValueTypeSchema.getFormat())) {
if (!isValid(consumerValueTypeSchema.getFormat(), providerValueTypeSchema.getFormat())) {
errors.add(String.format(ERROR_FORMAT,
consumerSchema.getId(),
"format",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ class ArraySchemaValidatorUT extends Specification {
@Subject
def validator = new ArraySchemaValidator()

def 'Should return no errors for the same ArraySchemas'() {
given:
ArraySchema consumerSchema = getSampleSchema()
ArraySchema providerSchema = getSampleSchema()

def 'Should return no errors for matching ArraySchemas'() {
expect:
validator.validate(consumerSchema, providerSchema).size() == 0

where:
consumerSchema | providerSchema
new ArraySchema() | getSampleSchema()
getSampleSchema() | getSampleSchema()
}

@Unroll
Expand Down Expand Up @@ -60,20 +61,22 @@ class ArraySchemaValidatorUT extends Specification {
def consumerSchema = new ArraySchema()
consumerSchema.setId('a')
consumerSchema.setEnums(consumerEnums)
consumerSchema.setOneOf(consumerEnums)

def providerSchema = new ArraySchema()
providerSchema.setId('a')
providerSchema.setEnums(providerEnums)
providerSchema.setOneOf(providerEnums)

expect:
validator.validate(consumerSchema, providerSchema) == errors

where:
consumerEnums | providerEnums | errors
Sets.newHashSet('abc', 'def', 'geh') | Sets.newHashSet('abc', 'def', 'geh', 'ijk') | []
Sets.newHashSet('abc', 'def', 'geh', 'ijk') | Sets.newHashSet('abc', 'def', 'geh') | ['Schema with id a has not matching enums - consumer: ' + consumerEnums + ', provider: ' + providerEnums]
Sets.newHashSet('abc', 'def', 'geh', 'ijk') | Sets.newHashSet('abc', 'def', 'geh') | ['Schema with id a has not matching enums - consumer: ' + consumerEnums + ', provider: ' + providerEnums, 'Schema with id a has not matching oneOf - consumer: ' + consumerEnums + ', provider: ' + providerEnums]
Sets.newHashSet('abc', 'def', 'geh') | new HashSet<String>() | []
new HashSet<String>() | Sets.newHashSet('abc', 'def', 'geh') | ['Schema with id a has not matching enums - consumer: ' + consumerEnums + ', provider: ' + providerEnums]
new HashSet<String>() | Sets.newHashSet('abc', 'def', 'geh') | ['Schema with id a has not matching enums - consumer: ' + consumerEnums + ', provider: ' + providerEnums, 'Schema with id a has not matching oneOf - consumer: ' + consumerEnums + ', provider: ' + providerEnums]
}

def 'Should pass validation when provider schema is required and consumer is not'() {
Expand All @@ -95,8 +98,6 @@ class ArraySchemaValidatorUT extends Specification {
maxItems: 1,
minItems: 1,
uniqueItems: true,
enums: ['a', 'b'],
oneOf: ['a', 'b'],
defaultdefault: 'ab',
links: [new LinkDescriptionObject(href: 'abc')],
pathStart: 'ab',
Expand Down
Loading

0 comments on commit aaedfcd

Please sign in to comment.