You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by cl...@apache.org on 2015/05/10 15:04:11 UTC
[42/50] [abbrv] jena git commit: Added initial contract tests added
testing_framework
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestSuite.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestSuite.java b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestSuite.java
new file mode 100644
index 0000000..7e19122
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestSuite.java
@@ -0,0 +1,143 @@
+/*
+ * 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.testing_framework.manifest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.ParentRunner;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.jena.shared.JenaException;
+
+/**
+ * Class that runs the Manifest annotated tests.
+ *
+ * Used with <code>@RunWith( ManifestSuite.class )</code> this class loads a
+ * manifest test suite file and adds the tests.
+ * <p>
+ * Tests annotated with <code>@RunWith( ManifestSuite.class )</code> must
+ * have a <code>ManifestFile</code> annotation specifying the path to the manifest file
+ * </p>
+ */
+public class ManifestSuite extends ParentRunner<Runner> {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(ManifestSuite.class);
+ private final List<Runner> fRunners;
+ private final ManifestItemHandler itemHandler;
+ private final ManifestFile mf;
+
+ /**
+ * Called reflectively on classes annotated with
+ * <code>@RunWith(Suite.class)</code>
+ *
+ * @param cls
+ * the root class
+ * @param builder
+ * builds runners for classes in the suite
+ * @throws Throwable
+ */
+ public ManifestSuite(Class<? extends ManifestItemHandler> cls,
+ RunnerBuilder builder) throws Throwable {
+ super(cls);
+
+ List<Throwable> errors = new ArrayList<Throwable>();
+
+ mf = cls.getAnnotation(ManifestFile.class);
+ if (mf == null) {
+ throw new IllegalStateException(
+ "ManifestSuite requries ManifestFile annotation");
+ }
+ itemHandler = cls.newInstance();
+
+ Runner[] runner = new Runner[1];
+ try {
+ runner[0] = oneManifest(new Manifest(mf.value()),
+ new ArrayList<Runner>());
+ } catch (JenaException ex) {
+ runner[0] = new ErrorReportingRunner(null, ex);
+ }
+
+ if (!errors.isEmpty()) {
+ throw new InitializationError(errors);
+ }
+ fRunners = Collections.unmodifiableList(Arrays.asList(runner));
+ }
+
+ private Runner oneManifest(final Manifest manifest, List<Runner> r) {
+
+ // Recurse
+ for (Iterator<String> iter = manifest.includedManifests(); iter
+ .hasNext();) {
+ try {
+ r.add(oneManifest(new Manifest(iter.next()),
+ new ArrayList<Runner>()));
+ } catch (JenaException ex) {
+ r.add(new ErrorReportingRunner(null, ex));
+ }
+ }
+ itemHandler.setTestRunnerList(r);
+ manifest.apply(itemHandler);
+ try {
+ return new Suite((Class<?>) null, r) {
+
+ @Override
+ protected String getName() {
+ return manifest.getName();
+ }
+
+ };
+ } catch (InitializationError e) {
+ return new ErrorReportingRunner(null, e);
+ }
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return fRunners;
+ }
+
+ @Override
+ protected Description describeChild(Runner child) {
+ return child.getDescription();
+ }
+
+ @Override
+ protected void runChild(Runner child, RunNotifier notifier) {
+ child.run(notifier);
+ }
+
+ /**
+ * Returns a name used to describe this Runner
+ */
+ @Override
+ protected String getName() {
+ return String.format("%s - %s", super.getName(), mf.value());
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTest.java b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTest.java
new file mode 100644
index 0000000..cfde240
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTest.java
@@ -0,0 +1,13 @@
+package org.apache.jena.testing_framework.manifest;
+
+public abstract class ManifestTest {
+
+ protected ManifestItem manifestItem;
+
+ public final void setManifestItem(ManifestItem manifestItem) {
+ this.manifestItem = manifestItem;
+ }
+
+ abstract public void runTest();
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTestRunner.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTestRunner.java b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTestRunner.java
new file mode 100644
index 0000000..616b444
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/manifest/ManifestTestRunner.java
@@ -0,0 +1,75 @@
+package org.apache.jena.testing_framework.manifest;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+
+public class ManifestTestRunner extends BlockJUnit4ClassRunner {
+
+ private ManifestItem manifestItem;
+
+ public ManifestTestRunner(ManifestItem manifestItem,
+ Class<? extends ManifestTest> cls) throws InitializationError {
+ super(cls);
+ this.manifestItem = manifestItem;
+ }
+
+ /**
+ * Returns the name that describes {@code method} for {@link Description}s.
+ * Default implementation is the method's name
+ */
+ @Override
+ protected String testName(FrameworkMethod method) {
+ return manifestItem.getTestName();
+ }
+
+ /**
+ * Returns the methods that run tests. Default implementation returns all
+ * methods annotated with {@code @Test} on this class and superclasses that
+ * are not overridden.
+ */
+ @Override
+ protected List<FrameworkMethod> computeTestMethods() {
+ FrameworkMethod[] lst = new FrameworkMethod[1];
+
+ try {
+ lst[0] = new FrameworkMethod(getTestClass().getJavaClass()
+ .getMethod("runTest")) {
+
+ @Override
+ public String getName() {
+ return manifestItem.getTestName();
+ }
+ };
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException(e);
+ } catch (SecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ return Arrays.asList(lst);
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.createTestDescription(this.getTestClass()
+ .getJavaClass(), manifestItem.getTestName(), new Annotation[0]);
+ }
+
+ /**
+ * Returns a new fixture for running a test. Default implementation executes
+ * the test class's no-argument constructor (validation should have ensured
+ * one exists).
+ */
+ @Override
+ protected Object createTest() throws Exception {
+ ManifestTest instance = (ManifestTest) super.createTest();
+ instance.setManifestItem(manifestItem);
+ return instance;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/package-info.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/package-info.java b/jena-core/src/test/java/org/apache/jena/testing_framework/package-info.java
new file mode 100644
index 0000000..96f3e42
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/package-info.java
@@ -0,0 +1,109 @@
+/*
+ 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.testing_framework;
+
+/**
+ * Foo set of classes providing support for testing.
+ * <p>
+ * Testing guidelines/suggestions.
+ * </p><p>
+ * Interface tests are built so that developers may test that implementations meet the contract
+ * set out in the interface and accompanying documentation.
+ * </p>
+ * <h4>Producers</h4>
+ * <p>
+ * The test and suites use an instance of the [INTERFACE]ProducerInterface to create an instance
+ * of the the Object being tested.
+ * </p>
+ * <h4>Tests</h4>
+ * <p>
+ * Interface tests are noted as Abstract[INTERFACE]Test. Implementations of [INTERFACE] should
+ * create a concrete implementation of Abstract[INTERFACE]Test with an [INTERFACE]Producer to create
+ * instances of the Object. Passing the test indicates a compliance with the base interface
+ * definition.
+ * </p><p>
+ * In general to implement a test requires a few lines of code as is noted in the example below
+ * where the new Foo graph implementation is being tested.</p>
+ * <pre><code>
+ * public class FooGraphTest extends AbstractGraphTest {
+ *
+ * // the graph producer to use while running
+ * GraphProducerInterface graphProducer = new FooGraphTest.GraphProducer();
+ *
+ * @Override
+ * protected GraphProducerInterface getGraphProducer() {
+ * return graphProducer;
+ * }
+ *
+ * // the implementation of the graph producer.
+ * public static class GraphProducer extends AbstractGraphProducer {
+ *
+ * @Override
+ * protected Graph createNewGraph() {
+ * return new FooGraph();
+ * }
+ * }
+ * }
+ * </code></pre>
+ * <h4>Suites</h4>
+ * <p>
+ * Test suites are named as Abstract[INTERFACE]Suite. Suites contain several tests (see above)
+ * that exercise all of the tests for the components of the object under test. For example the
+ * graph suite includes tests for the graph itself, the reifier, finding literals, recursive
+ * subgraph extraction, event manager, and transactions. Running the suites is a bit more
+ * complicated then running the tests.
+ * </p>
+ * Suites are created using the JUnit 4 <code>@RunWith(Suite.class)</code and
+ * <code>@Suite.SuiteClasses({ })</code> annotations. This has several effects that the developer
+ * should know about:</p>
+ * <ul>
+ * <li>The suite class does not get instantiated during the run.</li>
+ * <li>The test class names must be known at coding time (not run time) as they are listed in the
+ * annotation.</li>
+ * <li>Configuration of the tests has to occur during the static initialization phase of class
+ * loading.</li>
+ * </ul>
+ * <p>
+ * To meet these requirements the AbstractGraphSuite has a static variable that holds the instance
+ * of the GraphProducerInterface and a number of local static implementations of the Abstract tests
+ * that implement the "getGraphProducer()" method by returning the static instance. The names of
+ * the local graphs are then used in the @Suite.SuiteClasses annotation. This makes creating an
+ * instance of the AbstractGraphSuite for a graph implementation fairly simple as is noted below.
+ * </p>
+ * <pre><code>
+ * public class FooGraphSuite extends AbstractGraphSuite {
+ * @BeforeClass
+ * public static void beforeClass() {
+ * setGraphProducer(new GraphProducer());
+ * }
+ *
+ * public static class GraphProducer extends AbstractGraphProducer {
+ * @Override
+ * protected Graph createNewGraph() {
+ * return new FooGraph();
+ * }
+ * }
+ * }
+ * </code></pre>
+ * <p>
+ * <b>Note:</b> that the beforeClass() method is annotated with @BeforeClass. the @BeforeClass
+ * causes it to be run once before any of the test methods in the class. This will set the static
+ * instance of the graph producer before the suite is run so that it is provided to the enclosed
+ * tests.
+ * </p>
+ */
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleItem.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleItem.java b/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleItem.java
new file mode 100644
index 0000000..65aff5b
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleItem.java
@@ -0,0 +1,84 @@
+/*
+ * 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.testing_framework.tuples;
+
+/**
+ * The unit found in a line of a tuple. Can be a string (quoted, possibly with
+ * the datatype, or unquoted) or a URI.
+ */
+public class TupleItem {
+ public static final int URI = 0;
+ public static final int STRING = 1;
+ public static final int UNKNOWN = 2;
+ public static final int UNQUOTED = 3;
+ public static final int ANON = 4;
+
+ String rep;
+ String datatype;
+ String asFound;
+ int itemType;
+
+ TupleItem(String value, String valAsFound, int type, String dt) {
+ rep = value;
+ asFound = valAsFound;
+ itemType = type;
+ datatype = dt;
+ }
+
+ public int getType() {
+ return itemType;
+ }
+
+ public boolean isURI() {
+ return itemType == URI;
+ }
+
+ public boolean isString() {
+ return itemType == STRING;
+ }
+
+ public boolean isUnknown() {
+ return itemType == UNKNOWN;
+ }
+
+ public boolean isUnquoted() {
+ return itemType == UNQUOTED;
+ }
+
+ public boolean isAnon() {
+ return itemType == ANON;
+ }
+
+ public String get() {
+ return rep;
+ }
+
+ public String getDT() {
+ return datatype;
+ }
+
+ public String asQuotedString() {
+ return asFound;
+ }
+
+ @Override
+ public String toString() {
+ return rep;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleSet.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleSet.java b/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleSet.java
new file mode 100644
index 0000000..8e78879
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/tuples/TupleSet.java
@@ -0,0 +1,274 @@
+/*
+ * 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.testing_framework.tuples;
+
+import java.io.*;
+import java.util.*;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TupleSet implements Iterator<List<TupleItem>> {
+ BufferedReader in;
+ public String line = null;
+ public int lineNumber = 0;
+
+ static final char COMMENTCHAR = '#';
+ List<TupleItem> current = null;
+ boolean finished = false;
+
+ protected static Logger logger = LoggerFactory.getLogger(TupleSet.class);
+
+ /** Creates new TupleSet */
+ public TupleSet(Reader r) {
+ if (!(r instanceof BufferedReader))
+ in = new BufferedReader(r);
+ else
+ in = (BufferedReader) r;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (finished)
+ return false;
+
+ if (current == null)
+ current = tuple();
+ return current != null;
+ }
+
+ @Override
+ public List<TupleItem> next() {
+ if (hasNext()) {
+ List<TupleItem> x = current;
+ current = null;
+ return x;
+ } else
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new java.lang.UnsupportedOperationException("TupleSet.remove");
+ }
+
+ private List<TupleItem> tuple() {
+
+ try {
+ lineNumber++;
+ line = in.readLine();
+ } catch (IOException e) {
+ }
+
+ if (line == null) {
+ finished = true;
+ return null;
+ }
+
+ // System.out.println("Line: "+line) ;
+ List<TupleItem> tuple = new ArrayList<TupleItem>();
+ int i = 0;
+ int j = 0;
+ boolean errorFound = false;
+
+ tupleLoop: for (;;) {
+ // Move to beginning of next item.
+ i = skipwhitespace(line, j);
+
+ if (i < 0)
+ break;
+
+ int iStart = -2; // Points to the beginning of the item as found
+ int jStart = -2; // Points to the item without quotes
+ int iFinish = -2; // Points after the end of the item as found
+ int jFinish = -2; // Points after the end of the item without quotes
+ int dtStart = -2; // Points to start of datatype (after < quote)
+ int dtFinish = -2; // Points to end of datatype
+ int type = TupleItem.UNKNOWN;
+
+ switch (line.charAt(i)) {
+ case COMMENTCHAR:
+ break tupleLoop;
+ case '<':
+ type = TupleItem.URI;
+ iStart = i;
+ jStart = i + 1;
+ int newPosn = parseURI(i, line);
+ if (newPosn < 0) {
+ errorFound = true;
+ break tupleLoop;
+ }
+ j = newPosn;
+
+ iFinish = j + 1;
+ jFinish = j;
+ break;
+ case '"':
+ type = TupleItem.STRING;
+ iStart = i;
+ jStart = i + 1;
+ boolean inEscape = false;
+ for (j = i + 1; j < line.length(); j++) {
+ char ch = line.charAt(j);
+ if (inEscape) {
+ // ToDo: escape
+ inEscape = false;
+ continue;
+ }
+ // Not an escape
+ if (ch == '"')
+ break;
+
+ if (ch == '\\')
+ inEscape = true;
+ if (ch == '\n' || ch == '\r') {
+ errorFound = true;
+ break tupleLoop;
+
+ }
+ }
+
+ // Malformed
+ if (j == line.length()) {
+ errorFound = true;
+ break tupleLoop;
+ }
+
+ iFinish = j + 1;
+ jFinish = j;
+ // RDF literals may be followed by their type.
+
+ if (j < line.length() - 3 && line.charAt(j + 1) == '^'
+ && line.charAt(j + 2) == '^'
+ && line.charAt(j + 3) == '<') {
+ dtFinish = parseURI(j + 3, line);
+ dtStart = j + 4;
+ if (dtFinish < 0) {
+ errorFound = true;
+ break tupleLoop;
+ }
+ j = dtFinish + 1;
+ // String dt = line.substring(dtStart, dtFinish) ;
+ // System.out.println("I see a datatype:"+dt) ;
+ }
+
+ break;
+ case '_':
+ type = TupleItem.ANON;
+ iStart = i;
+ for (j = i + 1; j < line.length(); j++) {
+ char ch = line.charAt(j);
+ if (ch == ' ' || ch == '\t' || ch == '.')
+ break;
+ if (!Character.isLetterOrDigit(ch) && !(ch == '_')
+ && !(ch == ':')) {
+ errorFound = true;
+ break tupleLoop;
+ }
+ }
+ iFinish = j;
+ jStart = iStart;
+ jFinish = iFinish;
+ break;
+ case '.':
+ case '\n':
+ case '\r':
+ return tuple;
+ default:
+ type = TupleItem.UNQUOTED;
+ iStart = i;
+ jStart = i;
+ for (j = i + 1; j < line.length(); j++) {
+ char ch = line.charAt(j);
+ if (ch == ' ' || ch == '\t' || ch == '.')
+ break;
+
+ // if ( ! Character.isLetterOrDigit(line.charAt(i)) )
+ // {
+ // errorFound = true ;
+ // break tupleLoop;
+ // }
+ }
+ // Malformed
+ if (j == line.length() + 1) {
+ errorFound = true;
+ break tupleLoop;
+ }
+ iFinish = j;
+ jFinish = j;
+ break;
+ }
+ String item = line.substring(jStart, jFinish);
+ String literal = line.substring(iStart, iFinish);
+ String dt = null;
+ if (dtStart > 0)
+ dt = line.substring(dtStart, dtFinish);
+
+ tuple.add(new TupleItem(item, literal, type, dt));
+ j++;
+ // End of item.
+ }
+ // End of this line.
+ if (errorFound) {
+ logger.error("Error in TupleSet.tuple: " + line);
+
+ String s = "";
+ int k = 0;
+ for (; k < i; k++)
+ s = s + " ";
+ s = s + "^";
+ for (; k < j - 1; k++)
+ s = s + " ";
+ s = s + "^";
+ logger.error(s);
+ return null;
+ }
+
+ if (tuple.size() == 0) {
+ // Nothing found : loop by tail recursion
+ return tuple();
+ }
+ return tuple;
+ }
+
+ private int skipwhitespace(String s, int i) {
+ for (; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ // Horizonal whitespace
+ if (ch != ' ' && ch != '\t')
+ return i;
+ }
+ return -1;
+ }
+
+ private int parseURI(int i, String line) {
+ int j;
+ for (j = i + 1; j < line.length(); j++) {
+ char ch = line.charAt(j);
+ if (ch == '>')
+ break;
+ if (ch == '\n' || ch == '\r')
+ return -1;
+ }
+ // Malformed
+ if (j == line.length())
+ return -2;
+ return j;
+ }
+}