001: /******************************************************************
002: * File: TestReasoners.java
003: * Created by: Dave Reynolds
004: * Created on: 19-Jan-03
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: TestReasoners.java,v 1.35 2008/01/02 12:08:31 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.test;
010:
011: import com.hp.hpl.jena.reasoner.transitiveReasoner.*;
012: import com.hp.hpl.jena.reasoner.rulesys.RDFSRuleReasonerFactory;
013: import com.hp.hpl.jena.reasoner.*;
014: import com.hp.hpl.jena.rdf.model.*;
015: import com.hp.hpl.jena.graph.*;
016: import com.hp.hpl.jena.ontology.*;
017: import com.hp.hpl.jena.util.FileManager;
018: import com.hp.hpl.jena.util.IteratorCollection;
019: import com.hp.hpl.jena.util.PrintUtil;
020: import com.hp.hpl.jena.vocabulary.*;
021:
022: import junit.framework.TestCase;
023: import junit.framework.TestSuite;
024: import java.io.IOException;
025: import java.util.ArrayList;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Set;
029:
030: /**
031: * Outline unit tests for initial experimental reasoners
032: *
033: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
034: * @version $Revision: 1.35 $ on $Date: 2008/01/02 12:08:31 $
035: */
036: public class TestReasoners extends TestCase {
037:
038: /**
039: * Boilerplate for junit
040: */
041: public TestReasoners(String name) {
042: super (name);
043: }
044:
045: /**
046: * Boilerplate for junit.
047: * This is its own test suite
048: */
049: public static TestSuite suite() {
050: return new TestSuite(TestReasoners.class);
051: }
052:
053: /**
054: * Test the basic functioning of a Transitive closure cache
055: */
056: public void testTransitiveReasoner() throws IOException {
057: ReasonerTester tester = new ReasonerTester(
058: "transitive/manifest.rdf");
059: ReasonerFactory rf = TransitiveReasonerFactory.theInstance();
060: assertTrue("transitive reasoner tests", tester.runTests(rf,
061: this , null));
062: }
063:
064: /**
065: * Test rebind operation for the transitive reasoner
066: */
067: public void testTransitiveRebind() {
068: Graph data = Factory.createGraphMem();
069: Node C1 = Node.createURI("C1");
070: Node C2 = Node.createURI("C2");
071: Node C3 = Node.createURI("C3");
072: Node C4 = Node.createURI("C4");
073: data.add(new Triple(C1, RDFS.subClassOf.asNode(), C2));
074: data.add(new Triple(C2, RDFS.subClassOf.asNode(), C3));
075: Reasoner reasoner = TransitiveReasonerFactory.theInstance()
076: .create(null);
077: assertTrue(reasoner.supportsProperty(RDFS.subClassOf));
078: assertTrue(!reasoner.supportsProperty(RDFS.domain));
079: InfGraph infgraph = reasoner.bind(data);
080: TestUtil.assertIteratorValues(this , infgraph.find(C1, null,
081: null), new Object[] {
082: new Triple(C1, RDFS.subClassOf.asNode(), C1),
083: new Triple(C1, RDFS.subClassOf.asNode(), C2),
084: new Triple(C1, RDFS.subClassOf.asNode(), C3) });
085: Graph data2 = Factory.createGraphMem();
086: data2.add(new Triple(C1, RDFS.subClassOf.asNode(), C2));
087: data2.add(new Triple(C2, RDFS.subClassOf.asNode(), C4));
088: infgraph.rebind(data2);
089:
090: // Incremental additions
091: Node a = Node.createURI("a");
092: Node b = Node.createURI("b");
093: Node c = Node.createURI("c");
094: infgraph.add(new Triple(a, RDFS.subClassOf.asNode(), b));
095: infgraph.add(new Triple(b, RDFS.subClassOf.asNode(), c));
096: TestUtil.assertIteratorValues(this , infgraph.find(b,
097: RDFS.subClassOf.asNode(), null), new Object[] {
098: new Triple(b, RDFS.subClassOf.asNode(), c),
099: new Triple(b, RDFS.subClassOf.asNode(), b) });
100: TestUtil.assertIteratorValues(this , infgraph.find(a,
101: RDFS.subClassOf.asNode(), null), new Object[] {
102: new Triple(a, RDFS.subClassOf.asNode(), a),
103: new Triple(a, RDFS.subClassOf.asNode(), b),
104: new Triple(a, RDFS.subClassOf.asNode(), c) });
105: Node p = Node.createURI("p");
106: Node q = Node.createURI("q");
107: Node r = Node.createURI("r");
108: infgraph.add(new Triple(p, RDFS.subPropertyOf.asNode(), q));
109: infgraph.add(new Triple(q, RDFS.subPropertyOf.asNode(), r));
110: TestUtil.assertIteratorValues(this , infgraph.find(q,
111: RDFS.subPropertyOf.asNode(), null), new Object[] {
112: new Triple(q, RDFS.subPropertyOf.asNode(), q),
113: new Triple(q, RDFS.subPropertyOf.asNode(), r) });
114: TestUtil.assertIteratorValues(this , infgraph.find(p,
115: RDFS.subPropertyOf.asNode(), null), new Object[] {
116: new Triple(p, RDFS.subPropertyOf.asNode(), p),
117: new Triple(p, RDFS.subPropertyOf.asNode(), q),
118: new Triple(p, RDFS.subPropertyOf.asNode(), r) });
119: }
120:
121: /**
122: * Test delete operation for Transtive reasoner.
123: */
124: public void testTransitiveRemove() {
125: Graph data = Factory.createGraphMem();
126: Node a = Node.createURI("a");
127: Node b = Node.createURI("b");
128: Node c = Node.createURI("c");
129: Node d = Node.createURI("d");
130: Node e = Node.createURI("e");
131: Node closedP = RDFS.subClassOf.asNode();
132: data.add(new Triple(a, RDFS.subClassOf.asNode(), b));
133: data.add(new Triple(a, RDFS.subClassOf.asNode(), c));
134: data.add(new Triple(b, RDFS.subClassOf.asNode(), d));
135: data.add(new Triple(c, RDFS.subClassOf.asNode(), d));
136: data.add(new Triple(d, RDFS.subClassOf.asNode(), e));
137: Reasoner reasoner = TransitiveReasonerFactory.theInstance()
138: .create(null);
139: InfGraph infgraph = reasoner.bind(data);
140: TestUtil.assertIteratorValues(this , infgraph.find(a,
141: RDFS.subClassOf.asNode(), null), new Object[] {
142: new Triple(a, closedP, a), new Triple(a, closedP, b),
143: new Triple(a, closedP, b), new Triple(a, closedP, c),
144: new Triple(a, closedP, d), new Triple(a, closedP, e) });
145: TestUtil.assertIteratorValues(this , infgraph.find(b,
146: RDFS.subClassOf.asNode(), null), new Object[] {
147: new Triple(b, closedP, b), new Triple(b, closedP, d),
148: new Triple(b, closedP, e) });
149: infgraph.delete(new Triple(b, closedP, d));
150: TestUtil.assertIteratorValues(this , infgraph.find(a,
151: RDFS.subClassOf.asNode(), null), new Object[] {
152: new Triple(a, closedP, a), new Triple(a, closedP, b),
153: new Triple(a, closedP, b), new Triple(a, closedP, c),
154: new Triple(a, closedP, d), new Triple(a, closedP, e) });
155: TestUtil.assertIteratorValues(this , infgraph.find(b,
156: RDFS.subClassOf.asNode(), null),
157: new Object[] { new Triple(b, closedP, b), });
158: infgraph.delete(new Triple(a, closedP, c));
159: TestUtil.assertIteratorValues(this , infgraph.find(a,
160: RDFS.subClassOf.asNode(), null), new Object[] {
161: new Triple(a, closedP, a), new Triple(a, closedP, b) });
162: TestUtil.assertIteratorValues(this , infgraph.find(b,
163: RDFS.subClassOf.asNode(), null),
164: new Object[] { new Triple(b, closedP, b) });
165: TestUtil.assertIteratorValues(this , data.find(null,
166: RDFS.subClassOf.asNode(), null), new Object[] {
167: new Triple(a, closedP, b), new Triple(c, closedP, d),
168: new Triple(d, closedP, e) });
169: }
170:
171: /**
172: * Test metalevel add/remove subproperty operations for transitive reasoner.
173: */
174: public void testTransitiveMetaLevel() {
175: doTestMetaLevel(TransitiveReasonerFactory.theInstance());
176: }
177:
178: /**
179: * Test metalevel add/remove subproperty operations for rdsf reasoner.
180: */
181: public void testRDFSMetaLevel() {
182: doTestMetaLevel(RDFSRuleReasonerFactory.theInstance());
183: }
184:
185: /**
186: * Test metalevel add/remove subproperty operations for a reasoner.
187: */
188: public void doTestMetaLevel(ReasonerFactory rf) {
189: Graph data = Factory.createGraphMem();
190: Node c1 = Node.createURI("C1");
191: Node c2 = Node.createURI("C2");
192: Node c3 = Node.createURI("C3");
193: Node p = Node.createURI("p");
194: Node q = Node.createURI("q");
195: Node sC = RDFS.subClassOf.asNode();
196: Node sP = RDFS.subPropertyOf.asNode();
197: Node ty = RDF.type.asNode();
198: data.add(new Triple(c2, sC, c3));
199: data.add(new Triple(c1, p, c2));
200: Reasoner reasoner = rf.create(null);
201: InfGraph infgraph = reasoner.bind(data);
202: TestUtil.assertIteratorValues(this ,
203: infgraph.find(c1, sC, null), new Object[] {});
204: infgraph.add(new Triple(p, q, sC));
205: TestUtil.assertIteratorValues(this ,
206: infgraph.find(c1, sC, null), new Object[] {});
207: infgraph.add(new Triple(q, sP, sP));
208: TestUtil.assertIteratorValues(this ,
209: infgraph.find(c1, sC, null), new Object[] {
210: new Triple(c1, sC, c1), new Triple(c1, sC, c2),
211: new Triple(c1, sC, c3) });
212: infgraph.delete(new Triple(p, q, sC));
213: TestUtil.assertIteratorValues(this ,
214: infgraph.find(c1, sC, null), new Object[] {});
215: }
216:
217: /**
218: * Check a complex graph's transitive reduction.
219: */
220: public void testTransitiveReduction() {
221: Model test = FileManager.get().loadModel(
222: "testing/reasoners/bugs/subpropertyModel.n3");
223: Property dp = test
224: .getProperty(TransitiveReasoner.directSubPropertyOf
225: .getURI());
226: doTestTransitiveReduction(test, dp);
227: }
228:
229: /**
230: * Test that a transitive reduction is complete.
231: * Assumes test graph has no cycles (other than the trivial
232: * identity ones).
233: */
234: public void doTestTransitiveReduction(Model model, Property dp) {
235: InfModel im = ModelFactory.createInfModel(ReasonerRegistry
236: .getTransitiveReasoner(), model);
237:
238: for (ResIterator i = im.listSubjects(); i.hasNext();) {
239: Resource base = i.nextResource();
240:
241: List directLinks = new ArrayList();
242: for (Iterator j = im.listObjectsOfProperty(base, dp); j
243: .hasNext();) {
244: directLinks.add(j.next());
245: }
246:
247: for (int n = 0; n < directLinks.size(); n++) {
248: Resource d1 = (Resource) directLinks.get(n);
249: for (int m = n + 1; m < directLinks.size(); m++) {
250: Resource d2 = (Resource) directLinks.get(m);
251:
252: if (im.contains(d1, dp, d2) && !base.equals(d1)
253: && !base.equals(d2)) {
254: assertTrue(
255: "Triangle discovered in transitive reduction",
256: false);
257: }
258: }
259: }
260: }
261: }
262:
263: /**
264: * The reasoner contract for bind(data) is not quite precise. It allows for
265: * reasoners which have state so that reusing the same reasoner on a second data
266: * model might lead to interference. This in fact used to happen with the transitive
267: * reasoner. This is a test to check the top level symptoms of this which can be
268: * solved just be not reusing reasoners.
269: * @todo this test might be better moved to OntModel tests somewhere
270: */
271: public void testTransitiveSpecReuse() {
272: OntModel om1 = ModelFactory
273: .createOntologyModel(OntModelSpec.OWL_MEM_TRANS_INF);
274: Resource c1 = om1.createResource(PrintUtil.egNS + "Class1");
275: Resource c2 = om1.createResource(PrintUtil.egNS + "Class2");
276: Resource c3 = om1.createResource(PrintUtil.egNS + "Class3");
277: om1.add(c1, RDFS.subClassOf, c2);
278: om1.add(c2, RDFS.subClassOf, c3);
279: om1.prepare();
280: assertFalse(om1.isEmpty());
281: OntModel om2 = ModelFactory
282: .createOntologyModel(OntModelSpec.OWL_MEM_TRANS_INF);
283: StmtIterator si = om2.listStatements();
284: boolean ok = !si.hasNext();
285: si.close();
286: assertTrue("Transitive reasoner state leak", ok);
287: }
288:
289: /**
290: * The reasoner contract for bind(data) is not quite precise. It allows for
291: * reasoners which have state so that reusing the same reasoner on a second data
292: * model might lead to interference. This in fact used to happen with the transitive
293: * reasoner. This is a test to check that the transitive reasoner state reuse has been fixed at source.
294: */
295: public void testTransitiveBindReuse() {
296: Reasoner r = ReasonerRegistry.getTransitiveReasoner();
297: InfModel om1 = ModelFactory.createInfModel(r, ModelFactory
298: .createDefaultModel());
299: Resource c1 = om1.createResource(PrintUtil.egNS + "Class1");
300: Resource c2 = om1.createResource(PrintUtil.egNS + "Class2");
301: Resource c3 = om1.createResource(PrintUtil.egNS + "Class3");
302: om1.add(c1, RDFS.subClassOf, c2);
303: om1.add(c2, RDFS.subClassOf, c3);
304: om1.prepare();
305: assertFalse(om1.isEmpty());
306: InfModel om2 = ModelFactory.createInfModel(r, ModelFactory
307: .createDefaultModel());
308: StmtIterator si = om2.listStatements();
309: boolean ok = !si.hasNext();
310: si.close();
311: assertTrue("Transitive reasoner state leak", ok);
312: }
313:
314: /**
315: * Test rebind operation for the RDFS reasoner
316: */
317: public void testRDFSRebind() {
318: Graph data = Factory.createGraphMem();
319: Node C1 = Node.createURI("C1");
320: Node C2 = Node.createURI("C2");
321: Node C3 = Node.createURI("C3");
322: Node C4 = Node.createURI("C4");
323: data.add(new Triple(C1, RDFS.subClassOf.asNode(), C2));
324: data.add(new Triple(C2, RDFS.subClassOf.asNode(), C3));
325: Reasoner reasoner = RDFSRuleReasonerFactory.theInstance()
326: .create(null);
327: InfGraph infgraph = reasoner.bind(data);
328: TestUtil.assertIteratorValues(this , infgraph.find(C1,
329: RDFS.subClassOf.asNode(), null), new Object[] {
330: new Triple(C1, RDFS.subClassOf.asNode(), C1),
331: new Triple(C1, RDFS.subClassOf.asNode(), C2),
332: new Triple(C1, RDFS.subClassOf.asNode(), C3) });
333: Graph data2 = Factory.createGraphMem();
334: data2.add(new Triple(C1, RDFS.subClassOf.asNode(), C2));
335: data2.add(new Triple(C2, RDFS.subClassOf.asNode(), C4));
336: infgraph.rebind(data2);
337: TestUtil.assertIteratorValues(this , infgraph.find(C1,
338: RDFS.subClassOf.asNode(), null), new Object[] {
339: new Triple(C1, RDFS.subClassOf.asNode(), C1),
340: new Triple(C1, RDFS.subClassOf.asNode(), C2),
341: new Triple(C1, RDFS.subClassOf.asNode(), C4) });
342: }
343:
344: /**
345: * Test remove operations on an RDFS reasoner instance.
346: * This is an example to test that rebing is invoked correctly rather
347: * than an RDFS-specific test.
348: */
349: public void testRDFSRemove() {
350: InfModel m = ModelFactory.createRDFSModel(ModelFactory
351: .createDefaultModel());
352: String NS = PrintUtil.egNS;
353: Property p = m.createProperty(NS, "p");
354: Resource D = m.createResource(NS + "D");
355: Resource i = m.createResource(NS + "i");
356: Resource c = m.createResource(NS + "c");
357: Resource d = m.createResource(NS + "d");
358: p.addProperty(RDFS.domain, D);
359: i.addProperty(p, c);
360: i.addProperty(p, d);
361: TestUtil
362: .assertIteratorValues(this , i.listProperties(),
363: new Object[] {
364: m.createStatement(i, p, c),
365: m.createStatement(i, p, d),
366: m.createStatement(i, RDF.type, D),
367: m.createStatement(i, RDF.type,
368: RDFS.Resource), });
369: i.removeAll(p);
370: TestUtil.assertIteratorValues(this , i.listProperties(),
371: new Object[] {});
372: }
373:
374: /**
375: * Cycle bug in transitive reasoner
376: */
377: public void testTransitiveCycleBug() {
378: Model m = FileManager.get().loadModel(
379: "file:testing/reasoners/bugs/unbroken.n3");
380: OntModel om = ModelFactory.createOntologyModel(
381: OntModelSpec.RDFS_MEM_TRANS_INF, m);
382: OntClass rootClass = om.getOntClass(RDFS.Resource.getURI());
383: Resource c = m.getResource("c");
384: Set direct = IteratorCollection.iteratorToSet(rootClass
385: .listSubClasses(true));
386: assertFalse(direct.contains(c));
387:
388: }
389:
390: /**
391: * Test the ModelFactory interface
392: */
393: public void testModelFactoryRDFS() {
394: Model data = ModelFactory.createDefaultModel();
395: Property p = data.createProperty("urn:x-hp:ex/p");
396: Resource a = data.createResource("urn:x-hp:ex/a");
397: Resource b = data.createResource("urn:x-hp:ex/b");
398: Resource C = data.createResource("urn:x-hp:ex/c");
399: data.add(p, RDFS.range, C).add(a, p, b);
400: Model result = ModelFactory.createRDFSModel(data);
401: StmtIterator i = result.listStatements(b, RDF.type,
402: (RDFNode) null);
403: TestUtil.assertIteratorValues(this , i, new Object[] {
404: data.createStatement(b, RDF.type, RDFS.Resource),
405: data.createStatement(b, RDF.type, C) });
406:
407: }
408:
409: /**
410: * Run test on findWithPremies for Transitive reasoner.
411: */
412: public void testTransitiveFindWithPremises() {
413: doTestFindWithPremises(TransitiveReasonerFactory.theInstance());
414: }
415:
416: /**
417: * Run test on findWithPremies for RDFS reasoner.
418: */
419: public void testRDFSFindWithPremises() {
420: doTestFindWithPremises(RDFSRuleReasonerFactory.theInstance());
421: }
422:
423: /**
424: * Test a reasoner's ability to implement find with premises.
425: * Assumes the reasoner can at least implement RDFS subClassOf.
426: */
427: public void doTestFindWithPremises(ReasonerFactory rf) {
428: Node c1 = Node.createURI("C1");
429: Node c2 = Node.createURI("C2");
430: Node c3 = Node.createURI("C3");
431: Node sC = RDFS.subClassOf.asNode();
432: Graph data = Factory.createGraphMem();
433: data.add(new Triple(c2, sC, c3));
434: Graph premise = Factory.createGraphMem();
435: premise.add(new Triple(c1, sC, c2));
436: Reasoner reasoner = rf.create(null);
437: InfGraph infgraph = reasoner.bind(data);
438: TestUtil.assertIteratorValues(this ,
439: infgraph.find(c1, sC, null), new Object[] {});
440: TestUtil.assertIteratorValues(this , infgraph.find(c1, sC, null,
441: premise), new Object[] { new Triple(c1, sC, c2),
442: new Triple(c1, sC, c3), new Triple(c1, sC, c1) });
443: TestUtil.assertIteratorValues(this ,
444: infgraph.find(c1, sC, null), new Object[] {});
445:
446: }
447:
448: /**
449: * Test for duplicate statements in a constructed ontology.
450: */
451: public void testDuplicateStatements() {
452: String NS = "http://swt/test#";
453: OntModelSpec s = new OntModelSpec(ModelFactory
454: .createMemModelMaker(), null, null,
455: ProfileRegistry.DAML_LANG);
456: OntModel model = ModelFactory.createOntologyModel(
457: OntModelSpec.OWL_DL_MEM_RULE_INF, null);
458:
459: OntClass documentC = model.createClass(NS + "DOCUMENT");
460: OntClass topicC = model.createClass(NS + "TOPIC");
461:
462: ObjectProperty hasTopicP = model.createObjectProperty(NS
463: + "hasTopic");
464: hasTopicP.addDomain(documentC);
465: hasTopicP.addRange(topicC);
466: ObjectProperty hasDocP = model.createObjectProperty(NS
467: + "hasDocument");
468: hasDocP.addDomain(topicC);
469: hasDocP.addRange(documentC);
470: hasDocP.setInverseOf(hasTopicP);
471:
472: Individual fooTopic = model.createIndividual(NS + "fooTopic",
473: topicC);
474: Individual fooDoc = model.createIndividual(NS + "fooDoc",
475: documentC);
476:
477: fooDoc.addProperty(hasTopicP, fooTopic);
478:
479: TestUtil.assertIteratorLength(fooDoc.listProperties(hasTopicP),
480: 1);
481: }
482:
483: }
484:
485: /*
486: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
487: All rights reserved.
488:
489: Redistribution and use in source and binary forms, with or without
490: modification, are permitted provided that the following conditions
491: are met:
492:
493: 1. Redistributions of source code must retain the above copyright
494: notice, this list of conditions and the following disclaimer.
495:
496: 2. Redistributions in binary form must reproduce the above copyright
497: notice, this list of conditions and the following disclaimer in the
498: documentation and/or other materials provided with the distribution.
499:
500: 3. The name of the author may not be used to endorse or promote products
501: derived from this software without specific prior written permission.
502:
503: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
504: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
505: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
506: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
507: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
508: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
509: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
510: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
511: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
512: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
513: */
|