Skip to content

Commit

Permalink
W-10984850: filter non-applicable validations when validating enum va…
Browse files Browse the repository at this point in the history
…lues in dialect definition
  • Loading branch information
nschejtman committed Apr 12, 2022
1 parent 0c3e26a commit 1c58a5f
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,35 @@ import org.yaml.model.{YNode, YScalar}
case class DialectEnumValidator() extends ShaclReportAdaptation {

def validate(dialect: Dialect): AMFValidationReport = {
val eh = new SyamlAMFErrorHandler(DefaultErrorHandler())
val candidates = LiteralCandidateCollector.collect(dialect)
val reports = candidates.map { candidate =>
val validations =
new AMFDialectValidations(dialect)(DefaultNodeMappableFinder(dialect)).propertyValidations(candidate.node)
val nodes = candidate.enums.flatMap(toNode)
parseErrors(eh, candidate, nodes)
val reports = nodes.map {
case (_, scalar) =>
val report = validate(scalar, candidate, validations)
adaptToAmfReport(dialect,
AmlProfile,
report,
scalar.annotations.location(),
LexicalInformation(scalar.annotations.lexical()))
}
val mergedReport: AMFValidationReport = mergeReports(dialect, reports)
mergedReport.copy(results = mergedReport.results ++ eh.getResults)
val eh = new SyamlAMFErrorHandler(DefaultErrorHandler()) // create error handler for each candidate to avoid duplicating errors in report
validateCandidate(dialect, eh, candidate)
}
val mergedReport = mergeReports(dialect, reports)
mergedReport
}

private def validateCandidate(dialect: Dialect, eh: SyamlAMFErrorHandler, candidate: AmlValidationCandidate) = {
val validations =
new AMFDialectValidations(dialect)(DefaultNodeMappableFinder(dialect))
.propertyValidations(candidate.node)
.filter(_.propertyConstraints.exists(_.ramlPropertyId == candidate.mapping.nodePropertyMapping().value())) // should optimize this
val nodes = candidate.enums.flatMap(toNode)
parseErrors(eh, candidate, nodes)
val reports = nodes.map {
case (_, scalar) =>
val report = validate(scalar, candidate, validations)
adaptToAmfReport(dialect,
AmlProfile,
report,
scalar.annotations.location(),
LexicalInformation(scalar.annotations.lexical()))
}
val mergedReport: AMFValidationReport = mergeReports(dialect, reports)
mergedReport.copy(results = mergedReport.results ++ eh.getResults)
}

private def mergeReports(dialect: Dialect, reports: Seq[AMFValidationReport]) = {
val mergedReport = reports.foldLeft(AMFValidationReport.empty(dialect.id, AmlProfile)) { (acc, curr) =>
acc.merge(curr)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$type": "Dialect 1.0",
"nodeMappings": {
"MyNodeMapping": {
"mapping": {
"propertyA": {
"range": "integer",
"mandatory": true,
"enum": [
"some-enum-value"
]
},
"propertyB": {
"range": "boolean",
"mandatory": false,
"enum": [
60
]
},
"propertyC": {
"range": "boolean",
"mandatory": false,
"enum": [
10000
]
}
},
"additionalProperties": true
}
},
"dialect": "Test",
"version": "1.0",
"documents": {
"root": {
"encodes": "MyNodeMapping"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
{
"@type": "http://www.w3.org/ns/shacl#ValidationReport",
"http://www.w3.org/ns/shacl#conforms": false,
"http://www.w3.org/ns/shacl#result": [
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "anId"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyA"
},
"http://www.w3.org/ns/shacl#resultMessage": "Cannot find expected range for property http://a.ml/vocabularies/data#propertyA (propertyA). Found 'http://www.w3.org/2001/XMLSchema#string', expected 'http://www.w3.org/2001/XMLSchema#integer'",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "http://a.ml/vocabularies/amf/aml#inconsistent-property-range-value"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 10,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 10,
"http://a.ml/vocabularies/amf/parser#column": 29
}
}
},
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyA"
},
"http://www.w3.org/ns/shacl#resultMessage": "Property 'propertyA' value must be of type http://www.w3.org/2001/XMLSchema#integer",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json#/declarations/MyNodeMapping_propertyA_dataRange_validation"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 10,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 10,
"http://a.ml/vocabularies/amf/parser#column": 29
}
}
},
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "anId"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyB"
},
"http://www.w3.org/ns/shacl#resultMessage": "Cannot find expected range for property http://a.ml/vocabularies/data#propertyB (propertyB). Found 'http://www.w3.org/2001/XMLSchema#integer', expected 'http://www.w3.org/2001/XMLSchema#boolean'",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "http://a.ml/vocabularies/amf/aml#inconsistent-property-range-value"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 17,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 17,
"http://a.ml/vocabularies/amf/parser#column": 14
}
}
},
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyB"
},
"http://www.w3.org/ns/shacl#resultMessage": "Property 'propertyB' value must be of type http://www.w3.org/2001/XMLSchema#boolean",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json#/declarations/MyNodeMapping_propertyB_dataRange_validation"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 17,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 17,
"http://a.ml/vocabularies/amf/parser#column": 14
}
}
},
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "anId"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyC"
},
"http://www.w3.org/ns/shacl#resultMessage": "Cannot find expected range for property http://a.ml/vocabularies/data#propertyC (propertyC). Found 'http://www.w3.org/2001/XMLSchema#integer', expected 'http://www.w3.org/2001/XMLSchema#boolean'",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "http://a.ml/vocabularies/amf/aml#inconsistent-property-range-value"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 24,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 24,
"http://a.ml/vocabularies/amf/parser#column": 17
}
}
},
{
"@type": "http://www.w3.org/ns/shacl#ValidationResult",
"http://www.w3.org/ns/shacl#resultSeverity": {
"@id": "http://www.w3.org/ns/shacl#Violation"
},
"http://www.w3.org/ns/shacl#focusNode": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json"
},
"http://www.w3.org/ns/shacl#resultPath": {
"@id": "http://a.ml/vocabularies/data#propertyC"
},
"http://www.w3.org/ns/shacl#resultMessage": "Property 'propertyC' value must be of type http://www.w3.org/2001/XMLSchema#boolean",
"http://www.w3.org/ns/shacl#sourceShape": {
"@id": "file://amf-aml/shared/src/test/resources/vocabularies2/instances/invalids/dialect-enum-multiple-validations/invalid.json#/declarations/MyNodeMapping_propertyC_dataRange_validation"
},
"http://a.ml/vocabularies/amf/parser#lexicalPosition": {
"@type": "http://a.ml/vocabularies/amf/parser#Position",
"http://a.ml/vocabularies/amf/parser#start": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 24,
"http://a.ml/vocabularies/amf/parser#column": 12
},
"http://a.ml/vocabularies/amf/parser#end": {
"@type": "http://a.ml/vocabularies/amf/parser#Location",
"http://a.ml/vocabularies/amf/parser#line": 24,
"http://a.ml/vocabularies/amf/parser#column": 17
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$type": "Dialect 1.0",
"nodeMappings": {
"MyNodeMapping": {
"mapping": {
"propertyA": {
"range": "string",
"mandatory": true,
"enum": [
"some-enum-value"
]
},
"propertyB": {
"range": "integer",
"mandatory": false,
"enum": [
60
]
},
"propertyC": {
"range": "integer",
"mandatory": false,
"enum": [
10000
]
}
},
"additionalProperties": true
}
},
"dialect": "Test",
"version": "1.0",
"documents": {
"root": {
"encodes": "MyNodeMapping"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$type": "Dialect 1.0",
"nodeMappings": {
"MyNodeMapping": {
"mapping": {
"propertyA": {
"range": "integer",
"mandatory": true,
"enum": [
"some-enum-value"
]
}
},
"additionalProperties": true
}
},
"dialect": "Test",
"version": "1.0",
"documents": {
"root": {
"encodes": "MyNodeMapping"
}
}
}
Loading

0 comments on commit 1c58a5f

Please sign in to comment.