| /** |
| * 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. |
| |
| 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 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(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()); |
| } |
| } |
| } |