Added tests for validations

This commit is contained in:
Xavi Aracil 2022-12-12 11:10:48 +01:00
parent 6eb8b66560
commit de610f7f3e
2 changed files with 213 additions and 12 deletions

View File

@ -6,13 +6,19 @@ import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.util.IllformedLocaleException; import java.util.IllformedLocaleException;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern;
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator; import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
import org.oneedtech.inspect.util.json.ObjectMapperCache;
import org.oneedtech.inspect.util.json.ObjectMapperCache.Config;
import com.apicatalog.jsonld.JsonLd; import com.apicatalog.jsonld.JsonLd;
import com.apicatalog.jsonld.JsonLdError; import com.apicatalog.jsonld.JsonLdError;
@ -20,11 +26,9 @@ import com.apicatalog.jsonld.document.JsonDocument;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
/** /**
* Validator for ValueType. Translated into java from PrimitiveValueValidator in validation.py * Validator for ValueType. Translated into java from PrimitiveValueValidator in validation.py
*/ */
@ -39,13 +43,30 @@ public class PrimitiveValueValidator {
return true; return true;
} }
ObjectMapper mapper = ObjectMapperCache.get(Config.DEFAULT); // TODO: get from RunContext
try {
JsonNode node = mapper.readTree(Resources.getResource("contexts/ob-v2p0.json"));
ObjectReader readerForUpdating = mapper.readerForUpdating(node);
JsonNode merged = readerForUpdating.readValue("{\"" + value.asText() + "\" : \"TEST\"}");
JsonDocument jsonDocument = JsonDocument.of(new StringReader(merged.toString()));
JsonNode expanded = mapper.readTree(JsonLd.expand(jsonDocument).get().toString());
if (expanded.isArray() && ((ArrayNode) expanded).size() > 0) {
return true;
}
} catch (NullPointerException | IOException | JsonLdError e) {
return false;
}
return false; return false;
} }
public static boolean validateDataUri(JsonNode value) { public static boolean validateDataUri(JsonNode value) {
try { try {
URI uri = new URI(value.asText()); URI uri = new URI(value.asText());
return "data".equalsIgnoreCase(uri.getScheme()); return "data".equalsIgnoreCase(uri.getScheme()) && uri.getSchemeSpecificPart().contains(",");
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
return false; return false;
@ -55,14 +76,29 @@ public class PrimitiveValueValidator {
return validateUrl(value) || validateDataUri(value); return validateUrl(value) || validateDataUri(value);
} }
private static DateTimeFormatter ISO_OFFSET_TIME_JOINED = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.parseLenient()
.appendOffset("+Hmmss", "Z")
.parseStrict()
.toFormatter();
public static boolean validateDatetime(JsonNode value) { public static boolean validateDatetime(JsonNode value) {
boolean valid = List.of(ISO_OFFSET_TIME_JOINED,
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
DateTimeFormatter.ISO_INSTANT)
.stream().anyMatch(formatter -> {
try { try {
DateTimeFormatter.ISO_INSTANT.parse(value.asText()); formatter.parse(value.asText());
return true; return true;
} catch (DateTimeParseException | NullPointerException ignored) { } catch (DateTimeParseException | NullPointerException ignored) {
}
return false; return false;
} }
});
return valid;
}
public static boolean validateEmail(JsonNode value) { public static boolean validateEmail(JsonNode value) {
return value.asText().matches("(^[^@\\s]+@[^@\\s]+$)"); return value.asText().matches("(^[^@\\s]+@[^@\\s]+$)");
@ -88,7 +124,10 @@ public class PrimitiveValueValidator {
* @return * @return
*/ */
public static boolean validateIri(JsonNode value) { public static boolean validateIri(JsonNode value) {
return validateUrl(value) || value.asText().matches("^_:") || value.asText().matches("^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"); return
Pattern.compile("^_:.+", Pattern.CASE_INSENSITIVE).matcher(value.asText()).matches()
|| Pattern.compile("^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", Pattern.CASE_INSENSITIVE).matcher(value.asText()).matches()
|| validateUrl(value);
} }
public static boolean validateLanguage(JsonNode value) { public static boolean validateLanguage(JsonNode value) {
@ -109,7 +148,7 @@ public class PrimitiveValueValidator {
return false; return false;
} }
ObjectMapper mapper = new ObjectMapper(); // TODO: get from RunContext ObjectMapper mapper = ObjectMapperCache.get(Config.DEFAULT); // TODO: get from RunContext
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper); // TODO: get from RunContext JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper); // TODO: get from RunContext
try { try {

View File

@ -0,0 +1,162 @@
package org.oneedtech.inspect.vc.util;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
import java.util.List;
import java.util.function.Function;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.oneedtech.inspect.util.json.ObjectMapperCache;
import org.oneedtech.inspect.vc.Assertion.ValueType;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test case for PrimitiveValueValidator.
* Maps to "PropertyValidationTests" in python implementation
*/
public class PrimitiveValueValidatorTests {
private static ObjectMapper mapper;
@BeforeAll
static void setup() {
mapper = ObjectMapperCache.get(DEFAULT);
}
@Test
void testDataUri() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("data:image/gif;base64,R0lGODlhyAAiALM...DfD0QAADs=",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
"data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678",
"data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh",
"data:,actually%20a%20valid%20data%20URI",
"data:,");
List<String> badValues = List.of("data:image/gif",
"http://someexample.org",
"data:bad:path");
assertFunction(ValueType.DATA_URI, goodValues, badValues);
}
@Test
void testDataUriOrUrl() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("data:image/gif;base64,R0lGODlhyAAiALM...DfD0QAADs=",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
"data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678",
"data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh",
"http://www.example.com:8080/", "http://www.example.com:8080/foo/bar",
"http://www.example.com/foo%20bar", "http://www.example.com/foo/bar?a=b&c=d",
"http://www.example.com/foO/BaR", "HTTPS://www.EXAMPLE.cOm/",
"http://142.42.1.1:8080/", "http://142.42.1.1/",
"http://foo.com/blah_(wikipedia)#cite-1", "http://a.b-c.de",
"http://userid:password@example.com/", "http://-.~:%40:80%2f:password@example.com",
"http://code.google.com/events/#&product=browser");
List<String> badValues = List.of("///", "///f", "//",
"rdar://12345", "h://test", ":// should fail", "", "a",
"urn:uuid:129487129874982374", "urn:uuid:9d278beb-36cf-4bc8-888d-674ff9843d72");
assertFunction(ValueType.DATA_URI_OR_URL, goodValues, badValues);
}
@Test
void testUrl() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("http://www.example.com:8080/", "http://www.example.com:8080/foo/bar",
"http://www.example.com/foo%20bar", "http://www.example.com/foo/bar?a=b&c=d",
"http://www.example.com/foO/BaR", "HTTPS://www.EXAMPLE.cOm/",
"http://142.42.1.1:8080/", "http://142.42.1.1/", "http://localhost:3000/123",
"http://foo.com/blah_(wikipedia)#cite-1", "http://a.b-c.de",
"http://userid:password@example.com/", "http://-.~:%40:80%2f:password@example.com",
"http://code.google.com/events/#&product=browser");
List<String> badValues = List.of("data:image/gif;base64,R0lGODlhyAAiALM...DfD0QAADs=", "///", "///f", "//",
"rdar://12345", "h://test", ":// should fail", "", "a",
"urn:uuid:129487129874982374", "urn:uuid:9d278beb-36cf-4bc8-888d-674ff9843d72");
assertFunction(ValueType.URL, goodValues, badValues);
}
@Test
void testIri() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("http://www.example.com:8080/", "_:b0", "_:b12", "_:b107", "_:b100000001232",
"urn:uuid:9d278beb-36cf-4bc8-888d-674ff9843d72",
"urn:uuid:9D278beb-36cf-4bc8-888d-674ff9843d72");
List<String> badValues = List.of("data:image/gif;base64,R0lGODlhyAAiALM...DfD0QAADs=", "urn:uuid", "urn:uuid:123",
"", "urn:uuid:", "urn:uuid:zz278beb-36cf-4bc8-888d-674ff9843d72");
assertFunction(ValueType.IRI, goodValues, badValues);
}
@Test
void testUrlAuthority() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("google.com", "nerds.example.com");
List<String> badValues = List.of("666", "http://google.com/", "https://www.google.com/search?q=murder+she+wrote&oq=murder+she+wrote",
"ftp://123.123.123.123", "bears", "lots of hungry bears", "bears.com/thewoods",
"192.168.0.1", "1::6:7:8");
assertFunction(ValueType.URL_AUTHORITY, goodValues, badValues);
}
@Test
void testCompactedIRI() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("id", "email", "telephone", "url");
List<String> badValues = List.of("sloths");
assertFunction(ValueType.COMPACT_IRI, goodValues, badValues);
}
@Test
void testBasicText() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("string value");
List<Integer> badValues = List.of(3, 4);
assertFunction(ValueType.TEXT, goodValues, badValues);
}
@Test
void testTelephone() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("+64010", "+15417522845", "+18006664358", "+18006662344;ext=666");
List<String> badValues = List.of("1-800-666-DEVIL", "1 (555) 555-5555", "+99 55 22 1234", "+18006664343 x666");
assertFunction(ValueType.TELEPHONE, goodValues, badValues);
}
@Test
void testEmail() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("abc@localhost", "cool+uncool@example.org");
List<String> badValues = List.of(" spacey@gmail.com", "steveman [at] gee mail dot com");
assertFunction(ValueType.EMAIL, goodValues, badValues);
}
@Test
void testBoolean() throws JsonMappingException, JsonProcessingException {
List<Boolean> goodValues = List.of(true, false);
List<String> badValues = List.of(" spacey@gmail.com", "steveman [at] gee mail dot com");
assertFunction(ValueType.BOOLEAN, goodValues, badValues);
}
@Test
void testDateTime() throws JsonMappingException, JsonProcessingException {
List<String> goodValues = List.of("1977-06-10T12:00:00+0800",
"1977-06-10T12:00:00-0800",
"1977-06-10T12:00:00+08",
"1977-06-10T12:00:00+08:00");
List<String> badValues = List.of("notadatetime", "1977-06-10T12:00:00");
assertFunction(ValueType.DATETIME, goodValues, badValues);
}
private void assertFunction(ValueType valueType, List<? extends Object> goodValues, List<? extends Object> badValues) throws JsonMappingException, JsonProcessingException {
Function<JsonNode, Boolean> validationFunction = valueType.getValidationFunction();
for (Object goodValue : goodValues) {
assertTrue(validationFunction.apply(parseNode(goodValue)),
"`" + goodValue + "` should pass " + valueType + " validation but failed.");
}
for (Object badValue : badValues) {
assertFalse(validationFunction.apply(parseNode(badValue)),
"`" + badValue + "` should fail " + valueType + " validation but passed.");
}
}
private JsonNode parseNode(Object value) throws JsonMappingException, JsonProcessingException {
if (value instanceof String) {
return mapper.readTree("\"" + value + "\"");
}
return mapper.readTree(value.toString());
}
}