/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003, 2004 The JRDF Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* the JRDF Project (http://jrdf.sf.net/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The JRDF Project" and "JRDF" must not be used to endorse
* or promote products derived from this software without prior written
* permission. For written permission, please contact
* newmana@users.sourceforge.net.
*
* 5. Products derived from this software may not be called "JRDF"
* nor may "JRDF" appear in their names without prior written
* permission of the JRDF Project.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the JRDF Project. For more
* information on JRDF, please see <http://jrdf.sourceforge.net/>.
*/
package org.jrdf.graph;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jrdf.util.ClosableIterator;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Abstract test case for graph implementations.
*
* @author <a href="mailto:pgearon@users.sourceforge.net">Paula Gearon</a>
* @author Andrew Newman
*
* @version $Revision: 624 $
*/
public abstract class AbstractGraphTest extends TestCase {
/**
* Instance of a graph object.
*/
protected Graph graph;
/**
* Instance of a factory for the graph.
*/
private GraphElementFactory elementFactory;
/**
* Blank node 1.
*/
protected BlankNode blank1;
/**
* Blank node 2.
*/
protected BlankNode blank2;
private URI uri1;
private URI uri2;
private URI uri3;
protected URIReference ref1;
protected URIReference ref2;
protected URIReference ref3;
/**
* Used to create literal.
*/
private static final String TEST_STR1 = "A test string";
/**
* Used to create literal.
*/
private static final String TEST_STR2 = "Another test string";
/**
* Literal 1.
*/
protected static Literal l1;
/**
* Literal 2.
*/
protected static Literal l2;
/**
* Hook for test runner to obtain an empty test suite from, because this test
* can't be run (it's abstract). This must be overridden in subclasses.
* @return The test suite
*/
public static Test suite() {
TestSuite suite = new TestSuite();
return suite;
}
/**
* Constructs a new test with the given name.
*
* @param name the name of the test
*/
protected AbstractGraphTest(String name) {
super(name);
}
/**
* Create test instance.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void setUp() throws Exception {
graph = newGraph();
elementFactory = graph.getElementFactory();
blank1 = elementFactory.createResource();
blank2 = elementFactory.createResource();
uri1 = new URI("http://namespace#somevalue");
uri2 = new URI("http://namespace#someothervalue");
uri3 = new URI("http://namespace#yetanothervalue");
ref1 = elementFactory.createResource(uri1);
ref2 = elementFactory.createResource(uri2);
ref3 = elementFactory.createResource(uri3);
l1 = elementFactory.createLiteral(TEST_STR1);
l2 = elementFactory.createLiteral(TEST_STR2);
}
//
// implementation interfaces
//
/**
* Create a graph implementation.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
* @return A new Graph.
*/
protected abstract Graph newGraph() throws Exception;
//
// Test cases
//
/**
* Tests that a new graph is empty.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testEmpty() throws Exception {
assertTrue(graph.isEmpty());
assertEquals(0, graph.getNumberOfTriples());
}
/**
* Tests that it is possible to get a NodeFactory from a graph.
*/
public void testFactory() {
GraphElementFactory f = graph.getElementFactory();
assertTrue(null != f);
}
/**
* Tests addition.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testAddition() throws Exception {
// add in a triple by nodes
graph.add(blank1, ref1, blank2);
assertFalse(graph.isEmpty());
assertEquals(1, graph.getNumberOfTriples());
// add in a whole triple
Triple triple2 = elementFactory.createTriple(blank2, ref1, blank2);
graph.add(triple2);
assertFalse(graph.isEmpty());
assertEquals(2, graph.getNumberOfTriples());
// add in the first triple again
graph.add(blank1, ref1, blank2);
assertFalse(graph.isEmpty());
assertEquals(2, graph.getNumberOfTriples());
// add in the second whole triple again
Triple triple2b = elementFactory.createTriple(blank2, ref1, blank2);
graph.add(triple2b);
assertFalse(graph.isEmpty());
assertEquals(2, graph.getNumberOfTriples());
// and again
graph.add(triple2);
assertFalse(graph.isEmpty());
assertEquals(2, graph.getNumberOfTriples());
// Add using iterator
List<Triple> list = new ArrayList<Triple>();
list.add(elementFactory.createTriple(ref1, ref1, ref1));
list.add(elementFactory.createTriple(ref2, ref2, ref2));
graph.add(list.iterator());
assertFalse(graph.isEmpty());
assertEquals(4, graph.getNumberOfTriples());
}
/**
* Tests removal.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testRemoval() throws Exception {
// add some test data
graph.add(blank1, ref1, blank2);
graph.add(blank1, ref2, blank2);
graph.add(ref1, ref2, l2);
Triple t1 = elementFactory.createTriple(blank2, ref1, blank1);
graph.add(t1);
Triple t2 = elementFactory.createTriple(blank2, ref2, blank1);
graph.add(t2);
Triple t3 = elementFactory.createTriple(blank2, ref1, l1);
graph.add(t3);
// check that all is well
assertFalse(graph.isEmpty());
assertEquals(6, graph.getNumberOfTriples());
// delete the first statement
graph.remove(blank1, ref1, blank2);
assertEquals(5, graph.getNumberOfTriples());
// delete the last statement
graph.remove(t3);
assertEquals(4, graph.getNumberOfTriples());
// delete the next last statement with a new "triple object"
t2 = elementFactory.createTriple(blank2, ref2, blank1);
graph.remove(t2);
assertEquals(3, graph.getNumberOfTriples());
// delete the next last statement with a triple different to what it was built with
graph.remove(blank2, ref1, blank1);
assertEquals(2, graph.getNumberOfTriples());
// delete the next last statement with a triple different to what it was built with
graph.remove(ref1, ref2, l2);
assertEquals(1, graph.getNumberOfTriples());
// delete the wrong triple
try {
graph.remove(blank2, ref1, blank1);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
assertEquals(1, graph.getNumberOfTriples());
// delete a triple that never existed
try {
graph.remove(blank2, ref2, l2);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
assertEquals(1, graph.getNumberOfTriples());
// and delete with a triple object
t1 = elementFactory.createTriple(blank2, ref1, blank1);
try {
graph.remove(t1);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
assertEquals(1, graph.getNumberOfTriples());
// now clear out the graph
assertFalse(graph.isEmpty());
graph.remove(blank1, ref2, blank2);
assertTrue(graph.isEmpty());
assertEquals(0, graph.getNumberOfTriples());
// check that we can't still remove things
try {
graph.remove(blank1, ref2, blank2);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
assertTrue(graph.isEmpty());
assertEquals(0, graph.getNumberOfTriples());
// Check removal using iterator
graph.add(elementFactory.createTriple(ref1, ref1, ref1));
graph.add(elementFactory.createTriple(ref2, ref2, ref2));
List<Triple> list = new ArrayList<Triple>();
list.add(elementFactory.createTriple(ref1, ref1, ref1));
list.add(elementFactory.createTriple(ref2, ref2, ref2));
graph.remove(list.iterator());
// check that we can't still remove things
try {
graph.remove(ref2, ref2, ref2);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
assertTrue(graph.isEmpty());
assertEquals(0, graph.getNumberOfTriples());
}
/**
* Tests containership.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testContains() throws Exception {
// add some test data
graph.add(blank1, ref1, blank2);
graph.add(blank1, ref2, blank2);
graph.add(ref1, ref2, l2);
Triple t1 = elementFactory.createTriple(blank2, ref1, blank1);
graph.add(t1);
Triple t2 = elementFactory.createTriple(blank2, ref2, blank1);
graph.add(t2);
Triple t3 = elementFactory.createTriple(blank2, ref1, l1);
graph.add(t3);
// test containership
assertTrue(graph.contains(blank1, ref1, blank2));
// test with existing and built triples
assertTrue(graph.contains(t1));
t1 = elementFactory.createTriple(blank2, ref2, blank1);
assertTrue(graph.contains(t1));
// test non containership
assertFalse(graph.contains(blank1, ref1, blank1));
t1 = elementFactory.createTriple(blank2, ref2, ref1);
assertFalse(graph.contains(t1));
// test containership after removal
graph.remove(blank1, ref1, blank2);
assertFalse(graph.contains(blank1, ref1, blank2));
t1 = elementFactory.createTriple(blank1, ref1, blank2);
assertFalse(graph.contains(t1));
// put it back in and test again
graph.add(blank1, ref1, blank2);
assertTrue(graph.contains(blank1, ref1, blank2));
assertTrue(graph.contains(t1));
// Null in contains.
Graph newGraph = newGraph();
assertFalse(newGraph.contains(null, null, null));
// Add a statement
GraphElementFactory newElementFactory = newGraph.getElementFactory();
blank1 = newElementFactory.createResource();
blank2 = newElementFactory.createResource();
ref1 = newElementFactory.createResource(uri1);
t1 = newElementFactory.createTriple(blank1, ref1, blank2);
newGraph.add(t1);
// Check for existance
assertTrue(newGraph.contains(null, ref1, blank2));
assertTrue(newGraph.contains(null, null, blank2));
assertTrue(newGraph.contains(null, null, null));
assertTrue(newGraph.contains(blank1, null, blank2));
assertTrue(newGraph.contains(blank1, null, null));
assertTrue(newGraph.contains(blank1, ref1, null));
// Check non-existance
assertFalse(newGraph.contains(null, ref2, blank1));
assertFalse(newGraph.contains(null, null, blank1));
assertFalse(newGraph.contains(blank2, null, blank1));
assertFalse(newGraph.contains(blank2, null, null));
assertFalse(newGraph.contains(blank2, ref2, null));
}
/**
* Tests finding.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testFinding() throws Exception {
graph.add(blank1, ref1, blank2);
graph.add(blank1, ref1, l1);
graph.add(blank1, ref2, blank2);
graph.add(blank1, ref1, l2);
graph.add(blank2, ref1, blank2);
graph.add(blank2, ref2, blank2);
graph.add(blank2, ref1, l1);
graph.add(blank2, ref1, l2);
// look for the first triple and check that one is returned
ClosableIterator<Triple> it = graph.find(blank1, ref1, blank2);
assertTrue(it.hasNext());
it.close();
// look for a non-existent triple
it = graph.find(ref1, ref1, blank1);
assertFalse(it.hasNext());
it.close();
// look for doubles and check that there is data there
it = graph.find(blank1, ref1, null);
assertTrue(it.hasNext());
it.close();
it = graph.find(blank1, null, blank2);
assertTrue(it.hasNext());
it.close();
it = graph.find(null, ref1, blank2);
assertTrue(it.hasNext());
it.close();
// look for a non-existent double
it = graph.find(ref1, ref1, null);
assertFalse(it.hasNext());
it.close();
it = graph.find(ref1, null, blank2);
assertFalse(it.hasNext());
it.close();
it = graph.find(null, ref3, blank2);
assertFalse(it.hasNext());
it.close();
// look for singles
it = graph.find(blank1, null, null);
assertTrue(it.hasNext());
it.close();
it = graph.find(null, ref1, null);
assertTrue(it.hasNext());
it.close();
it = graph.find(null, null, l1);
assertTrue(it.hasNext());
it.close();
// look for non-existent singles
it = graph.find(ref1, null, null);
assertFalse(it.hasNext());
it.close();
it = graph.find(null, ref3, null);
assertFalse(it.hasNext());
it.close();
it = graph.find(null, null, ref1);
assertFalse(it.hasNext());
it.close();
// do it all again with triples
// look for the first triple and check that one is returned
Triple t = elementFactory.createTriple(blank1, ref1, blank2);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
// look for a non-existent triple
t = elementFactory.createTriple(ref1, ref1, blank1);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
// look for doubles and check that there is data there
t = elementFactory.createTriple(blank1, ref1, null);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
t = elementFactory.createTriple(blank1, null, blank2);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
t = elementFactory.createTriple(null, ref1, blank2);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
// look for a non-existent double
t = elementFactory.createTriple(ref1, ref1, null);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
t = elementFactory.createTriple(ref1, null, blank2);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
t = elementFactory.createTriple(null, ref3, blank2);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
// look for singles
t = elementFactory.createTriple(blank1, null, null);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
t = elementFactory.createTriple(null, ref1, null);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
t = elementFactory.createTriple(null, null, l1);
it = graph.find(t);
assertTrue(it.hasNext());
it.close();
// look for non-existent singles
t = elementFactory.createTriple(ref1, null, null);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
t = elementFactory.createTriple(null, ref3, null);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
t = elementFactory.createTriple(null, null, ref1);
it = graph.find(t);
assertFalse(it.hasNext());
it.close();
}
/**
* Tests iteration over a found set.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testIteration() throws Exception {
GraphElementFactory factory = graph.getElementFactory();
//create nodes
BlankNode bNode1 = factory.createResource();
BlankNode bNode2 = factory.createResource();
URIReference testUri1 = factory.createResource(new URI(
"http://tucana.org/tucana#testUri1"));
URIReference testUri2 = factory.createResource(new URI(
"http://tucana.org/tucana#testUri2"));
Literal literal1 = factory.createLiteral("literal1");
Literal literal2 = factory.createLiteral("literal2");
//create some statements
Triple[] triples = new Triple[16];
triples[0] = factory.createTriple(bNode1, testUri1, literal1);
triples[1] = factory.createTriple(bNode1, testUri1, literal2);
triples[2] = factory.createTriple(bNode1, testUri2, literal1);
triples[3] = factory.createTriple(bNode1, testUri2, literal2);
triples[4] = factory.createTriple(bNode2, testUri1, literal1);
triples[5] = factory.createTriple(bNode2, testUri1, literal2);
triples[6] = factory.createTriple(bNode2, testUri2, literal1);
triples[7] = factory.createTriple(bNode2, testUri2, literal2);
triples[8] = factory.createTriple(bNode1, testUri1, bNode2);
triples[9] = factory.createTriple(bNode1, testUri2, bNode2);
triples[10] = factory.createTriple(bNode1, testUri1, testUri2);
triples[11] = factory.createTriple(bNode1, testUri2, testUri1);
triples[12] = factory.createTriple(testUri1, testUri2, bNode1);
triples[13] = factory.createTriple(testUri2, testUri1, bNode1);
triples[14] = factory.createTriple(testUri1, testUri2, bNode2);
triples[15] = factory.createTriple(testUri2, testUri1, bNode2);
//add them
for (int i = 0; i < triples.length; i++) {
graph.add(triples[i]);
}
//query them and put contents of iterator in a set for checking
//(iterator may return results in a different order)
Set<Triple> statements = new HashSet<Triple>();
ClosableIterator<Triple> iter = graph.find(null, null, null);
assertTrue("ClosableIterator is returning false for hasNext().", iter.hasNext());
while (iter.hasNext()) {
statements.add(iter.next());
}
iter.close();
//check that the iterator contained the correct number of statements
assertEquals("ClosableIterator is incomplete.", graph.getNumberOfTriples(),
statements.size());
//check the the set contains all the original triples
for (int i = 0; i < triples.length; i++) {
if (!statements.contains(triples[i])) {
fail("Iterator did not contain triple: " + triples[i] + ".");
}
}
}
/**
* Tests iterative removal.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testIterativeRemoval() throws Exception {
// add some test data
graph.add(blank1, ref1, blank2);
graph.add(blank1, ref2, blank2);
graph.add(ref1, ref2, l2);
Triple t1 = elementFactory.createTriple(blank2, ref1, blank1);
graph.add(t1);
Triple t2 = elementFactory.createTriple(blank2, ref2, blank1);
graph.add(t2);
Triple t3 = elementFactory.createTriple(blank2, ref1, l1);
graph.add(t3);
// check that all is well
assertFalse(graph.isEmpty());
assertEquals(6, graph.getNumberOfTriples());
// get an iterator for the blank2,ref1 elements
ClosableIterator<Triple> ci = graph.find(blank2, ref1, null);
checkInvalidRemove(ci);
// remove the first element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(5, graph.getNumberOfTriples());
// remove the second element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(4, graph.getNumberOfTriples());
assertFalse(ci.hasNext());
// get an iterator for the blank1 elements
ci = graph.find(blank1, null, null);
checkInvalidRemove(ci);
// remove the first element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(3, graph.getNumberOfTriples());
// remove the second element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(2, graph.getNumberOfTriples());
assertFalse(ci.hasNext());
// get an iterator for the ref1, ref2, l2 element
ci = graph.find(ref1, ref2, l2);
checkInvalidRemove(ci);
// remove the element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(1, graph.getNumberOfTriples());
assertFalse(ci.hasNext());
// get an iterator for the final element
ci = graph.find(null, null, null);
checkInvalidRemove(ci);
// remove the element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(0, graph.getNumberOfTriples());
assertTrue(graph.isEmpty());
assertFalse(ci.hasNext());
ci.close();
// check that we can't still remove things
try {
graph.remove(ref2, ref2, ref2);
assertTrue(false);
}
catch (GraphException e) { /* no-op */}
}
private void checkInvalidRemove(ClosableIterator<Triple> ci) {
try {
ci.remove();
fail("Must throw an exception.");
}
catch (IllegalStateException ise) {
assertTrue(ise.getMessage().indexOf("Next not called or beyond end of data") != -1);
}
}
/**
* Tests full iterative removal.
*
* @throws Exception A generic exception - this should cause the tests to
* fail.
*/
public void testFullIterativeRemoval() throws Exception {
// add some test data
graph.add(blank1, ref1, blank2);
graph.add(blank1, ref2, blank2);
graph.add(ref1, ref2, l2);
Triple t1 = elementFactory.createTriple(blank2, ref1, blank1);
graph.add(t1);
Triple t2 = elementFactory.createTriple(blank2, ref2, blank1);
graph.add(t2);
Triple t3 = elementFactory.createTriple(blank2, ref1, l1);
graph.add(t3);
// check that all is well
assertFalse(graph.isEmpty());
assertEquals(6, graph.getNumberOfTriples());
// get an iterator for all the elements
ClosableIterator<Triple> ci = graph.find(null, null, null);
for (int i = 5; 0 <= i; i--) {
// remove the element
assertTrue(ci.hasNext());
ci.next();
ci.remove();
assertEquals(i, graph.getNumberOfTriples());
}
assertTrue(graph.isEmpty());
assertFalse(ci.hasNext());
ci.close();
}
}