Skip to content

Commit

Permalink
Merge pull request #126 from zazuko/fix125
Browse files Browse the repository at this point in the history
fix #125
  • Loading branch information
giacomociti authored Apr 11, 2024
2 parents 3bf052c + 3f77cc9 commit 3a88720
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/angry-goats-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rdf-validate-shacl": patch
---

fix #125 (phantom result details)
10 changes: 7 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class SHACLValidator {
*/
validateNode(data, focusNode, shapeNode) {
this.$data = clownface({ dataset: data, factory: this.factory })
this.nodeConformsToShape(focusNode, shapeNode)
this.nodeConformsToShape(focusNode, shapeNode, this.validationEngine)
return this.validationEngine.getReport()
}

Expand All @@ -67,16 +67,20 @@ class SHACLValidator {
}

// Exposed to be available from validation functions as `SHACL.nodeConformsToShape`
nodeConformsToShape(focusNode, shapeNode) {
nodeConformsToShape(focusNode, shapeNode, engine = this.validationEngine.clone()) {
const shape = this.shapesGraph.getShape(shapeNode)
try {
this.depth++
const foundViolations = this.validationEngine.validateNodeAgainstShape(focusNode, shape, this.$data)
const foundViolations = engine.validateNodeAgainstShape(focusNode, shape, this.$data)
return !foundViolations
} finally {
this.depth--
}
}

validateNodeAgainstShape (focusNode, shapeNode) {
return this.nodeConformsToShape(focusNode, shapeNode, this.validationEngine)
}
}

export default SHACLValidator
4 changes: 4 additions & 0 deletions src/validation-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class ValidationEngine {
this.nestedResults = {}
}

clone () {
return new ValidationEngine(this.context, { maxErrors: this.maxErrors })
}

initReport() {
const { rdf, sh } = this.context.ns

Expand Down
2 changes: 1 addition & 1 deletion src/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ function validateNodeKind(context, focusNode, valueNode, constraint) {
function validateNode(context, focusNode, valueNode, constraint) {
const { sh } = context.ns
const nodeNode = constraint.getParameterValue(sh.node)
return context.nodeConformsToShape(valueNode, nodeNode)
return context.validateNodeAgainstShape(valueNode, nodeNode)
}

function validateNot(context, focusNode, valueNode, constraint) {
Expand Down
9 changes: 9 additions & 0 deletions test/data/validation-details/node-constraint-details.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <https://example.org/> .

ex:person1 a ex:Person .
[] a ex:Person .

ex:personShape a sh:NodeShape ;
sh:targetClass ex:Person ;
sh:node [ sh:nodeKind sh:BlankNode ] .
7 changes: 7 additions & 0 deletions test/data/validation-repro/repro125-data.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@prefix ex: <https://example.org/> .

ex:person1 a ex:Person ; ex:address ex:address1 .

ex:address1 ex:city "London" .

ex:tv ex:size ex:big .
23 changes: 23 additions & 0 deletions test/data/validation-repro/repro125-shapes.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <https://example.org/> .

ex:personShape a sh:NodeShape ;
sh:targetClass ex:Person ;
sh:property [
sh:path ex:address ;
sh:message "ex:city should be sh:IRI" ;
sh:node ex:cityShape
] .

ex:cityShape
sh:property [
sh:path ex:city ;
sh:nodeKind sh:IRI
] .

ex:sizeShape
sh:targetObjectsOf ex:size ;
sh:or (
[ sh:hasValue ex:small ]
[ sh:hasValue ex:big ]
) .
32 changes: 32 additions & 0 deletions test/validation_details_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-env mocha */
import path from 'path'
import assert from 'assert'
import * as url from 'url'
import RDF from '@zazuko/env-node'
import SHACLValidator from '../index.js'
import { loadDataset } from './utils.js'

const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const rootPath = path.join(__dirname, '/data/validation-details')

describe('validation details', () => {
it('creates detail for node constraint', async () => {
const data = await loadDataset(path.join(rootPath, 'node-constraint-details.ttl'))
const shapes = data

const validator = new SHACLValidator(shapes)
const report = validator.validate(data)

assert.equal(1, report.results.length)
const result = report.results[0]
assert.deepStrictEqual(result.sourceConstraintComponent, RDF.ns.sh.NodeConstraintComponent)
assert.deepStrictEqual(result.focusNode, RDF.namedNode('https://example.org/person1'))
assert.deepStrictEqual(result.value, RDF.namedNode('https://example.org/person1'))

assert.equal(1, result.detail.length)
const detail = result.detail[0]
assert.deepStrictEqual(detail.sourceConstraintComponent, RDF.ns.sh.NodeKindConstraintComponent)
assert.deepStrictEqual(detail.focusNode, RDF.namedNode('https://example.org/person1'))
assert.deepStrictEqual(detail.value, RDF.namedNode('https://example.org/person1'))
})
})
35 changes: 35 additions & 0 deletions test/validation_repro.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-env mocha */
import path from 'path'
import assert from 'assert'
import * as url from 'url'
import RDF from '@zazuko/env-node'
import SHACLValidator from '../index.js'
import { loadDataset } from './utils.js'

const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const rootPath = path.join(__dirname, '/data/validation-repro')

describe('validation repro', () => {
it('repro #125', async () => {
const data = await loadDataset(path.join(rootPath, 'repro125-data.ttl'))
const shapes = await loadDataset(path.join(rootPath, 'repro125-shapes.ttl'))

const validator = new SHACLValidator(shapes)
const report = validator.validate(data)

assert.equal(1, report.results.length)
const result = report.results[0]
assert.deepStrictEqual(result.sourceConstraintComponent, RDF.ns.sh.NodeConstraintComponent)
assert.deepStrictEqual(result.focusNode, RDF.namedNode('https://example.org/person1'))
assert.deepStrictEqual(result.path, RDF.namedNode('https://example.org/address'))
assert.deepStrictEqual(result.value, RDF.namedNode('https://example.org/address1'))
assert.deepStrictEqual(result.message, [RDF.literal('ex:city should be sh:IRI')])

assert.equal(1, result.detail.length)
const detail = result.detail[0]
assert.deepStrictEqual(detail.sourceConstraintComponent, RDF.ns.sh.NodeKindConstraintComponent)
assert.deepStrictEqual(detail.focusNode, RDF.namedNode('https://example.org/address1'))
assert.deepStrictEqual(detail.path, RDF.namedNode('https://example.org/city'))
assert.deepStrictEqual(detail.value, RDF.literal('London'))
})
})

0 comments on commit 3a88720

Please sign in to comment.