diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java index 19d6fa5..0cd395f 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java @@ -201,7 +201,7 @@ public class Assertion extends Credential { new Validation.Builder().name("image").type(ValueType.IMAGE).build(), new Validation.Builder().name("@language").type(ValueType.LANGUAGE).build(), new Validation.Builder().name("version").type(ValueType.TEXT_OR_NUMBER).build(), - new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Assertion).many(true).build(), + new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Assertion).many(true).fullValidate(false).build(), new Validation.Builder().name("endorsement").type(ValueType.ID).allowRemoteUrl(true).fetch(true).expectedType(Type.Endorsement).many(true).build() )) .put(Type.BadgeClass, List.of( @@ -216,7 +216,7 @@ public class Assertion extends Credential { new Validation.Builder().name("tags").type(ValueType.TEXT).many(true).build(), new Validation.Builder().name("@language").type(ValueType.LANGUAGE).build(), new Validation.Builder().name("version").type(ValueType.TEXT_OR_NUMBER).build(), - new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.BadgeClass).many(true).build(), + new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.BadgeClass).many(true).fullValidate(false).build(), new Validation.Builder().name("endorsement").type(ValueType.ID).allowRemoteUrl(true).fetch(true).expectedType(Type.Endorsement).many(true).build() )) .put(Type.AlignmentObject, List.of( @@ -241,13 +241,13 @@ public class Assertion extends Credential { .put(Type.Endorsement, List.of( new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(), new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.Endorsement)).build(), - new Validation.Builder().name("claim").type(ValueType.ID).required(true).expectedTypes(List.of(Type.EndorsementClaim, Type.Endorsement)).build(), + new Validation.Builder().name("claim").type(ValueType.ID).required(true).expectedTypes(List.of(Type.EndorsementClaim, Type.Endorsement)).fullValidate(false).build(), new Validation.Builder().name("issuedOn").type(ValueType.DATETIME).required(true).build(), new Validation.Builder().name("issuer").type(ValueType.ID).expectedType(Type.Profile).fetch(true).required(true).build(), new Validation.Builder().name("verification").build(), new Validation.Builder().name("@language").type(ValueType.LANGUAGE).build(), new Validation.Builder().name("version").type(ValueType.TEXT_OR_NUMBER).build(), - new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Endorsement).many(true).build(), + new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Endorsement).many(true).fullValidate(false).build(), new Validation.Builder().name("endorsement").type(ValueType.ID).allowRemoteUrl(true).fetch(true).expectedType(Type.Endorsement).many(true).build() )) .put(Type.EndorsementClaim, List.of( @@ -303,7 +303,7 @@ public class Assertion extends Credential { new Validation.Builder().name("id").type(ValueType.ISSUER).messageLevel(MessageLevel.Warning).build(), new Validation.Builder().name("@language").type(ValueType.LANGUAGE).build(), new Validation.Builder().name("version").type(ValueType.TEXT_OR_NUMBER).build(), - new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Issuer).many(true).build(), + new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Issuer).many(true).fullValidate(false).build(), new Validation.Builder().name("endorsement").type(ValueType.ID).allowRemoteUrl(true).fetch(true).expectedType(Type.Endorsement).many(true).build() )) .put(Type.Profile, List.of( @@ -320,7 +320,7 @@ public class Assertion extends Credential { new Validation.Builder().name("id").type(ValueType.ISSUER).messageLevel(MessageLevel.Warning).build(), new Validation.Builder().name("@language").type(ValueType.LANGUAGE).build(), new Validation.Builder().name("version").type(ValueType.TEXT_OR_NUMBER).build(), - new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Profile).many(true).build(), + new Validation.Builder().name("related").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Profile).many(true).fullValidate(false).build(), new Validation.Builder().name("endorsement").type(ValueType.ID).allowRemoteUrl(true).fetch(true).expectedType(Type.Endorsement).many(true).build() )) .put(Type.RevocationList, List.of( diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Validation.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Validation.java index 4e2fb2e..7815376 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Validation.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Validation.java @@ -122,6 +122,7 @@ public class Validation { this.prerequisites = new ArrayList<>(); this.expectedTypes = new ArrayList<>(); this.messageLevel = MessageLevel.Error; + this.fullValidate = true; // by default, full validation } public Builder name(String name) { diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbe.java index 53e0055..c371d90 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbe.java @@ -40,11 +40,11 @@ public class ValidationPropertyProbe extends PropertyProbe { protected final boolean fullValidate; // TODO: fullValidate public ValidationPropertyProbe(Validation validation) { - this(ID, validation, false); + this(ID, validation, true); } public ValidationPropertyProbe(String id, Validation validation) { - this(ID, validation, false); + this(ID, validation, true); } public ValidationPropertyProbe(Validation validation, boolean fullValidate) { @@ -60,10 +60,10 @@ public class ValidationPropertyProbe extends PropertyProbe { @Override protected ReportItems reportForNonExistentProperty(JsonNode node, RunContext ctx) { - if (validation.isRequired()) { + if (fullValidate && validation.isRequired()) { return error("Required property " + validation.getName() + " not present in " + node.toPrettyString(), ctx); } else { - // optional property + // optional property or not doing full validation return success(ctx); } } diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbeFactory.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbeFactory.java index 243aa37..816b6bd 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbeFactory.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationPropertyProbeFactory.java @@ -11,7 +11,7 @@ import org.oneedtech.inspect.vc.Validation; */ public class ValidationPropertyProbeFactory { public static ValidationPropertyProbe of(Validation validation) { - return of(validation, false); + return of(validation, true); } public static ValidationPropertyProbe of(Validation validation, boolean fullValidate) { diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationRdfTypePropertyProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationRdfTypePropertyProbe.java index fc9ecf1..60bbc15 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationRdfTypePropertyProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/validation/ValidationRdfTypePropertyProbe.java @@ -39,6 +39,10 @@ public class ValidationRdfTypePropertyProbe extends ValidationPropertyProbe { } } + // if we're not doing a full validation and it's not and id field, pass + if (!fullValidate && !validation.getName().equals("id")) { + return success(ctx); + } return error("Required property " + validation.getName() + " not present in " + node.toPrettyString(), ctx); } diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB20Tests.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB20Tests.java index 2394592..6a8071b 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB20Tests.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB20Tests.java @@ -216,6 +216,15 @@ public class OB20Tests { }); } + @Test + void testAssertionWithLanguage() { + assertDoesNotThrow(()->{ + Report report = validator.run(Samples.OB20.JSON.BASIC_WITH_LANGUAGE_JSON.asFileResource()); + if(verbose) PrintHelper.print(report, true); + assertValid(report); + }); + } + @Nested static class WarningTests { @BeforeAll diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java index 5412da7..4c1d087 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java @@ -81,6 +81,8 @@ public class Samples { public final static Sample SIMPLE_EXPIRED_BEFORE_ISSUED_ASSERTION_JSON = new Sample("ob20/basic-assertion-expired-before-issued.json", true); // original: test_validation: test_assertion_not_issued_in_future public final static Sample SIMPLE_FUTURE_ASSERTION_JSON = new Sample("ob20/basic-assertion-in-future.json", true); + // original: test_validate_related: test_validate_related_language + public final static Sample BASIC_WITH_LANGUAGE_JSON = new Sample("ob20/basic-assertion-with-language.json", true); } public static final class PNG { diff --git a/inspector-vc/src/test/resources/ob20/assets/badgeclass-with-language.json b/inspector-vc/src/test/resources/ob20/assets/badgeclass-with-language.json new file mode 100644 index 0000000..0e0eee7 --- /dev/null +++ b/inspector-vc/src/test/resources/ob20/assets/badgeclass-with-language.json @@ -0,0 +1,15 @@ +{ + "@context": "https://w3id.org/openbadges/v2", + "type": "BadgeClass", + "id": "https://example.org/badgeclass-with-language.json", + "@language": "es", + "name": "Insignia fantastica", + "description": "For doing awesome things with robots that people think is pretty great.", + "image": "https://example.org/robotics-badge.png", + "criteria": "https://example.org/badgecriteria.json", + "issuer": "https://example.org/organization.json", + "related": { + "id": "https://example.org/robotics-badge.json", + "@language": "en-US" + } +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob20/basic-assertion-with-language.json b/inspector-vc/src/test/resources/ob20/basic-assertion-with-language.json new file mode 100644 index 0000000..daf3d18 --- /dev/null +++ b/inspector-vc/src/test/resources/ob20/basic-assertion-with-language.json @@ -0,0 +1,18 @@ +{ + "@context": "https://w3id.org/openbadges/v2", + "type": "Assertion", + "recipient": { + "type": "email", + "hashed": true, + "salt": "deadsea", + "identity": "sha256$ecf5409f3f4b91ab60cc5ef4c02aef7032354375e70cf4d8e43f6a1d29891942" + }, + "id": "https://example.org/beths-robotics-badge.json", + "image": "https://example.org/beths-robot-badge.png", + "evidence": "https://example.org/beths-robot-work.html", + "issuedOn": "2016-12-31T23:59:59Z", + "badge": "https://example.org/badgeclass-with-language.json", + "verification": { + "type": "hosted" + } +} \ No newline at end of file