|
15 | 15 |
|
16 | 16 | import static org.assertj.core.api.Assertions.assertThat;
|
17 | 17 | import static org.junit.jupiter.api.Assertions.assertTrue;
|
18 |
| -import static org.junit.jupiter.api.Assertions.fail; |
19 | 18 |
|
20 | 19 | import java.io.ByteArrayInputStream;
|
21 |
| -import java.io.File; |
22 |
| -import java.io.FileInputStream; |
23 |
| -import java.io.IOException; |
24 | 20 | import java.io.InputStream;
|
25 | 21 | import java.math.BigInteger;
|
26 | 22 | import java.nio.charset.StandardCharsets;
|
|
31 | 27 | import org.eclipse.esmf.aspectmodel.shacl.constraint.MinCountConstraint;
|
32 | 28 | import org.eclipse.esmf.aspectmodel.shacl.constraint.NodeKindConstraint;
|
33 | 29 | import org.eclipse.esmf.aspectmodel.shacl.path.PredicatePath;
|
| 30 | +import org.eclipse.esmf.aspectmodel.shacl.path.SequencePath; |
34 | 31 | import org.eclipse.esmf.aspectmodel.shacl.violation.ClassTypeViolation;
|
35 | 32 | import org.eclipse.esmf.aspectmodel.shacl.violation.ClosedViolation;
|
36 | 33 | import org.eclipse.esmf.aspectmodel.shacl.violation.DatatypeViolation;
|
@@ -1838,7 +1835,7 @@ public void testOrConstraint() {
|
1838 | 1835 | }
|
1839 | 1836 |
|
1840 | 1837 | @Test
|
1841 |
| - public void testXoneConstraint() { |
| 1838 | + public void testXoneConstraintInPropertyShape() { |
1842 | 1839 | final Model shapesModel = model( """
|
1843 | 1840 | @prefix sh: <http://www.w3.org/ns/shacl#> .
|
1844 | 1841 | @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
@@ -1888,7 +1885,7 @@ public void testXoneConstraint() {
|
1888 | 1885 | }
|
1889 | 1886 |
|
1890 | 1887 | @Test
|
1891 |
| - void testXoneConstraintWithNoSubViolations() { |
| 1888 | + void testXoneConstraintInPropertyShapeWithNoSubViolations() { |
1892 | 1889 | final Model shapesModel = model( """
|
1893 | 1890 | @prefix sh: <http://www.w3.org/ns/shacl#> .
|
1894 | 1891 | @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
@@ -1939,6 +1936,114 @@ void testXoneConstraintWithNoSubViolations() {
|
1939 | 1936 | "Exactly one of the following conditions should lead to a violation, but all of them passed successfully" );
|
1940 | 1937 | }
|
1941 | 1938 |
|
| 1939 | + @Test |
| 1940 | + void testXoneConstraintInNodeShapeExpectSuccess() { |
| 1941 | + final Model shapesModel = model( """ |
| 1942 | + @prefix sh: <http://www.w3.org/ns/shacl#> . |
| 1943 | + @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . |
| 1944 | + @prefix : <http://example.com#> . |
| 1945 | +
|
| 1946 | + :MyShape |
| 1947 | + a sh:NodeShape ; |
| 1948 | + sh:targetClass :TestClass ; |
| 1949 | + sh:name "Test shape" ; |
| 1950 | + sh:description "Test shape description" ; |
| 1951 | + sh:xone ( |
| 1952 | + :Property1Shape |
| 1953 | + :Property2Shape |
| 1954 | + ) . |
| 1955 | + |
| 1956 | + :Property1Shape |
| 1957 | + a sh:PropertyShape ; |
| 1958 | + sh:path :foo ; |
| 1959 | + sh:minCount 1 . |
| 1960 | + |
| 1961 | + :Property2Shape |
| 1962 | + a sh:PropertyShape ; |
| 1963 | + sh:path :bar ; |
| 1964 | + sh:minCount 1 . |
| 1965 | + """ ); |
| 1966 | + |
| 1967 | + final Model dataModel = model( """ |
| 1968 | + @prefix : <http://example.com#> . |
| 1969 | + :Foo a :TestClass ; |
| 1970 | + :foo 1 . |
| 1971 | + """ ); |
| 1972 | + |
| 1973 | + final ShaclValidator validator = new ShaclValidator( shapesModel ); |
| 1974 | + final Resource element = dataModel.createResource( namespace + "Foo" ); |
| 1975 | + final List<Violation> violations = validator.validateElement( element ); |
| 1976 | + |
| 1977 | + assertThat( violations ).isEmpty(); |
| 1978 | + } |
| 1979 | + |
| 1980 | + @Test |
| 1981 | + void testXoneConstraintInNodeShapeExpectFailure() { |
| 1982 | + final Model shapesModel = model( |
| 1983 | + """ |
| 1984 | + @prefix sh: <http://www.w3.org/ns/shacl#> . |
| 1985 | + @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . |
| 1986 | + @prefix : <http://example.com#> . |
| 1987 | +
|
| 1988 | + :MyShape |
| 1989 | + a sh:NodeShape ; |
| 1990 | + sh:targetClass :TestClass ; |
| 1991 | + sh:name "Test shape" ; |
| 1992 | + sh:description "Test shape description" ; |
| 1993 | + sh:xone ( |
| 1994 | + :Property1Shape |
| 1995 | + :Property2Shape |
| 1996 | + ) . |
| 1997 | + |
| 1998 | + :Property1Shape |
| 1999 | + a sh:PropertyShape ; |
| 2000 | + sh:path :foo ; |
| 2001 | + sh:minCount 1 . |
| 2002 | + |
| 2003 | + :Property2Shape |
| 2004 | + a sh:PropertyShape ; |
| 2005 | + sh:path ( :bar :baz ) ; |
| 2006 | + sh:minCount 1 . |
| 2007 | + """ |
| 2008 | + ); |
| 2009 | + |
| 2010 | + final Model dataModel = model( """ |
| 2011 | + @prefix : <http://example.com#> . |
| 2012 | + :Foo a :TestClass ; |
| 2013 | + :testProperty 42 . |
| 2014 | + """ ); |
| 2015 | + |
| 2016 | + final ShaclValidator validator = new ShaclValidator( shapesModel ); |
| 2017 | + final Resource element = dataModel.createResource( namespace + "Foo" ); |
| 2018 | + final List<Violation> violations = validator.validateElement( element ); |
| 2019 | + |
| 2020 | + assertThat( violations.size() ).isEqualTo( 1 ); |
| 2021 | + final Violation finding = violations.get( 0 ); |
| 2022 | + assertThat( finding ).isInstanceOf( XoneViolation.class ); |
| 2023 | + assertThat( finding.message() ).startsWith( "Exactly one of the following violations must be fixed:" ); |
| 2024 | + assertThat( finding.message() ).contains( "Mandatory property :foo is missing on :Foo" ); |
| 2025 | + assertThat( finding.message() ).contains( "Mandatory property :bar/:baz is missing on :Foo" ); |
| 2026 | + assertThat( finding ).isInstanceOfSatisfying( XoneViolation.class, xoneViolation -> |
| 2027 | + assertThat( xoneViolation.violations() ).satisfiesExactly( |
| 2028 | + violation -> |
| 2029 | + assertThat( violation ).isInstanceOfSatisfying( MinCountViolation.class, minCountViolation -> { |
| 2030 | + assertThat( minCountViolation.allowed() ).isEqualTo( 1 ); |
| 2031 | + assertThat( minCountViolation.actual() ).isEqualTo( 0 ); |
| 2032 | + assertThat( minCountViolation.context().propertyShape() ).hasValueSatisfying( property -> |
| 2033 | + assertThat( property.path() ).isInstanceOfSatisfying( PredicatePath.class, predicatePath -> |
| 2034 | + assertThat( predicatePath.toString() ).isEqualTo( ":foo" ) ) ); |
| 2035 | + } ), |
| 2036 | + violation -> |
| 2037 | + assertThat( violation ).isInstanceOfSatisfying( MinCountViolation.class, minCountViolation -> { |
| 2038 | + assertThat( minCountViolation.allowed() ).isEqualTo( 1 ); |
| 2039 | + assertThat( minCountViolation.actual() ).isEqualTo( 0 ); |
| 2040 | + assertThat( minCountViolation.context().propertyShape() ).hasValueSatisfying( property -> |
| 2041 | + assertThat( property.path() ).isInstanceOfSatisfying( SequencePath.class, sequencePath -> |
| 2042 | + assertThat( sequencePath.toString() ).isEqualTo( ":bar/:baz" ) ) ); |
| 2043 | + } ) |
| 2044 | + ) ); |
| 2045 | + } |
| 2046 | + |
1942 | 2047 | @Test
|
1943 | 2048 | void testSparqlTargetWithGenericConstraint() {
|
1944 | 2049 | final Model shapesModel = model( """
|
|
0 commit comments