Bläddra i källkod

Merge branch 'extract'

Sam Jaffe 6 år sedan
förälder
incheckning
971e6313ee

+ 8 - 19
src/main/lombok/org/leumasjaffe/json/JsonHelper.java

@@ -1,5 +1,6 @@
 package org.leumasjaffe.json;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -15,7 +16,6 @@ import com.fasterxml.jackson.databind.JsonNode;
 import lombok.experimental.UtilityClass;
 
 @UtilityClass
-
 public class JsonHelper {
 	public List<JsonNode> toArray(final JsonNode array) {
 		return StreamSupport.stream(array.spliterator(), false).collect(Collectors.toList());
@@ -25,33 +25,22 @@ public class JsonHelper {
 		return StreamSupport.stream(array.spliterator(), false).map(transform).collect(Collectors.toList());
 	}
 	
-	public Set<String> fieldNames(final JsonNode object) {
-		Set<String> rval = new HashSet<>();
-		object.fieldNames().forEachRemaining(rval::add);
-		return rval;
-	}
-	
 	public <T> Set<T> fieldNames(final JsonNode object, Function<String, T> transform) {
 		Set<T> rval = new HashSet<>();
 		object.fieldNames().forEachRemaining(s -> rval.add(transform.apply(s)));
 		return rval;
 	}
-	
-	public Map<String, JsonNode> fields(final JsonNode object) {
-		Map<String, JsonNode> rval = new HashMap<>();
-		object.fields().forEachRemaining(pair -> rval.put(pair.getKey(), pair.getValue()));
-		return rval;
-	}
-	
-	public <T> Map<String, T> fields(final JsonNode object, Function<JsonNode, T> transform) {
+
+	public <T> Map<String, T> fields(final JsonNode object, BiFunction<String, JsonNode, T> transform) {
 		Map<String, T> rval = new HashMap<>();
-		object.fields().forEachRemaining(pair -> rval.put(pair.getKey(), transform.apply(pair.getValue())));
+		object.fields().forEachRemaining(pair -> rval.put(pair.getKey(),
+				transform.apply(pair.getKey(), pair.getValue())));
 		return rval;
 	}
 	
-	public <T> Map<String, T> fields(final JsonNode object, BiFunction<String, JsonNode, T> transform) {
-		Map<String, T> rval = new HashMap<>();
-		object.fields().forEachRemaining(pair -> rval.put(pair.getKey(),
+	public <T> List<T> values(final JsonNode object, BiFunction<String, JsonNode, T> transform) {
+		List<T> rval = new ArrayList<>();
+		object.fields().forEachRemaining(pair -> rval.add(
 				transform.apply(pair.getKey(), pair.getValue())));
 		return rval;
 	}

+ 17 - 36
src/main/lombok/org/leumasjaffe/json/schema/factory/SchemaV6Factory.java

@@ -1,15 +1,15 @@
 package org.leumasjaffe.json.schema.factory;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
+import java.util.function.Predicate;
 
 import org.leumasjaffe.json.JsonHelper;
 import org.leumasjaffe.json.schema.Tester;
+import org.leumasjaffe.json.schema.tester.AllItemsTester;
 import org.leumasjaffe.json.schema.tester.AllOfTester;
 import org.leumasjaffe.json.schema.tester.AnyOfTester;
 import org.leumasjaffe.json.schema.tester.ContainsTester;
 import org.leumasjaffe.json.schema.tester.FormatTester;
+import org.leumasjaffe.json.schema.tester.ItemsTester;
 import org.leumasjaffe.json.schema.tester.NotTester;
 import org.leumasjaffe.json.schema.tester.NumberTester;
 import org.leumasjaffe.json.schema.tester.OneOfTester;
@@ -46,23 +46,8 @@ class SchemaV6Factory extends SchemaFactory {
 		case "maxLength": return new SizeTester(JsonNodeType.STRING, i -> i < value.asInt());
 		case "minLength": return new SizeTester(JsonNodeType.STRING, i -> i >= value.asInt(0));
 		case "pattern": return j -> j.isTextual() && j.asText().matches(value.asText());
-		case "additionalItems": return j -> JsonHelper.toArray(j).stream().allMatch(create(value)::accepts);
-		case "items": 
-			if (value.isArray()) {
-				return j -> {
-					List<Tester> tests = createArray(value);
-					List<JsonNode> data = JsonHelper.toArray(j);
-					for (int i = 0; i < Math.min(value.size(), data.size()); ++i) {
-						if (!tests.get(i).accepts(data.get(i))) {
-							return false;
-						}
-					}
-					return true;
-				};
-			}
-			else {
-				return j -> JsonHelper.toArray(j).stream().allMatch(create(value)::accepts);
-			}
+		case "additionalItems": return new AllItemsTester(create(value));
+		case "items": return value.isArray() ? new ItemsTester(createArray(value)) : new AllItemsTester(create(value));
 		case "maxItems": return new SizeTester(JsonNodeType.ARRAY, i -> i < value.asInt());
 		case "minItems": return new SizeTester(JsonNodeType.ARRAY, i -> i >= value.asInt(0));
 		case "uniqueItems": return value.asBoolean() ? UniqueItemTester.INSTANCE : Tester.ACCEPT;
@@ -72,22 +57,10 @@ class SchemaV6Factory extends SchemaFactory {
 		case "required": return json -> JsonHelper.toArray(value, JsonNode::asText).stream().allMatch(json::has);
 		case "additionalProperties": return j -> JsonHelper.toArray(j).stream().allMatch(create(value)::accepts);
 		// case "definitions": ; // TODO Implement definitions creation
-		case "properties": {
-			final List<PropertyTester.Pair> list = new ArrayList<>();
-			value.fields().forEachRemaining(e -> {
-				final String k = e.getKey();
-				list.add(new PropertyTester.Pair(s -> k.equals(s), create(e.getValue())));
-			});
-			return new PropertyTester(list);
-		}
-		case "patternProperties": {
-			final List<PropertyTester.Pair> list = new ArrayList<>();
-			value.fields().forEachRemaining(e -> {
-				final Pattern k = Pattern.compile(e.getKey());
-				list.add(new PropertyTester.Pair(s -> k.matcher(s).matches(), create(e.getValue())));
-			});
-			return new PropertyTester(list);
-		}
+		case "properties": return new PropertyTester(JsonHelper.values(value,
+				(k, v) -> new PropertyTester.Pair(stringEqual(k), create(v))));
+		case "patternProperties": return new PropertyTester(JsonHelper.values(value,
+				(k, v) -> new PropertyTester.Pair(stringMatches(k), create(v))));
 		// case "dependencies": ; // TODO Implement array(required) and object(schema) versions
 		case "propertyNames": return new PropertyNameTester(create(value));
 		case "const": return value::equals;
@@ -102,4 +75,12 @@ class SchemaV6Factory extends SchemaFactory {
 			throw new IllegalArgumentException("Unknown matcher: " + key);
 		}
 	}
+	
+	private static Predicate<String> stringEqual(String to) {
+		return s -> s.equals(to);
+	}
+	
+	private static Predicate<String> stringMatches(String toRegex) {
+		return s -> s.matches(toRegex);
+	}
 }

+ 31 - 0
src/main/lombok/org/leumasjaffe/json/schema/tester/AllItemsTester.java

@@ -0,0 +1,31 @@
+package org.leumasjaffe.json.schema.tester;
+
+import java.util.List;
+
+import org.leumasjaffe.json.JsonHelper;
+import org.leumasjaffe.json.schema.Tester;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.FieldDefaults;
+
+@RequiredArgsConstructor
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+public class AllItemsTester implements Tester {
+	Tester schema;
+
+	@Override
+	public boolean accepts(JsonNode node) {
+		if (!node.isArray()) return false;
+		List<JsonNode> data = JsonHelper.toArray(node);
+		for (int i = 0; i < data.size(); ++i) {
+			if (!schema.accepts(data.get(i))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+}

+ 36 - 0
src/main/lombok/org/leumasjaffe/json/schema/tester/ItemsTester.java

@@ -0,0 +1,36 @@
+package org.leumasjaffe.json.schema.tester;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.leumasjaffe.json.JsonHelper;
+import org.leumasjaffe.json.schema.Tester;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.FieldDefaults;
+
+@RequiredArgsConstructor
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+public class ItemsTester implements Tester {
+	List<Tester> schemas;
+
+	public ItemsTester(Tester...testers) {
+		this(Arrays.asList(testers));
+	}
+	
+	@Override
+	public boolean accepts(JsonNode node) {
+		if (!node.isArray()) return false;
+		List<JsonNode> data = JsonHelper.toArray(node);
+		for (int i = 0; i < Math.min(schemas.size(), data.size()); ++i) {
+			if (!schemas.get(i).accepts(data.get(i))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+}

+ 4 - 0
src/test/java/org/leumasjaffe/json/schema/JsonTesterSuite.java

@@ -2,10 +2,12 @@ package org.leumasjaffe.json.schema;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
+import org.leumasjaffe.json.schema.tester.AllItemsTesterTest;
 import org.leumasjaffe.json.schema.tester.AllOfTesterTest;
 import org.leumasjaffe.json.schema.tester.AnyOfTesterTest;
 import org.leumasjaffe.json.schema.tester.ContainsTesterTest;
 import org.leumasjaffe.json.schema.tester.FormatTesterTest;
+import org.leumasjaffe.json.schema.tester.ItemsTesterTest;
 import org.leumasjaffe.json.schema.tester.NotTesterTest;
 import org.leumasjaffe.json.schema.tester.NumberTesterTest;
 import org.leumasjaffe.json.schema.tester.OneOfTesterTest;
@@ -17,10 +19,12 @@ import org.leumasjaffe.json.schema.tester.UniqueItemTesterTest;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+	AllItemsTesterTest.class,
 	AllOfTesterTest.class,
 	AnyOfTesterTest.class,
 	ContainsTesterTest.class,
 	FormatTesterTest.class,
+	ItemsTesterTest.class,
 	NotTesterTest.class,
 	NumberTesterTest.class,
 	OneOfTesterTest.class,

+ 49 - 0
src/test/java/org/leumasjaffe/json/schema/tester/AllItemsTesterTest.java

@@ -0,0 +1,49 @@
+package org.leumasjaffe.json.schema.tester;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.leumasjaffe.json.schema.Tester;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.NullNode;
+
+public class AllItemsTesterTest {
+
+	@Test
+	public void testRejectsNonArray() {
+		assertFalse(new AllItemsTester(Tester.ACCEPT).accepts(NullNode.getInstance()));
+	}
+
+	@Test
+	public void testAcceptsEmptyArray() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		assertTrue(new AllItemsTester(Tester.ACCEPT).accepts(node));
+	}
+	
+	@Test
+	public void testRejectsIfAllFail() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(false);
+		node.add(true);
+		assertFalse(new AllItemsTester(Tester.REJECT).accepts(node));
+	}
+	
+	@Test
+	public void testRejectsIfAnyPass() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(false);
+		node.add(true);
+		assertFalse(new AllItemsTester(JsonNode::asBoolean).accepts(node));
+	}
+	
+	@Test
+	public void testAcceptsIfAllPass() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(true);
+		node.add(true);
+		assertTrue(new AllItemsTester(JsonNode::asBoolean).accepts(node));
+	}
+}

+ 50 - 0
src/test/java/org/leumasjaffe/json/schema/tester/ItemsTesterTest.java

@@ -0,0 +1,50 @@
+package org.leumasjaffe.json.schema.tester;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.leumasjaffe.json.schema.Tester;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.NullNode;
+
+public class ItemsTesterTest {
+
+	@Test
+	public void testRejectsNonArray() {
+		assertFalse(new ItemsTester(Tester.ACCEPT).accepts(NullNode.getInstance()));
+	}
+
+	@Test
+	public void testAcceptsEmptyArray() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		assertTrue(new ItemsTester(Tester.ACCEPT).accepts(node));
+	}
+	
+	@Test
+	public void testRejectsIfFail() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(false);
+		node.add(true);
+		assertFalse(new ItemsTester(Tester.REJECT).accepts(node));
+	}
+	
+	@Test
+	public void testAcceptsIfNumTestersPass() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(true);
+		node.add(false);
+		assertTrue(new ItemsTester(JsonNode::asBoolean).accepts(node));
+	}
+	
+	@Test
+	public void testAcceptsIfNumElemsPass() {
+		final ArrayNode node = new ArrayNode(JsonNodeFactory.instance);
+		node.add(true);
+		node.add(false);
+		assertTrue(new ItemsTester(JsonNode::asBoolean,
+				Tester.ACCEPT, Tester.REJECT).accepts(node));
+	}
+}