Skip to content

Commit 964ba38

Browse files
duncdrumclaude
andcommitted
[test] Add cross-validator-backend comparison test for tournament fixtures
Tournament.xsd and Tournament.rng (siblings of tournament-schema.sch, the only one of the three actually exercised by any existing test) were dead/unused. Their own embedded comment explains why they exist side by side: Tournament-valid.xml and Tournament-invalid.xml only differ in a Singles-tournament co-occurrence constraint (nbrParticipants must equal nbrTeams) that neither RELAX NG nor W3C XML Schema can express on their own -- Schematron rules are embedded in both via xsd:appinfo/RELAX NG annotations to add it. Add TournamentSchemaLanguageComparisonTest, validating both documents against the bare XSD (via directory-search) and bare RNG grammars. RNG reports both as valid, as documented. XSD reports both as invalid, but for an unrelated, pre-existing reason in this 2001-vintage sample: Match m3 references a Team t5 that's never declared, caught by XSD's built-in ID/IDREF referential-integrity check, which this Tournament.rng doesn't declare for the same elements. Both documents fail with the exact same error either way, which is itself the point: XSD's verdict doesn't change based on the co-occurrence violation either. JingSchematronTest already covers the Schematron leg against the same fixtures, correctly distinguishing the two documents. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1bbda5f commit 964ba38

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
* info@exist-db.org
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery.functions.validate;
23+
24+
import org.custommonkey.xmlunit.exceptions.XpathException;
25+
import org.exist.test.ExistXmldbEmbeddedServer;
26+
import org.exist.util.io.InputStreamUtil;
27+
import org.junit.*;
28+
29+
import static org.exist.collections.CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE;
30+
import static org.exist.samples.Samples.SAMPLES;
31+
import static org.junit.Assert.*;
32+
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
33+
34+
import java.io.IOException;
35+
import java.io.InputStream;
36+
37+
import org.xml.sax.SAXException;
38+
import org.xmldb.api.base.Collection;
39+
import org.xmldb.api.base.ResourceSet;
40+
import org.xmldb.api.base.XMLDBException;
41+
42+
/**
43+
* The {@code tournament/1.5} sample fixtures ship an XSD, an RNG, and a Schematron schema side by
44+
* side, all describing the same {@code Tournament} document shape. Their own embedded comment
45+
* explains why: {@code Tournament-valid.xml} and {@code Tournament-invalid.xml} only differ in a
46+
* co-occurrence constraint -- for a {@code Singles} tournament, {@code nbrParticipants} must equal
47+
* {@code nbrTeams} -- that neither RELAX NG nor W3C XML Schema can express on their own. Schematron
48+
* rules are embedded in both {@code Tournament.xsd} (via {@code xsd:appinfo}) and {@code
49+
* Tournament.rng} (via RELAX NG annotations) specifically to add that missing constraint, but {@code
50+
* validation:jaxp()}/{@code validation:jing()} only enforce the structural grammar, not embedded
51+
* Schematron annotations. {@link JingSchematronTest} validates the same pair against {@code
52+
* tournament-schema.sch} and correctly reports the second document as invalid.
53+
*
54+
* <p>Bare RNG bears this out directly: both documents are structurally valid against {@code
55+
* Tournament.rng} below, since it doesn't express the co-occurrence constraint either.</p>
56+
*
57+
* <p>Bare XSD does not -- both documents are structurally <em>invalid</em> against {@code
58+
* Tournament.xsd}, but for an unrelated reason: {@code Match} {@code m3} references a {@code Team}
59+
* {@code t5} that is never declared in {@code Teams} (only {@code t1}/{@code t2}/{@code t3} exist).
60+
* This is a pre-existing defect in this 2001-vintage third-party sample, present identically in both
61+
* documents -- caught by XSD's built-in {@code xsd:ID}/{@code xsd:IDREF} referential-integrity check
62+
* (which this {@code Tournament.rng} does not declare for the same elements), not by anything related
63+
* to the documented co-occurrence constraint. The two XSD tests below assert that both documents fail
64+
* with the exact same error, which is itself the point: XSD's verdict does not change based on whether
65+
* {@code nbrParticipants} matches {@code nbrTeams}, confirming it can't see that constraint either.</p>
66+
*/
67+
public class TournamentSchemaLanguageComparisonTest {
68+
69+
private static final String[] TEST_RESOURCES =
70+
{ "Tournament-valid.xml", "Tournament-invalid.xml", "Tournament.xsd", "Tournament.rng" };
71+
72+
@ClassRule
73+
public static final ExistXmldbEmbeddedServer existEmbeddedServer = new ExistXmldbEmbeddedServer(false, true, true);
74+
75+
private static final String noValidation = "<?xml version='1.0'?>" +
76+
"<collection xmlns='http://exist-db.org/collection-config/1.0'>" +
77+
" <validation mode='no'/>" +
78+
"</collection>";
79+
80+
@BeforeClass
81+
public static void prepareResources() throws Exception {
82+
83+
// Switch off validation
84+
try (Collection conf = existEmbeddedServer.createCollection(existEmbeddedServer.getRoot(), "system/config/db/tournament")) {
85+
ExistXmldbEmbeddedServer.storeResource(conf, DEFAULT_COLLECTION_CONFIG_FILE, noValidation.getBytes());
86+
}
87+
88+
try (Collection col15 = existEmbeddedServer.createCollection(existEmbeddedServer.getRoot(), "tournament/1.5")) {
89+
for (final String testResource : TEST_RESOURCES) {
90+
try (final InputStream is = SAMPLES.getSample("validation/tournament/1.5/" + testResource)) {
91+
assertNotNull(is);
92+
ExistXmldbEmbeddedServer.storeResource(col15, testResource, InputStreamUtil.readAll(is));
93+
}
94+
}
95+
}
96+
}
97+
98+
@Test
99+
public void xsdStructureRejectsValidDocumentOnUnrelatedIdrefDefect() throws XMLDBException, SAXException, XpathException, IOException {
100+
// No xsi:schemaLocation hint on the instance -- resolved purely by Tournament.xsd's
101+
// targetNamespace via directory-search, the same mechanism JaxpXsdCatalogTest's
102+
// xsd_searched_* tests use. See the class javadoc for why this is "invalid".
103+
executeAndEvaluateMessage("validation:jaxp-report( doc('/db/tournament/1.5/Tournament-valid.xml'), false(), " +
104+
"xs:anyURI('/db/tournament/1.5/') )", "invalid",
105+
"cvc-id.1: There is no ID/IDREF binding for IDREF 't5'.");
106+
}
107+
108+
@Test
109+
public void xsdStructureRejectsCoOccurrenceViolatingDocumentIdentically() throws XMLDBException, SAXException, XpathException, IOException {
110+
// Bare XSD structural validation cannot see the Singles/nbrParticipants-vs-nbrTeams
111+
// co-occurrence constraint -- proven here by getting the exact same verdict and error as
112+
// the "valid" document above, despite the co-occurrence violation. Only the accompanying
113+
// Schematron rules (tested separately in JingSchematronTest) catch that constraint.
114+
executeAndEvaluateMessage("validation:jaxp-report( doc('/db/tournament/1.5/Tournament-invalid.xml'), false(), " +
115+
"xs:anyURI('/db/tournament/1.5/') )", "invalid",
116+
"cvc-id.1: There is no ID/IDREF binding for IDREF 't5'.");
117+
}
118+
119+
@Test
120+
public void rngStructureAcceptsValidDocument() throws XMLDBException, SAXException, XpathException, IOException {
121+
executeAndEvaluate("validation:jing-report( doc('/db/tournament/1.5/Tournament-valid.xml'), " +
122+
"doc('/db/tournament/1.5/Tournament.rng') )", "valid");
123+
}
124+
125+
@Test
126+
public void rngStructureAcceptsCoOccurrenceViolatingDocument() throws XMLDBException, SAXException, XpathException, IOException {
127+
// Same co-occurrence limitation as the XSD case above, for RELAX NG.
128+
executeAndEvaluate("validation:jing-report( doc('/db/tournament/1.5/Tournament-invalid.xml'), " +
129+
"doc('/db/tournament/1.5/Tournament.rng') )", "valid");
130+
}
131+
132+
private void executeAndEvaluate(final String query, final String expectedValue) throws XMLDBException, SAXException, IOException, XpathException {
133+
final ResourceSet results = existEmbeddedServer.executeQuery(query);
134+
assertEquals(1, results.getSize());
135+
136+
final String r = (String) results.getResource(0).getContent();
137+
assertXpathEvaluatesTo(expectedValue, "//status/text()", r);
138+
}
139+
140+
private void executeAndEvaluateMessage(final String query, final String expectedValue, final String expectedMessage)
141+
throws XMLDBException, SAXException, IOException, XpathException {
142+
final ResourceSet results = existEmbeddedServer.executeQuery(query);
143+
assertEquals(1, results.getSize());
144+
145+
final String r = (String) results.getResource(0).getContent();
146+
assertXpathEvaluatesTo(expectedValue, "//status/text()", r);
147+
assertXpathEvaluatesTo(expectedMessage, "//message/text()", r);
148+
}
149+
}

0 commit comments

Comments
 (0)