Skip to content

Commit

Permalink
Fix enum validator messages for object, array and text nodes (#1095)
Browse files Browse the repository at this point in the history
  • Loading branch information
justin-tay authored Jul 25, 2024
1 parent a9e8a49 commit b160c11
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 5 deletions.
10 changes: 9 additions & 1 deletion src/main/java/com/networknt/schema/EnumValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public class EnumValidator extends BaseJsonValidator implements JsonValidator {
private final Set<JsonNode> nodes;
private final String error;

static String asText(JsonNode node) {
if (node.isObject() || node.isArray() || node.isTextual()) {
// toString for isTextual is so that there are quotes
return node.toString();
}
return node.asText();
}

public EnumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ENUM, validationContext);
if (schemaNode != null && schemaNode.isArray()) {
Expand All @@ -58,7 +66,7 @@ public EnumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath,
}

sb.append(separator);
sb.append(n.asText());
sb.append(asText(n));
separator = ", ";
}

Expand Down
115 changes: 115 additions & 0 deletions src/test/java/com/networknt/schema/EnumValidatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.networknt.schema;

import static org.junit.jupiter.api.Assertions.*;

import java.util.List;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Test;

import com.networknt.schema.SpecVersion.VersionFlag;

/**
* EnumValidator test.
*/
class EnumValidatorTest {

@Test
void enumWithObjectNodes() {
String schemaData = "{\r\n"
+ " \"title\": \"Severity\",\r\n"
+ " \"type\": \"object\",\r\n"
+ " \"properties\": {\r\n"
+ " \"name\": {\r\n"
+ " \"title\": \"Name\",\r\n"
+ " \"description\": \"The human readable name of the severity\",\r\n"
+ " \"type\": \"string\"\r\n"
+ " },\r\n"
+ " \"cardinality\": {\r\n"
+ " \"title\": \"Cardinality\",\r\n"
+ " \"description\": \"The severities cardinality, the higher the worse it gets\",\r\n"
+ " \"type\": \"integer\",\r\n"
+ " \"minimum\": 0,\r\n"
+ " \"maximum\": 50,\r\n"
+ " \"multipleOf\": 10\r\n"
+ " }\r\n"
+ " },\r\n"
+ " \"additionalProperties\": false,\r\n"
+ " \"required\": [\r\n"
+ " \"name\",\r\n"
+ " \"cardinality\"\r\n"
+ " ],\r\n"
+ " \"enum\": [\r\n"
+ " {\r\n"
+ " \"name\": \"EMPTY\",\r\n"
+ " \"cardinality\": 0\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"name\": \"OK\",\r\n"
+ " \"cardinality\": 20\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"name\": \"UNKNOWN\",\r\n"
+ " \"cardinality\": 30\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"name\": \"WARNING\",\r\n"
+ " \"cardinality\": 40\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"name\": \"CRITICAL\",\r\n"
+ " \"cardinality\": 50\r\n"
+ " }\r\n"
+ " ],\r\n"
+ " \"default\": {\r\n"
+ " \"name\": \"UNKNOWN\",\r\n"
+ " \"cardinality\": 30\r\n"
+ " }\r\n"
+ "}";
String inputData = "{\r\n"
+ " \"name\": \"FOO\",\r\n"
+ " \"cardinality\": 50\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData,
SchemaValidatorsConfig.builder().build());
List<ValidationMessage> messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList());
assertEquals(1, messages.size());
ValidationMessage message = messages.get(0);
assertEquals(
": does not have a value in the enumeration [{\"name\":\"EMPTY\",\"cardinality\":0}, {\"name\":\"OK\",\"cardinality\":20}, {\"name\":\"UNKNOWN\",\"cardinality\":30}, {\"name\":\"WARNING\",\"cardinality\":40}, {\"name\":\"CRITICAL\",\"cardinality\":50}]",
message.toString());
}

@Test
void enumWithHeterogenousNodes() {
String schemaData = "{\r\n"
+ " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n"
+ " \"enum\": [6, \"foo\", [], true, {\"foo\": 12}]\r\n"
+ " }";
String inputData = "{\r\n"
+ " \"name\": \"FOO\",\r\n"
+ " \"cardinality\": 50\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData,
SchemaValidatorsConfig.builder().build());
List<ValidationMessage> messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList());
assertEquals(1, messages.size());
ValidationMessage message = messages.get(0);
assertEquals(": does not have a value in the enumeration [6, \"foo\", [], true, {\"foo\":12}]", message.toString());
}
}
2 changes: 1 addition & 1 deletion src/test/java/com/networknt/schema/Issue342Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ public void propertyNameEnumShouldFailV7() throws Exception {
Assertions.assertEquals(1, errors.size());
final ValidationMessage error = errors.iterator().next();
Assertions.assertEquals("$", error.getInstanceLocation().toString());
Assertions.assertEquals("$: property 'z' name is not valid: does not have a value in the enumeration [a, b, c]", error.getMessage());
Assertions.assertEquals("$: property 'z' name is not valid: does not have a value in the enumeration [\"a\", \"b\", \"c\"]", error.getMessage());
}
}
2 changes: 1 addition & 1 deletion src/test/java/com/networknt/schema/Issue662Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void testCorrectErrorForInvalidValue() throws IOException {
assertTrue(errorMessages
.contains("$.properties.optionalObject.anyOf[0].type = $.optionalObject: object found, null expected"));
assertTrue(errorMessages.contains(
"$.properties.optionalObject.anyOf[1].properties.value.enum = $.optionalObject.value: does not have a value in the enumeration [one, two]"));
"$.properties.optionalObject.anyOf[1].properties.value.enum = $.optionalObject.value: does not have a value in the enumeration [\"one\", \"two\"]"));
}

private static String resource(String name) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/networknt/schema/Issue898Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void testMessagesWithSingleQuotes() throws Exception {
.collect(toList());

Assertions.assertEquals(2, messages.size());
Assertions.assertEquals("/foo: n'a pas de valeur dans l'énumération [foo1, foo2]", messages.get(0));
Assertions.assertEquals("/foo: n'a pas de valeur dans l'énumération [\"foo1\", \"foo2\"]", messages.get(0));
Assertions.assertEquals("/bar: ne correspond pas au modèle d'expression régulière (bar)+", messages.get(1));
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/networknt/schema/OutputFormatTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void customFormat() {
+ " \"id\": 1\n"
+ "}";
List<ValidationMessage> messages = schema.validate(inputData, InputFormat.JSON, DETAILED).stream().collect(Collectors.toList());
assertEquals("[/type] with value 'cat' does not have a value in the enumeration [book, author]", messages.get(0).getMessage());
assertEquals("[/type] with value 'cat' does not have a value in the enumeration [\"book\", \"author\"]", messages.get(0).getMessage());
assertEquals("[/id] with value '1' integer found, string expected", messages.get(1).getMessage());
}
}

0 comments on commit b160c11

Please sign in to comment.