001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.http.commons.responses;
019
020import static com.google.common.collect.ImmutableMap.of;
021import static org.apache.jena.graph.NodeFactory.createBlankNode;
022import static org.apache.jena.graph.NodeFactory.createLiteral;
023import static org.apache.jena.graph.NodeFactory.createURI;
024import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
025import static org.apache.jena.rdf.model.ResourceFactory.createResource;
026import static org.apache.jena.rdf.model.ResourceFactory.createTypedLiteral;
027import static org.apache.jena.vocabulary.DC.title;
028import static org.apache.jena.vocabulary.RDF.type;
029import static org.apache.jena.vocabulary.RDFS.label;
030import static org.apache.jena.vocabulary.SKOS.prefLabel;
031import static org.fcrepo.http.commons.test.util.TestHelpers.getUriInfoImpl;
032import static org.fcrepo.kernel.api.RdfLexicon.CONTAINS;
033import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
034import static org.fcrepo.kernel.api.RdfLexicon.HAS_VERSION_LABEL;
035import static org.fcrepo.kernel.api.RdfLexicon.HAS_VERSION;
036import static org.fcrepo.kernel.api.RdfLexicon.DESCRIBES;
037import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
038import static org.fcrepo.kernel.api.RdfLexicon.WRITABLE;
039import static org.junit.Assert.assertEquals;
040import static org.junit.Assert.assertFalse;
041import static org.junit.Assert.assertTrue;
042import static java.time.Instant.now;
043
044import java.time.Instant;
045import java.util.Iterator;
046import java.util.List;
047import java.util.Map;
048
049import javax.ws.rs.core.UriInfo;
050
051import org.apache.jena.graph.Graph;
052import org.apache.jena.graph.Triple;
053import org.junit.Before;
054import org.junit.Test;
055
056import org.apache.jena.graph.Node;
057import org.apache.jena.graph.NodeFactory;
058import org.apache.jena.rdf.model.Literal;
059import org.apache.jena.rdf.model.Model;
060import org.apache.jena.rdf.model.Property;
061import org.apache.jena.rdf.model.Resource;
062import org.apache.jena.rdf.model.ResourceFactory;
063import org.apache.jena.vocabulary.DCTerms;
064
065/**
066 * <p>ViewHelpersTest class.</p>
067 *
068 * @author awoods
069 */
070public class ViewHelpersTest {
071
072    private ViewHelpers testObj;
073
074    @Before
075    public void setUp() {
076        testObj = ViewHelpers.getInstance();
077    }
078
079    @Test
080    public void testGetVersions() {
081        final Graph mem = createDefaultModel().getGraph();
082        final Node version = createURI("http://localhost/fcrepo/abc/fcr:version/adcd");
083        mem.add(new Triple(createURI("http://localhost/fcrepo/abc"), HAS_VERSION.asNode(),
084                version));
085        mem.add(new Triple(version, CREATED_DATE.asNode(), createLiteral(now().toString())));
086        assertEquals("Version should be available.",
087                     version, testObj.getVersions(mem, createURI("http://localhost/fcrepo/abc")).next());
088    }
089
090    @Test
091    public void testGetOrderedVersions() {
092        final Node resource = createURI("http://localhost/fcrepo/abc");
093        final Node v1 = createURI("http://localhost/fcrepo/abc/fcr:version/1");
094        final Node v2 = createURI("http://localhost/fcrepo/abc/fcr:version/2");
095        final Node v3 = createURI("http://localhost/fcrepo/abc/fcr:version/3");
096        final Instant date = now();
097
098        final Graph mem = createDefaultModel().getGraph();
099        mem.add(new Triple(resource, HAS_VERSION.asNode(), v1));
100        mem.add(new Triple(v1, CREATED_DATE.asNode(), createLiteral(date.toString())));
101        mem.add(new Triple(resource, HAS_VERSION.asNode(), v2));
102        mem.add(new Triple(v2, CREATED_DATE.asNode(), createLiteral(date.toString())));
103        mem.add(new Triple(resource, HAS_VERSION.asNode(), v3));
104        mem.add(new Triple(v3, CREATED_DATE.asNode(),
105                createLiteral(date.plusMillis(10000l).toString())));
106
107        final Iterator<Node> versions = testObj.getOrderedVersions(mem, resource, HAS_VERSION);
108        versions.next();
109        versions.next();
110        final Node r3 = versions.next();
111        assertEquals("Latest version should be last.", v3, r3);
112    }
113
114    @Test
115    public void shouldConvertAUriToNodeBreadcrumbs() {
116
117        final UriInfo mockUriInfo = getUriInfoImpl();
118
119        final Map<String, String> nodeBreadcrumbs =
120            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
121                    "http://localhost/fcrepo/a/b/c").asNode());
122
123        assertEquals(of("http://localhost/fcrepo/a", "a",
124                "http://localhost/fcrepo/a/b", "b",
125                "http://localhost/fcrepo/a/b/c", "c"), nodeBreadcrumbs);
126    }
127
128    @Test
129    public void shouldRefuseToConvertAForeignUriToNodeBreadcrumbs() {
130
131        final UriInfo mockUriInfo = getUriInfoImpl();
132
133        final Map<String, String> nodeBreadcrumbs =
134            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
135                    "http://somewhere/else/a/b/c").asNode());
136
137        assertTrue(nodeBreadcrumbs.isEmpty());
138    }
139
140    @Test
141    public void testIsWritable() {
142        final Graph mem = createDefaultModel().getGraph();
143        mem.add(new Triple(createURI("a/b/c"), WRITABLE.asNode(), createLiteral(Boolean.TRUE.toString())));
144        assertTrue("Node is should be writable.", testObj.isWritable(mem, createURI("a/b/c")));
145    }
146
147    @Test
148    public void testIsWritableFalse() {
149        final Graph mem = createDefaultModel().getGraph();
150        mem.add(new Triple(createURI("a/b/c"), WRITABLE.asNode(), createLiteral(Boolean.FALSE.toString())));
151        assertFalse("Node should not be writable.", testObj.isWritable(mem, createURI("a/b/c")));
152    }
153
154    @Test
155    public void testIsWritableFalseJunk() {
156        final Graph mem = createDefaultModel().getGraph();
157        mem.add(new Triple(createURI("a/b/c"), DESCRIBES.asNode(), createLiteral("junk")));
158        assertFalse("Node should not be writable.", testObj.isWritable(mem, createURI("a/b/c")));
159    }
160
161    @Test
162    public void testIsVersionedNode() {
163        final Graph mem = createDefaultModel().getGraph();
164        mem.add(new Triple(createURI("a/b/c"), type.asNode(), createURI(REPOSITORY_NAMESPACE + "Version")));
165        assertTrue("Node is a versioned node.", testObj.isVersionedNode(mem, createURI("a/b/c")));
166    }
167
168    @Test
169    public void testRdfResource() {
170        final String ns = "http://any/namespace#";
171        final String rdfType = "anyType";
172        final Graph mem = createDefaultModel().getGraph();
173        mem.add(new Triple(createURI("a/b"), type.asNode(),
174                createResource(ns + rdfType).asNode()));
175
176        assertTrue("Node is a " + rdfType + " node.",
177                testObj.isRdfResource(mem, createURI("a/b"), ns, rdfType));
178        assertFalse("Node is not a " + rdfType + " node.",
179                testObj.isRdfResource(mem, createURI("a/b"), ns, "otherType"));
180    }
181
182    @Test
183    public void shouldFindVersionRoot() {
184
185        final UriInfo mockUriInfo = getUriInfoImpl();
186
187        final String nodeUri = testObj.getVersionSubjectUrl(mockUriInfo, createResource(
188                        "http://localhost/fcrepo/a/b/fcr:versions/c").asNode());
189        assertEquals("http://localhost/fcrepo/a/b", nodeUri);
190    }
191
192    @Test
193    public void testGetLabeledVersion() {
194        final Graph mem = createDefaultModel().getGraph();
195        final String label = "testLabel";
196        mem.add(new Triple(createURI("a/b/c"), HAS_VERSION_LABEL.asNode(),
197                createLiteral(label)));
198        assertEquals("Version label should be available.", label, testObj.getVersionLabel(mem, createURI("a/b/c"))
199                .orElse(""));
200    }
201
202    @Test
203    public void testGetUnlabeledVersion() {
204        final Graph mem = createDefaultModel().getGraph();
205        assertEquals("Default version label should be used.",
206                     "d", testObj.getVersionLabel(mem, createURI("a/b/c")).orElse("d"));
207    }
208
209    @Test
210    public void testGetVersionDate() {
211        final Graph mem = createDefaultModel().getGraph();
212        final String date = now().toString();
213        mem.add(new Triple(createURI("a/b/c"), CREATED_DATE.asNode(),
214                createLiteral(date)));
215        assertEquals("Date should be available.", date, testObj.getVersionDate(mem, createURI("a/b/c")).get());
216    }
217
218    @Test
219    public void testGetMissingVersionDate() {
220        final Graph mem = createDefaultModel().getGraph();
221        assertFalse("Date should not be available.", testObj.getVersionDate(mem, createURI("a/b/c")).isPresent());
222    }
223
224    @Test
225    public void shouldExtractTitleFromNode() {
226        shouldExtractTitleFromNode(title);
227        shouldExtractTitleFromNode(DCTerms.title);
228        shouldExtractTitleFromNode(label);
229        shouldExtractTitleFromNode(prefLabel);
230    }
231
232    private void shouldExtractTitleFromNode( final Property property ) {
233        final Graph mem = createDefaultModel().getGraph();
234        mem.add(new Triple(createURI("a/b/c"), property.asNode(), createLiteral("abc")));
235        assertEquals("abc", testObj.getObjectTitle(mem, createURI("a/b/c")));
236    }
237
238    @Test
239    public void shouldUseTheObjectUriIfATitleIsNotAvailable() {
240        final Graph mem = createDefaultModel().getGraph();
241        mem.add(new Triple(createURI("a/b/c"), title.asNode(), createURI("d/e/f")));
242
243        assertEquals("a/b/c", testObj.getObjectTitle(mem, createURI("a/b/c")));
244
245    }
246
247    @Test
248    public void shouldUsetheBNodeIdIfItIsABNode() {
249        final Graph mem = createDefaultModel().getGraph();
250        final Node anon = createBlankNode();
251        assertEquals(anon.getBlankNodeLabel(), testObj
252                .getObjectTitle(mem, anon));
253    }
254
255    @Test
256    public void shouldJustUseTheStringIfItIsALiteral() {
257        final Graph mem = createDefaultModel().getGraph();
258        final Node lit = createLiteral("xyz");
259        assertEquals("\"xyz\"", testObj.getObjectTitle(mem, lit));
260    }
261
262    @Test
263    public void shouldConvertRdfObjectsToStrings() {
264
265        final Graph mem = createDefaultModel().getGraph();
266        mem.add(new Triple(createURI("subject"), createURI("a/b/c"),
267                NodeFactory.createLiteral("abc")));
268        mem.add(new Triple(createURI("subject"),
269                createURI("a-numeric-type"), createTypedLiteral(0).asNode()));
270        mem.add(new Triple(createURI("subject"),
271                createURI("an-empty-string"), createLiteral("")));
272        mem.add(new Triple( createURI("subject"), createURI("a-uri"),
273                createURI("some-uri")));
274
275        assertEquals("abc", testObj.getObjectsAsString(mem,
276                createURI("subject"), createResource("a/b/c"), true));
277        assertEquals("0", testObj.getObjectsAsString(mem, createURI("subject"),
278                createResource("a-numeric-type"), true));
279        assertEquals("<empty>", testObj.getObjectsAsString(mem,
280                createURI("subject"), createResource("an-empty-string"), true));
281        assertEquals("&lt;<a href=\"some-uri\">some-uri</a>&gt;", testObj
282                .getObjectsAsString(mem, createURI("subject"),
283                        createResource("a-uri"), true));
284
285        assertEquals("some-uri", testObj
286                .getObjectsAsString(mem, createURI("subject"),
287                        createResource("a-uri"), false));
288        assertEquals("", testObj.getObjectsAsString(mem, createURI("subject"),
289                createResource("a-nonexistent-uri"), true));
290
291    }
292
293    @Test
294    public void shouldExtractNamespaceAndPrefix() {
295        final Model model = createDefaultModel();
296        model.setNsPrefix("prefix", "namespace");
297
298        assertEquals("prefix:", testObj.getNamespacePrefix(model, "namespace", false));
299        assertEquals("some-other-namespace", testObj.getNamespacePrefix(model,
300                "some-other-namespace", false));
301    }
302
303    @Test
304    public void shouldSortTriplesForDisplay() {
305        final Model model = createDefaultModel();
306
307        model.setNsPrefix("prefix", "namespace");
308        final Property propertyA = model.createProperty("namespace", "a");
309        final Property propertyB = model.createProperty("namespace", "b");
310        final Property propertyC = model.createProperty("c");
311        final Literal literalA = model.createLiteral("a");
312        final Literal literalB = model.createLiteral("b");
313        final Resource resourceB = model.createResource("b");
314        model.add(resourceB, propertyA, literalA);
315
316        final Resource a = model.createResource("a");
317        model.add(a, propertyC, literalA);
318
319        model.add(a, propertyB, literalA);
320
321        model.add(a, propertyA, literalA);
322        model.add(a, propertyA, literalB);
323
324        final Iterator<Triple> iterator = model.getGraph().find(null, null, null);
325
326        final List<Triple> sortedTriples =
327            testObj.getSortedTriples(model, iterator);
328
329        sortedTriples.get(0).matches(a.asNode(), propertyA.asNode(),
330                literalA.asNode());
331        sortedTriples.get(1).matches(a.asNode(), propertyA.asNode(),
332                literalB.asNode());
333        sortedTriples.get(2).matches(a.asNode(), propertyB.asNode(),
334                literalA.asNode());
335        sortedTriples.get(3).matches(a.asNode(), propertyC.asNode(),
336                literalA.asNode());
337        sortedTriples.get(4).matches(resourceB.asNode(),
338                propertyC.asNode(), literalA.asNode());
339
340    }
341
342    @Test
343    public void shouldConvertPrefixMappingToSparqlUpdatePrefixPreamble() {
344
345        final Model model = createDefaultModel();
346
347        model.setNsPrefix("prefix", "namespace");
348
349        final String prefixPreamble = testObj.getPrefixPreamble(model);
350
351        assertEquals("PREFIX prefix: <namespace>\n\n", prefixPreamble);
352    }
353
354    @Test
355    public void shouldConvertStringLiteralsToNodes() {
356        final String uri = "fedora:resource";
357        final Literal URIRES = ResourceFactory.createPlainLiteral(uri);
358        assertEquals(URIRES.asNode(), testObj.asLiteralStringNode(uri));
359    }
360
361    @Test
362    public void testGetNumChildren() {
363        final Graph mem = createDefaultModel().getGraph();
364        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/1").asNode()));
365        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/2").asNode()));
366        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/3").asNode()));
367        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/4").asNode()));
368        assertEquals(4, testObj.getNumChildren(mem, createURI("a/b/c")));
369    }
370
371    @Test
372    public void testGetNumChildrenEmpty() {
373        final Graph mem = createDefaultModel().getGraph();
374        assertEquals(0, testObj.getNumChildren(mem, createURI("a/b/c")));
375    }
376
377    @Test
378    public void testGetNumChildrenNone() {
379        final Graph mem = createDefaultModel().getGraph();
380        assertEquals(0, testObj.getNumChildren(mem, createURI("a/b/c")));
381    }
382
383}