Browse Source

Start writing validation by creating "SimpleValidationTester" to wrap up a recurring pattern of `if (!accepts(node)) throw ...`.
Add validate() to EqualsTester, FormatTester, NumberTester, and TypeTester
Add Tests for validate() to FormatTester, NumberTester, and TypeTester.

Sam Jaffe 6 years ago
parent
commit
51edbe91b5

+ 18 - 4
src/main/lombok/org/leumasjaffe/json/schema/tester/EqualsTester.java

@@ -3,8 +3,6 @@ package org.leumasjaffe.json.schema.tester;
 import java.util.Arrays;
 import java.util.List;
 
-import org.leumasjaffe.json.schema.Tester;
-
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.JsonNodeType;
 
@@ -14,11 +12,27 @@ import lombok.experimental.FieldDefaults;
 
 @RequiredArgsConstructor
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
-public class EqualsTester implements Tester {
+public class EqualsTester extends SimpleValidationTester {
+	private static final String ERROR_ENUM = " is not defined in enum";
+	private static final String ERROR_CONST = " does not match const";
+	boolean isExplicitlySingleValue;
 	List<JsonNode> values;
 	
+	public EqualsTester(JsonNode value) {
+		this(true, Arrays.asList(value));
+	}
+	
 	public EqualsTester(JsonNode...values) {
-		this(Arrays.asList(values));
+		this(false, Arrays.asList(values));
+	}
+
+	public EqualsTester(List<JsonNode> values) {
+		this(false, values);
+	}
+	
+	@Override
+	public String errorMessage(final JsonNode node) {
+		return node + (isExplicitlySingleValue ? ERROR_CONST : ERROR_ENUM);
 	}
 
 	@Override

+ 6 - 1
src/main/lombok/org/leumasjaffe/json/schema/tester/FormatTester.java

@@ -20,7 +20,7 @@ import lombok.experimental.FieldDefaults;
 
 @RequiredArgsConstructor
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
-public abstract class FormatTester implements Tester {
+public abstract class FormatTester extends SimpleValidationTester {
 	// TODO Make these into subclasses instead of this
 	static Tester UUID = new FormatTester("uuid") {
 		@Override
@@ -135,6 +135,11 @@ public abstract class FormatTester implements Tester {
 	
 	String format;
 	
+	@Override
+	public String errorMessage(final JsonNode node) {
+		return node + " does not match format: '" + format + "'";
+	}
+	
 	@Override
 	public JsonNodeType[] acceptedTypes() {
 		return new JsonNodeType[] {JsonNodeType.STRING};

+ 6 - 3
src/main/lombok/org/leumasjaffe/json/schema/tester/NumberTester.java

@@ -1,7 +1,5 @@
 package org.leumasjaffe.json.schema.tester;
 
-import org.leumasjaffe.json.schema.Tester;
-
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.JsonNodeType;
 
@@ -11,7 +9,7 @@ import lombok.experimental.FieldDefaults;
 
 @RequiredArgsConstructor(access=AccessLevel.PRIVATE)
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
-public class NumberTester implements Tester {
+public class NumberTester extends SimpleValidationTester {
 	private static enum Rule {
 		MINIMUM, EXCLUSIVE_MINIMUM, MAXIMUM, EXCLUSIVE_MAXIMUM, MULTIPLE_OF;
 
@@ -50,6 +48,11 @@ public class NumberTester implements Tester {
 	Rule rule;
 	double value;
 	
+	@Override
+	public String errorMessage(final JsonNode node) {
+		return node + " is not " + rule.toString() + value;
+	}
+	
 	@Override
 	public JsonNodeType[] acceptedTypes() {
 		return new JsonNodeType[]{JsonNodeType.NUMBER};

+ 13 - 0
src/main/lombok/org/leumasjaffe/json/schema/tester/SimpleValidationTester.java

@@ -0,0 +1,13 @@
+package org.leumasjaffe.json.schema.tester;
+
+import org.leumasjaffe.json.schema.Tester;
+import org.leumasjaffe.json.schema.ValidationException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+abstract class SimpleValidationTester implements Tester {
+	abstract String errorMessage(final JsonNode node);
+	public final void validate(final JsonNode node) throws ValidationException {
+		if (!accepts(node)) throw new ValidationException(errorMessage(node));
+	}
+}

+ 14 - 10
src/main/lombok/org/leumasjaffe/json/schema/tester/TypeTester.java

@@ -2,8 +2,6 @@ package org.leumasjaffe.json.schema.tester;
 
 import java.util.function.Predicate;
 
-import org.leumasjaffe.json.schema.Tester;
-
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.JsonNodeType;
 
@@ -13,23 +11,29 @@ import lombok.experimental.FieldDefaults;
 
 @RequiredArgsConstructor(access=AccessLevel.PRIVATE)
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
-public class TypeTester implements Tester {
+public class TypeTester extends SimpleValidationTester {
 
 	public static TypeTester fromType(final String type) {
 		switch (type) {
-		case "array": return new TypeTester(JsonNode::isArray);
-		case "boolean": return new TypeTester(JsonNode::isBoolean);
-		case "integer": return new TypeTester(JsonNode::isInt);
-		case "null": return new TypeTester(JsonNode::isNull);
-		case "number": return new TypeTester(JsonNode::isNumber);
-		case "object": return new TypeTester(JsonNode::isObject);
-		case "string": return new TypeTester(JsonNode::isTextual);
+		case "array": return new TypeTester("array", JsonNode::isArray);
+		case "boolean": return new TypeTester("boolean", JsonNode::isBoolean);
+		case "integer": return new TypeTester("integer", JsonNode::isInt);
+		case "null": return new TypeTester("null", JsonNode::isNull);
+		case "number": return new TypeTester("number", JsonNode::isNumber);
+		case "object": return new TypeTester("object", JsonNode::isObject);
+		case "string": return new TypeTester("string", JsonNode::isTextual);
 		default: throw new IllegalArgumentException("Invalid type: " + type);
 		}
 	}
 	
+	String name;
 	Predicate<JsonNode> test;
 	
+	@Override
+	public String errorMessage(final JsonNode node) {
+		return "type mismatch. expected: " + name + " got: " + node.getNodeType();
+	}
+	
 	@Override
 	public JsonNodeType[] acceptedTypes() {
 		return ANY;

+ 16 - 0
src/test/java/org/leumasjaffe/json/schema/tester/FormatTesterTest.java

@@ -1,12 +1,14 @@
 package org.leumasjaffe.json.schema.tester;
 
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 import static org.leumasjaffe.json.schema.matcher.Accepts.accepts;
 import static org.leumasjaffe.json.schema.matcher.AcceptedTypes.acceptsTypes;
 import static org.leumasjaffe.json.schema.matcher.Not.not;
 
 import org.junit.Test;
 import org.leumasjaffe.json.schema.Tester;
+import org.leumasjaffe.json.schema.ValidationException;
 
 import com.fasterxml.jackson.databind.node.JsonNodeType;
 import com.fasterxml.jackson.databind.node.NullNode;
@@ -140,4 +142,18 @@ public class FormatTesterTest {
 		assertThat(test, not(accepts(new TextNode("Text with(|out parenthesis"))));
 	}
 	
+	@Test
+	public void testValidateDoesNothingOnSuccess() {
+		try {
+			FormatTester.forCode("ipv6").validate(new TextNode("::1"));
+		} catch (ValidationException ve) {
+			fail("An exception occured: " + ve.getMessage());
+		}
+	}
+	
+	@Test(expected=ValidationException.class)
+	public void testThrowsOnValidationFailure() {
+		FormatTester.forCode("ipv4").validate(new TextNode("::1"));
+	}
+	
 }

+ 16 - 0
src/test/java/org/leumasjaffe/json/schema/tester/NumberTesterTest.java

@@ -1,6 +1,7 @@
 package org.leumasjaffe.json.schema.tester;
 
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 import static org.leumasjaffe.json.schema.matcher.AcceptedTypes.acceptsTypes;
 import static org.leumasjaffe.json.schema.matcher.Accepts.accepts;
 import static org.leumasjaffe.json.schema.matcher.Not.not;
@@ -8,6 +9,7 @@ import static org.leumasjaffe.json.schema.matcher.Not.not;
 import java.util.function.DoublePredicate;
 
 import org.junit.Test;
+import org.leumasjaffe.json.schema.ValidationException;
 
 import com.fasterxml.jackson.databind.node.DoubleNode;
 import com.fasterxml.jackson.databind.node.JsonNodeType;
@@ -79,4 +81,18 @@ public class NumberTesterTest {
 		assertThat(test, accepts(new DoubleNode(1.0)));
 	}
 	
+	@Test
+	public void testValidateDoesNothingOnSuccess() {
+		try {
+			NumberTester.multipleOf(1.0).validate(new DoubleNode(2.0));
+		} catch (ValidationException ve) {
+			fail("An exception occured: " + ve.getMessage());
+		}
+	}
+	
+	@Test(expected=ValidationException.class)
+	public void testThrowsOnValidationFailure() {
+		NumberTester.multipleOf(1.0).validate(new DoubleNode(0.5));
+	}
+	
 }

+ 16 - 0
src/test/java/org/leumasjaffe/json/schema/tester/TypeTesterTest.java

@@ -1,12 +1,14 @@
 package org.leumasjaffe.json.schema.tester;
 
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 import static org.leumasjaffe.json.schema.matcher.Accepts.accepts;
 import static org.leumasjaffe.json.schema.matcher.AcceptedTypes.acceptsTypes;
 import static org.leumasjaffe.json.schema.matcher.Not.not;
 
 import org.junit.Test;
 import org.leumasjaffe.json.schema.Tester;
+import org.leumasjaffe.json.schema.ValidationException;
 import org.leumasjaffe.json.schema.tester.TypeTester;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -123,4 +125,18 @@ public class TypeTesterTest {
 		assertThat(t, not(accepts(array)));
 		assertThat(t, accepts(object));
 	}
+	
+	@Test
+	public void testValidateDoesNothingOnSuccess() {
+		try {
+			TypeTester.fromType("number").validate(new DoubleNode(2.0));
+		} catch (ValidationException ve) {
+			fail("An exception occured: " + ve.getMessage());
+		}
+	}
+	
+	@Test(expected=ValidationException.class)
+	public void testThrowsOnValidationFailure() {
+		TypeTester.fromType("object").validate(new DoubleNode(0.5));
+	}
 }