You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2021/02/14 09:31:55 UTC
[jena] branch main updated: JENA-2019: Parser fix; printing fix;
more tests
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 7d095fd JENA-2019: Parser fix; printing fix; more tests
new 7812905 Merge pull request #922 from afs/jena2019-rule-parser
7d095fd is described below
commit 7d095fdbf04bef7d06a1737938067027ba0bf16c
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Sat Feb 13 18:52:01 2021 +0000
JENA-2019: Parser fix; printing fix; more tests
---
.github/workflows/maven.yml | 23 ++
.../java/org/apache/jena/datatypes/TypeMapper.java | 11 +
.../org/apache/jena/reasoner/rulesys/Functor.java | 68 ++---
.../jena/reasoner/rulesys/FunctorDatatype.java | 50 +++
.../org/apache/jena/reasoner/rulesys/Rule.java | 54 ++--
.../reasoner/rulesys/impl/RETEClauseFilter.java | 2 +-
.../main/java/org/apache/jena/util/PrintUtil.java | 45 +--
.../main/java/org/apache/jena/util/Tokenizer.java | 88 +++---
.../jena/reasoner/rulesys/test/TestBasics.java | 338 +++++++++++++--------
9 files changed, 432 insertions(+), 247 deletions(-)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..0d16a49
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,23 @@
+## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
+
+name: Apache Jena CI
+
+on:
+ push:
+ branches: [ main ]
+# pull_request:
+# branches: [ main ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: '11'
+ - name: Build with Maven
+ run: mvn -B verify --file pom.xml
diff --git a/jena-core/src/main/java/org/apache/jena/datatypes/TypeMapper.java b/jena-core/src/main/java/org/apache/jena/datatypes/TypeMapper.java
index 1f03d86..872f0bb 100644
--- a/jena-core/src/main/java/org/apache/jena/datatypes/TypeMapper.java
+++ b/jena-core/src/main/java/org/apache/jena/datatypes/TypeMapper.java
@@ -189,4 +189,15 @@ public class TypeMapper {
classToDT.put(jc, type);
}
}
+
+ /**
+ * Remove a datatype registration.
+ */
+ public void unregisterDatatype(final RDFDatatype type) {
+ uriToDT.remove(type.getURI());
+ final Class<?> jc = type.getJavaClass();
+ if (jc != null) {
+ classToDT.remove(jc);
+ }
+ }
}
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Functor.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Functor.java
index 1491e44..db5c733 100755
--- a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Functor.java
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Functor.java
@@ -18,17 +18,19 @@
package org.apache.jena.reasoner.rulesys;
-import org.apache.jena.datatypes.* ;
-import org.apache.jena.graph.* ;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Node_ANY;
+import org.apache.jena.graph.Triple;
import org.apache.jena.util.PrintUtil ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
-import java.util.function.Predicate;
-
/**
- * A functor comprises a functor name and a list of
+ * A functor comprises a functor name and a list of
* arguments. The arguments are Nodes of any type except functor nodes
* (there is no functor nesting). Functors play three roles in rules -
* in heads they represent actions (procedural attachment); in bodies they
@@ -39,24 +41,24 @@ import java.util.function.Predicate;
public class Functor implements ClauseEntry {
/** Functor's name */
protected String name;
-
+
/** Argument list - an array of nodes */
protected Node[] args;
-
+
/** A built in that implements the functor */
protected Builtin implementor;
-
+
/** A static Predicate instance that detects triples with Functor objects */
public static final Predicate<Triple> acceptFilter = t -> {
if (t.getSubject().isLiteral()) return true;
Node n = t.getObject();
return n.isLiteral() && n.getLiteralDatatype() == FunctorDatatype.theFunctorDatatype;
};
-
+
protected static Logger logger = LoggerFactory.getLogger(Functor.class);
/**
- * Constructor.
+ * Constructor.
* @param name the name of the functor
* @param args an array of nodes defining the arguments, this will not be copied so beware of
* accidental structure sharing
@@ -65,7 +67,7 @@ public class Functor implements ClauseEntry {
this.name = name;
this.args = args;
}
-
+
/**
* Constructor
* @param name the name of the functor
@@ -113,28 +115,28 @@ public class Functor implements ClauseEntry {
this.args = args;
this.implementor = impl;
}
-
+
/**
* Return the functor name
*/
public String getName() {
return name;
}
-
+
/**
* Return the functor arguments as an array of nodes
*/
public Node[] getArgs() {
return args;
}
-
+
/**
* Return the length of the functor argument array.
*/
public int getArgLength() {
return args.length;
}
-
+
/**
* Returns true if the functor is fully ground, no variables
*/
@@ -148,7 +150,7 @@ public class Functor implements ClauseEntry {
}
return true;
}
-
+
/**
* Returns true if the functor is fully ground in the given environment
*/
@@ -162,7 +164,7 @@ public class Functor implements ClauseEntry {
}
return true;
}
-
+
/**
* Execute the given built in as a body clause.
* @param context an execution context giving access to other relevant data
@@ -175,7 +177,7 @@ public class Functor implements ClauseEntry {
}
return implementor.bodyCall(getBoundArgs(context.getEnv()), args.length, context);
}
-
+
/**
* Execute the given built in as a body clause, only if it is side-effect-free.
* @param context an execution context giving access to other relevant data
@@ -192,7 +194,7 @@ public class Functor implements ClauseEntry {
return false;
}
}
-
+
/**
* Return a new Node array containing the bound versions of this Functor's arguments
*/
@@ -203,7 +205,7 @@ public class Functor implements ClauseEntry {
}
return boundargs;
}
-
+
/**
* Return the Builtin that implements this functor
* @return the Builtin or null if there isn't one
@@ -214,14 +216,14 @@ public class Functor implements ClauseEntry {
}
return implementor;
}
-
+
/**
* Set the Builtin that implements this functor.
*/
public void setImplementor(Builtin implementor) {
this.implementor = implementor;
}
-
+
/**
* Printable string describing the functor
*/
@@ -246,7 +248,7 @@ public class Functor implements ClauseEntry {
if (n == null) return false;
return n.isLiteral() && n.getLiteralDatatype() == FunctorDatatype.theFunctorDatatype;
}
-
+
/**
* Equality is based on structural comparison
*/
@@ -263,13 +265,13 @@ public class Functor implements ClauseEntry {
}
return false;
}
-
+
/** hash function override */
@Override
public int hashCode() {
return (name.hashCode()) ^ (args.length << 2);
}
-
+
/**
* Compare Functors, taking into account variable indices.
* The equality function ignores differences between variables.
@@ -305,18 +307,4 @@ public class Functor implements ClauseEntry {
public static Node makeFunctorNode(Functor f) {
return NodeFactory.createLiteralByValue(f, FunctorDatatype.theFunctorDatatype);
}
-
- /**
- * Inner class. Dummy datatype definition for
- * functor-valued literals.
- */
- public static class FunctorDatatype extends BaseDatatype {
-
- public FunctorDatatype() {
- super("urn:x-hp-jena:Functor");
- }
-
- public static final RDFDatatype theFunctorDatatype = new FunctorDatatype();
- }
-
}
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/FunctorDatatype.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/FunctorDatatype.java
new file mode 100644
index 0000000..56f7977
--- /dev/null
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/FunctorDatatype.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import org.apache.jena.datatypes.BaseDatatype;
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.graph.impl.LiteralLabel;
+
+/**
+ * Datatype definition for functor-valued literals.
+ */
+public class FunctorDatatype extends BaseDatatype {
+
+ /** Used when print a functor as an RDF literal, and in parsing tests */
+ public static final RDFDatatype theFunctorDatatype = new FunctorDatatype();
+
+ private FunctorDatatype() {
+ super("urn:org.apache.jena:Functor");
+ }
+
+ /**
+ * Compares two instances of values of the given datatype.
+ */
+ @Override
+ public boolean isEqual(LiteralLabel value1, LiteralLabel value2) {
+ return isEqualByTerm(value1, value2) ;
+ }
+
+ @Override
+ public Object parse(String lexicalForm) { return lexicalForm ; }
+
+ @Override
+ public String unparse(Object value) { return value.toString(); }
+}
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Rule.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Rule.java
index afa9dc6..df3f29d 100755
--- a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Rule.java
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Rule.java
@@ -712,7 +712,8 @@ public class Rule implements ClauseEntry {
// Literal parse state flags
private static final int NORMAL = 0;
- private static final int STARTED_LITERAL = 1;
+ private static final int IN_LITERAL = 1;
+ private static final int END_LITERAL = 2;
/** Literal parse state */
private int literalState = NORMAL;
@@ -785,27 +786,38 @@ public class Rule implements ClauseEntry {
String temp = lookahead;
lookahead = null;
return temp;
- } else {
- String token = stream.nextToken();
- if (literalState == NORMAL) {
- // Skip separators unless within a literal
+ }
+ if ( !stream.hasMoreTokens() ) {}
+ String token = stream.nextToken();
+
+ // Three states
+ // NORMAL
+ // IN_LITERAL: entered when a literal string delimite is found.
+ // END_LITERAL: expecting finish delimiter
+ switch( literalState ) {
+ case NORMAL:
+ // Skip separators - not in a literal
while (isSeparator(token)) {
token = stream.nextToken();
}
- }
- if (token.equals("'")) {
- if (literalState == NORMAL) {
- literalState = STARTED_LITERAL;
- } else {
- literalState = NORMAL;
- }
- }
- priorTokens.add(0, token);
- if (priorTokens.size() > maxPriors) {
- priorTokens.remove(priorTokens.size()-1);
- }
- return token;
+ // Start delimiter
+ if ( token.equals("'") || token.equals("\"") )
+ literalState = IN_LITERAL;
+ break;
+ case IN_LITERAL:
+ // Between delimiters
+ literalState = END_LITERAL;
+ break;
+ case END_LITERAL:
+ // Finish Delimiter.
+ literalState = NORMAL;
+ break;
+ }
+ priorTokens.add(0, token);
+ if (priorTokens.size() > maxPriors) {
+ priorTokens.remove(priorTokens.size()-1);
}
+ return token;
}
/**
@@ -934,7 +946,7 @@ public class Rule implements ClauseEntry {
RDFDatatype dt = TypeMapper.getInstance().getSafeTypeByName(dtURI);
return NodeFactory.createLiteral(lit, dt);
} else {
- return NodeFactory.createLiteral(lit, "");
+ return NodeFactory.createLiteral(lit);
}
} else if ( Character.isDigit(token.charAt(0)) ||
(token.charAt(0) == '-' && token.length() > 1 && Character.isDigit(token.charAt(1))) ) {
@@ -1018,7 +1030,7 @@ public class Rule implements ClauseEntry {
List<Node> args = parseNodeList();
Functor clause = new Functor(name, args, registry);
if (clause.getImplementor() == null) {
- // Not a.error error becase later processing can add this
+ // Not an error because later processing can add this
// implementation to the registry
logger.warn("Rule references unimplemented functor: " + name);
}
@@ -1036,7 +1048,7 @@ public class Rule implements ClauseEntry {
/**
* Parse a rule, terminated by a "]" or "." character.
- * @param retainVarMap set to true to ccause the existing varMap to be left in place, which
+ * @param retainVarMap set to true to cause the existing varMap to be left in place, which
* is required for nested rules.
*/
private Rule doParseRule(boolean retainVarMap) {
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
index 9620e33..f864eab 100644
--- a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
@@ -206,7 +206,7 @@ public class RETEClauseFilter implements RETESourceNode {
// for possible later functor argument accesses
n = triple.getObject();
if ( !n.isLiteral() ) return;
- if ( n.getLiteralDatatype() != Functor.FunctorDatatype.theFunctorDatatype) return;
+ if ( n.getLiteralDatatype() != FunctorDatatype.theFunctorDatatype) return;
lastFunctor = (Functor)n.getLiteralValue();
if ( !lastFunctor.getName().equals(args[instructions[pc++]]) ) return;
break;
diff --git a/jena-core/src/main/java/org/apache/jena/util/PrintUtil.java b/jena-core/src/main/java/org/apache/jena/util/PrintUtil.java
index 5253b74..8d4f2cc 100755
--- a/jena-core/src/main/java/org/apache/jena/util/PrintUtil.java
+++ b/jena-core/src/main/java/org/apache/jena/util/PrintUtil.java
@@ -40,16 +40,16 @@ import org.apache.jena.vocabulary.ReasonerVocabulary ;
* prefix map which is preloaded with known prefixes.
*/
public class PrintUtil {
-
+
protected static PrefixMapping prefixMapping = PrefixMapping.Factory.create();
-
+
/** Default built in eg namespace used in testing */
public static final String egNS = "urn:x-hp:eg/";
-
+
static {
init();
}
-
+
/**
* Load built in prefixes.
*/
@@ -63,7 +63,7 @@ public class PrintUtil {
registerPrefix("eg", egNS);
registerPrefix("xsd", XSDDatatype.XSD + "#");
}
-
+
/**
* Register a new prefix/namespace mapping which will be used to shorten
* the print strings for resources in known namespaces.
@@ -71,7 +71,7 @@ public class PrintUtil {
public static void registerPrefix(String prefix, String namespace) {
prefixMapping.setNsPrefix( prefix, namespace );
}
-
+
/**
* Register a set of new prefix/namespace mapping which will be used to shorten
* the print strings for resources in known namespaces.
@@ -79,14 +79,14 @@ public class PrintUtil {
public static void registerPrefixMap(Map<String, String> map) {
prefixMapping.setNsPrefixes( map );
}
-
+
/**
* Remove a registered prefix from the table of known short forms
*/
public static void removePrefix(String prefix) {
prefixMapping.removeNsPrefix(prefix);
}
-
+
/**
* Remove a set of prefix mappings from the table of known short forms
*/
@@ -96,9 +96,9 @@ public class PrintUtil {
prefixMapping.removeNsPrefix( s );
}
}
-
+
/**
- * Return a simplified print string for a Node.
+ * Return a simplified print string for a Node.
*/
public static String print(Node node) {
if (node instanceof Node_URI) {
@@ -111,8 +111,11 @@ public class PrintUtil {
}
} else if (node instanceof Node_Literal) {
String lf = node.getLiteralLexicalForm();
- // RDF 1.1 : Print xsd:string without ^^xsd:string
- return "'" + lf + "'" + (Util.isSimpleString(node) ? "" : "^^" + node.getLiteralDatatypeURI());
+ String singleQuote = "'";
+ if ( lf.contains(singleQuote) )
+ lf = lf.replace(singleQuote, "\\'");
+ // RDF 1.1 : Print xsd:string without ^^xsd:string
+ return singleQuote + lf + singleQuote + (Util.isSimpleString(node) ? "" : "^^" + node.getLiteralDatatypeURI());
} else if (node instanceof Node_ANY) {
return "*";
}
@@ -121,15 +124,15 @@ public class PrintUtil {
}
return node.toString();
}
-
+
/**
- * Return a simplified print string for an RDFNode.
+ * Return a simplified print string for an RDFNode.
*/
public static String print(RDFNode node) {
if (node == null) return "null";
return print(node.asNode());
}
-
+
/**
* Return a simplified print string for a Triple
*/
@@ -139,7 +142,7 @@ public class PrintUtil {
print(triple.getPredicate()) + " " +
print(triple.getObject()) + ")";
}
-
+
/**
* Return a simplified print string for a TriplePattern
*/
@@ -149,7 +152,7 @@ public class PrintUtil {
print(triple.getPredicate()) + " " +
print(triple.getObject()) + ")";
}
-
+
/**
* Return a simplified print string for a statement
*/
@@ -157,7 +160,7 @@ public class PrintUtil {
if (stmt == null) return "(null)";
return print(stmt.asTriple());
}
-
+
/**
* Default print which just uses tostring
*/
@@ -177,7 +180,7 @@ public class PrintUtil {
return obj.toString();
}
}
-
+
/**
* Expand qnames to URIs. If the given URI appears
* to start with one of the registered prefixes then
@@ -186,7 +189,7 @@ public class PrintUtil {
public static String expandQname(String uri) {
return prefixMapping.expandPrefix( uri );
}
-
+
/**
* Print an n-space indent to the given output stream
*/
@@ -195,7 +198,7 @@ public class PrintUtil {
for (int i = 0; i < indent; i++) spaces.append(" ");
out.print(spaces.toString());
}
-
+
/**
* Print all the Triple values from a find iterator.
*/
diff --git a/jena-core/src/main/java/org/apache/jena/util/Tokenizer.java b/jena-core/src/main/java/org/apache/jena/util/Tokenizer.java
index 0ad5414..61526bc 100644
--- a/jena-core/src/main/java/org/apache/jena/util/Tokenizer.java
+++ b/jena-core/src/main/java/org/apache/jena/util/Tokenizer.java
@@ -25,37 +25,37 @@ import java.util.NoSuchElementException;
* character strings which can include other separators.
*/
public class Tokenizer {
-
+
/** The string being parsed */
protected String source;
-
+
/** The index of the first unreturned char in source */
protected int p;
/** The set of delimiter characters */
protected String delim;
-
+
/** If true then delimiters should be returned as tokens */
protected boolean returnDelims;
-
+
/** Literal string delimiters */
protected String literalDelim;
-
+
/** The lex state */
protected int state;
-
+
/** A lookahead for tokens */
protected String lookahead;
-
+
/** State flag: normal parse */
protected static final int NORMAL = 1;
-
+
/** State flag: start of literal */
protected static final int LITERAL_START = 2;
-
+
/** State flag: end of literal */
protected static final int LITERAL_END = 3;
-
+
/**
* Constructor.
* @param str the source string to be parsed
@@ -68,10 +68,10 @@ public class Tokenizer {
this.delim = delim;
this.literalDelim = literalDelim;
this.returnDelims = returnDelims;
- p = 0;
+ p = 0;
state = NORMAL;
}
-
+
/**
* Return the next token.
* @throws java.util.NoSuchElementException if there are no more tokens available
@@ -86,7 +86,7 @@ public class Tokenizer {
}
if (result == null) {
throw new NoSuchElementException("No more elements in tokenized string");
- }
+ }
if (!returnDelims) {
if (result.length() == 1) {
char c = result.charAt(0);
@@ -97,7 +97,7 @@ public class Tokenizer {
}
return result;
}
-
+
/**
* Test if there are more tokens which can be returned.
*/
@@ -105,7 +105,7 @@ public class Tokenizer {
if (lookahead == null) lookahead = getNextToken();
return lookahead != null;
}
-
+
/**
* Find the next token which can either be a delimiter or a real token.
*/
@@ -114,46 +114,44 @@ public class Tokenizer {
return null;
}
switch(state) {
- case NORMAL:
- if (is(literalDelim)) {
- state = LITERAL_START;
- p++;
- return source.substring(p-1, p);
- } else if (is(delim)) {
- p++;
- return source.substring(p-1, p);
- } else {
+ case NORMAL:
+ if (is(literalDelim)) {
+ state = LITERAL_START;
+ p++;
+ return source.substring(p-1, p);
+ } else if (is(delim)) {
+ p++;
+ return source.substring(p-1, p);
+ }
int start = p;
p++;
while (p < source.length() && ! is(delim)) p++;
return source.substring(start, p);
- }
- case LITERAL_START:
- char delim = source.charAt(p-1);
- StringBuilder literal = new StringBuilder();
- while (p < source.length()) {
- char c = source.charAt(p);
- if (c == '\\') {
+ case LITERAL_START:
+ char delim = source.charAt(p-1);
+ StringBuilder literal = new StringBuilder();
+ while (p < source.length()) {
+ char c = source.charAt(p);
+ if (c == '\\') {
+ p++;
+ if (p >= source.length()) break;
+ c = source.charAt(p);
+ } else {
+ if (c == delim) break;
+ }
+ literal.append(c);
p++;
- if (p >= source.length()) break;
- c = source.charAt(p);
- } else {
- if (c == delim) break;
}
- literal.append(c);
+ state = LITERAL_END;
+ return literal.toString();
+ case LITERAL_END:
+ state = NORMAL;
p++;
- }
- state = LITERAL_END;
- return literal.toString();
- case LITERAL_END:
- state = NORMAL;
- p++;
- return source.substring(p-1, p);
+ return source.substring(p-1, p);
}
return null;
}
-
-
+
/**
* Returns true if the current character is contained in the given classification.
*/
diff --git a/jena-core/src/test/java/org/apache/jena/reasoner/rulesys/test/TestBasics.java b/jena-core/src/test/java/org/apache/jena/reasoner/rulesys/test/TestBasics.java
index 6d9abd2..db4d7cd 100755
--- a/jena-core/src/test/java/org/apache/jena/reasoner/rulesys/test/TestBasics.java
+++ b/jena-core/src/test/java/org/apache/jena/reasoner/rulesys/test/TestBasics.java
@@ -24,6 +24,8 @@ import junit.framework.TestSuite;
import java.util.*;
import java.io.*;
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.datatypes.TypeMapper;
import org.apache.jena.graph.* ;
import org.apache.jena.rdf.model.* ;
import org.apache.jena.reasoner.* ;
@@ -37,10 +39,10 @@ import org.apache.jena.vocabulary.* ;
* Unit tests for simple infrastructure pieces of the rule systems.
*/
public class TestBasics extends TestCase {
-
+
// Maximum size of binding environment needed in the tests
private static final int MAX_VARS = 10;
-
+
// Useful constants
Node p = NodeFactory.createURI("p");
Node q = NodeFactory.createURI("q");
@@ -52,93 +54,191 @@ public class TestBasics extends TestCase {
Node n4 = NodeFactory.createURI("n4");
Node n5 = NodeFactory.createURI("n5");
Node res = NodeFactory.createURI("res");
-
-
+
+
/**
* Boilerplate for junit
- */
+ */
public TestBasics( String name ) {
- super( name );
+ super( name );
}
-
+
/**
* Boilerplate for junit.
* This is its own test suite
*/
public static TestSuite suite() {
- return new TestSuite( TestBasics.class );
- }
+ return new TestSuite( TestBasics.class );
+ }
/**
* Test the internal rule parser
*/
- public void testRuleParser() {
- String[] testRules = new String[] {
- "(?a rdf:type ?_) -> (?a rdf:type ?b).",
- "(?a rdf:type ?_), (?a rdf:type ?_) -> (?a rdf:type ?b).",
- "(?a rdf:type max(?a,1)) -> (?a rdf:type 'foo').",
- "(?a rdf:type ?_) -> addOne(?a).",
- "(?a rdf:type ?_) -> [(?a rdf:type ?_) -> addOne(?a)].",
- "(?a rdf:type ?_) -> (?a rdf:type '42').",
- "(?a rdf:type ?_) -> (?a rdf:type 4.2).",
- "(?a rdf:type ?_) -> (?a rdf:type ' fool that,I(am)').",
- "[rule1: (?a rdf:type ?_) -> (?a rdf:type a)]",
- "-> print(' ').",
- "-> print(' literal with embedded \\' characters ').",
- "-> print(\" literal characters \").",
- "-> print(42). ",
- "-> print('42'^^xsd:byte). ",
- "-> print('42'^^http://www.w3.org/2001/XMLSchema#int). ",
- "-> print('42'^^foobar:byte). ",
- "-> print(<foo://a/file>). " ,
- "-> print('(').",
- "-> print(\"(\")."
- };
- String[] testResults = new String[] {
- "[ (?a rdf:type ?_) -> (?a rdf:type ?b) ]",
- "[ (?a rdf:type ?_) (?a rdf:type ?_) -> (?a rdf:type ?b) ]",
- "[ (?a rdf:type 'max(?a '1'^^http://www.w3.org/2001/XMLSchema#int)'^^urn:x-hp-jena:Functor) -> (?a rdf:type 'foo') ]",
- "[ (?a rdf:type ?_) -> addOne(?a) ]",
- "[ (?a rdf:type ?_) -> [ (?a rdf:type ?_) -> addOne(?a) ] ]",
- "[ (?a rdf:type ?_) -> (?a rdf:type '42') ]",
- "[ (?a rdf:type ?_) -> (?a rdf:type '4.2'^^http://www.w3.org/2001/XMLSchema#float) ]",
- "[ (?a rdf:type ?_) -> (?a rdf:type ' fool that,I(am)') ]",
- "[ rule1: (?a rdf:type ?_) -> (?a rdf:type <a>) ]",
- "[ -> print(' ') ]",
- "[ -> print(' literal with embedded ' characters ') ]",
- "[ -> print(' literal characters ') ]",
- "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#int) ]",
- "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#byte) ]",
- "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#int) ]",
- "[ -> print('42'^^http://foobar#byte) ]",
- "[ -> print(<foo://a/file>) ]",
- "[ -> print('(') ]",
- "[ -> print('(') ]"
- };
-
+ public void testRuleParserBad01() {
+ execTestBad("(foo(?A) eg:p ?B) <- (?a, eg:p, ?B).");
+ }
+
+ public void testRuleParserBad02() {
+ execTestBad("(foo(?A) eg:p ?B) -> (?a, eg:p, ?B).");
+ }
+
+ private static void execTestBad(String ruleStr) {
+ boolean foundError = false;
+ try {
+ Rule r = Rule.parseRule(ruleStr);
+ } catch (Rule.ParserException e) {
+ foundError = true;
+ }
+ assertTrue("Failed to find illegal rule: " + ruleStr, foundError);
+ }
+
+ public void testParser01() {
+ execTest("(?a rdf:type ?_) -> (?a rdf:type ?b).", "[ (?a rdf:type ?_) -> (?a rdf:type ?b) ]");
+ }
+
+ public void testParser02() {
+ execTest("(?a rdf:type ?_), (?a rdf:type ?_) -> (?a rdf:type ?b).", "[ (?a rdf:type ?_) (?a rdf:type ?_) -> (?a rdf:type ?b) ]");
+ }
+
+ public void testParser03() {
+ // Register so that parsing the string form works.
+ RDFDatatype dt = FunctorDatatype.theFunctorDatatype;
+ TypeMapper.getInstance().registerDatatype(dt);
+ execTest("(?a rdf:type max(?a,1)) -> (?a rdf:type 'foo').",
+ "[ (?a rdf:type 'max(?a \\'1\\'^^http://www.w3.org/2001/XMLSchema#int)'^^urn:org.apache.jena:Functor) -> (?a rdf:type 'foo') ]");
+ TypeMapper.getInstance().unregisterDatatype(dt);
+ }
+
+ public void testParser04() {
+ execTest("(?a rdf:type ?_) -> addOne(?a).", "[ (?a rdf:type ?_) -> addOne(?a) ]");
+ }
+
+ public void testParser05() {
+ execTest("(?a rdf:type ?_) -> [(?a rdf:type ?_) -> addOne(?a)].", "[ (?a rdf:type ?_) -> [ (?a rdf:type ?_) -> addOne(?a) ] ]");
+ }
+
+ public void testParser06() {
+ execTest("(?a rdf:type ?_) -> (?a rdf:type '42').", "[ (?a rdf:type ?_) -> (?a rdf:type '42') ]");
+ }
+
+ public void testParser07() {
+ execTest("(?a rdf:type ?_) -> (?a rdf:type 4.2).",
+ "[ (?a rdf:type ?_) -> (?a rdf:type '4.2'^^http://www.w3.org/2001/XMLSchema#float) ]");
+ }
+
+ public void testParser08() {
+ execTest("(?a rdf:type ?_) -> (?a rdf:type ' fool that,I(am)').", "[ (?a rdf:type ?_) -> (?a rdf:type ' fool that,I(am)') ]");
+ }
+
+ public void testParser09() {
+ execTest("[rule1: (?a rdf:type ?_) -> (?a rdf:type a)]", "[ rule1: (?a rdf:type ?_) -> (?a rdf:type <a>) ]");
+ }
+
+ public void testParser10() {
+ execTest("-> print(' ').", "[ -> print(' ') ]");
+ }
+
+ public void testParser11() {
+ execTest("-> print(' literal with embedded \\' characters ').", "[ -> print(' literal with embedded \\' characters ') ]");
+ }
+
+ public void testParser12() {
+ execTest("-> print(\" literal characters \").", "[ -> print(' literal characters ') ]");
+ }
+
+ public void testParser13() {
+ execTest("-> print(42). ", "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#int) ]");
+ }
+
+ public void testParser14() {
+ execTest("-> print('42'^^xsd:byte). ", "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#byte) ]");
+ }
+
+ public void testParser15() {
+ execTest("-> print('42'^^http://www.w3.org/2001/XMLSchema#int). ", "[ -> print('42'^^http://www.w3.org/2001/XMLSchema#int) ]");
+ }
+
+ public void testParser16() {
PrintUtil.registerPrefix("foobar", "http://foobar#");
- for (int i = 0; i < testRules.length; i++) {
- Rule r = Rule.parseRule(testRules[i]);
- assertEquals(testResults[i], r.toString());
+ try {
+ execTest("-> print('42'^^foobar:byte). ", "[ -> print('42'^^http://foobar#byte) ]");
+ } finally {
+ PrintUtil.removePrefix("foobar");
}
-
- // Test for an illegal rule format
- String[] testBadRules = new String[] {
- "(foo(?A) eg:p ?B) <- (?a, eg:p, ?B)." ,
- "(foo(?A) eg:p ?B) -> (?a, eg:p, ?B)."
- };
- for ( String testBadRule : testBadRules )
- {
- boolean foundError = false;
- try
- {
- Rule r = Rule.parseRule( testBadRule );
- }
- catch ( Rule.ParserException e )
- {
- foundError = true;
- }
- assertTrue( "Failed to find illegal rule", foundError );
+ }
+
+ public void testParser17() {
+ execTest("-> print(<foo://a/file>). ", "[ -> print(<foo://a/file>) ]");
+ }
+
+ public void testParser18() {
+ execTest("-> print(\"(\").", "[ -> print('(') ]");
+ }
+
+ public void testParser19() {
+ execTest("-> print(\",\").", "[ -> print(',') ]");
+ }
+
+ public void testParser20() {
+ execTest("-> print(',').", "[ -> print(',') ]");
+ }
+
+ public void testParser21() {
+ // Leading quote!
+ execTest("-> print(\"\\\"\").", "[ -> print('\"') ]");
+ }
+
+ public void testParser22() {
+ execTest("-> print('\"').", "[ -> print('\"') ]");
+ }
+
+ public void testParser23() {
+ execTest("-> print(\"'\").", "[ -> print('\\'') ]");
+ }
+
+ public void testParser24() {
+ execTest("-> print('\\'').", "[ -> print('\\'') ]");
+ }
+
+ public void testParser25() {
+ execTest("-> print('(').", "[ -> print('(') ]");
+ }
+
+ public void testParser26() {
+ execTest("-> print(')').", "[ -> print(')') ]");
+ }
+
+ public void testParser27() {
+ execTest("-> print(']').", "[ -> print(']') ]");
+ }
+
+ public void testParser28() {
+ execTest("-> print('[').", "[ -> print('[') ]");
+ }
+
+ public void testParser29() {
+ execTest("-> print(123).", "[ -> print('123'^^http://www.w3.org/2001/XMLSchema#int) ]");
+ }
+
+ public void testParser30() {
+ execTest("-> print(123, 'AB' 'CD').", "[ -> print('123'^^http://www.w3.org/2001/XMLSchema#int 'AB' 'CD') ]");
+ }
+
+ public void testParser31() {
+ execTest("-> print(123) print('AB') print('CD').", "[ -> print('123'^^http://www.w3.org/2001/XMLSchema#int) print('AB') print('CD') ]");
+ }
+
+ private static void execTest(String ruleStr, String expected) {
+ // Parse , check, parse the output, check.
+ Rule r = Rule.parseRule(ruleStr);
+ assertEquals(expected, r.toString());
+ try {
+ // And run on expected
+ Rule r2 = Rule.parseRule(expected);
+ assertEquals(r, r2);
+ } catch (Rule.ParserException ex) {
+ System.err.println(expected);
+ throw ex;
}
}
@@ -162,14 +262,14 @@ public class TestBasics extends TestCase {
assertTrue(! r3.equals(r5));
assertTrue(! r3.equals(r6));
}
-
+
/**
* Test the BindingEnvironment machinery
*/
public void testBindingEnvironment() {
BindingStack env = new BindingStack();
env.reset(MAX_VARS);
-
+
env.bind(3, n1);
assertEquals(n1, env.getEnvironment()[3]);
env.push();
@@ -201,8 +301,8 @@ public class TestBasics extends TestCase {
assertTrue("Failed to catch end of stack", false);
} catch (IndexOutOfBoundsException e) {
}
- }
-
+ }
+
/**
* Test simple single clause binding
*/
@@ -227,21 +327,21 @@ public class TestBasics extends TestCase {
assertEquals(null, env.getEnvironment()[0]);
assertEquals(null, env.getEnvironment()[1]);
assertEquals(null, env.getEnvironment()[2]);
-
+
// Should succeed with two bindings
match = FRuleEngine.match(p1, new Triple(n2, n1, n3), env);
assertTrue(match);
assertEquals(n2, env.getEnvironment()[0]);
assertEquals(n3, env.getEnvironment()[1]);
assertEquals(null, env.getEnvironment()[2]);
-
+
// should fail but leave prior bindings intact
match = FRuleEngine.match(p2, new Triple(n1, n2, n2), env);
assertTrue(!match);
assertEquals(n2, env.getEnvironment()[0]);
assertEquals(n3, env.getEnvironment()[1]);
assertEquals(null, env.getEnvironment()[2]);
-
+
// should succeed with full binding set
match = FRuleEngine.match(p2, new Triple(n3, n1, n2), env);
assertTrue(match);
@@ -249,7 +349,7 @@ public class TestBasics extends TestCase {
assertEquals(n3, env.getEnvironment()[1]);
assertEquals(n1, env.getEnvironment()[2]);
}
-
+
/**
* Minimal rule tester to check basic pattern match
*/
@@ -259,13 +359,13 @@ public class TestBasics extends TestCase {
"[r3: (?a p ?a), (n1 p ?c), (n1, p, ?a) -> (?a, p, ?c)]" +
"[r4: (n4 ?p ?a) -> (n4, ?a, ?p)]";
List<Rule> ruleList = Rule.parseRules(rules);
-
+
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(Factory.createGraphMem());
infgraph.add(new Triple(n1, p, n2));
infgraph.add(new Triple(n2, p, n3));
infgraph.add(new Triple(n2, q, n3));
infgraph.add(new Triple(n4, p, n4));
-
+
TestUtil.assertIteratorValues(this, infgraph.find(null, null, null),
new Triple[] {
new Triple(n1, p, n2),
@@ -277,7 +377,7 @@ public class TestBasics extends TestCase {
new Triple(n4, n4, p),
});
}
-
+
/**
* Test derivation machinery
*/
@@ -286,7 +386,7 @@ public class TestBasics extends TestCase {
"[testRule2: (n1 q ?a) -> (n2, q, ?a)]" +
"[testRule3: (n2 p ?a), (n2 q ?a) -> (res p ?a)]";
List<Rule> ruleList = Rule.parseRules(rules);
-
+
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(Factory.createGraphMem());
infgraph.setDerivationLogging(true);
infgraph.add(new Triple(n1, p, n3));
@@ -303,7 +403,7 @@ public class TestBasics extends TestCase {
new Triple(n2, q, n3),
new Triple(res, p, n3)
});
-
+
Iterator<Derivation> derivs = infgraph.getDerivation(new Triple(res, p, n3));
StringWriter outString = new StringWriter(250);
PrintWriter out = new PrintWriter(outString);
@@ -312,7 +412,7 @@ public class TestBasics extends TestCase {
d.printTrace(out, true);
}
out.flush();
-
+
String testString = TestUtil.normalizeWhiteSpace("Rule testRule3 concluded (<res> <p> <n3>) <-\n" +
" Rule testRule1 concluded (<n2> <p> <n3>) <-\n" +
" Fact (<n1> <p> <n3>)\r\n" +
@@ -320,8 +420,8 @@ public class TestBasics extends TestCase {
" Fact (<n1> <q> <n3>)\r\n");
assertEquals(testString, TestUtil.normalizeWhiteSpace(outString.getBuffer().toString()));
}
-
-
+
+
/**
* Test axiom handling machinery
*/
@@ -331,14 +431,14 @@ public class TestBasics extends TestCase {
"[testRule3: (n2 p ?a), (n2 q ?a) -> (res p ?a)]" +
"[axiom1: -> (n1 p n3)]";
List<Rule> ruleList = Rule.parseRules(rules);
-
+
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(Factory.createGraphMem());
TestUtil.assertIteratorValues(this, infgraph.find(null, null, null),
new Triple[] {
new Triple(n1, p, n3),
new Triple(n2, p, n3),
});
-
+
infgraph.add(new Triple(n1, q, n4));
infgraph.add(new Triple(n1, q, n3));
@@ -352,9 +452,9 @@ public class TestBasics extends TestCase {
new Triple(n2, q, n3),
new Triple(res, p, n3)
});
-
+
}
-
+
/**
* Test schema partial binding machinery
*/
@@ -368,7 +468,7 @@ public class TestBasics extends TestCase {
Graph data = Factory.createGraphMem();
data.add(new Triple(n1, q, n4));
data.add(new Triple(n1, q, n3));
-
+
Reasoner reasoner = new BasicForwardRuleReasoner(ruleList);
Reasoner boundReasoner = reasoner.bindSchema(schema);
InfGraph infgraph = boundReasoner.bind(data);
@@ -384,7 +484,7 @@ public class TestBasics extends TestCase {
new Triple(res, p, n3)
});
}
-
+
/**
* Test functor handling
*/
@@ -396,7 +496,7 @@ public class TestBasics extends TestCase {
"[ (?x eg:prop functor(?v, ?*)) -> (?x eg:propfunc ?v) ]" +
"";
List<Rule> ruleList = Rule.parseRules(rules);
-
+
Model data = ModelFactory.createDefaultModel();
Resource R1 = data.createResource(PrintUtil.egNS + "R1");
Resource D = data.createResource(PrintUtil.egNS + "D");
@@ -406,13 +506,13 @@ public class TestBasics extends TestCase {
Property propfunc = data.createProperty(PrintUtil.egNS, "propfunc");
Property rbr = data.createProperty(ReasonerVocabulary.RBNamespace, "restriction");
R1.addProperty(OWL.onProperty, p).addProperty(OWL.allValuesFrom, D);
-
+
Reasoner reasoner = new BasicForwardRuleReasoner(ruleList);
InfGraph infgraph = reasoner.bind(data.getGraph());
Model infModel = ModelFactory.createModelForGraph(infgraph);
Resource foo = infModel.createResource(PrintUtil.egNS + "foo");
Resource bar = infModel.createResource(PrintUtil.egNS + "bar");
-
+
RDFNode flit = infModel.getResource(R1.getURI()).getRequiredProperty(rbr).getObject();
assertNotNull(flit);
assertEquals(flit.toString(), "allOK");
@@ -421,11 +521,11 @@ public class TestBasics extends TestCase {
// assertEquals("all", func.getName());
// assertEquals(p.getNode(), func.getArgs()[0]);
// assertEquals(D.getNode(), func.getArgs()[1]);
-
+
Literal one = (Literal)foo.getRequiredProperty(propbar).getObject();
assertEquals(Integer.valueOf(1), one.getValue());
}
-
+
/**
* The the minimal machinery for supporting builtins
*/
@@ -437,7 +537,7 @@ public class TestBasics extends TestCase {
"[axiom2: -> (n1 p 4)]" +
"";
List<Rule> ruleList = Rule.parseRules(rules);
-
+
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(Factory.createGraphMem());
TestUtil.assertIteratorValues(this, infgraph.find(n1, q, null),
new Triple[] {
@@ -448,14 +548,14 @@ public class TestBasics extends TestCase {
new Triple[] {
new Triple(n2, q, Util.makeIntNode(1))
});
-
+
}
-
+
/**
* The the "remove" builtin
*/
public void testRemoveBuiltin() {
- String rules =
+ String rules =
"[rule1: (?x p ?y), (?x q ?y) -> remove(0)]" +
"";
List<Rule> ruleList = Rule.parseRules(rules);
@@ -464,20 +564,20 @@ public class TestBasics extends TestCase {
infgraph.add(new Triple(n1, p, Util.makeIntNode(1)));
infgraph.add(new Triple(n1, p, Util.makeIntNode(2)));
infgraph.add(new Triple(n1, q, Util.makeIntNode(2)));
-
+
TestUtil.assertIteratorValues(this, infgraph.find(n1, null, null),
new Triple[] {
new Triple(n1, p, Util.makeIntNode(1)),
new Triple(n1, q, Util.makeIntNode(2))
});
-
+
}
-
+
/**
* The the "drop" builtin
*/
public void testDropBuiltin() {
- String rules =
+ String rules =
"[rule1: (?x p ?y) -> drop(0)]" +
"";
List<Rule> ruleList = Rule.parseRules(rules);
@@ -486,14 +586,14 @@ public class TestBasics extends TestCase {
infgraph.add(new Triple(n1, p, Util.makeIntNode(1)));
infgraph.add(new Triple(n1, p, Util.makeIntNode(2)));
infgraph.add(new Triple(n1, q, Util.makeIntNode(2)));
-
+
TestUtil.assertIteratorValues(this, infgraph.find(n1, null, null),
new Triple[] {
new Triple(n1, q, Util.makeIntNode(2))
});
-
+
}
-
+
/**
* Test the rebind operation.
*/
@@ -517,7 +617,7 @@ public class TestBasics extends TestCase {
new Triple(n1, q, n3)
});
}
-
+
/**
* Test size bug, used to blow up if size was called before any queries.
*/
@@ -529,7 +629,7 @@ public class TestBasics extends TestCase {
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(data);
assertEquals(infgraph.size(), 2);
}
-
+
/**
* Check validity report implementation, there had been a stupid bug here.
*/
@@ -540,7 +640,7 @@ public class TestBasics extends TestCase {
assertTrue(report.isValid());
report.add(true, "dummy", "dummy2");
assertTrue( ! report.isValid());
-
+
report = new StandardValidityReport();
report.add(false, "dummy", "dummy1");
report.add(true, "dummy", "dummy2");
@@ -553,7 +653,7 @@ public class TestBasics extends TestCase {
report.add(new ValidityReport.Report(false, "dummy", "dummy3"));
assertTrue( ! report.isValid());
}
-
+
/**
* Test the list conversion utility that is used in some of the builtins.
*/
@@ -572,11 +672,11 @@ public class TestBasics extends TestCase {
data.add(new Triple(n4, rest, n5));
data.add(new Triple(n5, first, q));
data.add(new Triple(n5, rest, nil));
-
+
String rules = "[rule1: (?x p ?y) -> (?x q ?y)]";
List<Rule> ruleList = Rule.parseRules(rules);
InfGraph infgraph = new BasicForwardRuleReasoner(ruleList).bind(data);
-
+
RuleContext context = new BFRuleContext( (ForwardRuleInfGraphI) infgraph);
List<Node> result = Util.convertList(n1, context);
assertEquals(result.size(), 2);
@@ -587,5 +687,5 @@ public class TestBasics extends TestCase {
assertEquals(result2.size(), 1);
assertEquals(result2.get(0), p);
}
-
+
}