View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.commons.rdf.api;
19  
20  import static org.junit.Assert.*;
21  
22  import java.util.Locale;
23  import java.util.Objects;
24  import java.util.Optional;
25  
26  import org.junit.Assume;
27  import org.junit.Before;
28  import org.junit.Test;
29  
30  /**
31   * Test RDF implementation (and thus its RDFTerm implementations)
32   * <p>
33   * To add to your implementation's tests, create a subclass with a name ending
34   * in <code>Test</code> and provide {@link #createFactory()} which minimally
35   * supports one of the operations, but ideally supports all operations.
36   *
37   * @see RDF
38   */
39  public abstract class AbstractRDFTest {
40  
41      private RDF factory;
42  
43      /**
44       *
45       * This method must be overridden by the implementing test to provide a
46       * factory for the test to create {@link Literal}, {@link IRI} etc.
47       *
48       * @return {@link RDF} instance to be tested.
49       */
50      protected abstract RDF createFactory();
51  
52      @Before
53      public void setUp() {
54          factory = createFactory();
55      }
56  
57      @Test
58      public void testCreateBlankNode() throws Exception {
59          final BlankNode bnode = factory.createBlankNode();
60  
61          final BlankNode bnode2 = factory.createBlankNode();
62          assertNotEquals("Second blank node has not got a unique internal identifier", bnode.uniqueReference(),
63                  bnode2.uniqueReference());
64      }
65  
66      @Test
67      public void testCreateBlankNodeIdentifierEmpty() throws Exception {
68          try {
69              factory.createBlankNode("");
70          } catch (final IllegalArgumentException e) {
71              // Expected exception
72          }
73      }
74  
75      @Test
76      public void testCreateBlankNodeIdentifier() throws Exception {
77          factory.createBlankNode("example1");
78      }
79  
80      @Test
81      public void testCreateBlankNodeIdentifierTwice() throws Exception {
82          BlankNode bnode1, bnode2, bnode3;
83          bnode1 = factory.createBlankNode("example1");
84          bnode2 = factory.createBlankNode("example1");
85          bnode3 = factory.createBlankNode("differ");
86          // We don't know what the identifier is, but it MUST be the same
87          assertEquals(bnode1.uniqueReference(), bnode2.uniqueReference());
88          // We don't know what the ntriplesString is, but it MUST be the same
89          assertEquals(bnode1.ntriplesString(), bnode2.ntriplesString());
90          // and here it MUST differ
91          assertNotEquals(bnode1.uniqueReference(), bnode3.uniqueReference());
92          assertNotEquals(bnode1.ntriplesString(), bnode3.ntriplesString());
93      }
94  
95      @Test
96      public void testCreateBlankNodeIdentifierTwiceDifferentFactories() throws Exception {
97          BlankNode bnode1, differentFactory;
98          bnode1 = factory.createBlankNode();
99          // it MUST differ from a second factory
100         differentFactory = createFactory().createBlankNode();
101 
102         // NOTE: We can't make similar assumption if we provide a
103         // name to createBlankNode(String) as its documentation
104         // only says:
105         //
106         // * BlankNodes created using this method with the same parameter, for
107         // * different instances of RDFFactory, SHOULD NOT be equivalent.
108         //
109         // https://github.com/apache/incubator-commonsrdf/pull/7#issuecomment-92312779
110         assertNotEquals(bnode1, differentFactory);
111         assertNotEquals(bnode1.uniqueReference(), differentFactory.uniqueReference());
112         // but we can't require:
113         // assertNotEquals(bnode1.ntriplesString(),
114         // differentFactory.ntriplesString());
115     }
116 
117     @Test
118     public void testCreateGraph() throws Exception {
119         try (final Graph graph = factory.createGraph(); final Graph graph2 = factory.createGraph()) {
120 
121             assertEquals("Graph was not empty", 0, graph.size());
122             graph.add(factory.createBlankNode(), factory.createIRI("http://example.com/"), factory.createBlankNode());
123 
124             assertNotSame(graph, graph2);
125             assertEquals("Graph was empty after adding", 1, graph.size());
126             assertEquals("New graph was not empty", 0, graph2.size());
127         }
128     }
129 
130     @Test
131     public void testCreateIRI() throws Exception {
132         final IRI example = factory.createIRI("http://example.com/");
133 
134         assertEquals("http://example.com/", example.getIRIString());
135         assertEquals("<http://example.com/>", example.ntriplesString());
136 
137         final IRI term = factory.createIRI("http://example.com/vocab#term");
138         assertEquals("http://example.com/vocab#term", term.getIRIString());
139         assertEquals("<http://example.com/vocab#term>", term.ntriplesString());
140 
141         // and now for the international fun!
142         // make sure this file is edited/compiled as UTF-8
143         final IRI latin1 = factory.createIRI("http://accént.example.com/première");
144         assertEquals("http://accént.example.com/première", latin1.getIRIString());
145         assertEquals("<http://accént.example.com/première>", latin1.ntriplesString());
146 
147         final IRI cyrillic = factory.createIRI("http://example.испытание/Кириллица");
148         assertEquals("http://example.испытание/Кириллица", cyrillic.getIRIString());
149         assertEquals("<http://example.испытание/Кириллица>", cyrillic.ntriplesString());
150 
151         final IRI deseret = factory.createIRI("http://𐐀.example.com/𐐀");
152         assertEquals("http://𐐀.example.com/𐐀", deseret.getIRIString());
153         assertEquals("<http://𐐀.example.com/𐐀>", deseret.ntriplesString());
154     }
155 
156     @Test
157     public void testCreateLiteral() throws Exception {
158         final Literal example = factory.createLiteral("Example");
159         assertEquals("Example", example.getLexicalForm());
160         assertFalse(example.getLanguageTag().isPresent());
161         assertEquals("http://www.w3.org/2001/XMLSchema#string", example.getDatatype().getIRIString());
162         // http://lists.w3.org/Archives/Public/public-rdf-comments/2014Dec/0004.html
163         assertEquals("\"Example\"", example.ntriplesString());
164     }
165 
166     @Test
167     public void testCreateLiteralDateTime() throws Exception {
168         final Literal dateTime = factory.createLiteral("2014-12-27T00:50:00T-0600",
169                 factory.createIRI("http://www.w3.org/2001/XMLSchema#dateTime"));
170         assertEquals("2014-12-27T00:50:00T-0600", dateTime.getLexicalForm());
171         assertFalse(dateTime.getLanguageTag().isPresent());
172         assertEquals("http://www.w3.org/2001/XMLSchema#dateTime", dateTime.getDatatype().getIRIString());
173         assertEquals("\"2014-12-27T00:50:00T-0600\"^^<http://www.w3.org/2001/XMLSchema#dateTime>",
174                 dateTime.ntriplesString());
175     }
176 
177     @Test
178     public void testCreateLiteralLang() throws Exception {
179         final Literal example = factory.createLiteral("Example", "en");
180 
181         assertEquals("Example", example.getLexicalForm());
182         assertEquals("en", example.getLanguageTag().get());
183         assertEquals("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", example.getDatatype().getIRIString());
184         assertEquals("\"Example\"@en", example.ntriplesString());
185     }
186 
187     @Test
188     public void testCreateLiteralLangISO693_3() throws Exception {
189         // see https://issues.apache.org/jira/browse/JENA-827
190         final Literal vls = factory.createLiteral("Herbert Van de Sompel", "vls"); // JENA-827
191 
192         assertEquals("vls", vls.getLanguageTag().get());
193         assertEquals("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", vls.getDatatype().getIRIString());
194         assertEquals("\"Herbert Van de Sompel\"@vls", vls.ntriplesString());
195     }
196 
197 
198     private void assertEqualsBothWays(final Object a, final Object b) {
199         assertEquals(a, b);
200         assertEquals(b, a);
201         // hashCode must match as well
202         assertEquals(a.hashCode(), b.hashCode());
203     }
204 
205     @Test
206     public void testCreateLiteralLangCaseInsensitive() throws Exception {
207         /*
208          * COMMONSRDF-51: Literal langtag may not be in lowercase, but must be
209          * COMPARED (aka .equals and .hashCode()) in lowercase as the language
210          * space is lower case.
211          */
212         final Literal upper = factory.createLiteral("Hello", "EN-GB");
213         final Literal lower = factory.createLiteral("Hello", "en-gb");
214         final Literal mixed = factory.createLiteral("Hello", "en-GB");
215 
216         /*
217          * Disabled as some RDF frameworks (namely RDF4J) can be c configured to
218          * do BCP47 normalization (e.g. "en-GB"), so we can't guarantee
219          * lowercase language tags are preserved.
220          */
221         // assertEquals("en-gb", lower.getLanguageTag().get());
222 
223         /*
224          * NOTE: the RDF framework is free to lowercase the language tag or
225          * leave it as-is, so we can't assume:
226          */
227         // assertEquals("en-gb", upper.getLanguageTag().get());
228         // assertEquals("en-gb", mixed.getLanguageTag().get());
229 
230         /* ..unless we do a case-insensitive comparison: */
231         assertEquals("en-gb",
232                 lower.getLanguageTag().get().toLowerCase(Locale.ROOT));
233         assertEquals("en-gb",
234                 upper.getLanguageTag().get().toLowerCase(Locale.ROOT));
235         assertEquals("en-gb",
236                 mixed.getLanguageTag().get().toLowerCase(Locale.ROOT));
237 
238         // However these should all be true using .equals
239         assertEquals(lower, lower);
240         assertEqualsBothWays(lower, upper);
241         assertEqualsBothWays(lower, mixed);
242         assertEquals(upper, upper);
243         assertEqualsBothWays(upper, mixed);
244         assertEquals(mixed, mixed);
245         // Note that assertEqualsBothWays also checks
246         // that .hashCode() matches
247     }
248 
249     @Test
250     public void testCreateLiteralLangCaseInsensitiveOther() throws Exception {
251         // COMMONSRDF-51: Ensure the Literal is using case insensitive
252         // comparison against any literal implementation
253         // which may not have done .toLowerString() in their constructor
254         final Literal upper = factory.createLiteral("Hello", "EN-GB");
255         final Literal lower = factory.createLiteral("Hello", "en-gb");
256         final Literal mixed = factory.createLiteral("Hello", "en-GB");
257 
258         final Literal otherLiteral = new Literal() {
259             @Override
260             public String ntriplesString() {
261                 return "Hello@eN-Gb";
262             }
263             @Override
264             public String getLexicalForm() {
265                 return "Hello";
266             }
267             @Override
268             public Optional<String> getLanguageTag() {
269                 return Optional.of("eN-Gb");
270             }
271             @Override
272             public IRI getDatatype() {
273                 return factory.createIRI("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString");
274             }
275             @Override
276             public boolean equals(final Object obj) {
277                 throw new RuntimeException("Wrong way comparison of literal");
278             }
279         };
280 
281         // NOTE: Our fake Literal can't do .equals() or .hashCode(),
282         // so don't check the wrong way around!
283         assertEquals(mixed, otherLiteral);
284         assertEquals(lower, otherLiteral);
285         assertEquals(upper, otherLiteral);
286     }
287 
288     @Test
289     public void testCreateLiteralLangCaseInsensitiveInTurkish() throws Exception {
290         // COMMONSRDF-51: Special test for Turkish issue where
291         // "i".toLowerCase() != "i"
292         // See also:
293         // https://garygregory.wordpress.com/2015/11/03/java-lowercase-conversion-turkey/
294         final Locale defaultLocale = Locale.getDefault();
295         try {
296             Locale.setDefault(Locale.ROOT);
297             final Literal mixedROOT = factory.createLiteral("moi", "fI");
298             final Literal lowerROOT = factory.createLiteral("moi", "fi");
299             final Literal upperROOT = factory.createLiteral("moi", "FI");
300 
301             final Locale turkish = Locale.forLanguageTag("TR");
302             Locale.setDefault(turkish);
303             // If the below assertion fails, then the Turkish
304             // locale no longer have this peculiarity that
305             // we want to test.
306             Assume.assumeFalse("FI".toLowerCase().equals("fi"));
307 
308             final Literal mixed = factory.createLiteral("moi", "fI");
309             final Literal lower = factory.createLiteral("moi", "fi");
310             final Literal upper = factory.createLiteral("moi", "FI");
311 
312             assertEquals(lower, lower);
313             assertEqualsBothWays(lower, upper);
314             assertEqualsBothWays(lower, mixed);
315 
316             assertEquals(upper, upper);
317             assertEqualsBothWays(upper, mixed);
318 
319             assertEquals(mixed, mixed);
320 
321             // And our instance created previously in ROOT locale
322             // should still be equal to the instance created in TR locale
323             // (e.g. test constructor is not doing a naive .toLowerCase())
324             assertEqualsBothWays(lower, lowerROOT);
325             assertEqualsBothWays(upper, lowerROOT);
326             assertEqualsBothWays(mixed, lowerROOT);
327 
328             assertEqualsBothWays(lower, upperROOT);
329             assertEqualsBothWays(upper, upperROOT);
330             assertEqualsBothWays(mixed, upperROOT);
331 
332             assertEqualsBothWays(lower, mixedROOT);
333             assertEqualsBothWays(upper, mixedROOT);
334             assertEqualsBothWays(mixed, mixedROOT);
335         } finally {
336             Locale.setDefault(defaultLocale);
337         }
338     }
339 
340     @Test
341     public void testCreateLiteralString() throws Exception {
342         final Literal example = factory.createLiteral("Example",
343                 factory.createIRI("http://www.w3.org/2001/XMLSchema#string"));
344         assertEquals("Example", example.getLexicalForm());
345         assertFalse(example.getLanguageTag().isPresent());
346         assertEquals("http://www.w3.org/2001/XMLSchema#string", example.getDatatype().getIRIString());
347         // http://lists.w3.org/Archives/Public/public-rdf-comments/2014Dec/0004.html
348         assertEquals("\"Example\"", example.ntriplesString());
349     }
350 
351     @Test
352     public void testCreateTripleBnodeBnode() {
353         final BlankNode subject = factory.createBlankNode("b1");
354         final IRI predicate = factory.createIRI("http://example.com/pred");
355         final BlankNode object = factory.createBlankNode("b2");
356         final Triple triple = factory.createTriple(subject, predicate, object);
357 
358         // bnode equivalence should be OK as we used the same
359         // factory and have not yet inserted Triple into a Graph
360         assertEquals(subject, triple.getSubject());
361         assertEquals(predicate, triple.getPredicate());
362         assertEquals(object, triple.getObject());
363     }
364 
365     @Test
366     public void testCreateTripleBnodeIRI() {
367         final BlankNode subject = factory.createBlankNode("b1");
368         final IRI predicate = factory.createIRI("http://example.com/pred");
369         final IRI object = factory.createIRI("http://example.com/obj");
370         final Triple triple = factory.createTriple(subject, predicate, object);
371 
372         // bnode equivalence should be OK as we used the same
373         // factory and have not yet inserted Triple into a Graph
374         assertEquals(subject, triple.getSubject());
375         assertEquals(predicate, triple.getPredicate());
376         assertEquals(object, triple.getObject());
377     }
378 
379     @Test
380     public void testCreateTripleBnodeTriple() {
381         final BlankNode subject = factory.createBlankNode();
382         final IRI predicate = factory.createIRI("http://example.com/pred");
383         final Literal object = factory.createLiteral("Example", "en");
384         final Triple triple = factory.createTriple(subject, predicate, object);
385 
386         // bnode equivalence should be OK as we used the same
387         // factory and have not yet inserted Triple into a Graph
388         assertEquals(subject, triple.getSubject());
389         assertEquals(predicate, triple.getPredicate());
390         assertEquals(object, triple.getObject());
391     }
392 
393     @Test
394     public void testPossiblyInvalidBlankNode() throws Exception {
395         BlankNode withColon;
396         try {
397             withColon = factory.createBlankNode("with:colon");
398         } catch (final IllegalArgumentException ex) {
399             // Good!
400             return;
401         }
402         // Factory allows :colon, which is OK as long as it's not causing an
403         // invalid ntriplesString
404         assertFalse(withColon.ntriplesString().contains("with:colon"));
405 
406         // and creating it twice gets the same ntriplesString
407         assertEquals(withColon.ntriplesString(), factory.createBlankNode("with:colon").ntriplesString());
408     }
409 
410     @Test(expected = IllegalArgumentException.class)
411     public void testInvalidIRI() throws Exception {
412         factory.createIRI("<no_brackets>");
413     }
414 
415     @Test(expected = IllegalArgumentException.class)
416     public void testInvalidLiteralLang() throws Exception {
417         factory.createLiteral("Example", "with space");
418     }
419 
420     @Test(expected = Exception.class)
421     public void testInvalidTriplePredicate() {
422         final BlankNode subject = factory.createBlankNode("b1");
423         final BlankNode predicate = factory.createBlankNode("b2");
424         final BlankNode object = factory.createBlankNode("b3");
425         factory.createTriple(subject, (IRI) predicate, object);
426     }
427 
428     @Test
429     public void hashCodeBlankNode() throws Exception {
430         final BlankNode bnode1 = factory.createBlankNode();
431         assertEquals(bnode1.uniqueReference().hashCode(), bnode1.hashCode());
432     }
433 
434     @Test
435     public void hashCodeIRI() throws Exception {
436         final IRI iri = factory.createIRI("http://example.com/");
437         assertEquals(iri.getIRIString().hashCode(), iri.hashCode());
438     }
439 
440     @Test
441     public void hashCodeLiteral() throws Exception {
442         final Literal literal = factory.createLiteral("Hello");
443         assertEquals(Objects.hash(literal.getLexicalForm(), literal.getDatatype(), literal.getLanguageTag()),
444                 literal.hashCode());
445     }
446 
447     @Test
448     public void hashCodeTriple() throws Exception {
449         final IRI iri = factory.createIRI("http://example.com/");
450         final Triple triple = factory.createTriple(iri, iri, iri);
451         assertEquals(Objects.hash(iri, iri, iri), triple.hashCode());
452     }
453 
454 }