001: /******************************************************************
002: * File: OWLWGTester.java
003: * Created by: Dave Reynolds
004: * Created on: 11-Apr-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: OWLWGTester.java,v 1.27 2008/01/02 12:08:19 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys.test;
010:
011: import com.hp.hpl.jena.reasoner.*;
012: import com.hp.hpl.jena.reasoner.rulesys.FBRuleInfGraph;
013: import com.hp.hpl.jena.reasoner.test.WGReasonerTester;
014: import com.hp.hpl.jena.util.FileManager;
015: import com.hp.hpl.jena.rdf.model.*;
016: import com.hp.hpl.jena.vocabulary.*;
017: import com.hp.hpl.jena.graph.*;
018: import com.hp.hpl.jena.graph.query.*;
019:
020: import com.hp.hpl.jena.shared.*;
021:
022: import junit.framework.TestCase;
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import java.io.*;
027: import java.util.*;
028:
029: /**
030: * A test harness for running the OWL working group tests. This
031: * differs from the RDF one in several ways (separate manifest files,
032: * different namespaces, document references lack suffix ...).
033: * <p>
034: * This version is used for running the core entailment tests as part of unit testing.
035: * A separate test harness for use in reporting OWL conformance is being developed and
036: * some code rationalization might be once once that stabilizes. </p>
037: *
038: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
039: * @version $Revision: 1.27 $ on $Date: 2008/01/02 12:08:19 $
040: */
041: public class OWLWGTester {
042: /** The base URI in which the files are purported to reside */
043: public static String BASE_URI = "http://www.w3.org/2002/03owlt/";
044:
045: /** The base directory in which the test data is actually stored */
046: public static String baseDir = "testing/wg/";
047:
048: /** The namespace for the test specification schema */
049: public static final String NS_OTEST = "http://www.w3.org/2002/03owlt/testOntology#";
050:
051: /** The namespace for the test specification schema */
052: public static final String NS_RTEST = "http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#";
053:
054: /** The rdf class for positive tests */
055: public static final Resource PositiveEntailmentTest;
056:
057: /** The rdf class for positive tests */
058: public static final Resource NegativeEntailmentTest;
059:
060: /** The predicate defining the description of the test */
061: public static final Property descriptionP;
062:
063: /** The predicate defining a premise for the test */
064: public static final Property premiseDocumentP;
065:
066: /** The predicate defining the conclusion from the test */
067: public static final Property conclusionDocumentP;
068:
069: /** The predicate defining the status of the test */
070: public static final Property statusP;
071:
072: /** The reasoner factory being tested */
073: protected ReasonerFactory reasonerF;
074:
075: /** The configuration information for the reasoner */
076: protected Resource configuration;
077:
078: /** The test case which has invoke this test */
079: protected TestCase testcase;
080:
081: /** The processing time used since testcase creation */
082: protected static long timeCost = 0;
083:
084: /** The total number of tests run */
085: protected static int numTests = 0;
086:
087: protected static Log logger = LogFactory.getLog(OWLWGTester.class);
088:
089: // Static initializer for the predicates
090: static {
091: PositiveEntailmentTest = ResourceFactory.createProperty(
092: NS_OTEST, "PositiveEntailmentTest");
093: NegativeEntailmentTest = ResourceFactory.createProperty(
094: NS_OTEST, "NegativeEntailmentTest");
095: descriptionP = ResourceFactory.createProperty(NS_RTEST,
096: "description");
097: premiseDocumentP = ResourceFactory.createProperty(NS_RTEST,
098: "premiseDocument");
099: conclusionDocumentP = ResourceFactory.createProperty(NS_RTEST,
100: "conclusionDocument");
101: statusP = ResourceFactory.createProperty(NS_RTEST, "status");
102: }
103:
104: /**
105: * Constructor
106: * @param reasonerF the factory for the reasoner to be tested
107: * @param testcase the JUnit test case which is requesting this test
108: * @param configuration optional configuration information
109: */
110: public OWLWGTester(ReasonerFactory reasonerF, TestCase testcase,
111: Resource configuration) {
112: this .reasonerF = reasonerF;
113: this .testcase = testcase;
114: this .configuration = configuration;
115: }
116:
117: /**
118: * Run all the tests in the manifest
119: * @param manifestFile the name of the manifest file relative to baseDir
120: * @param log set to true to enable derivation logging
121: * @param stats set to true to log performance statistics
122: * @return true if all the tests pass
123: * @throws IOException if one of the test files can't be found
124: */
125: public boolean runTests(String manifestFile, boolean log,
126: boolean stats) throws IOException {
127: // Load up the manifest
128: Model manifest = FileManager.get().loadModel(
129: baseDir + manifestFile);
130: ResIterator tests = manifest.listResourcesWithProperty(
131: RDF.type, PositiveEntailmentTest);
132: while (tests.hasNext()) {
133: Resource test = tests.nextResource();
134: if (!runTest(test, log, stats))
135: return false;
136: }
137: tests = manifest.listResourcesWithProperty(RDF.type,
138: NegativeEntailmentTest);
139: while (tests.hasNext()) {
140: Resource test = tests.nextResource();
141: if (!runTest(test, log, stats))
142: return false;
143: }
144: return true;
145: }
146:
147: /**
148: * Run a single designated test.
149: * @param test the root node descibing the test
150: * @param log set to true to enable derivation logging
151: * @param stats set to true to log performance statistics
152: * @return true if the test passes
153: * @throws IOException if one of the test files can't be found
154: */
155: public boolean runTest(Resource test, boolean log, boolean stats)
156: throws IOException {
157: // Find the specification for the named test
158: RDFNode testType = test.getRequiredProperty(RDF.type)
159: .getObject();
160: if (!(testType.equals(NegativeEntailmentTest) || testType
161: .equals(PositiveEntailmentTest))) {
162: throw new JenaException("Can't find test: " + test);
163: }
164:
165: String description = test.getRequiredProperty(descriptionP)
166: .getObject().toString();
167: String status = test.getRequiredProperty(statusP).getObject()
168: .toString();
169: logger.debug("WG test " + test.getURI() + " - " + status);
170:
171: // Load up the premise documents
172: Model premises = ModelFactory.createNonreifyingModel();
173: for (StmtIterator premisesI = test
174: .listProperties(premiseDocumentP); premisesI.hasNext();) {
175: premises.add(loadFile(premisesI.nextStatement().getObject()
176: .toString()
177: + ".rdf"));
178: }
179:
180: // Load up the conclusions document
181: Resource conclusionsRes = (Resource) test.getRequiredProperty(
182: conclusionDocumentP).getObject();
183: Model conclusions = loadFile(conclusionsRes.toString() + ".rdf");
184:
185: // Construct the inferred graph
186: // Optional logging
187: if (log) {
188: if (configuration == null) {
189: Model m = ModelFactory.createDefaultModel();
190: configuration = m.createResource();
191: }
192: configuration.addProperty(ReasonerVocabulary.PROPtraceOn,
193: "true").addProperty(
194: ReasonerVocabulary.PROPderivationLogging, "true");
195: }
196: Reasoner reasoner = reasonerF.create(configuration);
197: long t1 = System.currentTimeMillis();
198: InfGraph graph = reasoner.bind(premises.getGraph());
199: Model result = ModelFactory.createModelForGraph(graph);
200:
201: if (stats && graph instanceof FBRuleInfGraph) {
202: // ((FBRuleInfGraph)graph).resetLPProfile(true);
203: }
204:
205: // Check the results against the official conclusions
206: boolean correct = true;
207: if (testType.equals(PositiveEntailmentTest)) {
208: correct = testConclusions(conclusions.getGraph(), result
209: .getGraph());
210: } else {
211: // A negative entailment check
212: correct = !testConclusions(conclusions.getGraph(), result
213: .getGraph());
214: }
215: long t2 = System.currentTimeMillis();
216: timeCost += (t2 - t1);
217: numTests++;
218: if (stats) {
219: logger
220: .info("Time=" + (t2 - t1) + "ms for "
221: + test.getURI());
222: printStats();
223:
224: if (graph instanceof FBRuleInfGraph) {
225: ((FBRuleInfGraph) graph).printLPProfile();
226: }
227: }
228:
229: if (!correct) {
230: // List all the forward deductions for debugging
231: // if (graph instanceof FBRuleInfGraph) {
232: // System.out.println("Error: deductions graph was ...");
233: // FBRuleInfGraph fbGraph = (FBRuleInfGraph)graph;
234: // Graph deductions = fbGraph.getDeductionsGraph();
235: // com.hp.hpl.jena.util.PrintUtil.printOut(deductions.find(null,null,null));
236: // }
237: }
238:
239: // Signal the results
240: if (testcase != null) {
241: TestCase.assertTrue("Test: " + test + "\n"
242: + reasonerF.getURI() + "\n" + description, correct);
243: }
244: return correct;
245: }
246:
247: /**
248: * Utility to load a file as a Model.
249: * Files are assumed to be relative to the BASE_URI.
250: * @param file the file name, relative to baseDir
251: * @return the loaded Model
252: */
253: public static Model loadFile(String file) throws IOException {
254: String langType = "RDF/XML";
255: if (file.endsWith(".nt")) {
256: langType = "N-TRIPLE";
257: } else if (file.endsWith("n3")) {
258: langType = "N3";
259: }
260: Model result = ModelFactory.createNonreifyingModel();
261: String fname = file;
262: if (fname.startsWith(BASE_URI)) {
263: fname = fname.substring(BASE_URI.length());
264: }
265: Reader reader = new BufferedReader(new FileReader(baseDir
266: + fname));
267: result.read(reader, BASE_URI + fname, langType);
268: return result;
269: }
270:
271: /**
272: * Test a conclusions graph against a result graph. This works by
273: * translating the conclusions graph into a find query which contains one
274: * variable for each distinct bNode in the conclusions graph.
275: */
276: private boolean testConclusions(Graph conclusions, Graph result) {
277: QueryHandler qh = result.queryHandler();
278: Query query = WGReasonerTester.graphToQuery(conclusions);
279: Iterator i = qh.prepareBindings(query, new Node[] {})
280: .executeBindings();
281: return i.hasNext();
282: }
283:
284: /**
285: * Log (info level) some summary information on the timecost of the tests.
286: */
287: public void printStats() {
288: logger.info("Ran " + numTests + " in " + timeCost + "ms = "
289: + (timeCost / numTests) + "ms/test");
290: }
291:
292: }
293:
294: /*
295: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
296: * All rights reserved.
297: *
298: * Redistribution and use in source and binary forms, with or without
299: * modification, are permitted provided that the following conditions
300: * are met:
301: * 1. Redistributions of source code must retain the above copyright
302: * notice, this list of conditions and the following disclaimer.
303: * 2. Redistributions in binary form must reproduce the above copyright
304: * notice, this list of conditions and the following disclaimer in the
305: * documentation and/or other materials provided with the distribution.
306: * 3. The name of the author may not be used to endorse or promote products
307: * derived from this software without specific prior written permission.
308: *
309: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
310: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
311: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
312: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
313: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
314: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
315: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
316: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
317: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
318: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
319: */
|