blob: e931afcfa9eb8f2896b507eae070083f16bba92d [file] [log] [blame]
/**
* 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.assumeFalse(dataset.isEmpty());
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.
final Set<Quad> aliceQuads = new HashSet<>();
for (final 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 (final 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)
final 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()
final 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() throws Exception {
// Create two separate Dataset instances
try (final Dataset g1 = createDataset1();
final Dataset g2 = createDataset2();
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 {
try (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
try (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
try (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();
try (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
final 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);
final 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 honor 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(final 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
final 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());
}
}
}