KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > reasoner > test > WGReasonerTester


1 /******************************************************************
2  * File: WGReasonerTester.java
3  * Created by: Dave Reynolds
4  * Created on: 09-Feb-03
5  *
6  * (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
7  * [See end of file]
8  * $Id: WGReasonerTester.java,v 1.24 2005/02/21 12:18:17 andy_seaborne Exp $
9  *****************************************************************/

10 package com.hp.hpl.jena.reasoner.test;
11
12 import com.hp.hpl.jena.rdf.model.*;
13 import com.hp.hpl.jena.graph.*;
14 import com.hp.hpl.jena.graph.query.*;
15 import com.hp.hpl.jena.rdf.model.impl.PropertyImpl;
16 import com.hp.hpl.jena.rdf.model.impl.ResourceImpl;
17 import com.hp.hpl.jena.mem.GraphMem;
18 import com.hp.hpl.jena.reasoner.*;
19 import com.hp.hpl.jena.vocabulary.RDF;
20 import com.hp.hpl.jena.rdf.arp.test.ARPTests;
21
22 import com.hp.hpl.jena.shared.*;
23
24 import junit.framework.TestCase;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27
28 import java.io.*;
29 import java.util.*;
30 import java.net.*;
31
32 /**
33  * A utility to support execution of the RDFCode working group entailment
34  * tests as specified in <a HREF="http://www.w3.org/TR/2003/WD-rdf-testcases-20030123/">
35  * http://www.w3.org/TR/2003/WD-rdf-testcases-20030123/</a>.
36  *
37  * <p>The manifest file defines a set of tests. Only the positive and negative
38  * entailment tests are handled by this utility. Each test defines a set
39  * of data files to load. For normal positive entailment tests we check each
40  * triple in the conclusions file to ensure it is included in the inferred
41  * graph. For postive entailment tests which are supposed to entail the
42  * false document we run an additional validation check. For
43  * negative entailment tests which tests all triples in the non-conclusions file
44  * and check that at least one trile is missing. </p>
45  *
46  * @author <a HREF="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
47  * @version $Revision: 1.24 $ on $Date: 2005/02/21 12:18:17 $
48  */

49 public class WGReasonerTester {
50
51     /** The namespace for the test specification schema */
52     public static final String JavaDoc NS = "http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#";
53     
54     /** The base URI in which the files are purported to reside */
55     public static final String JavaDoc BASE_URI = "http://www.w3.org/2000/10/rdf-tests/rdfcore/";
56     
57     /** Default location for the test data */
58     public static final String JavaDoc DEFAULT_BASE_DIR = "testing/wg/";
59     
60     /** The base directory in which the test data is actually stored */
61     protected String JavaDoc baseDir = DEFAULT_BASE_DIR;
62     
63     /** The rdf class for positive tests */
64     public static final Resource PositiveEntailmentTest;
65     
66     /** The rdf class for positive tests */
67     public static final Resource NegativeEntailmentTest;
68     
69     /** The constant used to indicate an invalid document */
70     public static final Resource FalseDocument;
71     
72     /** The predicate defining the description of the test */
73     public static final Property descriptionP;
74     
75     /** The predicate defining the status of the test */
76     public static final Property statusP;
77     
78     /** The predicate defining the rule sets used */
79     public static final Property entailmentRulesP;
80     
81     /** The predicate defining a premise for the test */
82     public static final Property premiseDocumentP;
83     
84     /** The predicate defining the conclusion from the test */
85     public static final Property conclusionDocumentP;
86     
87     /** The type of the current test */
88     Resource testType;
89     
90     /** List of tests block because they are only intended for non-dt aware processors */
91     public static final String JavaDoc[] blockedTests = {
92         BASE_URI + "datatypes/Manifest.rdf#language-important-for-non-dt-entailment-1",
93         BASE_URI + "datatypes/Manifest.rdf#language-important-for-non-dt-entailment-2",
94     // Additional blocked tests, because we do not implement them ... jjc
95
BASE_URI + "pfps-10/Manifest.rdf#non-well-formed-literal-1",
96         BASE_URI + "xmlsch-02/Manifest.rdf#whitespace-facet-3",
97 // BASE_URI + "xmlsch-02/Manifest.rdf#whitespace-facet-2",
98
// BASE_URI + "xmlsch-02/Manifest.rdf#whitespace-facet-1",
99
// BASE_URI + "datatypes-intensional/Manifest.rdf#xsd-integer-string-incompatible",
100
};
101     
102     // Static initializer for the predicates
103
static {
104         PositiveEntailmentTest = new ResourceImpl(NS, "PositiveEntailmentTest");
105         NegativeEntailmentTest = new ResourceImpl(NS, "NegativeEntailmentTest");
106         FalseDocument = new ResourceImpl(NS, "False-Document");
107         descriptionP = new PropertyImpl(NS, "description");
108         statusP = new PropertyImpl(NS, "status");
109         entailmentRulesP = new PropertyImpl(NS, "entailmentRules");
110         premiseDocumentP = new PropertyImpl(NS, "premiseDocument");
111         conclusionDocumentP = new PropertyImpl(NS, "conclusionDocument");
112     }
113     
114     /** The rdf defining all the tests to be run */
115     protected Model testManifest;
116     
117     protected static Log logger = LogFactory.getLog(WGReasonerTester.class);
118     
119     /**
120      * Constructor.
121      * @param manifest the name of the manifest file defining these
122      * tests - relative to baseDir
123      * @param baseDir override default base directory for the tests and manifest
124      */

125     public WGReasonerTester(String JavaDoc manifest, String JavaDoc baseDir) throws IOException {
126         this.baseDir = baseDir;
127         testManifest = loadFile(manifest);
128     }
129     
130     /**
131      * Constructor.
132      * @param manifest the name of the manifest file defining these
133      * tests - relative to baseDir
134      */

135     public WGReasonerTester(String JavaDoc manifest) throws IOException {
136         testManifest = loadFile(manifest);
137     }
138     
139     /**
140      * Utility to load a file in rdf/nt/n3 format as a Model.
141      * Files are assumed to be relative to the BASE_URI.
142      * @param file the file name, relative to baseDir
143      * @return the loaded Model
144      */

145     public Model loadFile(String JavaDoc file) throws IOException {
146         String JavaDoc langType = "RDF/XML";
147         if (file.endsWith(".nt")) {
148             langType = "N-TRIPLE";
149         } else if (file.endsWith("n3")) {
150             langType = "N3";
151         }
152         Model result = ModelFactory.createNonreifyingModel();
153         String JavaDoc fname = file;
154         if (fname.startsWith(BASE_URI)) {
155             fname = fname.substring(BASE_URI.length());
156         }
157         
158         /* Change note - jjc
159          * Now use InputStream instead of Reader (general hygine).
160          * Also treat http:.... as URL not local file.
161          */

162         InputStream in;
163         if ( baseDir.startsWith("http:")) {
164             in = new URL(baseDir+fname).openStream();
165         } else {
166             in = new FileInputStream(baseDir + fname);
167         }
168         in = new BufferedInputStream(in);
169         
170         
171         result.read(in, BASE_URI + fname, langType);
172         return result;
173     }
174     
175     /**
176      * Load the datafile given by the property name.
177      * @param test the test being processed
178      * @param predicate the property of the test giving the file name to load
179      * @return a graph containing the file contents or an empty graph if the property
180      * is not present
181      * @throws IOException if the property is present but the file can't be found
182      */

183     private Graph loadTestFile(Resource test, Property predicate) throws IOException {
184         if (test.hasProperty(predicate)) {
185             String JavaDoc fileName = test.getRequiredProperty(predicate).getObject().toString();
186             return loadFile(fileName).getGraph();
187         } else {
188             return new GraphMem();
189         }
190     }
191     
192     /**
193      * Run all the tests in the manifest
194      * @param reasonerF the factory for the reasoner to be tested
195      * @param testcase the JUnit test case which is requesting this test
196      * @param configuration optional configuration information
197      * @return true if all the tests pass
198      * @throws IOException if one of the test files can't be found
199      * @throws RDFException if the test can't be found or fails internally
200      */

201     public boolean runTests(ReasonerFactory reasonerF, TestCase testcase, Resource configuration) throws IOException {
202         for (Iterator i = listTests().iterator(); i.hasNext(); ) {
203             String JavaDoc test = (String JavaDoc)i.next();
204             if (!runTest(test, reasonerF, testcase, configuration)) return false;
205         }
206         return true;
207     }
208     
209     /**
210      * Return a list of all test names defined in the manifest for this test harness.
211      */

212     public List listTests() {
213         List testList = new ArrayList();
214         ResIterator tests = testManifest.listSubjectsWithProperty(RDF.type, PositiveEntailmentTest);
215         while (tests.hasNext()) {
216             testList.add(tests.next().toString());
217         }
218         tests = testManifest.listSubjectsWithProperty(RDF.type, NegativeEntailmentTest);
219         while (tests.hasNext()) {
220             testList.add(tests.next().toString());
221         }
222         return testList;
223     }
224     
225     /**
226      * Return the type of the last test run. Nasty hack to enable calling test harness
227      * to interpret the success/fail boolen differently according to test type.
228      */

229     public Resource getTypeOfLastTest() {
230         return testType;
231     }
232     
233     /**
234      * Run a single designated test.
235      * @param uri the uri of the test, as defined in the manifest file
236      * @param reasonerF the factory for the reasoner to be tested
237      * @param testcase the JUnit test case which is requesting this test
238      * @param configuration optional configuration information
239      * @return true if the test passes
240      * @throws IOException if one of the test files can't be found
241      * @throws RDFException if the test can't be found or fails internally
242      */

243     public boolean runTest(String JavaDoc uri, ReasonerFactory reasonerF, TestCase testcase, Resource configuration) throws IOException {
244         return runTestDetailedResponse(uri,reasonerF,testcase,configuration) != FAIL;
245     }
246     static final public int FAIL = -1;
247     static final public int NOT_APPLICABLE = 0;
248     static final public int INCOMPLETE = 1;
249     static final public int PASS = 2;
250     
251     /**
252          * Run a single designated test.
253          * @param uri the uri of the test, as defined in the manifest file
254          * @param reasonerF the factory for the reasoner to be tested
255          * @param testcase the JUnit test case which is requesting this test
256          * @param configuration optional configuration information
257          * @return true if the test passes
258          * @throws IOException if one of the test files can't be found
259          * @throws RDFException if the test can't be found or fails internally
260          */

261     
262     
263        public int runTestDetailedResponse(String JavaDoc uri, ReasonerFactory reasonerF, TestCase testcase, Resource configuration) throws IOException {
264     
265         // Find the specification for the named test
266
Resource test = testManifest.getResource(uri);
267         testType = (Resource)test.getRequiredProperty(RDF.type).getObject();
268         if (!(testType.equals(NegativeEntailmentTest) ||
269                testType.equals(PositiveEntailmentTest) ) ) {
270             throw new JenaException("Can't find test: " + uri);
271         }
272
273         Statement descriptionS = test.getProperty(descriptionP);
274         String JavaDoc description = (descriptionS == null) ? "no description" : descriptionS.getObject().toString();
275         String JavaDoc status = test.getRequiredProperty(statusP).getObject().toString();
276         logger.debug("WG test " + test.getURI() + " - " + status);
277         if (! status.equals("APPROVED")) {
278             return NOT_APPLICABLE;
279         }
280         
281         // Skip the test designed for only non-datatype aware processors
282
for (int i = 0; i < blockedTests.length; i++) {
283             if (test.getURI().equals(blockedTests[i])) return NOT_APPLICABLE;
284         }
285                 
286         // Load up the premise documents
287
Model premises = ModelFactory.createNonreifyingModel();
288         for (StmtIterator premisesI = test.listProperties(premiseDocumentP); premisesI.hasNext(); ) {
289             premises.add(loadFile(premisesI.nextStatement().getObject().toString()));
290         }
291
292         // Load up the conclusions document
293
Model conclusions = null;
294         Resource conclusionsRes = (Resource) test.getRequiredProperty(conclusionDocumentP).getObject();
295         Resource conclusionsType = (Resource) conclusionsRes.getRequiredProperty(RDF.type).getObject();
296         if (!conclusionsType.equals(FalseDocument)) {
297             conclusions = loadFile(conclusionsRes.toString());
298         }
299         
300         // Construct the inferred graph
301
Reasoner reasoner = reasonerF.create(configuration);
302         InfGraph graph = reasoner.bind(premises.getGraph());
303         Model result = ModelFactory.createModelForGraph(graph);
304         
305         // Check the results against the official conclusions
306
boolean correct = true;
307         int goodResult = PASS;
308         boolean noisy = !(baseDir.equals(DEFAULT_BASE_DIR)
309                || ARPTests.internet );
310         if (testType.equals(PositiveEntailmentTest)) {
311             if (conclusions == null) {
312                 // Check that the result is flagged as semantically invalid
313
correct = ! graph.validate().isValid();
314                 if (noisy) {
315                     System.out.println("PositiveEntailmentTest of FalseDoc " + test.getURI() + (correct ? " - OK" : " - FAIL"));
316                 }
317             } else {
318                 correct = testConclusions(conclusions.getGraph(), result.getGraph());
319                 if (!graph.validate().isValid()) {
320                     correct = false;
321                 }
322                 if (noisy) {
323                     System.out.println("PositiveEntailmentTest " + test.getURI() + (correct ? " - OK" : " - FAIL"));
324                 }
325             }
326         } else {
327               goodResult = INCOMPLETE;
328             // A negative entailment check
329
if (conclusions == null) {
330                 // Check the result is not flagged as invalid
331
correct = graph.validate().isValid();
332                 if (noisy) {
333                     System.out.println("NegativentailmentTest of FalseDoc " + test.getURI() + (correct ? " - OK" : " - FAIL"));
334                 }
335             } else {
336                 correct = !testConclusions(conclusions.getGraph(), result.getGraph());
337                 if (noisy) {
338                     System.out.println("NegativeEntailmentTest " + test.getURI() + (correct ? " - OK" : " - FAIL"));
339                 }
340             }
341         }
342
343         // Debug output on failure
344
if (!correct) {
345             logger.debug("Premises: " );
346             for (StmtIterator i = premises.listStatements(); i.hasNext(); ) {
347                 logger.debug(" - " + i.nextStatement());
348             }
349             logger.debug("Conclusions: " );
350             if (conclusions != null) {
351                 for (StmtIterator i = conclusions.listStatements(); i.hasNext(); ) {
352                     logger.debug(" - " + i.nextStatement());
353                 }
354             }
355         }
356         
357         // Signal the results
358
if (testcase != null) {
359             TestCase.assertTrue("Test: " + test + "\n" + description, correct);
360         }
361         return correct?goodResult:FAIL;
362     }
363     
364     /**
365      * Test a conclusions graph against a result graph. This works by
366      * translating the conclusions graph into a find query which contains one
367      * variable for each distinct bNode in the conclusions graph.
368      */

369     private boolean testConclusions(Graph conclusions, Graph result) {
370         QueryHandler qh = result.queryHandler();
371         Query query = graphToQuery(conclusions);
372         Iterator i = qh.prepareBindings(query, new Node[] {}).executeBindings();
373         return i.hasNext();
374     }
375
376  
377     /**
378      * Translate a conclusions graph into a query pattern
379      */

380     public static Query graphToQuery(Graph graph) {
381         HashMap bnodeToVar = new HashMap();
382         Query query = new Query();
383         for (Iterator i = graph.find(null, null, null); i.hasNext(); ) {
384             Triple triple = (Triple)i.next();
385             query.addMatch(
386                 translate(triple.getSubject(), bnodeToVar),
387                 translate(triple.getPredicate(), bnodeToVar),
388                 translate(triple.getObject(), bnodeToVar) );
389         }
390         return query;
391     }
392    
393     /**
394      * Translate a blank node to a variable node
395      * @param node the bNode to translate
396      * @param bnodeToVar a map of translations already known about
397      * @return a variable node
398      */

399     private static Node translate(Node node, HashMap bnodeToVar) {
400         String JavaDoc varnames = "abcdefghijklmnopqrstuvwxyz";
401         if (node.isBlank()) {
402             Node t = (Node)bnodeToVar.get(node);
403             if (t == null) {
404                int i = bnodeToVar.size();
405                if (i > varnames.length()) {
406                    throw new ReasonerException("Too many bnodes in query");
407                }
408                t = Node.createVariable(varnames.substring(i, i+1));
409                bnodeToVar.put(node, t);
410             }
411             return t;
412         } else {
413             return node;
414         }
415     }
416  
417 }
418
419 /*
420     (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
421     All rights reserved.
422
423     Redistribution and use in source and binary forms, with or without
424     modification, are permitted provided that the following conditions
425     are met:
426
427     1. Redistributions of source code must retain the above copyright
428        notice, this list of conditions and the following disclaimer.
429
430     2. Redistributions in binary form must reproduce the above copyright
431        notice, this list of conditions and the following disclaimer in the
432        documentation and/or other materials provided with the distribution.
433
434     3. The name of the author may not be used to endorse or promote products
435        derived from this software without specific prior written permission.
436
437     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
438     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
439     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
440     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
441     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
442     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
443     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
444     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
445     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
446     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
447 */

448
449
Popular Tags