/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.testing_framework;
/**
* Foo set of static test helpers. Generally included as a static.
*/
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.jena.graph.Factory;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.GraphUtil;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.shared.JenaException;
import org.apache.jena.shared.PrefixMapping;
import org.apache.jena.util.CollectionFactory;
import org.apache.jena.util.IteratorCollection;
import org.apache.jena.util.iterator.ExtendedIterator;
public class GraphHelper extends TestUtils {
/**
* Answer a Node as described by <code>x</code>; a shorthand for
* <code>Node.create(x)</code>, which see.
*/
public static Node node(String x) {
return NodeCreateUtils.create(x);
}
/**
* Answer a set containing the elements from the iterator <code>it</code>; a
* shorthand for <code>IteratorCollection.iteratorToSet(it)</code>, which
* see.
*/
public static <T> Set<T> iteratorToSet(Iterator<? extends T> it) {
return IteratorCollection.iteratorToSet(it);
}
/**
* Answer a list containing the elements from the iterator <code>it</code>,
* in order; a shorthand for
* <code>IteratorCollection.iteratorToList(it)</code>, which see.
*/
public static <T> List<T> iteratorToList(Iterator<? extends T> it) {
return IteratorCollection.iteratorToList(it);
}
/**
* Answer a set of the nodes described (as per <code>node()</code>) by the
* space-separated substrings of <code>nodes</code>.
*/
public static Set<Node> nodeSet(String nodes) {
Set<Node> result = CollectionFactory.createHashedSet();
StringTokenizer st = new StringTokenizer(nodes);
while (st.hasMoreTokens())
result.add(node(st.nextToken()));
return result;
}
/**
* Answer a set of the elements of <code>Foo</code>.
*/
public static <T> Set<T> arrayToSet(T[] A) {
return CollectionFactory.createHashedSet(Arrays.asList(A));
}
/**
* Answer a triple described by the three space-separated node descriptions
* in <code>fact</code>; a shorthand for <code>Triple.create(fact)</code>,
* which see.
*/
public static Triple triple(String fact) {
return NodeCreateUtils.createTriple(fact);
}
/**
* Answer a triple described by the three space-separated node descriptions
* in <code>fact</code>, using prefix-mappings from <code>pm</code>; a
* shorthand for <code>Triple.create(pm, fact)</code>, which see.
*/
public static Triple triple(PrefixMapping pm, String fact) {
return NodeCreateUtils.createTriple(pm, fact);
}
/**
* Answer an array of triples; each triple is described by one of the
* semi-separated substrings of <code>facts</code>, as per
* <code>triple</code> with prefix-mapping <code>Extended</code>.
*/
public static Triple[] tripleArray(String facts) {
ArrayList<Triple> al = new ArrayList<Triple>();
StringTokenizer semis = new StringTokenizer(facts, ";");
while (semis.hasMoreTokens())
al.add(triple(PrefixMapping.Extended, semis.nextToken()));
return al.toArray(new Triple[al.size()]);
}
/**
* Answer a set of triples where the elements are described by the
* semi-separated substrings of <code>facts</code>, as per
* <code>triple</code>.
*/
public static Set<Triple> tripleSet(String facts) {
Set<Triple> result = new HashSet<Triple>();
StringTokenizer semis = new StringTokenizer(facts, ";");
while (semis.hasMoreTokens())
result.add(triple(semis.nextToken()));
return result;
}
/**
* Answer a list of nodes, where the nodes are described by the
* space-separated substrings of <code>items</code> as per
* <code>node()</code>.
*/
public static List<Node> nodeList(String items) {
ArrayList<Node> nl = new ArrayList<Node>();
StringTokenizer nodes = new StringTokenizer(items);
while (nodes.hasMoreTokens())
nl.add(node(nodes.nextToken()));
return nl;
}
/**
* Answer an array of nodes, where the nodes are described by the
* space-separated substrings of <code>items</code> as per
*/
public static Node[] nodeArray(String items) {
List<Node> nl = nodeList(items);
return nl.toArray(new Node[nl.size()]);
}
/**
* Answer the graph <code>g</code> after adding to it every triple encoded
* in <code>s</code> in the fashion of <code>tripleArray</code>, a
* semi-separated sequence of space-separated node descriptions.
*/
public static Graph graphAdd(Graph g, String s) {
StringTokenizer semis = new StringTokenizer(s, ";");
while (semis.hasMoreTokens())
g.add(triple(PrefixMapping.Extended, semis.nextToken()));
return g;
}
/**
* Like graphAdd but does it within a transaction if supported
*
* @param g
* The graph to add to
* @param s
* The string describing the graph
* @return The populated graph.
*/
public static Graph graphAddTxn(Graph g, String s) {
txnBegin(g);
StringTokenizer semis = new StringTokenizer(s, ";");
while (semis.hasMoreTokens())
g.add(triple(PrefixMapping.Extended, semis.nextToken()));
txnCommit(g);
return g;
}
/**
* Used to create a graph with values.
*
* @param g
* The newly created graph
* @param s
* The string representing the graph data.
* @return The populated graph
*/
public static Graph graphWith(Graph g, String s) {
return graphAddTxn(g, s);
}
/**
* Answer a new memory-based graph with Extended prefixes.
*/
public static Graph memGraph() {
Graph result = Factory.createGraphMem();
result.getPrefixMapping().setNsPrefixes(PrefixMapping.Extended);
return result;
}
/**
* Answer a new memory-based graph with initial contents as described by
* <code>s</code> in the fashion of <code>graphAdd()</code>. Not
* over-ridable; do not use for abstraction.
*/
public static Graph graphWith(String s) {
return graphWith(memGraph(), s);
}
/**
* Assert that the graph <code>g</code> is isomorphic to the graph described
* by <code>template</code> in the fashion of <code>graphWith</code>.
*/
public static void assertEqualsTemplate(String title, Graph g,
String template) {
assertIsomorphic(title, graphWith(template), g);
}
/**
* Assert that the supplied graph <code>got</code> is isomorphic with the
* the desired graph <code>expected</code>; if not, display a readable
* description of both graphs.
*/
public static void assertIsomorphic(String title, Graph expected, Graph got) {
if (!expected.isIsomorphicWith(got)) {
Map<Node, Object> map = CollectionFactory.createHashedMap();
fail(title + ": wanted " + nice(expected, map) + "\nbut got "
+ nice(got, map));
}
}
/**
* Answer a string which is a newline-separated list of triples (as produced
* by niceTriple) in the graph <code>g</code>. The map <code>bnodes</code>
* maps already-seen bnodes to their "nice" strings.
*/
public static String nice(Graph g, Map<Node, Object> bnodes) {
StringBuffer b = new StringBuffer(g.size() * 100);
ExtendedIterator<Triple> it = GraphUtil.findAll(g);
while (it.hasNext())
niceTriple(b, bnodes, it.next());
return b.toString();
}
/**
* Append to the string buffer <code>b</code> a "nice" representation of the
* triple <code>t</code> on a new line, using (and updating)
* <code>bnodes</code> to supply "nice" strings for any blank nodes.
*/
protected static void niceTriple(StringBuffer b, Map<Node, Object> bnodes,
Triple t) {
b.append("\n ");
appendNode(b, bnodes, t.getSubject());
appendNode(b, bnodes, t.getPredicate());
appendNode(b, bnodes, t.getObject());
}
/**
* Foo counter for new bnode strings; it starts at 1000 so as to make the
* bnode strings more uniform (at least for the first 9000 bnodes).
*/
protected static int bnc = 1000;
/**
* Append to the string buffer <code>b</code> a space followed by the "nice"
* representation of the node <code>n</code>. If <code>n</code> is a bnode,
* re-use any existing string for it from <code>bnodes</code> or make a new
* one of the form <i>_bNNNN</i> with NNNN a new integer.
*/
protected static void appendNode(StringBuffer b, Map<Node, Object> bnodes,
Node n) {
b.append(' ');
if (n.isBlank()) {
Object already = bnodes.get(n);
if (already == null)
bnodes.put(n, already = "_b" + bnc++);
b.append(already);
} else
b.append(nice(n));
}
// protected static Graph graphWithTxn(IProducer<? extends Graph> producer,
// String s) {
// Graph g = producer.newInstance();
// txnBegin(g);
// try {
// graphAdd(g, s);
// txnCommit(g);
// } catch (Exception e) {
// txnRollback(g);
// fail(e.getMessage());
// }
// return g;
// }
/**
* Answer the "nice" representation of this node, the string returned by
* <code>n.toString(PrefixMapping.Extended,true)</code>.
*/
protected static String nice(Node n) {
return n.toString(PrefixMapping.Extended, true);
}
/**
* Assert that the computed graph <code>got</code> is isomorphic with the
* desired graph <code>expected</code>; if not, fail with a default message
* (and pretty output of the graphs).
*/
public static void assertIsomorphic(Graph expected, Graph got) {
assertIsomorphic("graphs must be isomorphic", expected, got);
}
/**
* Assert that the graph <code>g</code> must contain the triple described by
* <code>s</code>; if not, fail with pretty output of both graphs and a
* message containing <code>name</code>.
*/
public static void assertContains(String name, String s, Graph g) {
assertTrue(name + " must contain " + s, g.contains(triple(s)));
}
/**
* Assert that the graph <code>g</code> contains all the triples described
* by the string <code>s</code; if not, fail with a message containing
* <code>name</code>.
*/
public static void assertContainsAll(String name, Graph g, String s) {
StringTokenizer semis = new StringTokenizer(s, ";");
while (semis.hasMoreTokens())
assertContains(name, semis.nextToken(), g);
}
/**
* Assert that the graph <code>g</code> does not contain the triple
* described by <code>s<code>; if it does, fail with a message containing
<code>name</code>.
*/
public static void assertOmits(String name, Graph g, String s) {
assertFalse(name + " must not contain " + s, g.contains(triple(s)));
}
/**
* Assert that the graph <code>g</code> contains none of the triples
* described by <code>s</code> in the usual way; otherwise, fail with a
* message containing <code>name</code>.
*/
public static void assertOmitsAll(String name, Graph g, String s) {
StringTokenizer semis = new StringTokenizer(s, ";");
while (semis.hasMoreTokens())
assertOmits(name, g, semis.nextToken());
}
/**
* Assert that <code>g</code> contains the triple described by
* <code>fact</code> in the usual way.
*/
public static boolean contains(Graph g, String fact) {
return g.contains(triple(fact));
}
/**
* Assert that <code>g</code> contains every triple in <code>triples</code>.
*/
public static void testContains(Graph g, Triple[] triples) {
for (int i = 0; i < triples.length; i += 1)
assertTrue("contains " + triples[i], g.contains(triples[i]));
}
/**
* Assert that <code>g</code> contains every triple in <code>triples</code>.
*/
public static void testContains(Graph g, List<Triple> triples) {
for (int i = 0; i < triples.size(); i += 1)
assertTrue(g.contains(triples.get(i)));
}
/**
* Assert that <code>g</code> contains every triple in <code>it</code>.
*/
public static void testContains(Graph g, Iterator<Triple> it) {
while (it.hasNext())
assertTrue(g.contains(it.next()));
}
/**
* Assert that <code>g</code> contains every triple in <code>other</code>.
*/
public static void testContains(Graph g, Graph other) {
testContains(g, GraphUtil.findAll(other));
}
/**
* Assert that <code>g</code> contains none of the triples in
* <code>triples</code>.
*/
public static void testOmits(Graph g, Triple[] triples) {
for (int i = 0; i < triples.length; i += 1)
assertFalse("", g.contains(triples[i]));
}
/**
* Assert that <code>g</code> contains none of the triples in
* <code>triples</code>.
*/
public static void testOmits(Graph g, List<Triple> triples) {
for (int i = 0; i < triples.size(); i += 1)
assertFalse("", g.contains(triples.get(i)));
}
/**
* Assert that <code>g</code> contains none of the triples in
* <code>it</code>.
*/
public static void testOmits(Graph g, Iterator<Triple> it) {
while (it.hasNext())
assertFalse("", g.contains(it.next()));
}
/**
* Assert that <code>g</code> contains none of the triples in
* <code>other</code>.
*/
public static void testOmits(Graph g, Graph other) {
testOmits(g, GraphUtil.findAll(other));
}
/**
* Answer an instance of <code>graphClass</code>. If <code>graphClass</code>
* has a constructor that takes a <code>ReificationStyle</code> argument,
* then that constructor is run on <code>style</code> to get the instance.
* Otherwise, if it has a # constructor that takes an argument of
* <code>wrap</code>'s class before the <code>ReificationStyle</code>, that
* constructor is used; this allows non-static inner classes to be used for
* <code>graphClass</code>, with <code>wrap</code> being the outer class
* instance. If no suitable constructor exists, a JenaException is thrown.
*
* @param wrap
* the outer class instance if graphClass is an inner class
* @param graphClass
* a class implementing Graph
* @return an instance of graphClass with the given style
* @throws RuntimeException
* or JenaException if construction fails
*/
public static Graph getGraph(Object wrap, Class<? extends Graph> graphClass) {
try {
Constructor<?> cons = getConstructor(graphClass, new Class[] {});
if (cons != null)
return (Graph) cons.newInstance(new Object[] {});
Constructor<?> cons2 = getConstructor(graphClass,
new Class[] { wrap.getClass() });
if (cons2 != null)
return (Graph) cons2.newInstance(new Object[] { wrap });
throw new JenaException("no suitable graph constructor found for "
+ graphClass);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new JenaException(e);
}
}
/**
* Begin a transaction on the graph if transactions are supported.
*
* @param g
*/
public static void txnBegin(Graph g) {
if (g.getTransactionHandler().transactionsSupported()) {
g.getTransactionHandler().begin();
}
}
/**
* Commit the transaction on the graph if transactions are supported.
*
* @param g
*/
public static void txnCommit(Graph g) {
if (g.getTransactionHandler().transactionsSupported()) {
g.getTransactionHandler().commit();
}
}
/**
* Rollback (abort) the transaction on the graph if transactions are
* supported.
*
* @param g
*/
public static void txnRollback(Graph g) {
if (g.getTransactionHandler().transactionsSupported()) {
g.getTransactionHandler().abort();
}
}
}