You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2017/10/30 14:57:16 UTC
[16/22] commons-rdf git commit: Module names, directory names,
and artifact names should match.
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractDatasetTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractDatasetTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractDatasetTest.java
new file mode 100644
index 0000000..ab3dc32
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractDatasetTest.java
@@ -0,0 +1,778 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test Dataset implementation
+ * <p>
+ * To add to your implementation's tests, create a subclass with a name ending
+ * in <code>Test</code> and provide {@link #createFactory()} which minimally
+ * must support {@link RDF#createDataset()} and {@link RDF#createIRI(String)}, but
+ * ideally support all operations.
+ * <p>
+ * This test uses try-with-resources blocks for calls to {@link Dataset#stream()}
+ * and {@link Dataset#iterate()}.
+ *
+ * @see Dataset
+ * @see RDF
+ */
+public abstract class AbstractDatasetTest {
+
+ protected RDF factory;
+ protected Dataset dataset;
+ protected IRI alice;
+ protected IRI bob;
+ protected IRI name;
+ protected IRI knows;
+ protected IRI member;
+ protected BlankNode bnode1;
+ protected BlankNode bnode2;
+ protected Literal aliceName;
+ protected Literal bobName;
+ protected Literal secretClubName;
+ protected Literal companyName;
+ protected Quad bobNameQuad;
+ private IRI isPrimaryTopicOf;
+ private IRI graph1;
+ private BlankNode graph2;
+
+ /**
+ *
+ * This method must be overridden by the implementing test to provide a
+ * factory for the test to create {@link Dataset}, {@link IRI} etc.
+ *
+ * @return {@link RDF} instance to be tested.
+ */
+ protected abstract RDF createFactory();
+
+ @Before
+ public void createDatasetAndAdd() {
+ factory = createFactory();
+ dataset = factory.createDataset();
+ assertEquals(0, dataset.size());
+
+ graph1 = factory.createIRI("http://example.com/graph1");
+ graph2 = factory.createBlankNode();
+
+ alice = factory.createIRI("http://example.com/alice");
+ bob = factory.createIRI("http://example.com/bob");
+ name = factory.createIRI("http://xmlns.com/foaf/0.1/name");
+ knows = factory.createIRI("http://xmlns.com/foaf/0.1/knows");
+ member = factory.createIRI("http://xmlns.com/foaf/0.1/member");
+ bnode1 = factory.createBlankNode("org1");
+ bnode2 = factory.createBlankNode("org2");
+
+ secretClubName = factory.createLiteral("The Secret Club");
+ companyName = factory.createLiteral("A company");
+ aliceName = factory.createLiteral("Alice");
+ bobName = factory.createLiteral("Bob", "en-US");
+
+ dataset.add(graph1, alice, name, aliceName);
+ dataset.add(graph1, alice, knows, bob);
+
+ dataset.add(graph1, alice, member, bnode1);
+
+ bobNameQuad = factory.createQuad(graph2, bob, name, bobName);
+ dataset.add(bobNameQuad);
+
+ dataset.add(factory.createQuad(graph2, bob, member, bnode1));
+ dataset.add(factory.createQuad(graph2, bob, member, bnode2));
+ // NOTE: bnode1 used in both graph1 and graph2
+ dataset.add(graph1, bnode1, name, secretClubName);
+ dataset.add(graph2, bnode2, name, companyName);
+
+ // default graph describes graph1 and graph2
+ isPrimaryTopicOf = factory.createIRI("http://xmlns.com/foaf/0.1/isPrimaryTopicOf");
+ dataset.add(null, alice, isPrimaryTopicOf, graph1);
+ dataset.add(null, bob, isPrimaryTopicOf, graph2);
+
+
+ }
+
+ @Test
+ public void size() throws Exception {
+ assertEquals(10, dataset.size());
+ }
+
+ @Test
+ public void iterate() throws Exception {
+ Assume.assumeTrue(dataset.size() > 0);
+ final List<Quad> quads = new ArrayList<>();
+ for (final Quad t : dataset.iterate()) {
+ quads.add(t);
+ }
+ assertEquals(dataset.size(), quads.size());
+
+ //assertTrue(quads.contains(bobNameQuad));
+ // java.util.List won't do any BlankNode mapping, so
+ // instead bobNameQuad of let's check for an IRI-centric quad
+ final Quad q = factory.createQuad(graph1, alice, name, aliceName);
+ quads.contains(q);
+
+ // aborted iteration
+ final Iterable<Quad> iterate = dataset.iterate();
+ final Iterator<Quad> it = iterate.iterator();
+
+ assertTrue(it.hasNext());
+ it.next();
+ closeIterable(iterate);
+
+ // second iteration - should start from fresh and
+ // get the same count
+ long count = 0;
+ final Iterable<Quad> iterable = dataset.iterate();
+ for (@SuppressWarnings("unused") final
+ Quad t : iterable) {
+ count++;
+ }
+ assertEquals(dataset.size(), count);
+
+ // Pattern iteration which should cover multiple graphs.
+
+ Set<Quad> aliceQuads = new HashSet<>();
+ for (Quad aliceQ : dataset.iterate(null, alice, null, null)) {
+ aliceQuads.add(aliceQ);
+ }
+ assertTrue(aliceQuads.contains(factory.createQuad(graph1, alice, name, aliceName)));
+ assertTrue(aliceQuads.contains(factory.createQuad(graph1, alice, knows, bob)));
+ // We can't test this by Quad equality, as bnode1 might become mapped by the
+ // dataset
+ //assertTrue(aliceQuads.contains(factory.createQuad(graph1, alice, member, bnode1)));
+ assertTrue(aliceQuads.contains(factory.createQuad(null, alice, isPrimaryTopicOf, graph1)));
+ assertEquals(4, aliceQuads.size());
+
+ // Check the isPrimaryTopicOf statements in the default graph
+ int topics = 0;
+ for (Quad topic : dataset.iterate(null, null, isPrimaryTopicOf, null)) {
+ topics++;
+ // COMMONSRDF-55: should not be <urn:x-arq:defaultgraph> or similar
+ assertFalse(topic.getGraphName().isPresent());
+ }
+ assertEquals(2, topics);
+ }
+
+ @Test
+ public void streamDefaultGraphNameAlice() throws Exception {
+ // null below would match in ANY graph (including default graph)
+ Optional<? extends Quad> aliceTopic = dataset.stream(null, alice, isPrimaryTopicOf, null).findAny();
+ assertTrue(aliceTopic.isPresent());
+ // COMMONSRDF-55: should not be <urn:x-arq:defaultgraph> or similar
+ assertNull(aliceTopic.get().getGraphName().orElse(null));
+ assertFalse(aliceTopic.get().getGraphName().isPresent());
+ }
+
+
+ @Test
+ public void streamDefaultGraphNameByPattern() throws Exception {
+ // Explicitly select in only the default graph Optional.empty()
+ Optional<? extends Quad> aliceTopic = dataset.stream(Optional.empty(), null, null, null).findAny();
+ assertTrue(aliceTopic.isPresent());
+ // COMMONSRDF-55: should not be <urn:x-arq:defaultgraph> or similar
+ assertNull(aliceTopic.get().getGraphName().orElse(null));
+ assertFalse(aliceTopic.get().getGraphName().isPresent());
+ }
+
+
+ /**
+ * Special quad closing for RDF4J.
+ */
+ private void closeIterable(final Iterable<Quad> iterate) throws Exception {
+ if (iterate instanceof AutoCloseable) {
+ ((AutoCloseable) iterate).close();
+ }
+ }
+
+ @Test
+ public void iterateFilter() throws Exception {
+ final List<RDFTerm> friends = new ArrayList<>();
+ final IRI alice = factory.createIRI("http://example.com/alice");
+ final IRI knows = factory.createIRI("http://xmlns.com/foaf/0.1/knows");
+ for (final Quad t : dataset.iterate(null, alice, knows, null)) {
+ friends.add(t.getObject());
+ }
+ assertEquals(1, friends.size());
+ assertEquals(bob, friends.get(0));
+
+ // .. can we iterate over zero hits?
+ final Iterable<Quad> iterate = dataset.iterate(Optional.of(graph2), bob, knows, alice);
+ for (final Quad unexpected : iterate) {
+ fail("Unexpected quad " + unexpected);
+ }
+ // closeIterable(iterate);
+ }
+
+ @Test
+ public void contains() throws Exception {
+ assertFalse(dataset.contains(null, bob, knows, alice)); // or so he claims..
+
+ assertTrue(dataset.contains(Optional.of(graph1), alice, knows, bob));
+
+ try (Stream<? extends Quad> stream = dataset.stream()) {
+ final Optional<? extends Quad> first = stream.skip(4).findFirst();
+ Assume.assumeTrue(first.isPresent());
+ final Quad existingQuad = first.get();
+ assertTrue(dataset.contains(existingQuad));
+ }
+
+ final Quad nonExistingQuad = factory.createQuad(graph2, bob, knows, alice);
+ assertFalse(dataset.contains(nonExistingQuad));
+
+ // An existing quad
+ final Quad quad = factory.createQuad(graph1, alice, knows, bob);
+ // FIXME: Should not this always be true?
+ assertTrue(dataset.contains(quad));
+ }
+
+ @Test
+ public void remove() throws Exception {
+ final long fullSize = dataset.size();
+ dataset.remove(Optional.of(graph1), alice, knows, bob);
+ final long shrunkSize = dataset.size();
+ assertEquals(1, fullSize - shrunkSize);
+
+ dataset.remove(Optional.of(graph1), alice, knows, bob);
+ assertEquals(shrunkSize, dataset.size()); // unchanged
+
+ dataset.add(graph1, alice, knows, bob);
+ dataset.add(graph2, alice, knows, bob);
+ dataset.add(graph2, alice, knows, bob);
+ // Undetermined size at this point -- but at least it
+ // should be bigger
+ assertTrue(dataset.size() > shrunkSize);
+
+ // and after a single remove they should all be gone
+ dataset.remove(null, alice, knows, bob);
+ assertEquals(shrunkSize, dataset.size());
+
+ Quad otherQuad;
+ try (Stream<? extends Quad> stream = dataset.stream()) {
+ final Optional<? extends Quad> anyQuad = stream.findAny();
+ Assume.assumeTrue(anyQuad.isPresent());
+ otherQuad = anyQuad.get();
+ }
+
+ dataset.remove(otherQuad);
+ assertEquals(shrunkSize - 1, dataset.size());
+ dataset.remove(otherQuad);
+ assertEquals(shrunkSize - 1, dataset.size()); // no change
+
+ // for some reason in rdf4j this causes duplicates!
+ dataset.add(otherQuad);
+ // dataset.stream().forEach(System.out::println);
+ // should have increased
+ assertTrue(dataset.size() >= shrunkSize);
+ }
+
+ @Test
+ public void clear() throws Exception {
+ dataset.clear();
+ assertFalse(dataset.contains(null, alice, knows, bob));
+ assertEquals(0, dataset.size());
+ dataset.clear(); // no-op
+ assertEquals(0, dataset.size());
+ assertFalse(dataset.contains(null, null, null, null)); // nothing here
+ }
+
+ @Test
+ public void getQuads() throws Exception {
+ long quadCount;
+ try (Stream<? extends Quad> stream = dataset.stream()) {
+ quadCount = stream.count();
+ }
+ assertTrue(quadCount > 0);
+
+ try (Stream<? extends Quad> stream = dataset.stream()) {
+ assertTrue(stream.allMatch(t -> dataset.contains(t)));
+ }
+
+ // Check exact count
+ Assume.assumeNotNull(bnode1, bnode2, aliceName, bobName, secretClubName, companyName, bobNameQuad);
+ assertEquals(10, quadCount);
+ }
+
+ @Test
+ public void getQuadsQuery() throws Exception {
+
+ try (Stream<? extends Quad> stream = dataset.stream(Optional.of(graph1), alice, null, null)) {
+ final long aliceCount = stream.count();
+ assertTrue(aliceCount > 0);
+ Assume.assumeNotNull(aliceName);
+ assertEquals(3, aliceCount);
+ }
+
+ Assume.assumeNotNull(bnode1, bnode2, bobName, companyName, secretClubName);
+ try (Stream<? extends Quad> stream = dataset.stream(null, null, name, null)) {
+ assertEquals(4, stream.count());
+ }
+ Assume.assumeNotNull(bnode1);
+ try (Stream<? extends Quad> stream = dataset.stream(null, null, member, null)) {
+ assertEquals(3, stream.count());
+ }
+ }
+
+ @Test
+ public void addBlankNodesFromMultipleDatasets() {
+ // Create two separate Dataset instances
+ final Dataset g1 = createDataset1();
+ final Dataset g2 = createDataset2();
+
+ // and add them to a new Dataset g3
+ final Dataset g3 = factory.createDataset();
+ addAllQuads(g1, g3);
+ addAllQuads(g2, g3);
+
+ // Let's make a map to find all those blank nodes after insertion
+ // (The Dataset implementation is not currently required to
+ // keep supporting those BlankNodes with contains() - see
+ // COMMONSRDF-15)
+
+ final Map<String, BlankNodeOrIRI> whoIsWho = new ConcurrentHashMap<>();
+ // ConcurrentHashMap as we will try parallel forEach below,
+ // which should not give inconsistent results (it does with a
+ // HashMap!)
+
+ // look up BlankNodes by name
+ final IRI name = factory.createIRI("http://xmlns.com/foaf/0.1/name");
+ try (Stream<? extends Quad> stream = g3.stream(null, null, name, null)) {
+ stream.parallel().forEach(t -> whoIsWho.put(t.getObject().ntriplesString(), t.getSubject()));
+ }
+
+ assertEquals(4, whoIsWho.size());
+ // and contains 4 unique values
+ assertEquals(4, new HashSet<>(whoIsWho.values()).size());
+
+ final BlankNodeOrIRI b1Alice = whoIsWho.get("\"Alice\"");
+ assertNotNull(b1Alice);
+ final BlankNodeOrIRI b2Bob = whoIsWho.get("\"Bob\"");
+ assertNotNull(b2Bob);
+ final BlankNodeOrIRI b1Charlie = whoIsWho.get("\"Charlie\"");
+ assertNotNull(b1Charlie);
+ final BlankNodeOrIRI b2Dave = whoIsWho.get("\"Dave\"");
+ assertNotNull(b2Dave);
+
+ // All blank nodes should differ
+ notEquals(b1Alice, b2Bob);
+ notEquals(b1Alice, b1Charlie);
+ notEquals(b1Alice, b2Dave);
+ notEquals(b2Bob, b1Charlie);
+ notEquals(b2Bob, b2Dave);
+ notEquals(b1Charlie, b2Dave);
+
+ // And we should be able to query with them again
+ // as we got them back from g3
+ final IRI hasChild = factory.createIRI("http://example.com/hasChild");
+ // FIXME: Check graph2 BlankNode in these ..?
+ assertTrue(g3.contains(null, b1Alice, hasChild, b2Bob));
+ assertTrue(g3.contains(null, b2Dave, hasChild, b1Charlie));
+ // But not
+ assertFalse(g3.contains(null, b1Alice, hasChild, b1Alice));
+ assertFalse(g3.contains(null, b1Alice, hasChild, b1Charlie));
+ assertFalse(g3.contains(null, b1Alice, hasChild, b2Dave));
+ // nor
+ assertFalse(g3.contains(null, b2Dave, hasChild, b1Alice));
+ assertFalse(g3.contains(null, b2Dave, hasChild, b1Alice));
+
+ // and these don't have any children (as far as we know)
+ assertFalse(g3.contains(null, b2Bob, hasChild, null));
+ assertFalse(g3.contains(null, b1Charlie, hasChild, null));
+ }
+
+ private void notEquals(final BlankNodeOrIRI node1, final BlankNodeOrIRI node2) {
+ assertFalse(node1.equals(node2));
+ // in which case we should be able to assume
+ // (as they are in the same dataset)
+ assertFalse(node1.ntriplesString().equals(node2.ntriplesString()));
+ }
+
+ /**
+ * Add all quads from the source to the target.
+ * <p>
+ * The quads may be copied in any order. No special conversion or
+ * adaptation of {@link BlankNode}s are performed.
+ *
+ * @param source
+ * Source Dataset to copy quads from
+ * @param target
+ * Target Dataset where quads will be added
+ */
+ private void addAllQuads(final Dataset source, final Dataset target) {
+
+ // unordered() as we don't need to preserve quad order
+ // sequential() as we don't (currently) require target Dataset to be
+ // thread-safe
+
+ try (Stream<? extends Quad> stream = source.stream()) {
+ stream.unordered().sequential().forEach(t -> target.add(t));
+ }
+ }
+
+ /**
+ * Make a new dataset with two BlankNodes - each with a different
+ * uniqueReference
+ */
+ private Dataset createDataset1() {
+ final RDF factory1 = createFactory();
+
+ final IRI name = factory1.createIRI("http://xmlns.com/foaf/0.1/name");
+ final Dataset g1 = factory1.createDataset();
+ final BlankNode b1 = createOwnBlankNode("b1", "0240eaaa-d33e-4fc0-a4f1-169d6ced3680");
+ g1.add(b1, b1, name, factory1.createLiteral("Alice"));
+
+ final BlankNode b2 = createOwnBlankNode("b2", "9de7db45-0ce7-4b0f-a1ce-c9680ffcfd9f");
+ g1.add(b2, b2, name, factory1.createLiteral("Bob"));
+
+ final IRI hasChild = factory1.createIRI("http://example.com/hasChild");
+ g1.add(null, b1, hasChild, b2);
+
+ return g1;
+ }
+
+ /**
+ * Create a different implementation of BlankNode to be tested with
+ * dataset.add(a,b,c); (the implementation may or may not then choose to
+ * translate such to its own instances)
+ *
+ * @param name
+ * @return
+ */
+ private BlankNode createOwnBlankNode(final String name, final String uuid) {
+ return new BlankNode() {
+ @Override
+ public String ntriplesString() {
+ return "_: " + name;
+ }
+
+ @Override
+ public String uniqueReference() {
+ return uuid;
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof BlankNode)) {
+ return false;
+ }
+ final BlankNode other = (BlankNode) obj;
+ return uuid.equals(other.uniqueReference());
+ }
+ };
+ }
+
+ private Dataset createDataset2() {
+ final RDF factory2 = createFactory();
+ final IRI name = factory2.createIRI("http://xmlns.com/foaf/0.1/name");
+
+ final Dataset g2 = factory2.createDataset();
+
+ final BlankNode b1 = createOwnBlankNode("b1", "bc8d3e45-a08f-421d-85b3-c25b373abf87");
+ g2.add(b1, b1, name, factory2.createLiteral("Charlie"));
+
+ final BlankNode b2 = createOwnBlankNode("b2", "2209097a-5078-4b03-801a-6a2d2f50d739");
+ g2.add(b2, b2, name, factory2.createLiteral("Dave"));
+
+ final IRI hasChild = factory2.createIRI("http://example.com/hasChild");
+ // NOTE: Opposite direction of loadDataset1
+ g2.add(b2, b2, hasChild, b1);
+ return g2;
+ }
+
+ /**
+ * Ensure {@link Dataset#getGraphNames()} contains our two graphs.
+ *
+ * @throws Exception
+ * If test fails
+ */
+ @Test
+ public void getGraphNames() throws Exception {
+ final Set<BlankNodeOrIRI> names = dataset.getGraphNames().collect(Collectors.toSet());
+ assertTrue("Can't find graph name " + graph1, names.contains(graph1));
+ assertTrue("Found no quads in graph1", dataset.contains(Optional.of(graph1), null, null, null));
+
+ final Optional<BlankNodeOrIRI> graphName2 = dataset.getGraphNames().filter(BlankNode.class::isInstance).findAny();
+ assertTrue("Could not find graph2-like BlankNode", graphName2.isPresent());
+ assertTrue("Found no quads in graph2", dataset.contains(graphName2, null, null, null));
+
+ // Some implementations like Virtuoso might have additional internal graphs,
+ // so we can't assume this:
+ //assertEquals(2, names.size());
+ }
+
+ @Test
+ public void getGraph() throws Exception {
+ final Graph defaultGraph = dataset.getGraph();
+ // TODO: Can we assume the default graph was empty before our new triples?
+ assertEquals(2, defaultGraph.size());
+ assertTrue(defaultGraph.contains(alice, isPrimaryTopicOf, graph1));
+ // NOTE: graph2 is a BlankNode
+ assertTrue(defaultGraph.contains(bob, isPrimaryTopicOf, null));
+ }
+
+
+ @Test
+ public void getGraphNull() throws Exception {
+ // Default graph should be present
+ final Graph defaultGraph = dataset.getGraph(null).get();
+ // TODO: Can we assume the default graph was empty before our new triples?
+ assertEquals(2, defaultGraph.size());
+ assertTrue(defaultGraph.contains(alice, isPrimaryTopicOf, graph1));
+ // NOTE: wildcard as graph2 is a (potentially mapped) BlankNode
+ assertTrue(defaultGraph.contains(bob, isPrimaryTopicOf, null));
+ }
+
+
+ @Test
+ public void getGraph1() throws Exception {
+ // graph1 should be present
+ final Graph g1 = dataset.getGraph(graph1).get();
+ assertEquals(4, g1.size());
+
+ assertTrue(g1.contains(alice, name, aliceName));
+ assertTrue(g1.contains(alice, knows, bob));
+ assertTrue(g1.contains(alice, member, null));
+ assertTrue(g1.contains(null, name, secretClubName));
+ }
+
+ @Test
+ public void getGraph2() throws Exception {
+ // graph2 should be present, even if is named by a BlankNode
+ // We'll look up the potentially mapped graph2 blanknode
+ final BlankNodeOrIRI graph2Name = (BlankNodeOrIRI) dataset.stream(Optional.empty(), bob, isPrimaryTopicOf, null)
+ .map(Quad::getObject).findAny().get();
+
+ final Graph g2 = dataset.getGraph(graph2Name).get();
+ assertEquals(4, g2.size());
+ final Triple bobNameTriple = bobNameQuad.asTriple();
+ assertTrue(g2.contains(bobNameTriple));
+ assertTrue(g2.contains(bob, member, bnode1));
+ assertTrue(g2.contains(bob, member, bnode2));
+ assertFalse(g2.contains(bnode1, name, secretClubName));
+ assertTrue(g2.contains(bnode2, name, companyName));
+ }
+
+
+ @Test
+ public void containsLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can add/contains/remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Hello there", "en-gb");
+ final Literal upper = factory.createLiteral("Hello there", "EN-GB");
+ final Literal mixed = factory.createLiteral("Hello there", "en-GB");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+
+ dataset.add(null, example1, greeting, upper);
+
+ // any kind of Triple should match
+ assertTrue(dataset.contains(factory.createQuad(null, example1, greeting, upper)));
+ assertTrue(dataset.contains(factory.createQuad(null, example1, greeting, lower)));
+ assertTrue(dataset.contains(factory.createQuad(null, example1, greeting, mixed)));
+
+ // or as patterns
+ assertTrue(dataset.contains(null, null, null, upper));
+ assertTrue(dataset.contains(null, null, null, lower));
+ assertTrue(dataset.contains(null, null, null, mixed));
+ }
+
+ @Test
+ public void containsLanguageTagsCaseInsensitiveTurkish() {
+ // COMMONSRDF-51: Special test for Turkish issue where
+ // "i".toLowerCase() != "i"
+ // See also:
+ // https://garygregory.wordpress.com/2015/11/03/java-lowercase-conversion-turkey/
+
+ // This is similar to the test in AbstractRDFTest, but on a graph
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.ROOT);
+ final Literal lowerROOT = factory.createLiteral("moi", "fi");
+ final Literal upperROOT = factory.createLiteral("moi", "FI");
+ final Literal mixedROOT = factory.createLiteral("moi", "fI");
+ final IRI exampleROOT = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+ dataset.add(null, exampleROOT, greeting, mixedROOT);
+
+ Locale turkish = Locale.forLanguageTag("TR");
+ Locale.setDefault(turkish);
+ // If the below assertion fails, then the Turkish
+ // locale no longer have this peculiarity that
+ // we want to test.
+ Assume.assumeFalse("FI".toLowerCase().equals("fi"));
+
+ // Below is pretty much the same as in
+ // containsLanguageTagsCaseInsensitive()
+ final Literal lower = factory.createLiteral("moi", "fi");
+ final Literal upper = factory.createLiteral("moi", "FI");
+ final Literal mixed = factory.createLiteral("moi", "fI");
+
+ final IRI exampleTR = factory.createIRI("http://example.com/s2");
+ dataset.add(null, exampleTR, greeting, upper);
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, upper)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, upperROOT)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, lower)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, lowerROOT)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, mixed)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleTR, greeting, mixedROOT)));
+ assertTrue(dataset.contains(null, exampleTR, null, upper));
+ assertTrue(dataset.contains(null, exampleTR, null, upperROOT));
+ assertTrue(dataset.contains(null, exampleTR, null, lower));
+ assertTrue(dataset.contains(null, exampleTR, null, lowerROOT));
+ assertTrue(dataset.contains(null, exampleTR, null, mixed));
+ assertTrue(dataset.contains(null, exampleTR, null, mixedROOT));
+
+ // What about the triple we added while in ROOT locale?
+ assertTrue(dataset.contains(factory.createQuad(null, exampleROOT, greeting, upper)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleROOT, greeting, lower)));
+ assertTrue(dataset.contains(factory.createQuad(null, exampleROOT, greeting, mixed)));
+ assertTrue(dataset.contains(null, exampleROOT, null, upper));
+ assertTrue(dataset.contains(null, exampleROOT, null, lower));
+ assertTrue(dataset.contains(null, exampleROOT, null, mixed));
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
+
+ @Test
+ public void removeLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Howdy", "en-us");
+ final Literal upper = factory.createLiteral("Howdy", "EN-US");
+ final Literal mixed = factory.createLiteral("Howdy", "en-US");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+ dataset.add(null, example1, greeting, upper);
+
+ // Remove should also honour any case
+ dataset.remove(null, example1, null, mixed);
+ assertFalse(dataset.contains(null, null, greeting, null));
+
+ dataset.add(null, example1, greeting, lower);
+ dataset.remove(null, example1, null, upper);
+
+ // Check with Triple
+ dataset.add(factory.createQuad(null, example1, greeting, mixed));
+ dataset.remove(factory.createQuad(null, example1, greeting, upper));
+ assertFalse(dataset.contains(null, null, greeting, null));
+ }
+
+ private static Optional<? extends Quad> closableFindAny(Stream<? extends Quad> stream) {
+ try (Stream<? extends Quad> s = stream) {
+ return s.findAny();
+ }
+ }
+
+ @Test
+ public void streamLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can add/contains/remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Good afternoon", "en-gb");
+ final Literal upper = factory.createLiteral("Good afternoon", "EN-GB");
+ final Literal mixed = factory.createLiteral("Good afternoon", "en-GB");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+ dataset.add(null, example1, greeting, upper);
+
+ // or as patterns
+ assertTrue(closableFindAny(dataset.stream(null, null, null, upper)).isPresent());
+ assertTrue(closableFindAny(dataset.stream(null, null, null, lower)).isPresent());
+ assertTrue(closableFindAny(dataset.stream(null, null, null, mixed)).isPresent());
+
+ // Check the quad returned equal a new quad
+ Quad q = closableFindAny(dataset.stream(null, null, null, lower)).get();
+ assertEquals(q, factory.createQuad(null, example1, greeting, mixed));
+ }
+
+ /**
+ * An attempt to use the Java 8 streams to look up a more complicated query.
+ * <p>
+ * FYI, the equivalent SPARQL version (untested):
+ *
+ * <pre>
+ * SELECT ?orgName WHERE {
+ * ?org foaf:name ?orgName .
+ * ?alice foaf:member ?org .
+ * ?bob foaf:member ?org .
+ * ?alice foaf:knows ?bob .
+ * FILTER NOT EXIST { ?bob foaf:knows ?alice }
+ * }
+ * </pre>
+ *
+ * @throws Exception If test fails
+ */
+ @Test
+ public void whyJavaStreamsMightNotTakeOverFromSparql() throws Exception {
+ Assume.assumeNotNull(bnode1, bnode2, secretClubName);
+ // Find a secret organizations
+ try (Stream<? extends Quad> stream = dataset.stream(null, null, knows, null)) {
+ assertEquals("\"The Secret Club\"",
+ // Find One-way "knows"
+ stream.filter(t -> !dataset.contains(null, (BlankNodeOrIRI) t.getObject(), knows, t.getSubject()))
+ .map(knowsQuad -> {
+ try (Stream<? extends Quad> memberOf = dataset
+ // and those they know, what are they
+ // member of?
+ .stream(null, (BlankNodeOrIRI) knowsQuad.getObject(), member, null)) {
+ return memberOf
+ // keep those which first-guy is a
+ // member of
+ .filter(memberQuad -> dataset.contains(null, knowsQuad.getSubject(), member,
+ // First hit is good enough
+ memberQuad.getObject()))
+ .findFirst().get().getObject();
+ }
+ })
+ // then look up the name of that org
+ .map(org -> {
+ try (Stream<? extends Quad> orgName = dataset.stream(null, (BlankNodeOrIRI) org, name,
+ null)) {
+ return orgName.findFirst().get().getObject().ntriplesString();
+ }
+ }).findFirst().get());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
new file mode 100644
index 0000000..3020704
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
@@ -0,0 +1,683 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test Graph implementation
+ * <p>
+ * To add to your implementation's tests, create a subclass with a name ending
+ * in <code>Test</code> and provide {@link #createFactory()} which minimally
+ * must support {@link RDF#createGraph()} and {@link RDF#createIRI(String)}, but
+ * ideally support all operations.
+ * <p>
+ * This test uses try-with-resources blocks for calls to {@link Graph#stream()}
+ * and {@link Graph#iterate()}.
+ *
+ * @see Graph
+ * @see RDF
+ */
+public abstract class AbstractGraphTest {
+
+ protected RDF factory;
+ protected Graph graph;
+ protected IRI alice;
+ protected IRI bob;
+ protected IRI name;
+ protected IRI knows;
+ protected IRI member;
+ protected BlankNode bnode1;
+ protected BlankNode bnode2;
+ protected Literal aliceName;
+ protected Literal bobName;
+ protected Literal secretClubName;
+ protected Literal companyName;
+ protected Triple bobNameTriple;
+
+ /**
+ *
+ * This method must be overridden by the implementing test to provide a
+ * factory for the test to create {@link Graph}, {@link IRI} etc.
+ *
+ * @return {@link RDF} instance to be tested.
+ */
+ protected abstract RDF createFactory();
+
+ @Before
+ public void createGraphAndAdd() {
+ factory = createFactory();
+ graph = factory.createGraph();
+ assertEquals(0, graph.size());
+
+ alice = factory.createIRI("http://example.com/alice");
+ bob = factory.createIRI("http://example.com/bob");
+ name = factory.createIRI("http://xmlns.com/foaf/0.1/name");
+ knows = factory.createIRI("http://xmlns.com/foaf/0.1/knows");
+ member = factory.createIRI("http://xmlns.com/foaf/0.1/member");
+ try {
+ bnode1 = factory.createBlankNode("org1");
+ bnode2 = factory.createBlankNode("org2");
+ } catch (final UnsupportedOperationException ex) {
+ // leave as null
+ }
+
+ try {
+ secretClubName = factory.createLiteral("The Secret Club");
+ companyName = factory.createLiteral("A company");
+ aliceName = factory.createLiteral("Alice");
+ bobName = factory.createLiteral("Bob", "en-US");
+ } catch (final UnsupportedOperationException ex) {
+ // leave as null
+ }
+
+ if (aliceName != null) {
+ graph.add(alice, name, aliceName);
+ }
+ graph.add(alice, knows, bob);
+
+ if (bnode1 != null) {
+ graph.add(alice, member, bnode1);
+ }
+
+ if (bobName != null) {
+ try {
+ bobNameTriple = factory.createTriple(bob, name, bobName);
+ } catch (final UnsupportedOperationException ex) {
+ // leave as null
+ }
+ if (bobNameTriple != null) {
+ graph.add(bobNameTriple);
+ }
+ }
+ if (bnode1 != null) {
+ graph.add(factory.createTriple(bob, member, bnode1));
+ graph.add(factory.createTriple(bob, member, bnode2));
+ if (secretClubName != null) {
+ graph.add(bnode1, name, secretClubName);
+ graph.add(bnode2, name, companyName);
+ }
+ }
+ }
+
+ @Test
+ public void size() throws Exception {
+ assertTrue(graph.size() > 0);
+ Assume.assumeNotNull(bnode1, bnode2, aliceName, bobName, secretClubName, companyName, bobNameTriple);
+ // Can only reliably predict size if we could create all triples
+ assertEquals(8, graph.size());
+ }
+
+ @Test
+ public void iterate() throws Exception {
+
+ Assume.assumeTrue(graph.size() > 0);
+
+ final List<Triple> triples = new ArrayList<>();
+ for (final Triple t : graph.iterate()) {
+ triples.add(t);
+ }
+ assertEquals(graph.size(), triples.size());
+ if (bobNameTriple != null) {
+ assertTrue(triples.contains(bobNameTriple));
+ }
+
+ // aborted iteration
+ final Iterable<Triple> iterate = graph.iterate();
+ final Iterator<Triple> it = iterate.iterator();
+
+ assertTrue(it.hasNext());
+ it.next();
+ closeIterable(iterate);
+
+ // second iteration - should start from fresh and
+ // get the same count
+ long count = 0;
+ final Iterable<Triple> iterable = graph.iterate();
+ for (@SuppressWarnings("unused") final
+ Triple t : iterable) {
+ count++;
+ }
+ assertEquals(graph.size(), count);
+ }
+
+ /**
+ * Special triple closing for RDF4J.
+ */
+ private void closeIterable(final Iterable<Triple> iterate) throws Exception {
+ if (iterate instanceof AutoCloseable) {
+ ((AutoCloseable) iterate).close();
+ }
+ }
+
+ @Test
+ public void iterateFilter() throws Exception {
+ final List<RDFTerm> friends = new ArrayList<>();
+ final IRI alice = factory.createIRI("http://example.com/alice");
+ final IRI knows = factory.createIRI("http://xmlns.com/foaf/0.1/knows");
+ for (final Triple t : graph.iterate(alice, knows, null)) {
+ friends.add(t.getObject());
+ }
+ assertEquals(1, friends.size());
+ assertEquals(bob, friends.get(0));
+
+ // .. can we iterate over zero hits?
+ final Iterable<Triple> iterate = graph.iterate(bob, knows, alice);
+ for (final Triple unexpected : iterate) {
+ fail("Unexpected triple " + unexpected);
+ }
+ // closeIterable(iterate);
+ }
+
+ @Test
+ public void contains() throws Exception {
+ assertFalse(graph.contains(bob, knows, alice)); // or so he claims..
+
+ assertTrue(graph.contains(alice, knows, bob));
+
+ try (Stream<? extends Triple> stream = graph.stream()) {
+ final Optional<? extends Triple> first = stream.skip(4).findFirst();
+ Assume.assumeTrue(first.isPresent());
+ final Triple existingTriple = first.get();
+ assertTrue(graph.contains(existingTriple));
+ }
+
+ final Triple nonExistingTriple = factory.createTriple(bob, knows, alice);
+ assertFalse(graph.contains(nonExistingTriple));
+
+ Triple triple = null;
+ try {
+ triple = factory.createTriple(alice, knows, bob);
+ } catch (final UnsupportedOperationException ex) {
+ }
+ if (triple != null) {
+ // FIXME: Should not this always be true?
+ // assertTrue(graph.contains(triple));
+ }
+ }
+
+ @Test
+ public void remove() throws Exception {
+ final long fullSize = graph.size();
+ graph.remove(alice, knows, bob);
+ final long shrunkSize = graph.size();
+ assertEquals(1, fullSize - shrunkSize);
+
+ graph.remove(alice, knows, bob);
+ assertEquals(shrunkSize, graph.size()); // unchanged
+
+ graph.add(alice, knows, bob);
+ graph.add(alice, knows, bob);
+ graph.add(alice, knows, bob);
+ // Undetermined size at this point -- but at least it
+ // should be bigger
+ assertTrue(graph.size() > shrunkSize);
+
+ // and after a single remove they should all be gone
+ graph.remove(alice, knows, bob);
+ assertEquals(shrunkSize, graph.size());
+
+ Triple otherTriple;
+ try (Stream<? extends Triple> stream = graph.stream()) {
+ final Optional<? extends Triple> anyTriple = stream.findAny();
+ Assume.assumeTrue(anyTriple.isPresent());
+ otherTriple = anyTriple.get();
+ }
+
+ graph.remove(otherTriple);
+ assertEquals(shrunkSize - 1, graph.size());
+ graph.remove(otherTriple);
+ assertEquals(shrunkSize - 1, graph.size()); // no change
+
+ // for some reason in rdf4j this causes duplicates!
+ graph.add(otherTriple);
+ // graph.stream().forEach(System.out::println);
+ // should have increased
+ assertTrue(graph.size() >= shrunkSize);
+ }
+
+ @Test
+ public void clear() throws Exception {
+ graph.clear();
+ assertFalse(graph.contains(alice, knows, bob));
+ assertEquals(0, graph.size());
+ graph.clear(); // no-op
+ assertEquals(0, graph.size());
+ }
+
+ @Test
+ public void getTriples() throws Exception {
+ long tripleCount;
+ try (Stream<? extends Triple> stream = graph.stream()) {
+ tripleCount = stream.count();
+ }
+ assertTrue(tripleCount > 0);
+
+ try (Stream<? extends Triple> stream = graph.stream()) {
+ assertTrue(stream.allMatch(t -> graph.contains(t)));
+ }
+
+ // Check exact count
+ Assume.assumeNotNull(bnode1, bnode2, aliceName, bobName, secretClubName, companyName, bobNameTriple);
+ assertEquals(8, tripleCount);
+ }
+
+ @Test
+ public void getTriplesQuery() throws Exception {
+
+ try (Stream<? extends Triple> stream = graph.stream(alice, null, null)) {
+ final long aliceCount = stream.count();
+ assertTrue(aliceCount > 0);
+ Assume.assumeNotNull(aliceName);
+ assertEquals(3, aliceCount);
+ }
+
+ Assume.assumeNotNull(bnode1, bnode2, bobName, companyName, secretClubName);
+ try (Stream<? extends Triple> stream = graph.stream(null, name, null)) {
+ assertEquals(4, stream.count());
+ }
+ Assume.assumeNotNull(bnode1);
+ try (Stream<? extends Triple> stream = graph.stream(null, member, null)) {
+ assertEquals(3, stream.count());
+ }
+ }
+
+ @Test
+ public void addBlankNodesFromMultipleGraphs() {
+
+ try {
+ // Create two separate Graph instances
+ final Graph g1 = createGraph1();
+ final Graph g2 = createGraph2();
+
+ // and add them to a new Graph g3
+ final Graph g3 = factory.createGraph();
+ addAllTriples(g1, g3);
+ addAllTriples(g2, g3);
+
+ // Let's make a map to find all those blank nodes after insertion
+ // (The Graph implementation is not currently required to
+ // keep supporting those BlankNodes with contains() - see
+ // COMMONSRDF-15)
+
+ final Map<String, BlankNodeOrIRI> whoIsWho = new ConcurrentHashMap<>();
+ // ConcurrentHashMap as we will try parallel forEach below,
+ // which should not give inconsistent results (it does with a
+ // HashMap!)
+
+ // look up BlankNodes by name
+ final IRI name = factory.createIRI("http://xmlns.com/foaf/0.1/name");
+ try (Stream<? extends Triple> stream = g3.stream(null, name, null)) {
+ stream.parallel().forEach(t -> whoIsWho.put(t.getObject().ntriplesString(), t.getSubject()));
+ }
+
+ assertEquals(4, whoIsWho.size());
+ // and contains 4 unique values
+ assertEquals(4, new HashSet<>(whoIsWho.values()).size());
+
+ final BlankNodeOrIRI b1Alice = whoIsWho.get("\"Alice\"");
+ assertNotNull(b1Alice);
+ final BlankNodeOrIRI b2Bob = whoIsWho.get("\"Bob\"");
+ assertNotNull(b2Bob);
+ final BlankNodeOrIRI b1Charlie = whoIsWho.get("\"Charlie\"");
+ assertNotNull(b1Charlie);
+ final BlankNodeOrIRI b2Dave = whoIsWho.get("\"Dave\"");
+ assertNotNull(b2Dave);
+
+ // All blank nodes should differ
+ notEquals(b1Alice, b2Bob);
+ notEquals(b1Alice, b1Charlie);
+ notEquals(b1Alice, b2Dave);
+ notEquals(b2Bob, b1Charlie);
+ notEquals(b2Bob, b2Dave);
+ notEquals(b1Charlie, b2Dave);
+
+ // And we should be able to query with them again
+ // as we got them back from g3
+ final IRI hasChild = factory.createIRI("http://example.com/hasChild");
+ assertTrue(g3.contains(b1Alice, hasChild, b2Bob));
+ assertTrue(g3.contains(b2Dave, hasChild, b1Charlie));
+ // But not
+ assertFalse(g3.contains(b1Alice, hasChild, b1Alice));
+ assertFalse(g3.contains(b1Alice, hasChild, b1Charlie));
+ assertFalse(g3.contains(b1Alice, hasChild, b2Dave));
+ // nor
+ assertFalse(g3.contains(b2Dave, hasChild, b1Alice));
+ assertFalse(g3.contains(b2Dave, hasChild, b1Alice));
+
+ // and these don't have any children (as far as we know)
+ assertFalse(g3.contains(b2Bob, hasChild, null));
+ assertFalse(g3.contains(b1Charlie, hasChild, null));
+ } catch (final UnsupportedOperationException ex) {
+ Assume.assumeNoException(ex);
+ }
+ }
+
+ @Test
+ public void containsLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can add/contains/remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Hello", "en-gb");
+ final Literal upper = factory.createLiteral("Hello", "EN-GB");
+ final Literal mixed = factory.createLiteral("Hello", "en-GB");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+ final Graph graph = factory.createGraph();
+ graph.add(example1, greeting, upper);
+
+ // any kind of Triple should match
+ assertTrue(graph.contains(factory.createTriple(example1, greeting, upper)));
+ assertTrue(graph.contains(factory.createTriple(example1, greeting, lower)));
+ assertTrue(graph.contains(factory.createTriple(example1, greeting, mixed)));
+
+ // or as patterns
+ assertTrue(graph.contains(null, null, upper));
+ assertTrue(graph.contains(null, null, lower));
+ assertTrue(graph.contains(null, null, mixed));
+ }
+
+ @Test
+ public void containsLanguageTagsCaseInsensitiveTurkish() {
+ // COMMONSRDF-51: Special test for Turkish issue where
+ // "i".toLowerCase() != "i"
+ // See also:
+ // https://garygregory.wordpress.com/2015/11/03/java-lowercase-conversion-turkey/
+
+ // This is similar to the test in AbstractRDFTest, but on a graph
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.ROOT);
+ final Literal lowerROOT = factory.createLiteral("moi", "fi");
+ final Literal upperROOT = factory.createLiteral("moi", "FI");
+ final Literal mixedROOT = factory.createLiteral("moi", "fI");
+ final Graph g = factory.createGraph();
+ final IRI exampleROOT = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+ g.add(exampleROOT, greeting, mixedROOT);
+
+ Locale turkish = Locale.forLanguageTag("TR");
+ Locale.setDefault(turkish);
+ // If the below assertion fails, then the Turkish
+ // locale no longer have this peculiarity that
+ // we want to test.
+ Assume.assumeFalse("FI".toLowerCase().equals("fi"));
+
+ // Below is pretty much the same as in
+ // containsLanguageTagsCaseInsensitive()
+ final Literal lower = factory.createLiteral("moi", "fi");
+ final Literal upper = factory.createLiteral("moi", "FI");
+ final Literal mixed = factory.createLiteral("moi", "fI");
+
+ final IRI exampleTR = factory.createIRI("http://example.com/s2");
+ g.add(exampleTR, greeting, upper);
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, upper)));
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, upperROOT)));
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, lower)));
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, lowerROOT)));
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, mixed)));
+ assertTrue(g.contains(factory.createTriple(exampleTR, greeting, mixedROOT)));
+ assertTrue(g.contains(exampleTR, null, upper));
+ assertTrue(g.contains(exampleTR, null, upperROOT));
+ assertTrue(g.contains(exampleTR, null, lower));
+ assertTrue(g.contains(exampleTR, null, lowerROOT));
+ assertTrue(g.contains(exampleTR, null, mixed));
+ assertTrue(g.contains(exampleTR, null, mixedROOT));
+
+ // What about the triple we added while in ROOT locale?
+ assertTrue(g.contains(factory.createTriple(exampleROOT, greeting, upper)));
+ assertTrue(g.contains(factory.createTriple(exampleROOT, greeting, lower)));
+ assertTrue(g.contains(factory.createTriple(exampleROOT, greeting, mixed)));
+ assertTrue(g.contains(exampleROOT, null, upper));
+ assertTrue(g.contains(exampleROOT, null, lower));
+ assertTrue(g.contains(exampleROOT, null, mixed));
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
+
+ @Test
+ public void removeLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Hello", "en-gb");
+ final Literal upper = factory.createLiteral("Hello", "EN-GB");
+ final Literal mixed = factory.createLiteral("Hello", "en-GB");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+ final Graph graph = factory.createGraph();
+ graph.add(example1, greeting, upper);
+
+ // Remove should also honour any case
+ graph.remove(example1, null, mixed);
+ assertFalse(graph.contains(null, greeting, null));
+
+ graph.add(example1, greeting, lower);
+ graph.remove(example1, null, upper);
+
+ // Check with Triple
+ graph.add(factory.createTriple(example1, greeting, mixed));
+ graph.remove(factory.createTriple(example1, greeting, upper));
+ assertFalse(graph.contains(null, greeting, null));
+ }
+
+ private static Optional<? extends Triple> closableFindAny(Stream<? extends Triple> stream) {
+ try (Stream<? extends Triple> s = stream) {
+ return s.findAny();
+ }
+ }
+
+ @Test
+ public void streamLanguageTagsCaseInsensitive() {
+ // COMMONSRDF-51: Ensure we can add/contains/remove with any casing
+ // of literal language tag
+ final Literal lower = factory.createLiteral("Hello", "en-gb");
+ final Literal upper = factory.createLiteral("Hello", "EN-GB");
+ final Literal mixed = factory.createLiteral("Hello", "en-GB");
+
+ final IRI example1 = factory.createIRI("http://example.com/s1");
+ final IRI greeting = factory.createIRI("http://example.com/greeting");
+
+ final Graph graph = factory.createGraph();
+ graph.add(example1, greeting, upper);
+
+ // or as patterns
+ assertTrue(closableFindAny(graph.stream(null, null, upper)).isPresent());
+ assertTrue(closableFindAny(graph.stream(null, null, lower)).isPresent());
+ assertTrue(closableFindAny(graph.stream(null, null, mixed)).isPresent());
+
+ // Check the triples returned equal a new triple
+ Triple t = closableFindAny(graph.stream(null, null, lower)).get();
+ assertEquals(t, factory.createTriple(example1, greeting, mixed));
+ }
+
+ private void notEquals(final BlankNodeOrIRI node1, final BlankNodeOrIRI node2) {
+ assertFalse(node1.equals(node2));
+ // in which case we should be able to assume
+ // (as they are in the same graph)
+ assertFalse(node1.ntriplesString().equals(node2.ntriplesString()));
+ }
+
+ /**
+ * Add all triples from the source to the target.
+ * <p>
+ * The triples may be copied in any order. No special conversion or
+ * adaptation of {@link BlankNode}s are performed.
+ *
+ * @param source
+ * Source Graph to copy triples from
+ * @param target
+ * Target Graph where triples will be added
+ */
+ private void addAllTriples(final Graph source, final Graph target) {
+
+ // unordered() as we don't need to preserve triple order
+ // sequential() as we don't (currently) require target Graph to be
+ // thread-safe
+
+ try (Stream<? extends Triple> stream = source.stream()) {
+ stream.unordered().sequential().forEach(t -> target.add(t));
+ }
+ }
+
+ /**
+ * Make a new graph with two BlankNodes - each with a different
+ * uniqueReference
+ */
+ private Graph createGraph1() {
+ final RDF factory1 = createFactory();
+
+ final IRI name = factory1.createIRI("http://xmlns.com/foaf/0.1/name");
+ final Graph g1 = factory1.createGraph();
+ final BlankNode b1 = createOwnBlankNode("b1", "0240eaaa-d33e-4fc0-a4f1-169d6ced3680");
+ g1.add(b1, name, factory1.createLiteral("Alice"));
+
+ final BlankNode b2 = createOwnBlankNode("b2", "9de7db45-0ce7-4b0f-a1ce-c9680ffcfd9f");
+ g1.add(b2, name, factory1.createLiteral("Bob"));
+
+ final IRI hasChild = factory1.createIRI("http://example.com/hasChild");
+ g1.add(b1, hasChild, b2);
+
+ return g1;
+ }
+
+ /**
+ * Create a different implementation of BlankNode to be tested with
+ * graph.add(a,b,c); (the implementation may or may not then choose to
+ * translate such to its own instances)
+ *
+ * @param name
+ * @return
+ */
+ private BlankNode createOwnBlankNode(final String name, final String uuid) {
+ return new BlankNode() {
+ @Override
+ public String ntriplesString() {
+ return "_: " + name;
+ }
+
+ @Override
+ public String uniqueReference() {
+ return uuid;
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof BlankNode)) {
+ return false;
+ }
+ final BlankNode other = (BlankNode) obj;
+ return uuid.equals(other.uniqueReference());
+ }
+ };
+ }
+
+ private Graph createGraph2() {
+ final RDF factory2 = createFactory();
+ final IRI name = factory2.createIRI("http://xmlns.com/foaf/0.1/name");
+
+ final Graph g2 = factory2.createGraph();
+
+ final BlankNode b1 = createOwnBlankNode("b1", "bc8d3e45-a08f-421d-85b3-c25b373abf87");
+ g2.add(b1, name, factory2.createLiteral("Charlie"));
+
+ final BlankNode b2 = createOwnBlankNode("b2", "2209097a-5078-4b03-801a-6a2d2f50d739");
+ g2.add(b2, name, factory2.createLiteral("Dave"));
+
+ final IRI hasChild = factory2.createIRI("http://example.com/hasChild");
+ // NOTE: Opposite direction of loadGraph1
+ g2.add(b2, hasChild, b1);
+ return g2;
+ }
+
+ /**
+ * An attempt to use the Java 8 streams to look up a more complicated query.
+ * <p>
+ * FYI, the equivalent SPARQL version (untested):
+ *
+ * <pre>
+ * SELECT ?orgName WHERE {
+ * ?org foaf:name ?orgName .
+ * ?alice foaf:member ?org .
+ * ?bob foaf:member ?org .
+ * ?alice foaf:knows ?bob .
+ * FILTER NOT EXIST { ?bob foaf:knows ?alice }
+ * }
+ * </pre>
+ *
+ * @throws Exception If test fails
+ */
+ @Test
+ public void whyJavaStreamsMightNotTakeOverFromSparql() throws Exception {
+ Assume.assumeNotNull(bnode1, bnode2, secretClubName);
+ // Find a secret organizations
+ try (Stream<? extends Triple> stream = graph.stream(null, knows, null)) {
+ assertEquals("\"The Secret Club\"",
+ // Find One-way "knows"
+ stream.filter(t -> !graph.contains((BlankNodeOrIRI) t.getObject(), knows, t.getSubject()))
+ .map(knowsTriple -> {
+ try (Stream<? extends Triple> memberOf = graph
+ // and those they know, what are they
+ // member of?
+ .stream((BlankNodeOrIRI) knowsTriple.getObject(), member, null)) {
+ return memberOf
+ // keep those which first-guy is a
+ // member of
+ .filter(memberTriple -> graph.contains(knowsTriple.getSubject(), member,
+ // First hit is good enough
+ memberTriple.getObject()))
+ .findFirst().get().getObject();
+ }
+ })
+ // then look up the name of that org
+ .map(org -> {
+ try (Stream<? extends Triple> orgName = graph.stream((BlankNodeOrIRI) org, name,
+ null)) {
+ return orgName.findFirst().get().getObject().ntriplesString();
+ }
+ }).findFirst().get());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractRDFTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractRDFTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractRDFTest.java
new file mode 100644
index 0000000..bb4dc5b
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/AbstractRDFTest.java
@@ -0,0 +1,454 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.*;
+
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test RDF implementation (and thus its RDFTerm implementations)
+ * <p>
+ * To add to your implementation's tests, create a subclass with a name ending
+ * in <code>Test</code> and provide {@link #createFactory()} which minimally
+ * supports one of the operations, but ideally supports all operations.
+ *
+ * @see RDF
+ */
+public abstract class AbstractRDFTest {
+
+ private RDF factory;
+
+ /**
+ *
+ * This method must be overridden by the implementing test to provide a
+ * factory for the test to create {@link Literal}, {@link IRI} etc.
+ *
+ * @return {@link RDF} instance to be tested.
+ */
+ protected abstract RDF createFactory();
+
+ @Before
+ public void setUp() {
+ factory = createFactory();
+ }
+
+ @Test
+ public void testCreateBlankNode() throws Exception {
+ final BlankNode bnode = factory.createBlankNode();
+
+ final BlankNode bnode2 = factory.createBlankNode();
+ assertNotEquals("Second blank node has not got a unique internal identifier", bnode.uniqueReference(),
+ bnode2.uniqueReference());
+ }
+
+ @Test
+ public void testCreateBlankNodeIdentifierEmpty() throws Exception {
+ try {
+ factory.createBlankNode("");
+ } catch (final IllegalArgumentException e) {
+ // Expected exception
+ }
+ }
+
+ @Test
+ public void testCreateBlankNodeIdentifier() throws Exception {
+ factory.createBlankNode("example1");
+ }
+
+ @Test
+ public void testCreateBlankNodeIdentifierTwice() throws Exception {
+ BlankNode bnode1, bnode2, bnode3;
+ bnode1 = factory.createBlankNode("example1");
+ bnode2 = factory.createBlankNode("example1");
+ bnode3 = factory.createBlankNode("differ");
+ // We don't know what the identifier is, but it MUST be the same
+ assertEquals(bnode1.uniqueReference(), bnode2.uniqueReference());
+ // We don't know what the ntriplesString is, but it MUST be the same
+ assertEquals(bnode1.ntriplesString(), bnode2.ntriplesString());
+ // and here it MUST differ
+ assertNotEquals(bnode1.uniqueReference(), bnode3.uniqueReference());
+ assertNotEquals(bnode1.ntriplesString(), bnode3.ntriplesString());
+ }
+
+ @Test
+ public void testCreateBlankNodeIdentifierTwiceDifferentFactories() throws Exception {
+ BlankNode bnode1, differentFactory;
+ bnode1 = factory.createBlankNode();
+ // it MUST differ from a second factory
+ differentFactory = createFactory().createBlankNode();
+
+ // NOTE: We can't make similar assumption if we provide a
+ // name to createBlankNode(String) as its documentation
+ // only says:
+ //
+ // * BlankNodes created using this method with the same parameter, for
+ // * different instances of RDFFactory, SHOULD NOT be equivalent.
+ //
+ // https://github.com/apache/incubator-commonsrdf/pull/7#issuecomment-92312779
+ assertNotEquals(bnode1, differentFactory);
+ assertNotEquals(bnode1.uniqueReference(), differentFactory.uniqueReference());
+ // but we can't require:
+ // assertNotEquals(bnode1.ntriplesString(),
+ // differentFactory.ntriplesString());
+ }
+
+ @Test
+ public void testCreateGraph() {
+ final Graph graph = factory.createGraph();
+
+ assertEquals("Graph was not empty", 0, graph.size());
+ graph.add(factory.createBlankNode(), factory.createIRI("http://example.com/"), factory.createBlankNode());
+
+ final Graph graph2 = factory.createGraph();
+ assertNotSame(graph, graph2);
+ assertEquals("Graph was empty after adding", 1, graph.size());
+ assertEquals("New graph was not empty", 0, graph2.size());
+ }
+
+ @Test
+ public void testCreateIRI() throws Exception {
+ final IRI example = factory.createIRI("http://example.com/");
+
+ assertEquals("http://example.com/", example.getIRIString());
+ assertEquals("<http://example.com/>", example.ntriplesString());
+
+ final IRI term = factory.createIRI("http://example.com/vocab#term");
+ assertEquals("http://example.com/vocab#term", term.getIRIString());
+ assertEquals("<http://example.com/vocab#term>", term.ntriplesString());
+
+ // and now for the international fun!
+ // make sure this file is edited/compiled as UTF-8
+ final IRI latin1 = factory.createIRI("http://accént.example.com/première");
+ assertEquals("http://accént.example.com/première", latin1.getIRIString());
+ assertEquals("<http://accént.example.com/première>", latin1.ntriplesString());
+
+ final IRI cyrillic = factory.createIRI("http://example.испытание/Кириллица");
+ assertEquals("http://example.испытание/Кириллица", cyrillic.getIRIString());
+ assertEquals("<http://example.испытание/Кириллица>", cyrillic.ntriplesString());
+
+ final IRI deseret = factory.createIRI("http://𐐀.example.com/𐐀");
+ assertEquals("http://𐐀.example.com/𐐀", deseret.getIRIString());
+ assertEquals("<http://𐐀.example.com/𐐀>", deseret.ntriplesString());
+ }
+
+ @Test
+ public void testCreateLiteral() throws Exception {
+ final Literal example = factory.createLiteral("Example");
+ assertEquals("Example", example.getLexicalForm());
+ assertFalse(example.getLanguageTag().isPresent());
+ assertEquals("http://www.w3.org/2001/XMLSchema#string", example.getDatatype().getIRIString());
+ // http://lists.w3.org/Archives/Public/public-rdf-comments/2014Dec/0004.html
+ assertEquals("\"Example\"", example.ntriplesString());
+ }
+
+ @Test
+ public void testCreateLiteralDateTime() throws Exception {
+ final Literal dateTime = factory.createLiteral("2014-12-27T00:50:00T-0600",
+ factory.createIRI("http://www.w3.org/2001/XMLSchema#dateTime"));
+ assertEquals("2014-12-27T00:50:00T-0600", dateTime.getLexicalForm());
+ assertFalse(dateTime.getLanguageTag().isPresent());
+ assertEquals("http://www.w3.org/2001/XMLSchema#dateTime", dateTime.getDatatype().getIRIString());
+ assertEquals("\"2014-12-27T00:50:00T-0600\"^^<http://www.w3.org/2001/XMLSchema#dateTime>",
+ dateTime.ntriplesString());
+ }
+
+ @Test
+ public void testCreateLiteralLang() throws Exception {
+ final Literal example = factory.createLiteral("Example", "en");
+
+ assertEquals("Example", example.getLexicalForm());
+ assertEquals("en", example.getLanguageTag().get());
+ assertEquals("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", example.getDatatype().getIRIString());
+ assertEquals("\"Example\"@en", example.ntriplesString());
+ }
+
+ @Test
+ public void testCreateLiteralLangISO693_3() throws Exception {
+ // see https://issues.apache.org/jira/browse/JENA-827
+ final Literal vls = factory.createLiteral("Herbert Van de Sompel", "vls"); // JENA-827
+
+ assertEquals("vls", vls.getLanguageTag().get());
+ assertEquals("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", vls.getDatatype().getIRIString());
+ assertEquals("\"Herbert Van de Sompel\"@vls", vls.ntriplesString());
+ }
+
+
+ private void assertEqualsBothWays(Object a, Object b) {
+ assertEquals(a, b);
+ assertEquals(b, a);
+ // hashCode must match as well
+ assertEquals(a.hashCode(), b.hashCode());
+ }
+
+ @Test
+ public void testCreateLiteralLangCaseInsensitive() throws Exception {
+ /*
+ * COMMONSRDF-51: Literal langtag may not be in lowercase, but must be
+ * COMPARED (aka .equals and .hashCode()) in lowercase as the language
+ * space is lower case.
+ */
+ final Literal upper = factory.createLiteral("Hello", "EN-GB");
+ final Literal lower = factory.createLiteral("Hello", "en-gb");
+ final Literal mixed = factory.createLiteral("Hello", "en-GB");
+
+ /*
+ * Disabled as some RDF frameworks (namely RDF4J) can be c configured to
+ * do BCP47 normalization (e.g. "en-GB"), so we can't guarantee
+ * lowercase language tags are preserved.
+ */
+ // assertEquals("en-gb", lower.getLanguageTag().get());
+
+ /*
+ * NOTE: the RDF framework is free to lowercase the language tag or
+ * leave it as-is, so we can't assume:
+ */
+ // assertEquals("en-gb", upper.getLanguageTag().get());
+ // assertEquals("en-gb", mixed.getLanguageTag().get());
+
+ /* ..unless we do a case-insensitive comparison: */
+ assertEquals("en-gb",
+ lower.getLanguageTag().get().toLowerCase(Locale.ROOT));
+ assertEquals("en-gb",
+ upper.getLanguageTag().get().toLowerCase(Locale.ROOT));
+ assertEquals("en-gb",
+ mixed.getLanguageTag().get().toLowerCase(Locale.ROOT));
+
+ // However these should all be true using .equals
+ assertEquals(lower, lower);
+ assertEqualsBothWays(lower, upper);
+ assertEqualsBothWays(lower, mixed);
+ assertEquals(upper, upper);
+ assertEqualsBothWays(upper, mixed);
+ assertEquals(mixed, mixed);
+ // Note that assertEqualsBothWays also checks
+ // that .hashCode() matches
+ }
+
+ @Test
+ public void testCreateLiteralLangCaseInsensitiveOther() throws Exception {
+ // COMMONSRDF-51: Ensure the Literal is using case insensitive
+ // comparison against any literal implementation
+ // which may not have done .toLowerString() in their constructor
+ final Literal upper = factory.createLiteral("Hello", "EN-GB");
+ final Literal lower = factory.createLiteral("Hello", "en-gb");
+ final Literal mixed = factory.createLiteral("Hello", "en-GB");
+
+ Literal otherLiteral = new Literal() {
+ @Override
+ public String ntriplesString() {
+ return "Hello@eN-Gb";
+ }
+ @Override
+ public String getLexicalForm() {
+ return "Hello";
+ }
+ @Override
+ public Optional<String> getLanguageTag() {
+ return Optional.of("eN-Gb");
+ }
+ @Override
+ public IRI getDatatype() {
+ return factory.createIRI("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString");
+ }
+ @Override
+ public boolean equals(Object obj) {
+ throw new RuntimeException("Wrong way comparison of literal");
+ }
+ };
+
+ // NOTE: Our fake Literal can't do .equals() or .hashCode(),
+ // so don't check the wrong way around!
+ assertEquals(mixed, otherLiteral);
+ assertEquals(lower, otherLiteral);
+ assertEquals(upper, otherLiteral);
+ }
+
+ @Test
+ public void testCreateLiteralLangCaseInsensitiveInTurkish() throws Exception {
+ // COMMONSRDF-51: Special test for Turkish issue where
+ // "i".toLowerCase() != "i"
+ // See also:
+ // https://garygregory.wordpress.com/2015/11/03/java-lowercase-conversion-turkey/
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.ROOT);
+ final Literal mixedROOT = factory.createLiteral("moi", "fI");
+ final Literal lowerROOT = factory.createLiteral("moi", "fi");
+ final Literal upperROOT = factory.createLiteral("moi", "FI");
+
+ Locale turkish = Locale.forLanguageTag("TR");
+ Locale.setDefault(turkish);
+ // If the below assertion fails, then the Turkish
+ // locale no longer have this peculiarity that
+ // we want to test.
+ Assume.assumeFalse("FI".toLowerCase().equals("fi"));
+
+ final Literal mixed = factory.createLiteral("moi", "fI");
+ final Literal lower = factory.createLiteral("moi", "fi");
+ final Literal upper = factory.createLiteral("moi", "FI");
+
+ assertEquals(lower, lower);
+ assertEqualsBothWays(lower, upper);
+ assertEqualsBothWays(lower, mixed);
+
+ assertEquals(upper, upper);
+ assertEqualsBothWays(upper, mixed);
+
+ assertEquals(mixed, mixed);
+
+ // And our instance created previously in ROOT locale
+ // should still be equal to the instance created in TR locale
+ // (e.g. test constructor is not doing a naive .toLowerCase())
+ assertEqualsBothWays(lower, lowerROOT);
+ assertEqualsBothWays(upper, lowerROOT);
+ assertEqualsBothWays(mixed, lowerROOT);
+
+ assertEqualsBothWays(lower, upperROOT);
+ assertEqualsBothWays(upper, upperROOT);
+ assertEqualsBothWays(mixed, upperROOT);
+
+ assertEqualsBothWays(lower, mixedROOT);
+ assertEqualsBothWays(upper, mixedROOT);
+ assertEqualsBothWays(mixed, mixedROOT);
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
+ @Test
+ public void testCreateLiteralString() throws Exception {
+ final Literal example = factory.createLiteral("Example",
+ factory.createIRI("http://www.w3.org/2001/XMLSchema#string"));
+ assertEquals("Example", example.getLexicalForm());
+ assertFalse(example.getLanguageTag().isPresent());
+ assertEquals("http://www.w3.org/2001/XMLSchema#string", example.getDatatype().getIRIString());
+ // http://lists.w3.org/Archives/Public/public-rdf-comments/2014Dec/0004.html
+ assertEquals("\"Example\"", example.ntriplesString());
+ }
+
+ @Test
+ public void testCreateTripleBnodeBnode() {
+ final BlankNode subject = factory.createBlankNode("b1");
+ final IRI predicate = factory.createIRI("http://example.com/pred");
+ final BlankNode object = factory.createBlankNode("b2");
+ final Triple triple = factory.createTriple(subject, predicate, object);
+
+ // bnode equivalence should be OK as we used the same
+ // factory and have not yet inserted Triple into a Graph
+ assertEquals(subject, triple.getSubject());
+ assertEquals(predicate, triple.getPredicate());
+ assertEquals(object, triple.getObject());
+ }
+
+ @Test
+ public void testCreateTripleBnodeIRI() {
+ final BlankNode subject = factory.createBlankNode("b1");
+ final IRI predicate = factory.createIRI("http://example.com/pred");
+ final IRI object = factory.createIRI("http://example.com/obj");
+ final Triple triple = factory.createTriple(subject, predicate, object);
+
+ // bnode equivalence should be OK as we used the same
+ // factory and have not yet inserted Triple into a Graph
+ assertEquals(subject, triple.getSubject());
+ assertEquals(predicate, triple.getPredicate());
+ assertEquals(object, triple.getObject());
+ }
+
+ @Test
+ public void testCreateTripleBnodeTriple() {
+ final BlankNode subject = factory.createBlankNode();
+ final IRI predicate = factory.createIRI("http://example.com/pred");
+ final Literal object = factory.createLiteral("Example", "en");
+ final Triple triple = factory.createTriple(subject, predicate, object);
+
+ // bnode equivalence should be OK as we used the same
+ // factory and have not yet inserted Triple into a Graph
+ assertEquals(subject, triple.getSubject());
+ assertEquals(predicate, triple.getPredicate());
+ assertEquals(object, triple.getObject());
+ }
+
+ @Test
+ public void testPossiblyInvalidBlankNode() throws Exception {
+ BlankNode withColon;
+ try {
+ withColon = factory.createBlankNode("with:colon");
+ } catch (final IllegalArgumentException ex) {
+ // Good!
+ return;
+ }
+ // Factory allows :colon, which is OK as long as it's not causing an
+ // invalid ntriplesString
+ assertFalse(withColon.ntriplesString().contains("with:colon"));
+
+ // and creating it twice gets the same ntriplesString
+ assertEquals(withColon.ntriplesString(), factory.createBlankNode("with:colon").ntriplesString());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidIRI() throws Exception {
+ factory.createIRI("<no_brackets>");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidLiteralLang() throws Exception {
+ factory.createLiteral("Example", "with space");
+ }
+
+ @Test(expected = Exception.class)
+ public void testInvalidTriplePredicate() {
+ final BlankNode subject = factory.createBlankNode("b1");
+ final BlankNode predicate = factory.createBlankNode("b2");
+ final BlankNode object = factory.createBlankNode("b3");
+ factory.createTriple(subject, (IRI) predicate, object);
+ }
+
+ @Test
+ public void hashCodeBlankNode() throws Exception {
+ final BlankNode bnode1 = factory.createBlankNode();
+ assertEquals(bnode1.uniqueReference().hashCode(), bnode1.hashCode());
+ }
+
+ @Test
+ public void hashCodeIRI() throws Exception {
+ final IRI iri = factory.createIRI("http://example.com/");
+ assertEquals(iri.getIRIString().hashCode(), iri.hashCode());
+ }
+
+ @Test
+ public void hashCodeLiteral() throws Exception {
+ final Literal literal = factory.createLiteral("Hello");
+ assertEquals(Objects.hash(literal.getLexicalForm(), literal.getDatatype(), literal.getLanguageTag()),
+ literal.hashCode());
+ }
+
+ @Test
+ public void hashCodeTriple() throws Exception {
+ final IRI iri = factory.createIRI("http://example.com/");
+ final Triple triple = factory.createTriple(iri, iri, iri);
+ assertEquals(Objects.hash(iri, iri, iri), triple.hashCode());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultDatasetTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultDatasetTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultDatasetTest.java
new file mode 100644
index 0000000..024c2cf
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultDatasetTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class DefaultDatasetTest {
+
+ DummyDataset dataset = new DummyDataset();
+
+ @Test
+ public void close() throws Exception {
+ dataset.close(); // no-op
+ }
+
+ @Test
+ public void defaultIterate() throws Exception {
+ assertFalse(dataset.streamCalled);
+ assertFalse(dataset.filteredStreamCalled);
+ for (final Quad t : dataset.iterate()) {
+ assertEquals(t, new DummyQuad());
+ }
+ assertTrue(dataset.streamCalled);
+ assertFalse(dataset.filteredStreamCalled);
+ }
+
+ @Test
+ public void defaultFilteredIterate() throws Exception {
+ assertFalse(dataset.streamCalled);
+ assertFalse(dataset.filteredStreamCalled);
+ for (final Quad t : dataset.iterate(null, null, new DummyIRI(2), null)) {
+ assertEquals(t, new DummyQuad());
+ }
+ assertTrue(dataset.filteredStreamCalled);
+ assertFalse(dataset.streamCalled);
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultGraphTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultGraphTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultGraphTest.java
new file mode 100644
index 0000000..8d6f337
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultGraphTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class DefaultGraphTest {
+
+ DummyGraph graph = new DummyGraph();
+
+ @Test
+ public void close() throws Exception {
+ graph.close(); // no-op
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void defaultGetTriples() throws Exception {
+ assertFalse(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ assertEquals(1L, graph.getTriples().count());
+ assertTrue(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void defaultGetTriplesFiltered() throws Exception {
+ assertFalse(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ assertEquals(1L, graph.getTriples(null,null,null).count());
+ assertFalse(graph.streamCalled);
+ assertTrue(graph.filteredStreamCalled);
+ // Ensure arguments are passed on to graph.stream(s,p,o);
+ assertEquals(0L, graph.getTriples(new DummyIRI(0),null,null).count());
+ }
+
+ @Test
+ public void defaultIterate() throws Exception {
+ assertFalse(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ for (final Triple t : graph.iterate()) {
+ assertEquals(t, new DummyTriple());
+ }
+ assertTrue(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ }
+
+ @Test
+ public void defaultFilteredIterate() throws Exception {
+ assertFalse(graph.streamCalled);
+ assertFalse(graph.filteredStreamCalled);
+ for (final Triple t : graph.iterate(null, new DummyIRI(2), null)) {
+ assertEquals(t, new DummyTriple());
+ }
+ assertTrue(graph.filteredStreamCalled);
+ assertFalse(graph.streamCalled);
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/commons-rdf/blob/d59203ce/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultQuadTest.java
----------------------------------------------------------------------
diff --git a/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultQuadTest.java b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultQuadTest.java
new file mode 100644
index 0000000..00d66b5
--- /dev/null
+++ b/commons-rdf-api/src/test/java/org/apache/commons/rdf/api/DefaultQuadTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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.commons.rdf.api;
+
+import static org.junit.Assert.*;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class DefaultQuadTest {
+ @Test
+ public void asQuad() throws Exception {
+ final Quad q = new DummyQuad();
+ final Triple t = q.asTriple();
+ assertEquals(t, t);
+ assertNotEquals(t, q);
+ assertEquals(t, new DummyTriple());
+ assertEquals(t, new DummyQuad().asTriple());
+
+ // FIXME: This would not catch if asTriple() accidentally mixed up s/p/o
+ // as they are here all the same
+ assertEquals(new DummyIRI(1), t.getSubject());
+ assertEquals(new DummyIRI(2), t.getPredicate());
+ assertEquals(new DummyIRI(3), t.getObject());
+
+
+
+ assertEquals(Objects.hash(q.getSubject(), q.getPredicate(), q.getObject()), t.hashCode());
+ }
+
+}