/*
* 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.test;
/**
An extension of JenaTestBase (which see) with Graph-specific methods.
*/
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor ;
import java.net.URISyntaxException;
import java.net.URL;
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.* ;
import org.apache.jena.ontology.impl.TestListSyntaxCategories ;
import org.apache.jena.shared.JenaException ;
import org.apache.jena.shared.PrefixMapping ;
import org.apache.jena.test.JenaTestBase ;
import org.apache.jena.util.CollectionFactory ;
import org.apache.jena.util.IteratorCollection ;
import org.apache.jena.util.iterator.ExtendedIterator ;
public class GraphTestBase extends JenaTestBase
{
protected static String getFileName( String fn )
{
URL u = TestListSyntaxCategories.class.getClassLoader().getResource( fn );
if (u == null)
{
throw new RuntimeException( new FileNotFoundException( fn ));
}
try {
return u.toURI().toString();
} catch (URISyntaxException e) {
throw new RuntimeException( e );
}
}
public GraphTestBase( String name )
{ super( name ); }
/**
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 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>A</code>.
*/
public <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<>();
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<>();
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<>();
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;
}
/**
Answer a new memory-based graph with Extended prefixes.
*/
public static Graph newGraph()
{
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 graphAdd( newGraph(), 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() );
}
/**
A 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 ) );
}
/**
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 void testContains( Graph g, Triple [] triples )
{
for ( Triple triple : triples )
{
assertTrue( "contains " + triple, g.contains( triple ) );
}
}
/**
Assert that <code>g</code> contains every triple in <code>triples</code>.
*/
public void testContains( Graph g, List<Triple> triples )
{
for ( Triple triple : triples )
{
assertTrue( g.contains( triple ) );
}
}
/**
Assert that <code>g</code> contains every triple in <code>it</code>.
*/
public 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 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 void testOmits( Graph g, Triple [] triples )
{
for ( Triple triple : triples )
{
assertFalse( "", g.contains( triple ) );
}
}
/**
Assert that <code>g</code> contains none of the triples in
<code>triples</code>.
*/
public void testOmits( Graph g, List<Triple> triples )
{
for ( Triple triple : triples )
{
assertFalse( "", g.contains( triple ) );
}
}
/**
Assert that <code>g</code> contains none of the triples in
<code>it</code>.
*/
public 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 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 ); }
}
}