blob: 2ae12865596c202b59d65656e4d7e9df249361d4 [file] [log] [blame]
/*
* 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());
}
}