Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/networknt/schema/IfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,18 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String

Set<ValidationMessage> errors = new LinkedHashSet<ValidationMessage>();

Set<ValidationMessage> ifErrors = ifSchema.validate(node, rootNode, at);
if (ifErrors.isEmpty() && thenSchema != null) {
boolean ifConditionPassed;
try {
ifConditionPassed = ifSchema.validate(node, rootNode, at).isEmpty();
} catch (JsonSchemaException ex) {
// When failFast is enabled, validations are thrown as exceptions.
// An exception means the condition failed
ifConditionPassed = false;
}

if (ifConditionPassed && thenSchema != null) {
errors.addAll(thenSchema.validate(node, rootNode, at));
} else if (!ifErrors.isEmpty() && elseSchema != null) {
} else if (!ifConditionPassed && elseSchema != null) {
errors.addAll(elseSchema.validate(node, rootNode, at));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class Issue366FailFast {
public class Issue366FailFastTest {

@BeforeEach
public void setup() throws IOException {
Expand All @@ -35,7 +35,7 @@ private void setupSchema() throws IOException {

URI uri = getSchema();

InputStream in = getClass().getResourceAsStream("/draft7/issue366_schema.json");
InputStream in = getClass().getResourceAsStream("/schema/issue366_schema.json");
JsonNode testCases = objectMapper.readValue(in, JsonNode.class);
this.jsonSchema = schemaFactory.getSchema(uri, testCases,schemaValidatorsConfig);
}
Expand Down Expand Up @@ -75,21 +75,21 @@ public void secondOneValid() throws Exception {
@Test
public void bothValid() throws Exception {
String dataPath = "/data/issue366.json";

assertThrows(JsonSchemaException.class, () -> {
InputStream dataInputStream = getClass().getResourceAsStream(dataPath);
JsonNode node = getJsonNodeFromStreamContent(dataInputStream);
List<JsonNode> testNodes = node.findValues("tests");
JsonNode testNode = testNodes.get(0).get(2);
JsonNode dataNode = testNode.get("data");
jsonSchema.validate(dataNode);
jsonSchema.validate(dataNode);
});
}

@Test
public void neitherValid() throws Exception {
String dataPath = "/data/issue366.json";

assertThrows(JsonSchemaException.class, () -> {
InputStream dataInputStream = getClass().getResourceAsStream(dataPath);
JsonNode node = getJsonNodeFromStreamContent(dataInputStream);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class Issue366FailSlow {
public class Issue366FailSlowTest {

@BeforeEach
public void setup() throws IOException {
Expand Down
75 changes: 75 additions & 0 deletions src/test/java/com/networknt/schema/Issue386Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.networknt.schema;

import java.io.InputStream;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Issue386Test {
protected JsonSchema getJsonSchemaFromPathV7(String schemaPath, boolean failFast) {
InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath);
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setFailFast(failFast);
return factory.getSchema(schemaInputStream, config);
}

protected JsonNode getJsonNodeFromPath(String dataPath) throws Exception {
InputStream dataInputStream = getClass().getResourceAsStream(dataPath);
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(dataInputStream);
return node;
}

@ParameterizedTest
@ValueSource(booleans = { true, false } )
public void dataIsValid(boolean failFast) throws Exception {
String schemaPath = "/schema/issue386-v7.json";
String dataPath = "/data/issue386.json";
JsonSchema schema = getJsonSchemaFromPathV7(schemaPath, failFast);
JsonNode node = getJsonNodeFromPath(dataPath).get("valid");
node.forEach(testNode -> {
Set<ValidationMessage> errors = schema.validate(testNode.get("data"));
Assertions.assertEquals(0, errors.size(), "Expected no errors for " + testNode.get("data"));
});
}

@Test
public void dataIsInvalidFailFast() throws Exception {
String schemaPath = "/schema/issue386-v7.json";
String dataPath = "/data/issue386.json";
JsonSchema schema = getJsonSchemaFromPathV7(schemaPath, true);
JsonNode node = getJsonNodeFromPath(dataPath).get("invalid");
node.forEach(testNode -> {
try {
schema.validate(testNode.get("data"));
Assertions.fail();
} catch (JsonSchemaException e) {
Assertions.assertEquals(testNode.get("expectedErrors").get(0).asText(), e.getMessage());
}
});
}

@Test
public void dataIsInvalidFailSlow() throws Exception {
String schemaPath = "/schema/issue386-v7.json";
String dataPath = "/data/issue386.json";
JsonSchema schema = getJsonSchemaFromPathV7(schemaPath, false);
JsonNode node = getJsonNodeFromPath(dataPath).get("invalid");
node.forEach(testNode -> {
Set<ValidationMessage> errors = schema.validate(testNode.get("data"));
List<String> errorMessages = errors.stream().map(x -> x.getMessage()).collect(Collectors.toList());
testNode.get("expectedErrors").forEach(expectedError -> {
Assertions.assertTrue(errorMessages.contains(expectedError.asText()));
});
});
}
}
49 changes: 49 additions & 0 deletions src/test/resources/data/issue386.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have all of the test cases in https://json-schema.org/understanding-json-schema/reference/conditionals.html#if-then-else

You could maybe make two arrays like so

{
  "passing": [
      { your example above },
      { other passing example from the link },
      ...
    ],
   "failing": [
       { "data": { a failing example from the link }, "expectedErrors":["error1", "error2"] },
       ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed this to have all the tests above in this 'fail fast' test.
I've also updated the draft2019-09/if-then-else.json and draft7/if-then-else.json to have the full set of tests from that link too.

"valid": [
{
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"country": "United States of America",
"postal_code": "20500"
}
},
{
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "20500"
}
},
{
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "K1M 1M4"
}
},
{
"data": {
"street_address": "Adriaan Goekooplaan",
"country": "Netherlands",
"postal_code": "2517 JX"
}
}
],
"invalid": [
{
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "10000"
},
"expectedErrors": ["$.postal_code: does not match the regex pattern [A-Z][0-9][A-Z] [0-9][A-Z][0-9]"]
},
{
"description": "invalid through first then",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "K1M 1M4"
},
"expectedErrors": ["$.postal_code: does not match the regex pattern [0-9]{5}(-[0-9]{4})?"]
}
]
}
178 changes: 178 additions & 0 deletions src/test/resources/draft2019-09/if-then-else.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,183 @@
"valid": true
}
]
},
{
"description": "conditions by properties",
"schema": {
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada"]
}
},
"if": {
"properties": {
"country": {
"const": "United States of America"
}
}
},
"then": {
"properties": {
"postal_code": {
"pattern": "[0-9]{5}(-[0-9]{4})?"
}
}
},
"else": {
"properties": {
"postal_code": {
"pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]"
}
}
}
},
"tests": [
{
"description": "valid through then",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"country": "United States of America",
"postal_code": "20500"
},
"valid": true
},
{
"description": "valid through then, alternative match",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "20500"
},
"valid": true
},
{
"description": "valid through else",
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "K1M 1M4"
},
"valid": true
},
{
"description": "invalid through else",
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "10000"
},
"valid": false
}
,
{
"description": "invalid through then",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "K1M 1M4"
},
"valid": false
}
]
},
{
"description": "conditions by allOf properties",
"schema": {
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"default": "United States of America",
"enum": ["United States of America", "Canada", "Netherlands"]
}
},
"allOf": [
{
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
}
},
{
"if": {
"properties": { "country": { "const": "Canada" } },
"required": ["country"]
},
"then": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
},
{
"if": {
"properties": { "country": { "const": "Netherlands" } },
"required": ["country"]
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } }
}
}
]
},
"tests": [
{
"description": "valid first if",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"country": "United States of America",
"postal_code": "20500"
},
"valid": true
},
{
"description": "valid first if, alternative match",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "20500"
},
"valid": true
},
{
"description": "valid second if",
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "K1M 1M4"
},
"valid": true
},
{
"description": "valid third if",
"data": {
"street_address": "Adriaan Goekooplaan",
"country": "Netherlands",
"postal_code": "2517 JX"
},
"valid": true
},
{
"description": "invalid through second then",
"data": {
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "10000"
},
"valid": false
},
{
"description": "invalid through first then",
"data": {
"street_address": "1600 Pennsylvania Avenue NW",
"postal_code": "K1M 1M4"
},
"valid": false
}
]
}
]
Loading