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:13 UTC

[44/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/graph/RecordingGraphListener.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/RecordingGraphListener.java b/jena-core/src/test/java/org/apache/jena/graph/RecordingGraphListener.java
new file mode 100644
index 0000000..ed94c8f
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/RecordingGraphListener.java
@@ -0,0 +1,92 @@
+/*
+ * 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.graph;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphListener;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.testing_framework.AbstractRecordingListener;
+import org.apache.jena.testing_framework.GraphHelper;
+
+/**
+ * This testing listener records the event names and data, and provides a method
+ * for comparing the actual with the expected history.
+ */
+public class RecordingGraphListener extends AbstractRecordingListener implements
+		GraphListener {
+
+	@Override
+	public void notifyAddTriple(Graph g, Triple t) {
+		record("add", g, t);
+	}
+
+	@Override
+	public void notifyAddArray(Graph g, Triple[] triples) {
+		record("add[]", g, triples);
+	}
+
+	@Override
+	public void notifyAddList(Graph g, List<Triple> triples) {
+		record("addList", g, triples);
+	}
+
+	@Override
+	public void notifyAddIterator(Graph g, Iterator<Triple> it) {
+		record("addIterator", g, GraphHelper.iteratorToList(it));
+	}
+
+	@Override
+	public void notifyAddGraph(Graph g, Graph added) {
+		record("addGraph", g, added);
+	}
+
+	@Override
+	public void notifyDeleteTriple(Graph g, Triple t) {
+		record("delete", g, t);
+	}
+
+	@Override
+	public void notifyDeleteArray(Graph g, Triple[] triples) {
+		record("delete[]", g, triples);
+	}
+
+	@Override
+	public void notifyDeleteList(Graph g, List<Triple> triples) {
+		record("deleteList", g, triples);
+	}
+
+	@Override
+	public void notifyDeleteIterator(Graph g, Iterator<Triple> it) {
+		record("deleteIterator", g, GraphHelper.iteratorToList(it));
+	}
+
+	@Override
+	public void notifyDeleteGraph(Graph g, Graph removed) {
+		record("deleteGraph", g, removed);
+	}
+
+	@Override
+	public void notifyEvent(Graph source, Object event) {
+		record("someEvent", source, event);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/TransactionHandlerContractTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/TransactionHandlerContractTest.java b/jena-core/src/test/java/org/apache/jena/graph/TransactionHandlerContractTest.java
new file mode 100644
index 0000000..d26d7e9
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/TransactionHandlerContractTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.graph;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractTest;
+
+import static org.junit.Assert.*;
+
+import org.apache.jena.graph.TransactionHandler;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.graph.impl.SimpleTransactionHandler;
+import org.apache.jena.shared.Command;
+import org.apache.jena.shared.JenaException;
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.util.CollectionFactory;
+import static org.apache.jena.testing_framework.GraphHelper.*;
+
+/**
+ * AbstractTestGraph provides a bunch of basic tests for something that purports
+ * to be a Graph. The abstract method getGraph must be overridden in subclasses
+ * to deliver a Graph of interest.
+ */
+@Contract(TransactionHandler.class)
+public class TransactionHandlerContractTest {
+
+	private IProducer<TransactionHandler> producer;
+
+	public TransactionHandlerContractTest() {
+//		producer = new IProducer<TransactionHandler>() {
+//
+//			@Override
+//			public TransactionHandler newInstance() {
+//				return new SimpleTransactionHandler();
+//			}
+//
+//			@Override
+//			public void cleanUp() {
+//
+//			}
+//		};
+	}
+
+	@Contract.Inject
+	public void setProducer(IProducer<TransactionHandler> producer) {
+		this.producer = producer;
+	}
+
+	protected IProducer<TransactionHandler> getTransactionHandlerProducer() {
+		return producer;
+	}
+
+	/**
+	 * Test that Graphs have transaction support methods, and that if they fail
+	 * on some g they fail because they do not support the operation.
+	 */
+	@ContractTest
+	public void testTransactionsExistAsPerTransactionSupported() {
+		Command cmd = new Command() {
+			@Override
+			public Object execute() {
+				return null;
+			}
+		};
+
+		TransactionHandler th = getTransactionHandlerProducer().newInstance();
+
+		if (th.transactionsSupported()) {
+			th.begin();
+			th.abort();
+			th.begin();
+			th.commit();
+			th.executeInTransaction(cmd);
+		} else {
+			try {
+				th.begin();
+				fail("Should have thrown UnsupportedOperationException");
+			} catch (UnsupportedOperationException x) {
+			}
+
+			try {
+				th.abort();
+				fail("Should have thrown UnsupportedOperationException");
+			} catch (UnsupportedOperationException x) {
+			}
+			try {
+				th.commit();
+				fail("Should have thrown UnsupportedOperationException");
+			} catch (UnsupportedOperationException x) {
+			}
+			/* */
+			try {
+				th.executeInTransaction(cmd);
+				fail("Should have thrown UnsupportedOperationException");
+			} catch (UnsupportedOperationException x) {
+			}
+		}
+	}
+
+	@ContractTest
+	public void testExecuteInTransactionCatchesThrowable() {
+		TransactionHandler th = getTransactionHandlerProducer().newInstance();
+
+		if (th.transactionsSupported()) {
+			Command cmd = new Command() {
+				@Override
+				public Object execute() throws Error {
+					throw new Error();
+				}
+			};
+			try {
+				th.executeInTransaction(cmd);
+				fail("Should have thrown JenaException");
+			} catch (JenaException x) {
+			}
+		}
+	}
+
+	static final Triple[] tripleArray = tripleArray("S P O; Foo R B; X Q Y");
+
+	static final List<Triple> tripleList = Arrays
+			.asList(tripleArray("i lt j; p equals q"));
+
+	static final Triple[] setTriples = tripleArray("scissors cut paper; paper wraps stone; stone breaks scissors");
+
+	static final Set<Triple> tripleSet = CollectionFactory
+			.createHashedSet(Arrays.asList(setTriples));
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/compose/DeltaTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/compose/DeltaTest.java b/jena-core/src/test/java/org/apache/jena/graph/compose/DeltaTest.java
new file mode 100755
index 0000000..a0bf737
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/compose/DeltaTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.graph.compose;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.ContractTest;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(Delta.class)
+public class DeltaTest  {
+
+	protected IProducer<Delta> graphProducer;
+	
+	public DeltaTest() {
+		super();
+		graphProducer = new AbstractGraphProducer<Delta>() {
+			private Map<Graph, Graph> map = new HashMap<Graph, Graph>();
+
+			@Override
+			protected Delta createNewGraph() {
+				Graph g = memGraph();
+				Delta d = new Delta(g);
+				map.put(d, g);
+				return d;
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph d) {
+//				Delta dl = (Delta)d;
+//				Graph g = map.get(d);
+//				if (g == null) {
+//					throw new IllegalStateException("graph missing from map");
+//				}
+//				return new Graph[] { g,  (Graph)dl.getL(), (Graph)dl.getR() };
+				return null;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+			@Override
+			protected void afterClose(Graph g) {
+				map.remove(g);
+			}
+		};
+	}
+
+	@Contract.Inject
+	public final IProducer<Delta> getDeltaTestProducer() {
+		return graphProducer;
+	}
+
+	@ContractTest
+	public void testDelta() {
+		Graph x = graphWith(getDeltaTestProducer().newInstance(), "x R y");
+		assertContains("x", "x R y", x);
+		x.delete(triple("x R y"));
+		assertOmits("x", x, "x R y");
+		/* */
+		Graph base = graphWith("x R y; p S q; I like cheese; pins pop balloons");
+		Delta delta = new Delta(base);
+		assertContainsAll("Delta", delta,
+				"x R y; p S q; I like cheese; pins pop balloons");
+		assertContainsAll("Base", base,
+				"x R y; p S q; I like cheese; pins pop balloons");
+		/* */
+		delta.add(triple("pigs fly winglessly"));
+		delta.delete(triple("I like cheese"));
+		/* */
+		assertContainsAll("changed Delta", delta,
+				"x R y; p S q; pins pop balloons; pigs fly winglessly");
+		assertOmits("changed delta", delta, "I like cheese");
+		assertContains("delta additions", "pigs fly winglessly",
+				delta.getAdditions());
+		assertOmits("delta additions", delta.getAdditions(), "I like cheese");
+		assertContains("delta deletions", "I like cheese", delta.getDeletions());
+		assertOmits("delta deletions", delta.getDeletions(),
+				"pigs fly winglessly");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/compose/DifferenceTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/compose/DifferenceTest.java b/jena-core/src/test/java/org/apache/jena/graph/compose/DifferenceTest.java
new file mode 100755
index 0000000..213ae36
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/compose/DifferenceTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.graph.compose;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.ContractTest;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.compose.Difference;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(Difference.class)
+public class DifferenceTest {
+
+	protected IProducer<Difference> graphProducer;
+	
+	public DifferenceTest() {
+		graphProducer = new AbstractGraphProducer<Difference>() {
+			private Map<Graph, Graph[]> map = new HashMap<Graph, Graph[]>();
+
+			@Override
+			protected Difference createNewGraph() {
+				Graph g1 = memGraph();
+				Graph g2 = memGraph();
+				Difference d = new Difference(g1, g2);
+				map.put(d, new Graph[] { g1, g2 });
+				return d;
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph d) {
+				Graph[] dg = map.get(d);
+				if (dg == null) {
+					throw new IllegalStateException("graph not in map");
+				}
+				return dg;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+			@Override
+			protected void afterClose(Graph g) {
+				map.remove(g);
+			}
+		};
+	}
+
+	@Contract.Inject
+	public final IProducer<Difference> getDifferenceTestProducer() {
+		return graphProducer;
+	}
+
+	@ContractTest
+	public void testDifference() {
+		Graph g1 = graphWith("x R y; p R q");
+		Graph g2 = graphWith("r Foo s; x R y");
+		Graph d = new Difference(g1, g2);
+		assertOmits("Difference", d, "x R y");
+		assertContains("Difference", "p R q", d);
+		assertOmits("Difference", d, "r Foo s");
+		if (d.size() != 1)
+			fail("oops: size of difference is not 1");
+		d.add(triple("cats eat cheese"));
+		assertContains("Difference.L", "cats eat cheese", g1);
+		assertOmits("Difference.R", g2, "cats eat cheese");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/compose/IntersectionTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/compose/IntersectionTest.java b/jena-core/src/test/java/org/apache/jena/graph/compose/IntersectionTest.java
new file mode 100755
index 0000000..1e6db9b
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/compose/IntersectionTest.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.graph.compose;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.ContractTest;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.compose.Intersection;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(Intersection.class)
+public class IntersectionTest {
+
+	protected IProducer<Intersection> graphProducer;
+	
+	public IntersectionTest() {
+		super();
+		graphProducer = new AbstractGraphProducer<Intersection>() {
+			private Map<Graph, Graph[]> dependencyGraph = new HashMap<Graph, Graph[]>();
+
+			@Override
+			protected Intersection createNewGraph() {
+				Graph g1 = memGraph();
+				Graph g2 = memGraph();
+				Intersection retval = new Intersection(g1, g2);
+				dependencyGraph.put(retval, new Graph[] { g1, g2 });
+				return retval;
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph g) {
+				Graph[] dg = dependencyGraph.get(g);
+				if (dg == null) {
+					throw new IllegalStateException("graph missing from map");
+				}
+				return dg;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+			@Override
+			protected void afterClose(Graph g) {
+				dependencyGraph.remove(g);
+			}
+		};
+	}
+
+	@Contract.Inject
+	public final IProducer<Intersection> getIntersectionTestProducer() {
+		return graphProducer;
+	}
+
+	@ContractTest
+	public void testIntersection() {
+		Graph g1 = graphWith( "x R y; p R q");
+		Graph g2 = graphWith( "r Foo s; x R y");
+		Intersection i = new Intersection(g1, g2);
+		assertContains("Intersection", "x R y", i);
+		assertOmits("Intersection", i, "p R q");
+		assertOmits("Intersection", i, "r Foo s");
+		if (i.size() != 1)
+			fail("oops: size of intersection is not 1");
+		i.add(triple("cats eat cheese"));
+		assertContains("Intersection.L", "cats eat cheese", g1);
+		assertContains("Intersection.R", "cats eat cheese", g2);
+	}
+
+	@ContractTest
+	public void testDeleteDoesNotUpdateR() {
+		Graph L = graphWith("a pings b; b pings c; c pings a");
+		Graph R = graphWith("c pings a; b pings c; x captures y");
+		Graph join = new Intersection(L, R);
+		GraphUtil.deleteFrom(L, R);
+		assertIsomorphic("R should not change",
+				graphWith("c pings a; b pings c; x captures y"), R);
+		assertIsomorphic(graphWith("a pings b"), L);
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/compose/UnionTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/compose/UnionTest.java b/jena-core/src/test/java/org/apache/jena/graph/compose/UnionTest.java
new file mode 100755
index 0000000..44bf9fb
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/compose/UnionTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.graph.compose;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.ContractTest;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphStatisticsHandler;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.graph.compose.Union;
+import org.apache.jena.graph.impl.GraphBase;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(Union.class)
+public class UnionTest {
+	
+	protected IProducer<Union> graphProducer;
+	
+	public UnionTest() {
+		graphProducer = new AbstractGraphProducer<Union>() {
+			private Map<Graph, Graph[]> map = new HashMap<Graph, Graph[]>();
+
+			@Override
+			protected Union createNewGraph() {
+				Graph[] g = { memGraph(), memGraph() };
+				Union u = new Union(g[0], g[1]);
+				map.put(u, g);
+				return u;
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph d) {
+				Graph[] dg = map.get(d);
+				if (dg == null) {
+					throw new IllegalStateException("graph not in map");
+				}
+				return dg;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+			@Override
+			protected void afterClose(Graph g) {
+				map.remove(g);
+			}
+		};
+
+	}
+
+	@Contract.Inject
+	public final IProducer<Union> getUnionTestProducer() {
+		return graphProducer;
+	}
+
+	@ContractTest
+	public void testUnion() {
+		Graph g1 = graphWith("x R y; p R q");
+		Graph g2 = graphWith("r Foo s; x R y");
+		Union u = new Union(g1, g2);
+		assertContains("Union", "x R y", u);
+		assertContains("Union", "p R q", u);
+		assertContains("Union", "r Foo s", u);
+		if (u.size() != 3)
+			fail("oops: size of union is not 3");
+		u.add(triple("cats eat cheese"));
+		assertContains("Union", "cats eat cheese", u);
+		if (contains(g1, "cats eat cheese") == false
+				&& contains(g2, "cats eat cheese") == false)
+			fail("oops: neither g1 nor g2 contains `cats eat cheese`");
+	}
+
+	static class AnInteger {
+		public int value = 0;
+
+		public AnInteger(int value) {
+			this.value = value;
+		}
+	}
+
+	@ContractTest
+	public void testUnionValues() {
+		testUnion(0, 0, 0, 0);
+	}
+
+	@ContractTest
+	public void testCopiesSingleNonZeroResult() {
+		testUnion(1, 1, 0, 0);
+		testUnion(1, 0, 1, 0);
+		testUnion(1, 0, 0, 1);
+		testUnion(1, 1, 0, 0);
+		testUnion(2, 0, 2, 0);
+		testUnion(4, 0, 0, 4);
+	}
+
+	@ContractTest
+	public void testResultIsSumOfBaseResults() {
+		testUnion(3, 1, 2, 0);
+		testUnion(5, 1, 0, 4);
+		testUnion(6, 0, 2, 4);
+		testUnion(7, 1, 2, 4);
+		testUnion(3, 0, 2, 1);
+		testUnion(5, 4, 1, 0);
+		testUnion(6, 2, 2, 2);
+		testUnion(7, 6, 0, 1);
+	}
+
+	@ContractTest
+	public void testUnknownOverrulesAll() {
+		testUnion(-1, -1, 0, 0);
+		testUnion(-1, 0, -1, 0);
+		testUnion(-1, 0, 0, -1);
+		testUnion(-1, -1, 1, 1);
+		testUnion(-1, 1, -1, 1);
+		testUnion(-1, 1, 1, -1);
+	}
+
+	/**
+	 * Asserts that the statistic obtained by probing the three-element union
+	 * with statistics <code>av</code>, <code>bv</code>, and <code>cv</code> is
+	 * <code>expected</code>.
+	 */
+	private void testUnion(int expected, int av, int bv, int cv) {
+		AnInteger a = new AnInteger(av), b = new AnInteger(bv), c = new AnInteger(
+				cv);
+		Graph g1 = graphWithGivenStatistic(a);
+		Graph g2 = graphWithGivenStatistic(b);
+		Graph g3 = graphWithGivenStatistic(c);
+		Graph[] graphs = new Graph[] { g1, g2, g3 };
+		MultiUnion mu = new MultiUnion(graphs);
+		GraphStatisticsHandler gs = new MultiUnion.MultiUnionStatisticsHandler(
+				mu);
+		assertEquals(expected, gs.getStatistic(Node.ANY, Node.ANY, Node.ANY));
+	}
+
+	static Graph graphWithGivenStatistic(final AnInteger x) {
+		return new GraphBase() {
+			@Override
+			protected ExtendedIterator<Triple> graphBaseFind(Triple t) {
+				throw new RuntimeException("should never be called");
+			}
+
+			@Override
+			protected GraphStatisticsHandler createStatisticsHandler() {
+				return new GraphStatisticsHandler() {
+					@Override
+					public long getStatistic(Node S, Node P, Node O) {
+						return x.value;
+					}
+				};
+			}
+		};
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/impl/TestCollectionGraph.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/impl/TestCollectionGraph.java b/jena-core/src/test/java/org/apache/jena/graph/impl/TestCollectionGraph.java
index 3334da7..4d9f40d 100644
--- a/jena-core/src/test/java/org/apache/jena/graph/impl/TestCollectionGraph.java
+++ b/jena-core/src/test/java/org/apache/jena/graph/impl/TestCollectionGraph.java
@@ -18,22 +18,50 @@
 
 package org.apache.jena.graph.impl;
 
+import static org.apache.jena.testing_framework.GraphHelper.memGraph;
+
 import java.util.HashSet;
 
 import org.apache.jena.graph.Graph ;
 import org.apache.jena.graph.Triple ;
 import org.apache.jena.graph.impl.CollectionGraph ;
-import org.apache.jena.graph.test.AbstractTestGraph ;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.IProducer;
 
-public class TestCollectionGraph extends AbstractTestGraph {
+@RunWith(ContractSuite.class)
+@ContractImpl(CollectionGraph.class)
+public class TestCollectionGraph {
 	 
-	public TestCollectionGraph(String name) {
-		super(name);
+	protected IProducer<CollectionGraph> graphProducer;
+	
+	public TestCollectionGraph() {
+		graphProducer = new AbstractGraphProducer<CollectionGraph>() {
+			
+			@Override
+			protected CollectionGraph createNewGraph() {
+				return new CollectionGraph( new HashSet<Triple>() );
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph d) {
+				return null;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+		};
 	}
 
-	@Override
-	public Graph getGraph() {
-		return new CollectionGraph( new HashSet<Triple>() );
+	@Contract.Inject
+	public final IProducer<CollectionGraph> getDeltaTestProducer() {
+		return graphProducer;
 	}
 
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/impl/TestWrappedGraph.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/impl/TestWrappedGraph.java b/jena-core/src/test/java/org/apache/jena/graph/impl/TestWrappedGraph.java
new file mode 100644
index 0000000..7910660
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/impl/TestWrappedGraph.java
@@ -0,0 +1,63 @@
+/*
+ * 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.graph.impl;
+
+import static org.apache.jena.testing_framework.GraphHelper.memGraph;
+
+import org.apache.jena.graph.Graph ;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(WrappedGraph.class)
+public class TestWrappedGraph {
+	 
+	protected IProducer<WrappedGraph> graphProducer;
+	
+	public TestWrappedGraph() {
+		graphProducer = new AbstractGraphProducer<WrappedGraph>() {
+			
+			@Override
+			protected WrappedGraph createNewGraph() {
+				return new WrappedGraph( memGraph() );
+			}
+
+			@Override
+			public Graph[] getDependsOn(Graph d) {
+				return null;
+			}
+
+			@Override
+			public Graph[] getNotDependsOn(Graph g) {
+				return new Graph[] { memGraph() };
+			}
+
+		};
+	}
+
+	@Contract.Inject
+	public final IProducer<WrappedGraph> getDeltaTestProducer() {
+		return graphProducer;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/graph/impl/TripleStoreContractTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/graph/impl/TripleStoreContractTest.java b/jena-core/src/test/java/org/apache/jena/graph/impl/TripleStoreContractTest.java
new file mode 100644
index 0000000..0b074aa
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/impl/TripleStoreContractTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.graph.impl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractTest;
+
+import static org.junit.Assert.*;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+import org.apache.jena.mem.GraphTripleStore;
+import org.apache.jena.graph.impl.TripleStore;
+import org.apache.jena.testing_framework.ContractTemplate;
+
+import org.xenei.junit.contract.IProducer;
+
+/**
+ * AbstractTestTripleStore - post-hoc tests for TripleStores.
+ */
+
+@Contract(TripleStore.class)
+public class TripleStoreContractTest<T extends TripleStore> extends
+		ContractTemplate<IProducer<T>> {
+
+	protected TripleStore store;
+
+	public TripleStoreContractTest() {
+		IProducer<TripleStore> producer = new IProducer<TripleStore>() {
+
+			@Override
+			public TripleStore newInstance() {
+				return new GraphTripleStore(memGraph());
+			}
+
+			@Override
+			public void cleanUp() {
+				// TODO Auto-generated method stub
+
+			}
+
+		};
+		setProducer((IProducer<T>) producer);
+	}
+
+	/**
+	 * Subclasses must over-ride to return a new empty TripleStore.
+	 */
+	@Contract.Inject
+	public final void setTripleStoreContractTestProducer(IProducer<T> producer) {
+		super.setProducer(producer);
+	}
+
+	@Before
+	public final void beforeAbstractTripleStoreTest() {
+		store = getProducer().newInstance();
+	}
+
+	@After
+	public final void afterAbstractTripleStoreTest() {
+		getProducer().cleanUp();
+	}
+
+	@ContractTest
+	public void testEmpty() {
+		testEmpty(store);
+	}
+
+	@ContractTest
+	public void testAddOne() {
+		store.add(triple("x P y"));
+		assertEquals(false, store.isEmpty());
+		assertEquals(1, store.size());
+		assertEquals(true, store.contains(triple("x P y")));
+		assertEquals(nodeSet("x"), iteratorToSet(store.listSubjects()));
+		assertEquals(nodeSet("y"), iteratorToSet(store.listObjects()));
+		assertEquals(tripleSet("x P y"),
+				iteratorToSet(store.find(triple("?? ?? ??"))));
+	}
+
+	@ContractTest
+	public void testListSubjects() {
+		someStatements(store);
+		assertEquals(nodeSet("a x _z r q"), iteratorToSet(store.listSubjects()));
+	}
+
+	@ContractTest
+	public void testListObjects() {
+		someStatements(store);
+		assertEquals(nodeSet("b y i _j _t 17"),
+				iteratorToSet(store.listObjects()));
+	}
+
+	@ContractTest
+	public void testContains() {
+		someStatements(store);
+		assertEquals(true, store.contains(triple("a P b")));
+		assertEquals(true, store.contains(triple("x P y")));
+		assertEquals(true, store.contains(triple("a P i")));
+		assertEquals(true, store.contains(triple("_z Q _j")));
+		assertEquals(true, store.contains(triple("x R y")));
+		assertEquals(true, store.contains(triple("r S _t")));
+		assertEquals(true, store.contains(triple("q R 17")));
+		/* */
+		assertEquals(false, store.contains(triple("a P x")));
+		assertEquals(false, store.contains(triple("a P _j")));
+		assertEquals(false, store.contains(triple("b Z r")));
+		assertEquals(false, store.contains(triple("_a P x")));
+	}
+
+	@ContractTest
+	public void testFind() {
+		someStatements(store);
+		assertEquals(tripleSet(""),
+				iteratorToSet(store.find(triple("no such thing"))));
+		assertEquals(tripleSet("a P b; a P i"),
+				iteratorToSet(store.find(triple("a P ??"))));
+		assertEquals(tripleSet("a P b; x P y; a P i"),
+				iteratorToSet(store.find(triple("?? P ??"))));
+		assertEquals(tripleSet("x P y; x R y"),
+				iteratorToSet(store.find(triple("x ?? y"))));
+		assertEquals(tripleSet("_z Q _j"),
+				iteratorToSet(store.find(triple("?? ?? _j"))));
+		assertEquals(tripleSet("q R 17"),
+				iteratorToSet(store.find(triple("?? ?? 17"))));
+	}
+
+	@ContractTest
+	public void testRemove() {
+		store.add(triple("nothing before ace"));
+		store.add(triple("ace before king"));
+		store.add(triple("king before queen"));
+		store.delete(triple("ace before king"));
+		assertEquals(tripleSet("king before queen; nothing before ace"),
+				iteratorToSet(store.find(triple("?? ?? ??"))));
+		store.delete(triple("king before queen"));
+		assertEquals(tripleSet("nothing before ace"),
+				iteratorToSet(store.find(triple("?? ?? ??"))));
+	}
+
+	protected void someStatements(TripleStore ts) {
+		ts.add(triple("a P b"));
+		ts.add(triple("x P y"));
+		ts.add(triple("a P i"));
+		ts.add(triple("_z Q _j"));
+		ts.add(triple("x R y"));
+		ts.add(triple("r S _t"));
+		ts.add(triple("q R 17"));
+	}
+
+	protected void testEmpty(TripleStore ts) {
+		assertEquals(true, ts.isEmpty());
+		assertEquals(0, ts.size());
+		assertEquals(false, ts.find(triple("?? ?? ??")).hasNext());
+		assertEquals(false, ts.listObjects().hasNext());
+		assertEquals(false, ts.listSubjects().hasNext());
+		assertFalse(ts.contains(triple("x P y")));
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/mem/BunchMapContractTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/mem/BunchMapContractTest.java b/jena-core/src/test/java/org/apache/jena/mem/BunchMapContractTest.java
new file mode 100644
index 0000000..7807248
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/mem/BunchMapContractTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.mem;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractTest;
+
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/**
+ * Test triple bunch implementations - NOT YET FINISHED
+ */
+@Contract(BunchMap.class)
+public class BunchMapContractTest {
+	private BunchMap map;
+
+	private IProducer<? extends BunchMap> producer;
+
+	@Contract.Inject
+	public final void setBunchMapProducer(IProducer<? extends BunchMap> producer) {
+		this.producer = producer;
+	}
+
+	protected final IProducer<? extends BunchMap> getBunchMapProducer() {
+		return producer;
+	}
+
+	@Before
+	public final void beforeAbstractBunchMapTest() {
+		map = getBunchMapProducer().newInstance();
+	}
+
+	@After
+	public final void afterAbstractBunchMapTest() {
+		getBunchMapProducer().cleanUp();
+	}
+
+	@ContractTest
+	public void testClear() {
+		for (int i = 0; i < 5; i++) {
+			map.put(i, mock(TripleBunch.class));
+		}
+		assertEquals(5, map.size());
+
+		map.clear();
+		assertEquals(0, map.size());
+	}
+
+	@ContractTest
+	public void testSize() {
+		assertEquals(0, map.size());
+		for (int i = 0; i < 5; i++) {
+			map.put(i, mock(TripleBunch.class));
+			assertEquals(i + 1, map.size());
+		}
+	}
+
+	@ContractTest
+	public void testGet() {
+		List<TripleBunch> lst = new ArrayList<TripleBunch>();
+		for (int i = 0; i < 5; i++) {
+			TripleBunch tb = mock(TripleBunch.class);
+			lst.add(tb);
+			map.put(i, tb);
+		}
+		for (int i = 0; i < 5; i++) {
+			assertEquals(lst.get(i), map.get(i));
+		}
+	}
+
+	@ContractTest
+	public void testPut() {
+		List<TripleBunch> lst = new ArrayList<TripleBunch>();
+		for (int i = 0; i < 5; i++) {
+			map.put(i, mock(TripleBunch.class));
+		}
+		for (int i = 0; i < 5; i++) {
+			TripleBunch tb = mock(TripleBunch.class);
+			lst.add(tb);
+			map.put(i, tb);
+		}
+		for (int i = 0; i < 5; i++) {
+			assertEquals(lst.get(i), map.get(i));
+		}
+	}
+
+	@ContractTest
+	public void testRemove() {
+		List<TripleBunch> lst = new ArrayList<TripleBunch>();
+		for (int i = 0; i < 5; i++) {
+			TripleBunch tb = mock(TripleBunch.class);
+			lst.add(tb);
+			map.put(i, tb);
+		}
+
+		map.remove(0);
+		assertNull(map.get(0));
+		for (int i = 1; i < 5; i++) {
+			assertEquals(lst.get(i), map.get(i));
+		}
+		assertEquals(4, map.size());
+
+		map.remove(2);
+		assertNull(map.get(0));
+		assertEquals(lst.get(1), map.get(1));
+		assertNull(map.get(2));
+		assertEquals(lst.get(3), map.get(3));
+		assertEquals(lst.get(4), map.get(4));
+		assertEquals(3, map.size());
+
+		map.remove(4);
+		assertNull(map.get(0));
+		assertEquals(lst.get(1), map.get(1));
+		assertNull(map.get(2));
+		assertEquals(lst.get(3), map.get(3));
+		assertNull(map.get(4));
+		assertEquals(2, map.size());
+
+	}
+
+	@ContractTest
+	public void testKeyIterator() {
+		List<Integer> lst = new ArrayList<Integer>();
+		for (int i = 0; i < 5; i++) {
+			lst.add(i);
+			map.put(i, mock(TripleBunch.class));
+		}
+		ExtendedIterator<Object> iter = map.keyIterator();
+		while (iter.hasNext()) {
+			assertFalse("List is empty", lst.isEmpty());
+			Integer i = (Integer) iter.next();
+			assertTrue("Missing index: " + i, lst.contains(i));
+			lst.remove(i);
+		}
+		assertTrue("List is not empty", lst.isEmpty());
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/mem/GraphMemTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/mem/GraphMemTest.java b/jena-core/src/test/java/org/apache/jena/mem/GraphMemTest.java
new file mode 100644
index 0000000..8fed109
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/mem/GraphMemTest.java
@@ -0,0 +1,115 @@
+/*
+    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.mem;
+
+import static org.apache.jena.testing_framework.GraphHelper.*;
+import static org.junit.Assert.*;
+
+import java.util.Iterator;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract.Inject;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.ContractTest;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphStatisticsHandler;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Node_URI;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.shared.JenaException;
+import org.apache.jena.testing_framework.AbstractGraphProducer;
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(GraphMem.class)
+public class GraphMemTest {
+
+	protected IProducer<GraphMem> graphProducer = new AbstractGraphProducer<GraphMem>() {
+
+		@Override
+		protected GraphMem createNewGraph() {
+			return new GraphMem();
+		}
+
+		@Override
+		public Graph[] getDependsOn(Graph g) {
+			return null;
+		}
+
+		@Override
+		public Graph[] getNotDependsOn(Graph g) {
+			return new Graph[] { memGraph() };
+		}
+
+	};
+
+	@Inject
+	public IProducer<GraphMem> getGraphProducer() {
+		return graphProducer;
+	}
+
+	@ContractTest
+	public void testHasStatistics() {
+		GraphStatisticsHandler h = graphProducer.newInstance()
+				.getStatisticsHandler();
+		assertNotNull(h);
+	}
+
+	@ContractTest
+	public void testContainsConcreteDoesntUseFind() {
+		Graph g = new GraphMemWithoutFind();
+		graphAdd(g, "x P y; a Q b");
+		assertTrue(g.contains(triple("x P y")));
+		assertTrue(g.contains(triple("a Q b")));
+		assertFalse(g.contains(triple("a P y")));
+		assertFalse(g.contains(triple("y R b")));
+	}
+
+	protected final class GraphMemWithoutFind extends GraphMem {
+		@Override
+		public ExtendedIterator<Triple> graphBaseFind(Triple t) {
+			throw new JenaException("find is Not Allowed");
+		}
+	}
+
+	@ContractTest
+	public void testUnnecessaryMatches() {
+		Node special = new Node_URI("eg:foo") {
+			@Override
+			public boolean matches(Node s) {
+				fail("Matched called superfluously.");
+				return true;
+			}
+		};
+		Graph g = graphWith(graphProducer.newInstance(), "x p y");
+		g.add(new Triple(special, special, special));
+		exhaust(g.find(special, Node.ANY, Node.ANY));
+		exhaust(g.find(Node.ANY, special, Node.ANY));
+		exhaust(g.find(Node.ANY, Node.ANY, special));
+
+	}
+
+	protected void exhaust(Iterator<?> it) {
+		while (it.hasNext())
+			it.next();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/mem/GraphTripleStoreTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/mem/GraphTripleStoreTest.java b/jena-core/src/test/java/org/apache/jena/mem/GraphTripleStoreTest.java
new file mode 100644
index 0000000..1f82935
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/mem/GraphTripleStoreTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.mem;
+
+import org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.mem.GraphTripleStore;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(GraphTripleStore.class)
+public class GraphTripleStoreTest {
+
+	private IProducer<GraphTripleStore> producer = new IProducer<GraphTripleStore>() {
+
+		@Override
+		public GraphTripleStore newInstance() {
+			return new GraphTripleStore(Graph.emptyGraph);
+		}
+
+		@Override
+		public void cleanUp() {
+		}
+
+	};
+
+	@Contract.Inject
+	public IProducer<GraphTripleStore> getTripleStore() {
+		return producer;
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/mem/TripleBunchContractTest.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/mem/TripleBunchContractTest.java b/jena-core/src/test/java/org/apache/jena/mem/TripleBunchContractTest.java
new file mode 100644
index 0000000..505b57f
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/mem/TripleBunchContractTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.mem;
+
+import static org.junit.Assert.*;
+import static org.apache.jena.testing_framework.GraphHelper.*;
+
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractTest;
+
+import org.apache.jena.graph.Triple;
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.testing_framework.NodeCreateUtils;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/**
+ * Test triple bunch implementations - NOT YET FINISHED
+ */
+@Contract(TripleBunch.class)
+public class TripleBunchContractTest {
+	private IProducer<? extends TripleBunch> producer;
+
+	@Contract.Inject
+	public final void setTripleBunchProducer(
+			IProducer<? extends TripleBunch> producer) {
+		this.producer = producer;
+	}
+
+	protected final IProducer<? extends TripleBunch> getTripleBunchProducer() {
+		return producer;
+	}
+
+	public static final TripleBunch EMPTY_BUNCH = new ArrayBunch();
+
+	protected static final Triple tripleSPO = triple("s P o");
+	protected static final Triple tripleXQY = triple("x Q y");
+
+	private TripleBunch testingBunch;
+
+	@Before
+	public final void beforeAbstractTripleBunchTest() {
+		testingBunch = getTripleBunchProducer().newInstance();
+	}
+
+	@After
+	public final void afterAbstractTripleBunchTest() {
+		getTripleBunchProducer().cleanUp();
+	}
+
+	@ContractTest
+	public void testEmptyBunch() {
+		assertEquals(0, testingBunch.size());
+		assertFalse(testingBunch.contains(tripleSPO));
+		assertFalse(testingBunch.contains(tripleXQY));
+		assertFalse(testingBunch.iterator().hasNext());
+	}
+
+	@ContractTest
+	public void testAddElement() {
+		testingBunch.add(tripleSPO);
+		assertEquals(1, testingBunch.size());
+		assertTrue(testingBunch.contains(tripleSPO));
+		assertEquals(listOf(tripleSPO), iteratorToList(testingBunch.iterator()));
+	}
+
+	@ContractTest
+	public void testAddElements() {
+		testingBunch.add(tripleSPO);
+		testingBunch.add(tripleXQY);
+		assertEquals(2, testingBunch.size());
+		assertTrue(testingBunch.contains(tripleSPO));
+		assertTrue(testingBunch.contains(tripleXQY));
+		assertEquals(setOf(tripleSPO, tripleXQY),
+				iteratorToSet(testingBunch.iterator()));
+	}
+
+	@ContractTest
+	public void testRemoveOnlyElement() {
+		testingBunch.add(tripleSPO);
+		testingBunch.remove(tripleSPO);
+		assertEquals(0, testingBunch.size());
+		assertFalse(testingBunch.contains(tripleSPO));
+		assertFalse(testingBunch.iterator().hasNext());
+	}
+
+	@ContractTest
+	public void testRemoveFirstOfTwo() {
+		testingBunch.add(tripleSPO);
+		testingBunch.add(tripleXQY);
+		testingBunch.remove(tripleSPO);
+		assertEquals(1, testingBunch.size());
+		assertFalse(testingBunch.contains(tripleSPO));
+		assertTrue(testingBunch.contains(tripleXQY));
+		assertEquals(listOf(tripleXQY), iteratorToList(testingBunch.iterator()));
+	}
+
+	@ContractTest
+	public void testTableGrows() {
+		testingBunch.add(tripleSPO);
+		testingBunch.add(tripleXQY);
+		testingBunch.add(triple("a I b"));
+		testingBunch.add(triple("c J d"));
+	}
+
+	@ContractTest
+	public void testIterator() {
+		testingBunch.add(triple("a P b"));
+		testingBunch.add(triple("c Q d"));
+		testingBunch.add(triple("e R f"));
+		assertEquals(tripleSet("a P b; c Q d; e R f"), testingBunch.iterator()
+				.toSet());
+	}
+
+	@ContractTest
+	public void testIteratorRemoveOneItem() {
+		testingBunch.add(triple("a P b"));
+		testingBunch.add(triple("c Q d"));
+		testingBunch.add(triple("e R f"));
+		ExtendedIterator<Triple> it = testingBunch.iterator();
+		while (it.hasNext())
+			if (it.next().equals(triple("c Q d")))
+				it.remove();
+		assertEquals(tripleSet("a P b; e R f"), testingBunch.iterator().toSet());
+	}
+
+	@ContractTest
+	public void testIteratorRemoveAlltems() {
+		testingBunch.add(triple("a P b"));
+		testingBunch.add(triple("c Q d"));
+		testingBunch.add(triple("e R f"));
+		ExtendedIterator<Triple> it = testingBunch.iterator();
+		while (it.hasNext())
+			it.removeNext();
+		assertEquals(tripleSet(""), testingBunch.iterator().toSet());
+	}
+
+	protected List<Triple> listOf(Triple x) {
+		List<Triple> result = new ArrayList<Triple>();
+		result.add(x);
+		return result;
+	}
+
+	protected Set<Triple> setOf(Triple x, Triple y) {
+		Set<Triple> result = setOf(x);
+		result.add(y);
+		return result;
+	}
+
+	protected Set<Triple> setOf(Triple x) {
+		Set<Triple> result = new HashSet<Triple>();
+		result.add(x);
+		return result;
+	}
+
+	public void testAddThenNextThrowsCME() {
+		testingBunch.add(NodeCreateUtils.createTriple("a P b"));
+		testingBunch.add(NodeCreateUtils.createTriple("c Q d"));
+		ExtendedIterator<Triple> it = testingBunch.iterator();
+		it.next();
+		testingBunch.add(NodeCreateUtils.createTriple("change its state"));
+		try {
+			it.next();
+			fail("should have thrown ConcurrentModificationException");
+		} catch (ConcurrentModificationException e) {
+			// expected
+		}
+	}
+
+	public void testDeleteThenNextThrowsCME() {
+		testingBunch.add(NodeCreateUtils.createTriple("a P b"));
+		testingBunch.add(NodeCreateUtils.createTriple("c Q d"));
+		ExtendedIterator<Triple> it = testingBunch.iterator();
+		it.next();
+		testingBunch.remove(NodeCreateUtils.createTriple("a P b"));
+		try {
+			it.next();
+			fail("should have thrown ConcurrentModificationException");
+		} catch (ConcurrentModificationException e) {
+			// expected
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractGraphProducer.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractGraphProducer.java b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractGraphProducer.java
new file mode 100644
index 0000000..29cf9f0
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractGraphProducer.java
@@ -0,0 +1,104 @@
+/*
+    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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xenei.junit.contract.IProducer;
+
+import org.apache.jena.graph.Graph;
+
+/**
+ * An abstract implementation of the GraphProducerInterface.
+ * 
+ * This class handles tracking of the created graphs and closing them. It also
+ * provides a callback for the implementing class to perform extra cleanup when
+ * the graph is closed.
+ * 
+ */
+public abstract class AbstractGraphProducer<T extends Graph> implements
+		IProducer<T> {
+
+	/**
+	 * The list of graphs that have been opened in this test.
+	 */
+	protected List<Graph> graphList = new ArrayList<Graph>();
+
+	/**
+	 * The method to create a new graph.
+	 * 
+	 * @return a newly constructed graph of type under test.
+	 */
+	abstract protected T createNewGraph();
+
+	@Override
+	final public T newInstance() {
+		T retval = createNewGraph();
+		graphList.add(retval);
+		return retval;
+	}
+
+	/**
+	 * Method called after the graph is closed. This allows the implementer to
+	 * perform extra cleanup activities, like deleting the file associated with
+	 * a file based graph.
+	 * <p>
+	 * By default this does nothing.
+	 * </p>
+	 * 
+	 * @param g
+	 *            The graph that is closed
+	 */
+	protected void afterClose(Graph g) {
+	};
+
+	@Override
+	final public void cleanUp() {
+		for (Graph g : graphList) {
+			if (!g.isClosed()) {
+				g.close();
+			}
+			afterClose(g);
+		}
+		graphList.clear();
+	}
+
+	/**
+	 * Get a list of graphs that the created graph is dependent upon. The graph
+	 * must return true for each call to dependsOn() with one of the returned
+	 * graphs. Method may return null to disable the check.
+	 * 
+	 * @param g
+	 *            The graph we are looking for.
+	 * @return
+	 */
+	public abstract Graph[] getDependsOn(Graph g);
+
+	/**
+	 * Get a list of graphs that the created graph is not dependent upon. The
+	 * graph must return false for each call to dependsOn() with one of the
+	 * returned graphs. Method may return null to disable the check.
+	 * 
+	 * @param g
+	 *            The graph we are looking for.
+	 * @return
+	 */
+	public abstract Graph[] getNotDependsOn(Graph g);
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractInfModelProducer.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractInfModelProducer.java b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractInfModelProducer.java
new file mode 100644
index 0000000..898503d
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractInfModelProducer.java
@@ -0,0 +1,91 @@
+/*
+    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;
+
+import org.apache.jena.rdf.model.InfModel;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.Statement;
+import org.apache.jena.reasoner.Reasoner;
+
+/**
+ * An abstract implementation of the ModelProducerInterface.
+ * 
+ * This class handles tracking of the created models and closing them. It also
+ * provides a callback for the implementing class to perform extra cleanup when
+ * the model is closed.
+ * 
+ */
+public abstract class AbstractInfModelProducer<T extends InfModel> extends
+		AbstractModelProducer<T> {
+
+	
+	public boolean canBeEmpty( Model m ) 
+	{
+		return false;
+	}
+	/**
+	 * @return true if the models returned by this poducer are independent,
+	 *         false otherwise.
+	 * 
+	 */
+	abstract public Reasoner getReasoner();
+
+	/**
+	 * Returns the model that was used in the reasoner.bind() call.
+	 * 
+	 * @return
+	 */
+	abstract public Model getBoundModel();
+
+	/**
+	 * Populate the model with test data for the derivation test.
+	 * 
+	 * @param model
+	 */
+	abstract public void populateModel(InfModel model);
+
+	/**
+	 * Using the reasoner and the populated model, this statement should return
+	 * a derivation iterator when getDerivation() is called.
+	 * 
+	 * This is not a complete test but a simple test to show that the system
+	 * works in this specific case. A complete set of tests is left for later
+	 * development.
+	 * 
+	 * @return The Statement that should have at least one derivation.
+	 */
+	abstract public Statement getDerivationStatement();
+
+	/**
+	 * Using the reasoner and the populated model, this statement should return
+	 * an EMPTY derivation iterator when getDerivation() is called.
+	 * 
+	 * This is not a complete test but a simple test to show that the system
+	 * works in this specific case. A complete set of tests is left for later
+	 * development.
+	 * 
+	 * @return The Statement that should have no derivations.
+	 */
+	abstract public Statement getNoDerivationStatement();
+
+	/**
+	 * @return true if the InfModel supports the getDeductionsModel() call.
+	 */
+	abstract public boolean supportsDeductionsModel();
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractModelProducer.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractModelProducer.java b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractModelProducer.java
new file mode 100644
index 0000000..882e9d3
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractModelProducer.java
@@ -0,0 +1,88 @@
+/*
+    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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xenei.junit.contract.IProducer;
+import org.apache.jena.rdf.model.Model;
+
+/**
+ * An abstract implementation of the ModelProducerInterface.
+ * 
+ * This class handles tracking of the created models and closing them. It also
+ * provides a callback for the implementing class to perform extra cleanup when
+ * the model is closed.
+ * 
+ */
+public abstract class AbstractModelProducer<T extends Model> implements
+		IProducer<T> {
+
+	/**
+	 * The list of graphs that have been opened in this test.
+	 */
+	protected List<Model> modelList = new ArrayList<Model>();
+
+	/**
+	 * @return true if the models returned by this poducer are independent,
+	 *         false otherwise.
+	 * 
+	 */
+	abstract public boolean areIndependent();
+
+	/**
+	 * The method to create a new model.
+	 * 
+	 * @return a newly constructed model of type under test.
+	 */
+	abstract protected T createNewModel();
+
+	@Override
+	final public T newInstance() {
+		T retval = createNewModel();
+		modelList.add(retval);
+		return retval;
+	}
+
+	/**
+	 * Method called after the graph is closed. This allows the implementer to
+	 * perform extra cleanup activities, like deleting the file associated with
+	 * a file based graph.
+	 * <p>
+	 * By default this does nothing.
+	 * </p>
+	 * 
+	 * @param g
+	 *            The graph that is closed
+	 */
+	protected void afterClose(T g) {
+	};
+
+	@Override
+	final public void cleanUp() {
+		for (Model m : modelList) {
+			if (!m.isClosed()) {
+				m.close();
+			}
+			afterClose((T) m);
+		}
+		modelList.clear();
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractRecordingListener.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractRecordingListener.java b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractRecordingListener.java
new file mode 100644
index 0000000..e9e26a1
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/AbstractRecordingListener.java
@@ -0,0 +1,190 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Assert;
+
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.Statement;
+
+/**
+ * This testing listener records the event names and data, and provides a method
+ * for comparing the actual with the expected history.
+ */
+public class AbstractRecordingListener {
+
+	@SuppressWarnings("unchecked")
+	public static boolean checkEquality(final Object o1, final Object o2) {
+		if (o1 == o2) {
+			return true;
+		}
+		if (o1.getClass().isArray() && o2.getClass().isArray()) {
+			final Object[] o1a = (Object[]) o1;
+			final Object[] o2a = (Object[]) o2;
+
+			if (o1a.length == o2a.length) {
+				for (int i = 0; i < o1a.length; i++) {
+					if (!checkEquality(o1a[i], o2a[i])) {
+						return false;
+					}
+				}
+				return true;
+			}
+			return false;
+		} else if ((o1 instanceof Collection<?>)
+				&& (o2 instanceof Collection<?>)) {
+			return checkEquality(((Collection<Object>) o1).toArray(),
+					((Collection<Object>) o2).toArray());
+
+		} else if ((o1 instanceof Model) && (o2 instanceof Model)) {
+			return checkEquality(((Model) o1).listStatements().toList(),
+					((Model) o2).listStatements().toList());
+
+		} else if ((o1 instanceof Statement) && (o2 instanceof Statement)) {
+			return checkEquality(((Statement) o1).asTriple(),
+					((Statement) o2).asTriple());
+
+		} else {
+			return o1.equals(o2);
+		}
+	}
+
+	private List<Object> history = new ArrayList<Object>();
+
+	protected final void record(String tag, Object x, Object y) {
+		history.add(tag);
+		history.add(x);
+		history.add(y);
+	}
+
+	protected final void record(String tag, Object info) {
+		history.add(tag);
+		history.add(info);
+	}
+
+	public final int differ(Object... things) {
+		for (int i = 0; i < history.size(); i++) {
+			if (!things[i].equals(history.get(i))) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	public final boolean has(Object... things) {
+		return history.equals(Arrays.asList(things));
+	}
+
+	public final void assertHas(Object... things) {
+		if (has(things) == false) {
+			int idx = differ(things);
+			Assert.fail("expected " + Arrays.asList(things) + " but got "
+					+ history + " differ at position " + idx);
+		}
+	}
+
+	public final void assertEmpty() {
+		if (history.size() > 0) {
+			Assert.fail("Should be no history but got " + history);
+		}
+	}
+
+	public final int size() {
+		return history.size();
+	}
+
+	public final boolean has(List<?> things) {
+		return history.equals(things);
+	}
+
+	public final boolean hasStart(List<Object> L) {
+		return L.size() <= history.size()
+				&& L.equals(history.subList(0, L.size()));
+	}
+
+	public final boolean hasEnd(List<Object> L) {
+		return L.size() <= history.size()
+				&& L.equals(history.subList(history.size() - L.size(),
+						history.size()));
+	}
+
+	public final void assertHas(List<?> things) {
+		if (has(things) == false)
+			Assert.fail("expected " + things + " but got " + history);
+	}
+
+	public final void assertContains(Object... things) {
+		if (contains(things) == false)
+			Assert.fail(String.format("expected %s but got %s",
+					Arrays.asList(things), history));
+	}
+
+	public final void assertHasStart(Object... start) {
+		List<Object> L = Arrays.asList(start);
+		if (hasStart(L) == false)
+			Assert.fail("expected " + L + " at the beginning of " + history);
+	}
+
+	public final void assertHasEnd(Object... end) {
+		List<Object> L = Arrays.asList(end);
+		if (hasEnd(L) == false)
+			Assert.fail("expected " + L + " at the end of " + history);
+	}
+
+	public final void clear() {
+		history.clear();
+	}
+
+	public final boolean contains(Object... objects) {
+		for (int i = 0; i < history.size(); i++) {
+			if (history.get(i).equals(objects[0])) {
+				boolean found = true;
+				for (int j = 1; j < objects.length; j++) {
+					if (i + j >= history.size()) {
+						found = false;
+						break;
+					}
+					if (!history.get(i + j).equals(objects[j])) {
+						found = false;
+						break;
+					}
+				}
+				if (found) {
+					return true;
+				}
+			}
+
+		}
+		return false;
+
+	}
+
+	public final Iterator<Object> from(Object start) {
+		Iterator<Object> iter = history.iterator();
+		while (iter.hasNext() && !iter.next().equals(start))
+			; // loop
+		return iter;
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/ContractTemplate.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/ContractTemplate.java b/jena-core/src/test/java/org/apache/jena/testing_framework/ContractTemplate.java
new file mode 100644
index 0000000..f7a16e5
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/ContractTemplate.java
@@ -0,0 +1,17 @@
+package org.apache.jena.testing_framework;
+
+import org.xenei.junit.contract.IProducer;
+
+public class ContractTemplate<P extends IProducer<?>> {
+
+	private P producer;
+
+	public final void setProducer(P producer) {
+		this.producer = producer;
+	}
+
+	protected final P getProducer() {
+		return producer;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/b293ee8a/jena-core/src/test/java/org/apache/jena/testing_framework/GraphEventManagerProducerInterface.java
----------------------------------------------------------------------
diff --git a/jena-core/src/test/java/org/apache/jena/testing_framework/GraphEventManagerProducerInterface.java b/jena-core/src/test/java/org/apache/jena/testing_framework/GraphEventManagerProducerInterface.java
new file mode 100644
index 0000000..70e8182
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/testing_framework/GraphEventManagerProducerInterface.java
@@ -0,0 +1,35 @@
+/*
+    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;
+
+import org.apache.jena.graph.GraphEventManager;
+
+/**
+ * Foo producer for GraphEventManager testing.
+ * 
+ */
+public interface GraphEventManagerProducerInterface {
+
+	/**
+	 * Returns a GraphEventManager to take part in the test. Must be overridden
+	 * in a subclass.
+	 * 
+	 * @return The GraphEventManager implementation to test.
+	 */
+	public abstract GraphEventManager newEventManager();
+}