| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jena.reasoner.rulesys.test; |
| |
| import java.io.StringReader ; |
| import java.util.* ; |
| |
| import junit.framework.TestCase ; |
| import junit.framework.TestSuite ; |
| import org.apache.jena.graph.Node ; |
| import org.apache.jena.graph.NodeFactory ; |
| import org.apache.jena.graph.Triple ; |
| import org.apache.jena.graph.impl.LiteralLabelFactory ; |
| import org.apache.jena.ontology.* ; |
| import org.apache.jena.rdf.listeners.StatementListener ; |
| import org.apache.jena.rdf.model.* ; |
| import org.apache.jena.reasoner.* ; |
| import org.apache.jena.reasoner.rulesys.* ; |
| import org.apache.jena.reasoner.rulesys.builtins.BaseBuiltin ; |
| import org.apache.jena.reasoner.test.TestUtil ; |
| import org.apache.jena.util.FileManager ; |
| import org.apache.jena.util.PrintUtil ; |
| import org.apache.jena.util.iterator.ClosableIterator ; |
| import org.apache.jena.util.iterator.ExtendedIterator ; |
| import org.apache.jena.vocabulary.OWL ; |
| import org.apache.jena.vocabulary.RDF ; |
| import org.apache.jena.vocabulary.RDFS ; |
| import org.apache.jena.vocabulary.ReasonerVocabulary ; |
| |
| |
| /** |
| * Unit tests for reported bugs in the rule system. |
| */ |
| public class TestBugs extends TestCase { |
| |
| /** |
| * Boilerplate for junit |
| */ |
| public TestBugs( String name ) { |
| super( name ); |
| } |
| |
| /** |
| * Boilerplate for junit. |
| * This is its own test suite |
| */ |
| public static TestSuite suite() { |
| return new TestSuite( TestBugs.class ); |
| // TestSuite suite = new TestSuite(); |
| // suite.addTest(new TestBugs( "testLayeredValidation" )); |
| // return suite; |
| } |
| |
| @Override |
| public void setUp() { |
| // ensure the ont doc manager is in a consistent state |
| OntDocumentManager.getInstance().reset( true ); |
| } |
| |
| /** |
| * Report of NPE during processing on an ontology with a faulty intersection list, |
| * from Hugh Winkler. |
| */ |
| public void testIntersectionNPE() { |
| Model base = ModelFactory.createDefaultModel(); |
| base.read("file:testing/reasoners/bugs/bad-intersection.owl"); |
| boolean foundBadList = false; |
| try { |
| InfGraph infgraph = ReasonerRegistry.getOWLReasoner().bind(base.getGraph()); |
| ExtendedIterator<Triple> ci = infgraph.find(null, RDF.Nodes.type, OWL.Class.asNode()); |
| ci.close(); |
| } catch (ReasonerException e) { |
| foundBadList = true; |
| } |
| assertTrue("Correctly detected the illegal list", foundBadList); |
| } |
| |
| /** |
| * Report of functor literals leaking out of inference graphs and raising CCE |
| * in iterators. |
| */ |
| public void testFunctorCCE() { |
| Model base = ModelFactory.createDefaultModel(); |
| base.read("file:testing/reasoners/bugs/cceTest.owl"); |
| InfModel test = ModelFactory.createInfModel(ReasonerRegistry.getOWLReasoner(), base); |
| |
| // boolean b = |
| anyInstancesOfNothing(test); |
| ResIterator rIter = test.listSubjects(); |
| while (rIter.hasNext()) { |
| // Resource res = |
| rIter.nextResource(); |
| } |
| } |
| |
| /** Helper function used in testFunctorCCE */ |
| private boolean anyInstancesOfNothing(Model model) { |
| boolean hasAny = false; |
| try { |
| ExtendedIterator<Statement> it = model.listStatements(null, RDF.type, OWL.Nothing); |
| hasAny = it.hasNext(); |
| it.close(); |
| } catch (ConversionException x) { |
| hasAny = false; |
| } |
| return hasAny; |
| } |
| |
| public static final String INPUT_SUBCLASS = |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + |
| "" + |
| "<rdf:RDF" + |
| " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" + |
| " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"" + |
| " xmlns:daml=\"http://www.daml.org/2001/03/daml+oil#\"" + |
| " xmlns:ex=\"http://localhost:8080/axis/daml/a.daml#\"" + |
| " xml:base=\"http://localhost:8080/axis/daml/a.daml\">" + |
| " " + |
| " <daml:Ontology rdf:about=\"\">" + |
| " <daml:imports rdf:resource=\"http://www.daml.org/2001/03/daml+oil\"/>" + |
| " </daml:Ontology>" + |
| " " + |
| " <daml:Class rdf:ID=\"cls1\"/>" + |
| " <daml:Class rdf:ID=\"cls2\">" + |
| " <daml:subClassOf rdf:resource=\"#cls1\"/>" + |
| " </daml:Class>" + |
| " <ex:cls2 rdf:ID=\"test\"/>" + |
| "</rdf:RDF>"; |
| |
| public static final String INPUT_SUBPROPERTY = |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + |
| "" + |
| "<rdf:RDF" + |
| " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" + |
| " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"" + |
| " xmlns:daml=\"http://www.daml.org/2001/03/daml+oil#\"" + |
| " xmlns=\"urn:x-hp-jena:test#\"" + |
| " xml:base=\"urn:x-hp-jena:test\">" + |
| " " + |
| " <daml:Ontology rdf:about=\"\">" + |
| " <daml:imports rdf:resource=\"http://www.daml.org/2001/03/daml+oil\"/>" + |
| " </daml:Ontology>" + |
| " " + |
| " <daml:Class rdf:ID=\"A\"/>" + |
| "" + |
| " <daml:ObjectProperty rdf:ID=\"p\" />" + |
| " <daml:ObjectProperty rdf:ID=\"q\">" + |
| " <daml:subPropertyOf rdf:resource=\"#p\"/>" + |
| " </daml:ObjectProperty>" + |
| "" + |
| " <A rdf:ID=\"a0\"/>" + |
| " <A rdf:ID=\"a1\">" + |
| " <q rdf:resource=\"#a0\" />" + |
| " </A>" + |
| "</rdf:RDF>"; |
| |
| /** |
| * Test for a reported bug in delete |
| */ |
| public void testDeleteBug() { |
| Model modelo = ModelFactory.createDefaultModel(); |
| modelo.read("file:testing/reasoners/bugs/deleteBug.owl"); |
| OntModel modeloOnt = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM_RULE_INF, modelo ); |
| Individual indi = modeloOnt.getIndividual("http://decsai.ugr.es/~ontoserver/bacarex2.owl#JS"); |
| indi.remove(); |
| ClosableIterator<Statement> it = modeloOnt.listStatements(indi, null, (RDFNode) null); |
| boolean ok = ! it.hasNext(); |
| it.close(); |
| assertTrue(ok); |
| } |
| |
| /** |
| * Test bug caused by caching of deductions models. |
| */ |
| public void testDeteleBug2() { |
| Model m = ModelFactory.createDefaultModel(); |
| String NS = PrintUtil.egNS; |
| Resource r = m.createResource(NS + "r"); |
| Resource A = m.createResource(NS + "A"); |
| Resource B = m.createResource(NS + "B"); |
| Statement s = m.createStatement(r, RDF.type, A); |
| m.add(s); |
| String rules = "(?r rdf:type eg:A) -> (?r rdf:type eg:B)."; |
| GenericRuleReasoner grr = new GenericRuleReasoner(Rule.parseRules(rules)); |
| InfModel im = ModelFactory.createInfModel(grr, m); |
| assertTrue(im.contains(r, RDF.type, B)); |
| assertTrue(im.getDeductionsModel().contains(r, RDF.type, B)); |
| im.remove(s); |
| assertFalse(im.contains(r, RDF.type, B)); |
| assertFalse(im.getDeductionsModel().contains(r, RDF.type, B)); |
| } |
| |
| /** |
| * Test that prototype nodes are now hidden |
| */ |
| public void testHide() { |
| String NS = "http://jena.hpl.hp.com/bugs#"; |
| OntModel m = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_RULE_INF, null); |
| OntClass c = m.createClass(NS + "C"); |
| OntResource i = m.createIndividual(c); |
| Iterator<Statement> res = m.listStatements(null, RDF.type, c); |
| TestUtil.assertIteratorValues(this, res, new Statement[] { |
| m.createStatement(i, RDF.type, c) |
| }); |
| } |
| |
| /** |
| * Also want to have hidden rb:xsdRange |
| */ |
| public void testHideXSDRange() { |
| OntModelSpec[] specs = new OntModelSpec[] { |
| OntModelSpec.OWL_MEM_RULE_INF, |
| OntModelSpec.OWL_MEM_RDFS_INF, |
| OntModelSpec.OWL_MEM_MINI_RULE_INF, |
| OntModelSpec.OWL_MEM_MICRO_RULE_INF |
| }; |
| for (int os = 0; os < specs.length; os++) { |
| OntModelSpec spec = specs[os]; |
| OntModel m = ModelFactory.createOntologyModel(spec, null); |
| Iterator<OntProperty> i = m.listOntProperties(); |
| while (i.hasNext()) { |
| Resource r = i.next(); |
| if (r.getURI() != null && r.getURI().startsWith(ReasonerVocabulary.RBNamespace)) { |
| assertTrue("Rubrik internal property leaked out: " + r + "(" + os + ")", false); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Test problem with bindSchema not interacting properly with validation. |
| */ |
| public void testBindSchemaValidate() { |
| Reasoner reasoner = ReasonerRegistry.getOWLReasoner(); |
| Model schema = FileManager.getInternal().loadModelInternal("file:testing/reasoners/bugs/sbug.owl"); |
| Model data = FileManager.getInternal().loadModelInternal("file:testing/reasoners/bugs/sbug.rdf"); |
| |
| // Union version |
| InfModel infu = ModelFactory.createInfModel(reasoner, data.union(schema)); |
| ValidityReport validity = infu.validate(); |
| assertTrue( ! validity.isValid()); |
| // debug print |
| // for (Iterator i = validity.getReports(); i.hasNext(); ) { |
| // System.out.println(" - " + i.next()); |
| // } |
| |
| // bindSchema version |
| InfModel inf = ModelFactory.createInfModel(reasoner.bindSchema(schema), data); |
| validity = inf.validate(); |
| assertTrue( ! validity.isValid()); |
| } |
| |
| /** |
| * Delete bug in generic rule reasoner. |
| */ |
| public void testGenericDeleteBug() { |
| Model data = ModelFactory.createDefaultModel(); |
| String NS = "urn:x-hp:eg/"; |
| Property p = data.createProperty(NS, "p"); |
| Resource x = data.createResource(NS + "x"); |
| Resource y = data.createResource(NS + "y"); |
| Statement sy = data.createStatement(y, p, "foo"); |
| data.add(sy); |
| data.add(x, p, "foo"); |
| // String rule = "[(?x eg:p ?m) -> (?x eg:same ?x)]"; |
| String rule = "[(?x eg:p ?m) (?y eg:p ?m) -> (?x eg:same ?y) (?y eg:same ?x)]"; |
| GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory.theInstance().create(null); |
| reasoner.setMode(GenericRuleReasoner.FORWARD_RETE); |
| reasoner.setRules(Rule.parseRules(rule)); |
| InfModel inf = ModelFactory.createInfModel(reasoner, data); |
| TestUtil.assertIteratorLength(inf.listStatements(y, null, (RDFNode)null), 3); |
| inf.remove(sy); |
| TestUtil.assertIteratorLength(inf.listStatements(y, null, (RDFNode)null), 0); |
| } |
| |
| /** |
| * RETE incremental processing bug. |
| */ |
| public void testRETEInc() { |
| String rule = "(?x ?p ?y) -> (?p rdf:type rdf:Property) ."; |
| Reasoner r = new GenericRuleReasoner(Rule.parseRules(rule)); |
| InfModel m = ModelFactory.createInfModel(r, ModelFactory.createDefaultModel()); |
| |
| Resource source = m.createResource("urn:alfie:testResource"); |
| Property prop = m.createProperty("urn:alfie:testProperty"); |
| Statement s1=m.createStatement(source, prop, "value1"); |
| Statement s2=m.createStatement(source, prop, "value2"); |
| |
| m.add(s1); |
| assertIsProperty(m, prop); |
| m.add(s2); |
| m.remove(s1); |
| assertIsProperty(m, prop); |
| } |
| |
| /** |
| * RETE incremental processing bug. |
| */ |
| public void testRETEDec() { |
| String rule = "(?x ?p ?y) -> (?p rdf:type rdf:Property) ."; |
| Reasoner r = new GenericRuleReasoner(Rule.parseRules(rule)); |
| InfModel m = ModelFactory.createInfModel(r, ModelFactory.createDefaultModel()); |
| |
| Resource source = m.createResource("urn:alfie:testResource"); |
| Property prop = m.createProperty("urn:alfie:testProperty"); |
| Statement s1=m.createStatement(source, prop, "value1"); |
| m.createStatement(source, prop, "value2"); |
| |
| m.add(prop, RDF.type, RDF.Property); |
| m.add(s1); |
| m.prepare(); |
| m.remove(s1); |
| assertIsProperty(m, prop); |
| } |
| |
| private void assertIsProperty(Model m, Property prop) { |
| assertTrue(m.contains(prop, RDF.type, RDF.Property)); |
| } |
| |
| |
| /** |
| * Bug that exposed prototypes of owl:Thing despite hiding being switched on. |
| */ |
| public void testHideOnOWLThing() { |
| Reasoner r = ReasonerRegistry.getOWLReasoner(); |
| Model data = ModelFactory.createDefaultModel(); |
| InfModel inf = ModelFactory.createInfModel(r, data); |
| StmtIterator things = inf.listStatements(null, RDF.type, OWL.Thing); |
| TestUtil.assertIteratorLength(things, 0); |
| } |
| |
| /** |
| * Utility function. |
| * Create a model from an N3 string with OWL and EG namespaces defined. |
| */ |
| public static Model modelFromN3(String src) { |
| String fullSource = "@prefix owl: <http://www.w3.org/2002/07/owl#> .\n" + |
| "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n" + |
| "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n" + |
| "@prefix eg: <http://jena.hpl.hp.com/eg#> .\n" + |
| "@prefix : <#> .\n"+ src + "\n"; |
| Model result = ModelFactory.createDefaultModel(); |
| result.read(new StringReader(fullSource), "", "N3"); |
| return result; |
| } |
| |
| /** Bug report from Ole Hjalmar - direct subClassOf not reporting correct result with rule reasoner */ |
| /** TODO: ijd - I temporarily disabled this test: I think we either have to remove it, rewrite it or get a license from Ole */ |
| public void xxtest_oh_01() { |
| String NS = "http://www.idi.ntnu.no/~herje/ja/"; |
| Resource[] expected = new Resource[] { |
| ResourceFactory.createResource( NS+"reiseliv.owl#Reiseliv" ), |
| ResourceFactory.createResource( NS+"hotell.owl#Hotell" ), |
| ResourceFactory.createResource( NS+"restaurant.owl#Restaurant" ), |
| ResourceFactory.createResource( NS+"restaurant.owl#UteRestaurant" ), |
| ResourceFactory.createResource( NS+"restaurant.owl#UteBadRestaurant" ), |
| ResourceFactory.createResource( NS+"restaurant.owl#UteDoRestaurant" ), |
| ResourceFactory.createResource( NS+"restaurant.owl#SkogRestaurant" ), |
| }; |
| |
| test_oh_01scan( OntModelSpec.OWL_MEM, "No inf", expected ); |
| test_oh_01scan( OntModelSpec.OWL_MEM_MINI_RULE_INF, "Mini rule inf", expected ); |
| test_oh_01scan( OntModelSpec.OWL_MEM_MICRO_RULE_INF, "Micro rule inf", expected ); |
| test_oh_01scan( OntModelSpec.OWL_MEM_RULE_INF, "Full rule inf", expected ); |
| } |
| |
| /** Problem with bindSchema and validation rules */ |
| public void test_der_validation() { |
| Model abox = FileManager.getInternal().loadModelInternal("file:testing/reasoners/owl/nondetbug.rdf"); |
| List<Rule> rules = FBRuleReasoner.loadRules("testing/reasoners/owl/nondetbug.rules"); |
| GenericRuleReasoner r = new GenericRuleReasoner(rules); |
| // r.setTraceOn(true); |
| for (int i = 0; i < 10; i++) { |
| InfModel im = ModelFactory.createInfModel(r, abox); |
| assertTrue("failed on count " + i, im.contains(null, ReasonerVocabulary.RB_VALIDATION_REPORT, (RDFNode)null)); |
| } |
| } |
| |
| // Temporary for debug |
| private void test_oh_01scan( OntModelSpec s, String prompt, Resource[] expected ) { |
| String NS = "http://www.idi.ntnu.no/~herje/ja/reiseliv.owl#"; |
| OntModel m = ModelFactory.createOntologyModel(s, null); |
| m.read( "file:testing/ontology/bugs/test_oh_01.owl"); |
| |
| // System.out.println( prompt ); |
| OntClass r = m.getOntClass( NS + "Reiseliv" ); |
| |
| List<OntClass> q = new ArrayList<>(); |
| Set<OntClass> seen = new HashSet<>(); |
| q.add( r ); |
| |
| while (!q.isEmpty()) { |
| OntClass c = q.remove( 0 ); |
| seen.add( c ); |
| |
| for (Iterator<OntClass> i = c.listSubClasses( true ); i.hasNext(); ) { |
| OntClass sub = i.next(); |
| if (!seen.contains( sub )) { |
| q.add( sub ); |
| } |
| } |
| |
| // System.out.println( " Seen class " + c ); |
| } |
| |
| // check we got all classes |
| int mask = (1 << expected.length) - 1; |
| |
| for (int j = 0; j < expected.length; j++) { |
| if (seen.contains( expected[j] )) { |
| mask &= ~(1 << j); |
| } |
| else { |
| // System.out.println( "Expected but did not see " + expected[j] ); |
| } |
| } |
| |
| for ( OntClass res : seen ) |
| { |
| boolean isExpected = false; |
| for ( int j = 0; !isExpected && j < expected.length; j++ ) |
| { |
| isExpected = expected[j].equals( res ); |
| } |
| if ( !isExpected ) |
| { |
| // System.out.println( "Got unexpected result " + res ); |
| } |
| } |
| |
| assertEquals( "Some expected results were not seen", 0, mask ); |
| } |
| |
| /** |
| * Bug report from David A Bigwood |
| */ |
| public void test_domainInf() { |
| // create an OntModel |
| OntModel m = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_RULE_INF, null ); |
| // populate the model with stuff |
| String NS = "http://m3t4.com/ont/#"; |
| OntClass c1 = m.createClass( NS + "c1" ); |
| OntClass c2 = m.createClass( NS + "c2" ); |
| OntClass c3 = m.createClass( NS + "c3" ); |
| OntProperty p1 = m.createObjectProperty( NS + "p1" ); |
| // create a union class to contain the union operands |
| UnionClass uc = m.createUnionClass(null, null); |
| // add an operand |
| uc.addOperand( c1 ); |
| assertEquals( "Size should be 1", 1, uc.getOperands().size() ); |
| assertTrue( "uc should have c1 as union member", uc.getOperands().contains( c1 ) ); |
| // add another operand |
| uc.addOperand( c2 ); |
| assertEquals( "Size should be 2", 2, uc.getOperands().size() ); |
| TestUtil.assertIteratorValues(this, uc.listOperands(), new Object[] { c1, c2 } ); |
| // add a third operand |
| uc.addOperand( c3 ); |
| assertEquals( "Size should be 3", 3, uc.getOperands().size() ); |
| TestUtil.assertIteratorValues(this, uc.listOperands(), new Object[] { c1, c2, c3} ); |
| // add union class as domain of a property |
| p1.addDomain(uc); |
| } |
| |
| /** |
| * Bug report on bad conflict resolution between two non-monotonic rules. |
| */ |
| public void testNonmonotonicCR() { |
| String ruleSrc = "(eg:IndA eg:scoreA ?score), sum(?score 40 ?total), noValue(eg:IndA eg:flag_1 'true') -> drop(0), (eg:IndA eg:scoreA ?total), (eg:IndA eg:flag_1 'true')." + |
| "(eg:IndA eg:scoreA ?score), sum(?score 33 ?total), noValue(eg:IndA eg:flag_2 'true') -> drop(0), (eg:IndA eg:scoreA ?total), (eg:IndA eg:flag_2 'true')."; |
| List<Rule> rules = Rule.parseRules(ruleSrc); |
| Model data = ModelFactory.createDefaultModel(); |
| String NS = PrintUtil.egNS; |
| Resource i = data.createResource(NS + "IndA"); |
| Property scoreA = data.createProperty(NS, "scoreA"); |
| i.addProperty(scoreA, data.createTypedLiteral(100)); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| InfModel inf = ModelFactory.createInfModel(reasoner, data); |
| Iterator<RDFNode> values = inf.listObjectsOfProperty(i, scoreA); |
| TestUtil.assertIteratorValues(this, values, new Object[] { data.createTypedLiteral(173)}); |
| } |
| |
| /** |
| * Bug report - intersection processing does not work incrementally. |
| */ |
| public void testIncrementalIU() { |
| OntModel ontmodel = ModelFactory.createOntologyModel( |
| OntModelSpec.OWL_MEM_MINI_RULE_INF ); |
| String homeuri = "http://abc/bcd/"; |
| |
| Individual ind[] = new Individual[6]; |
| OntClass classb = ontmodel.createClass(homeuri + "C"); |
| for (int i = 0; i < 6; i++){ |
| ind[i] = classb.createIndividual(homeuri + String.valueOf(i)); |
| } |
| Individual subind[] = new Individual[] {ind[0], ind[1], ind[2]}; |
| |
| EnumeratedClass class1 = ontmodel.createEnumeratedClass( |
| homeuri+"C1", ontmodel.createList(subind) ); |
| EnumeratedClass class2 = ontmodel.createEnumeratedClass( |
| homeuri+"C2", ontmodel.createList(ind)); |
| |
| RDFList list = ontmodel.createList(new RDFNode[] { class1, class2 }); |
| IntersectionClass classI = ontmodel.createIntersectionClass(null, list); |
| UnionClass classU = ontmodel.createUnionClass(null, list); |
| |
| // Works with rebind, bug is that it doesn't work without rebind |
| // ontmodel.rebind(); |
| |
| TestUtil.assertIteratorValues(this, classI.listInstances(), subind); |
| TestUtil.assertIteratorValues(this, classU.listInstances(), ind); |
| } |
| |
| /** |
| * Fact rules with non-empty bodyies failed to fire. |
| */ |
| public void testFactRules() { |
| Model facts = ModelFactory.createDefaultModel(); |
| String NS = PrintUtil.egNS; |
| Property p = facts.createProperty(NS + "p"); |
| List<Rule> rules = Rule.parseRules("makeTemp(?x) -> (?x, eg:p, eg:z). " + |
| "makeTemp(?x) makeTemp(?y) -> (?x, eg:p, ?y) . " + |
| "(?x, eg:p, eg:z) -> (?a, eg:p, eg:b). " + |
| "-> [ (eg:a eg:p eg:y) <- ]." |
| ); |
| |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| InfModel inf = ModelFactory.createInfModel(reasoner, facts); |
| inf.prepare(); |
| TestUtil.assertIteratorLength(inf.listStatements(null, p, (RDFNode)null), 4); |
| } |
| |
| /** |
| * Test chainging rules from axioms which broke while trying to |
| * fix about test case. |
| */ |
| public void testFactChainRules() { |
| Model facts = ModelFactory.createDefaultModel(); |
| String NS = PrintUtil.egNS; |
| Property mother = facts.createProperty(NS + "mother"); |
| Resource female = facts.createProperty(NS + "Female"); |
| mother.addProperty(RDFS.range, female); |
| List<Rule> rules = Rule.parseRules( |
| "-> tableAll(). \n" + |
| "[rdfs6: (?p rdfs:subPropertyOf ?q), notEqual(?p,?q) -> [ (?a ?q ?b) <- (?a ?p ?b)] ] \n" + |
| "-> (eg:range rdfs:subPropertyOf rdfs:range). \n" + |
| "-> (rdfs:range rdfs:subPropertyOf eg:range). \n" ); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| reasoner.setTransitiveClosureCaching(true); |
| InfModel inf = ModelFactory.createInfModel(reasoner, facts); |
| Property egRange = inf.createProperty(NS + "range"); |
| TestUtil.assertIteratorValues(this, |
| inf.listStatements(null, egRange, (RDFNode)null), |
| new Object[] {inf.createStatement(mother, egRange, female)} ); |
| } |
| |
| /** |
| * test remove operator in case with empty data. |
| */ |
| public void testEmptyRemove() { |
| List<Rule> rules = Rule.parseRules( |
| "-> (eg:i eg:prop eg:foo) ." + |
| "(?X eg:prop ?V) -> (?X eg:prop2 ?V) ." + |
| "(?X eg:prop eg:foo) noValue(?X eg:guard 'done') -> remove(0) (?X eg:guard 'done') ." ); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| InfModel im = ModelFactory.createInfModel(reasoner, ModelFactory.createDefaultModel()); |
| Resource i = im.createResource(PrintUtil.egNS + "i"); |
| Property guard = im.createProperty(PrintUtil.egNS + "guard"); |
| TestUtil.assertIteratorValues(this, |
| im.listStatements(), new Object[] {im.createStatement(i, guard, "done")}); |
| } |
| |
| /** |
| * test duplicate removal when using pure backward rules |
| */ |
| public void testBackwardDupRemoval() { |
| String NS = PrintUtil.egNS; |
| Model base = ModelFactory.createDefaultModel(); |
| Resource i = base.createResource(NS + "i"); |
| Resource a = base.createResource(NS + "a"); |
| Property p = base.createProperty(NS, "p"); |
| Property q = base.createProperty(NS, "q"); |
| Property r = base.createProperty(NS, "r"); |
| base.add(i, p, a); |
| base.add(i, q, a); |
| List<Rule> rules = Rule.parseRules( |
| "(eg:i eg:r eg:a) <- (eg:i eg:p eg:a). (eg:i eg:r eg:a) <- (eg:i eg:q eg:a)."); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| reasoner.setMode(GenericRuleReasoner.BACKWARD); |
| InfModel im = ModelFactory.createInfModel(reasoner, base); |
| TestUtil.assertIteratorLength(im.listStatements(i, r, a), 1); |
| } |
| |
| /** |
| * Test closure of grounded choice points |
| */ |
| public void testGroundClosure() { |
| Flag myFlag = new Flag(); |
| BuiltinRegistry.theRegistry.register(myFlag); |
| String NS = "http://ont.com/"; |
| PrintUtil.registerPrefix("ns", NS); |
| String rules = |
| "[r1: (ns:a ns:p ns:b) <- (ns:a ns:p ns:a)] " + |
| "[r2: (ns:a ns:p ns:b) <- flag()] " + |
| "[rt: (?a ns:q ?b) <- (?a ns:p ?b)] "; |
| Model m = ModelFactory.createDefaultModel(); |
| Resource a = m.createResource(NS + "a"); |
| Resource b = m.createResource(NS + "b"); |
| Property p = m.createProperty(NS + "p"); |
| Property q = m.createProperty(NS + "q"); |
| m.add(a, p, a); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(Rule.parseRules(rules)); |
| InfModel infModel = ModelFactory.createInfModel(reasoner, m); |
| assertTrue( infModel.contains(a, q, b) ); |
| assertTrue( ! myFlag.fired ); |
| } |
| |
| /** |
| * Test closure of grounded choice points |
| */ |
| public void testGroundClosure2() { |
| Flag myFlag = new Flag(); |
| BuiltinRegistry.theRegistry.register(myFlag); |
| List<Rule> rules = Rule.rulesFromURL("file:testing/reasoners/bugs/groundClosure2.rules"); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner( rules ); |
| InfModel inf = ModelFactory.createInfModel(reasoner, ModelFactory.createDefaultModel()); |
| |
| String NS = "http://jena.hpl.hp.com/example#"; |
| Resource Phil = inf.getResource(NS + "Phil"); |
| Resource Paul = inf.getResource(NS + "Paul"); |
| Property parent = inf.getProperty(NS + "parent"); |
| assertTrue ( inf.contains(Paul, parent, Phil) ); |
| assertTrue( ! myFlag.fired ); |
| } |
| |
| /** |
| * Test case for a reported CME bug in the transitive reasoner |
| */ |
| public void testCMEInTrans() { |
| OntModel model = |
| ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_TRANS_INF); |
| model.read("file:testing/reasoners/bugs/tgcCMEbug.owl"); |
| } |
| |
| /** |
| * Test case for reported problem in detecting cardinality violations |
| */ |
| public void testIndCardValidation() { |
| final String NS = "http://dummy#"; |
| |
| // prepare TBox |
| OntModel tBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM); |
| OntClass moleculeClass = tBox.createClass(NS + "Molecule"); |
| // add value constraint on molecule2atom |
| ObjectProperty molecule2atomOntProperty = tBox.createObjectProperty(NS + "molecule2atom"); |
| molecule2atomOntProperty.setDomain(moleculeClass); |
| molecule2atomOntProperty.setRange(RDF.Bag); |
| // add cardinality constraint on molecule2atom |
| CardinalityRestriction molecule2atomCardinalityRestriction |
| = tBox.createCardinalityRestriction(null, molecule2atomOntProperty, 1); |
| moleculeClass.addSuperClass(molecule2atomCardinalityRestriction); |
| |
| // prepare ABox |
| Reasoner reasoner = ReasonerRegistry.getOWLReasoner(); |
| reasoner = reasoner.bindSchema(tBox); |
| Model model = ModelFactory.createDefaultModel(); |
| InfModel aBox = ModelFactory.createInfModel(reasoner, model); |
| |
| // make sure rdfs:member properties are inferred |
| // ((FBRuleInfGraph)aBox.getGraph()).addPreprocessingHook(new RDFSCMPPreprocessHook()); |
| |
| // create an invalid molecule |
| Bag bag1 = aBox.createBag(); |
| Bag bag2 = aBox.createBag(); |
| bag1.addProperty(OWL.differentFrom, bag2); |
| Resource molecule = aBox.createResource(); |
| molecule.addProperty(molecule2atomOntProperty, bag1); |
| molecule.addProperty(molecule2atomOntProperty, bag2); |
| |
| // check if model has become invalid |
| assertTrue(aBox.contains(molecule, RDF.type, moleculeClass)); |
| assertFalse(aBox.validate().isValid()); // fails: why? |
| } |
| |
| /** |
| * Listeners on deductions graph should be preserved across rebind operations |
| */ |
| public void testDeductionListener() { |
| final String NS = PrintUtil.egNS; |
| |
| // Data: (eg:i eg:p 'foo') |
| Model base = ModelFactory.createDefaultModel(); |
| Resource i = base.createResource(NS + "i"); |
| Property p = base.createProperty(NS + "p"); |
| i.addProperty(p, "foo"); |
| |
| // Inf model |
| List<Rule> rules = Rule.parseRules( "(?x eg:p ?y) -> (?x eg:q ?y). " ); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| InfModel infModel = ModelFactory.createInfModel(reasoner, base); |
| |
| TestListener listener = new TestListener(); |
| infModel.getDeductionsModel().register(listener); |
| infModel.rebind(); infModel.prepare(); |
| assertEquals("foo", listener.getLastValue()); |
| |
| i.removeAll(p); |
| i.addProperty(p, "bar"); |
| infModel.rebind(); infModel.prepare(); |
| assertEquals("bar", listener.getLastValue()); |
| } |
| |
| /** |
| * Listener class used in testing. Decects (* eg:q ?l) patterns |
| * and notes the last value of ?l seen and returns it as a literal string. |
| */ |
| private class TestListener extends StatementListener { |
| final Property Q = ResourceFactory.createProperty(PrintUtil.egNS + "q"); |
| RDFNode lastValue = null; |
| |
| public Object getLastValue() { |
| if (lastValue != null && lastValue.isLiteral()) { |
| return ((Literal)lastValue).getLexicalForm(); |
| } else { |
| return lastValue; |
| } |
| } |
| |
| @Override |
| public void addedStatement( Statement s ) { |
| if (s.getPredicate().equals(Q)) { |
| lastValue = s.getObject(); |
| } |
| } |
| } |
| |
| /** |
| * Problems with getDeductionsModel not rerunning prepare at OntModel level |
| */ |
| public void testOntModelGetDeductions() { |
| List<Rule> rules = Rule.parseRules( "(?x rdfs:subClassOf ?y) (?i rdf:type ?x) -> (?i rdf:type ?y)." ); |
| GenericRuleReasoner reasoner = new GenericRuleReasoner(rules); |
| OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM); |
| spec.setReasoner(reasoner); |
| OntModel om = ModelFactory.createOntologyModel(spec); |
| OntClass A = om.createClass(PrintUtil.egNS + "A"); |
| OntClass B = om.createClass(PrintUtil.egNS + "B"); |
| OntResource i = om.createOntResource(PrintUtil.egNS + "i"); |
| A.addSuperClass(B); |
| i.addRDFType(A); |
| Model deductions = om.getDeductionsModel(); |
| i.removeRDFType(A); |
| deductions = om.getDeductionsModel(); |
| assertFalse("Deductions model updating correctly", deductions.contains(i, RDF.type, B)); |
| } |
| |
| /** |
| * Builtin which just records whether it has been called. |
| * Used in implementing testGroundClosure. |
| */ |
| private static class Flag extends BaseBuiltin { |
| @Override |
| public String getName() { return "flag"; } |
| public boolean fired = false; |
| @Override |
| public boolean bodyCall(Node[] args, int length, RuleContext context) { |
| fired = true; |
| return true; |
| } |
| } |
| |
| /** |
| * Check ability to report literals as well as resources as culprits |
| */ |
| public void testLiteralsInErrorReports() { |
| RDFNode culprit = doTestLiteralsInErrorReports("-> (eg:a eg:p 42). (?X rb:violation error('test', 'arg')) <- (?S eg:p ?X)."); |
| assertEquals( culprit, ResourceFactory.createTypedLiteral( new Integer(42) )); |
| culprit = doTestLiteralsInErrorReports("-> (eg:a eg:p 'foo'). (?X rb:violation error('test', 'arg')) <- (?S eg:p ?X)."); |
| assertEquals( culprit, ResourceFactory.createPlainLiteral("foo")); |
| BuiltinRegistry.theRegistry.register( new SomeTriple() ); |
| culprit = doTestLiteralsInErrorReports("-> (eg:a eg:p 42). (?X rb:violation error('test', 'arg')) <- (?S eg:p ?Y), someTriple(?X)."); |
| assertTrue( culprit.isLiteral() ); |
| Object val = ((Literal)culprit).getValue(); |
| assertTrue( val instanceof Triple); |
| } |
| |
| private RDFNode doTestLiteralsInErrorReports(String rules) { |
| GenericRuleReasoner reasoner = new GenericRuleReasoner( Rule.parseRules(rules) ); |
| InfModel im = ModelFactory.createInfModel(reasoner, ModelFactory.createDefaultModel()); |
| ValidityReport validity = im.validate(); |
| assertTrue (! validity.isValid()); |
| ValidityReport.Report report = (validity.getReports().next()); |
| assertTrue( report.getExtension() instanceof RDFNode); |
| return (RDFNode)report.getExtension(); |
| } |
| |
| /** |
| * Builtin which generates an arbitrary Triple to for testing. |
| */ |
| private static class SomeTriple extends BaseBuiltin { |
| @Override |
| public String getName() { return "someTriple"; } |
| @Override |
| public int getArgLength() { return 1; } |
| @Override |
| public boolean bodyCall(Node[] args, int length, RuleContext context) { |
| checkArgs(length, context); |
| BindingEnvironment env = context.getEnv(); |
| Triple t = new Triple( NodeFactory.createBlankNode(), |
| NodeFactory.createURI("http://jena.hpl.hp.com/example#"), |
| NodeFactory.createBlankNode()); |
| Node l = NodeFactory.createLiteral( LiteralLabelFactory.createTypedLiteral(t) ); |
| return env.bind(args[0], l); |
| } |
| } |
| |
| /** |
| * Test a problem with the RDFS rule set. |
| * Arguably this should be moved to ../test/TestRDFSReasoners but that requires more |
| * fiddling with manifest files and declarative test specifications |
| */ |
| public void testRDFSSimple() { |
| doTestRDFSSimple(ReasonerVocabulary.RDFS_DEFAULT); |
| doTestRDFSSimple(ReasonerVocabulary.RDFS_SIMPLE); |
| } |
| |
| private void doTestRDFSSimple(String level) { |
| Model model = ModelFactory.createDefaultModel(); |
| String NS = "http://jena.hpl.hp.com/example#"; |
| Property prop = model.createProperty(NS + "prop"); |
| model.add(prop, RDF.type, RDF.Property); |
| |
| Reasoner reasoner = RDFSRuleReasonerFactory.theInstance().create(null); |
| reasoner.setParameter(ReasonerVocabulary.PROPsetRDFSLevel, level); |
| InfModel im = ModelFactory.createInfModel(reasoner, model); |
| assertTrue( im.contains(prop, RDFS.subPropertyOf, prop) ); |
| } |
| |
| |
| /** |
| * Layering one reasoner on another leads to exposed functors which |
| * used to trip up validation |
| */ |
| public void testLayeredValidation() { |
| Model ont = FileManager.getInternal().loadModelInternal("testing/reasoners/bugs/layeredValidation.owl"); |
| InfModel infModel = |
| ModelFactory.createInfModel(ReasonerRegistry.getOWLReasoner(), ont); |
| OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_RULE_INF, |
| infModel); |
| ValidityReport validity = model.validate(); |
| assertTrue(validity.isClean()); |
| } |
| |
| // debug assistant |
| // private void tempList(Model m, Resource s, Property p, RDFNode o) { |
| // System.out.println("Listing of " + PrintUtil.print(s) + " " + PrintUtil.print(p) + " " + PrintUtil.print(o)); |
| // for (StmtIterator i = m.listStatements(s, p, o); i.hasNext(); ) { |
| // System.out.println(" - " + i.next()); |
| // } |
| // } |
| |
| /** |
| * Potential problem in handling of maxCardinality(0) assertions in the |
| * presence of disjointness. |
| */ |
| public void testMaxCard2() { |
| doTestmaxCard2(OntModelSpec.OWL_MEM_MINI_RULE_INF); |
| doTestmaxCard2(OntModelSpec.OWL_MEM_RULE_INF); |
| } |
| |
| |
| private void doTestmaxCard2(OntModelSpec spec) { |
| String NS = "http://jena.hpl.hp.com/eg#"; |
| Model base = FileManager.getInternal().loadModelInternal("testing/reasoners/bugs/terrorism.owl"); |
| OntModel model = ModelFactory.createOntologyModel(spec, base); |
| OntClass event = model.getOntClass(NS + "Event"); |
| List<OntClass> subclasses = event.listSubClasses().toList(); |
| assertFalse( subclasses.contains( OWL.Nothing ) ); |
| assertEquals(3, subclasses.size()); |
| } |
| |
| } |