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.simple.experimental;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assume.assumeNotNull;
25  import java.io.ByteArrayInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.util.concurrent.TimeUnit;
31  
32  import org.apache.commons.rdf.api.Graph;
33  import org.apache.commons.rdf.api.IRI;
34  import org.apache.commons.rdf.api.Literal;
35  import org.apache.commons.rdf.api.RDFSyntax;
36  import org.apache.commons.rdf.api.RDFTerm;
37  import org.apache.commons.rdf.api.RDF;
38  import org.apache.commons.rdf.api.Triple;
39  import org.apache.commons.rdf.experimental.RDFParser;
40  import org.apache.commons.rdf.simple.DummyRDFParserBuilder;
41  import org.apache.commons.rdf.simple.SimpleRDF;
42  import org.apache.commons.rdf.simple.Types;
43  import org.junit.After;
44  import org.junit.Before;
45  import org.junit.Rule;
46  import org.junit.Test;
47  import org.junit.rules.ExpectedException;
48  
49  public class AbstractRDFParserTest {
50  
51      private final RDF factory = new SimpleRDF();
52  
53      private final DummyRDFParserBuilder dummyParser = new DummyRDFParserBuilder();
54      private Path testNt;
55      private Path testTtl;
56      private Path testXml;
57  
58  	private Path symlink;
59  
60      @Before
61      public void createTempFile() throws IOException {
62          testNt = Files.createTempFile("test", ".nt");
63          testTtl = Files.createTempFile("test", ".ttl");
64          testXml = Files.createTempFile("test", ".xml");
65          // No need to populate the files as the dummy parser
66          // doesn't actually read anything
67  
68          // If supported, we'll make a symbolic link
69          final Path symlinks = Files.createTempDirectory("symlinked");
70          try {
71          	symlink = Files.createSymbolicLink(
72          				symlinks.resolve("linked.ttl"), testNt);
73          } catch (IOException|UnsupportedOperationException ex) {
74          	symlink = null;
75          }
76      }
77  
78      @After
79      public void deleteTempFiles() throws IOException {
80          Files.deleteIfExists(testNt);
81          Files.deleteIfExists(testTtl);
82          Files.deleteIfExists(testXml);
83      }
84  
85      @Test
86      public void guessRDFSyntax() throws Exception {
87          assertEquals(RDFSyntax.NTRIPLES, AbstractRDFParser.guessRDFSyntax(testNt).get());
88          assertEquals(RDFSyntax.TURTLE, AbstractRDFParser.guessRDFSyntax(testTtl).get());
89          assertFalse(AbstractRDFParser.guessRDFSyntax(testXml).isPresent());
90      }
91  
92      private void checkGraph(final Graph g) throws Exception {
93          assertTrue(g.size() > 0);
94          final IRI greeting = factory.createIRI("http://example.com/greeting");
95          // Should only have parsed once!
96          assertEquals(1, g.stream(null, greeting, null).count());
97          final Triple triple = g.stream(null, greeting, null).findAny().get();
98          assertTrue(triple.getSubject() instanceof IRI);
99          final IRI parsing = (IRI) triple.getSubject();
100         assertTrue(parsing.getIRIString().startsWith("urn:uuid:"));
101 
102         assertEquals("http://example.com/greeting", triple.getPredicate().getIRIString());
103 
104         assertTrue(triple.getObject() instanceof Literal);
105         final Literal literal = (Literal) triple.getObject();
106         assertEquals("Hello world", literal.getLexicalForm());
107         assertFalse(literal.getLanguageTag().isPresent());
108         assertEquals(Types.XSD_STRING, literal.getDatatype());
109 
110         // Check uniqueness of properties that are always present
111         assertEquals(1, g.stream(null, factory.createIRI("http://example.com/source"), null).count());
112 
113         // Check optional properties that are unique
114         assertTrue(2 > g.stream(null, factory.createIRI("http://example.com/base"), null).count());
115         assertTrue(2 > g.stream(null, factory.createIRI("http://example.com/contentType"), null).count());
116         assertTrue(2 > g.stream(null, factory.createIRI("http://example.com/contentTypeSyntax"), null).count());
117     }
118 
119     @Test
120     public void parseFile() throws Exception {
121         try (final Graph g = factory.createGraph()) {
122             final RDFParser parser = dummyParser.source(testNt).target(g);
123             parser.parse().get(5, TimeUnit.SECONDS);
124             checkGraph(g);
125             // FIXME: this could potentially break if the equivalent of /tmp
126             // includes
127             // international characters
128             assertEquals("<" + testNt.toUri().toString() + ">", firstPredicate(g, "source"));
129             // Should be set to the file path - after following symlinks
130             assertEquals("<" + testNt.toRealPath().toUri().toString() + ">", firstPredicate(g, "base"));
131 
132             // Should NOT have guessed the content type
133             assertNull(firstPredicate(g, "contentType"));
134             assertNull(firstPredicate(g, "contentTypeSyntax"));
135         }
136     }
137 
138     @Test
139     public void parseFileSymlink() throws Exception {
140         // This test will typically not work in Windows
141         // which requires system privileges to create symlinks
142         assumeNotNull(symlink);
143         try (final Graph g = factory.createGraph()) {
144             final RDFParser parser = dummyParser.source(symlink).target(g);
145             parser.parse().get(5, TimeUnit.SECONDS);
146             checkGraph(g);
147             assertEquals("<" + symlink.toUri().toString() + ">", firstPredicate(g, "source"));
148             assertEquals("<" + testNt.toRealPath().toUri().toString() + ">", firstPredicate(g, "base"));
149         }
150     }
151 
152     @Test
153     public void parseNoSource() throws Exception {
154         thrown.expect(IllegalStateException.class);
155         dummyParser.parse();
156     }
157 
158     @Test
159     public void parseBaseAndContentTypeNoSource() throws Exception {
160         // Can set the other options, even without source()
161         final IRI base = dummyParser.createRDFTermFactory().createIRI("http://www.example.org/test.rdf");
162         final RDFParser parser = dummyParser.base(base).contentType(RDFSyntax.RDFXML);
163         thrown.expect(IllegalStateException.class);
164         thrown.expectMessage("No source has been set");
165         // but .parse() should fail
166         parser.parse();
167     }
168 
169     @Test
170     public void parseFileMissing() throws Exception {
171         Files.delete(testNt);
172         // This should not fail yet
173         final RDFParser parser = dummyParser.source(testNt);
174         // but here:
175         thrown.expect(IOException.class);
176         parser.parse();
177     }
178 
179     @Test
180     public void parseFileContentType() throws Exception {
181         try (final Graph g = factory.createGraph()) {
182             final RDFParser parser = dummyParser.source(testNt).contentType(RDFSyntax.NTRIPLES).target(g);
183             parser.parse().get(5, TimeUnit.SECONDS);
184             checkGraph(g);
185             // FIXME: this could potentially break if the equivalent of /tmp
186             // includes
187             // international characters
188             assertEquals("<" + testNt.toUri().toString() + ">", firstPredicate(g, "source"));
189             // Should be set to the file path - after following symlinks
190             assertEquals("<" + testNt.toRealPath().toUri().toString() + ">", firstPredicate(g, "base"));
191             assertEquals("\"" + RDFSyntax.NTRIPLES.name() + "\"", firstPredicate(g, "contentTypeSyntax"));
192             assertEquals("\"application/n-triples\"", firstPredicate(g, "contentType"));
193         }
194     }
195 
196     private String firstPredicate(final Graph g, final String pred) {
197         return g.stream(null, factory.createIRI("http://example.com/" + pred), null).map(Triple::getObject)
198                 .map(RDFTerm::ntriplesString).findAny().orElse(null);
199     }
200 
201     @Rule
202     public ExpectedException thrown = ExpectedException.none();
203 
204     @Test
205     public void parseInputStreamFailsIfBaseMissing() throws Exception {
206         final InputStream inputStream = new ByteArrayInputStream(new byte[0]);
207         // Should not fail at this point
208         final RDFParser parser = dummyParser.source(inputStream);
209         // but here:
210         thrown.expect(IllegalStateException.class);
211         thrown.expectMessage("base iri required for inputstream source");
212         parser.parse();
213     }
214 
215     @Test
216     public void parseInputStreamWithBase() throws Exception {
217         final InputStream inputStream = new ByteArrayInputStream(new byte[0]);
218         final IRI base = dummyParser.createRDFTermFactory().createIRI("http://www.example.org/test.rdf");
219         try (final Graph g = factory.createGraph()) {
220             final RDFParser parser = dummyParser.source(inputStream).base(base).target(g);
221             parser.parse().get(5, TimeUnit.SECONDS);
222             checkGraph(g);
223             assertEquals("<http://www.example.org/test.rdf>", firstPredicate(g, "base"));
224             // in our particular debug output,
225             // bnode source indicates InputStream
226             assertTrue(firstPredicate(g, "source").startsWith("_:"));
227             assertNull(firstPredicate(g, "contentType"));
228             assertNull(firstPredicate(g, "contentTypeSyntax"));
229         }
230     }
231 
232     @Test
233     public void parseInputStreamWithNQuads() throws Exception {
234         final InputStream inputStream = new ByteArrayInputStream(new byte[0]);
235         try (final Graph g = factory.createGraph()) {
236             final RDFParser parser = dummyParser.source(inputStream).contentType(RDFSyntax.NQUADS).target(g);
237             parser.parse().get(5, TimeUnit.SECONDS);
238             checkGraph(g);
239             assertNull(firstPredicate(g, "base"));
240             // in our particular debug output,
241             // bnode source indicates InputStream
242             assertTrue(firstPredicate(g, "source").startsWith("_:"));
243             assertEquals("\"application/n-quads\"", firstPredicate(g, "contentType"));
244             assertEquals("\"" + RDFSyntax.NQUADS.name() + "\"", firstPredicate(g, "contentTypeSyntax"));
245         }
246     }
247 
248     @Test
249     public void parseIRI() throws Exception {
250         final IRI iri = dummyParser.createRDFTermFactory().createIRI("http://www.example.net/test.ttl");
251         try (final Graph g = factory.createGraph()) {
252             final RDFParser parser = dummyParser.source(iri).target(g);
253             parser.parse().get(5, TimeUnit.SECONDS);
254             checkGraph(g);
255             assertEquals("<http://www.example.net/test.ttl>", firstPredicate(g, "source"));
256             // No base - assuming the above IRI is always
257             // the base would break server-supplied base from
258             // any HTTP Location redirects and Content-Location header
259             assertNull(firstPredicate(g, "base"));
260             // ".ttl" in IRI string does not imply any content type
261             assertNull(firstPredicate(g, "contentType"));
262             assertNull(firstPredicate(g, "contentTypeSyntax"));
263         }
264     }
265 
266     @Test
267     public void parseIRIBaseContentType() throws Exception {
268         final IRI iri = dummyParser.createRDFTermFactory().createIRI("http://www.example.net/test.ttl");
269         try (final Graph g = factory.createGraph()) {
270             final RDFParser parser = dummyParser.source(iri).base(iri).contentType(RDFSyntax.TURTLE).target(g);
271             parser.parse().get(5, TimeUnit.SECONDS);
272             checkGraph(g);
273             assertEquals("<http://www.example.net/test.ttl>", firstPredicate(g, "source"));
274             assertEquals("<http://www.example.net/test.ttl>", firstPredicate(g, "base"));
275             assertEquals("\"" + RDFSyntax.TURTLE.name() + "\"", firstPredicate(g, "contentTypeSyntax"));
276             assertEquals("\"text/turtle\"", firstPredicate(g, "contentType"));
277         }
278     }
279 
280 }