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.MEMENTO_TYPE;
035import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
036import static org.fcrepo.kernel.api.RdfLexicon.BASIC_CONTAINER;
037import static org.fcrepo.kernel.api.FedoraTypes.FCR_VERSIONS;
038import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_REPOSITORY_ROOT;
039import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_LABEL_FORMATTER;
040import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_RFC_1123_FORMATTER;
041import static org.junit.Assert.assertEquals;
042import static org.junit.Assert.assertFalse;
043import static org.junit.Assert.assertTrue;
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    private static final String REPOSITORY_ROOT_URI =
075        FEDORA_REPOSITORY_ROOT.replaceAll("fedora:", REPOSITORY_NAMESPACE);
076
077    @Before
078    public void setUp() {
079        testObj = ViewHelpers.getInstance();
080    }
081
082    @Test
083    public void testGetVersions() {
084        final Graph mem = createDefaultModel().getGraph();
085        final String resource_version = "http://localhost/fcrepo/abc/" + FCR_VERSIONS;
086        final Instant recent = Instant.now();
087        final Node version = createURI(resource_version + "/" + MEMENTO_LABEL_FORMATTER.format(recent));
088        mem.add(new Triple(createURI(resource_version), CONTAINS.asNode(), version));
089        mem.add(new Triple(version, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(recent))));
090        assertEquals("Version should be available.",
091            version, testObj.getVersions(mem, createURI(resource_version)).next());
092    }
093
094    @Test
095    public void testGetOrderedVersions() {
096        final Node resource_version = createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS);
097        final Instant recent = Instant.now();
098        final Instant past = recent.minus(3, java.time.temporal.ChronoUnit.DAYS);
099        final Instant way_past = recent.minus(60, java.time.temporal.ChronoUnit.DAYS);
100        final Node v1 =
101            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(recent));
102        final Node v2 =
103            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(past));
104        final Node v3 =
105            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(way_past));
106
107        final Graph mem = createDefaultModel().getGraph();
108        mem.add(new Triple(resource_version, CONTAINS.asNode(), v1));
109        mem.add(new Triple(resource_version, CONTAINS.asNode(), v2));
110        mem.add(new Triple(resource_version, CONTAINS.asNode(), v3));
111        mem.add(new Triple(v1, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(recent))));
112        mem.add(new Triple(v2, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(past))));
113        mem.add(new Triple(v3, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(way_past))));
114
115        final Iterator<Node> versions = testObj.getOrderedVersions(mem, resource_version, CONTAINS);
116        assertTrue(versions.hasNext());
117        final Node r1 = versions.next();
118        assertEquals("Version is out of order", v3, r1);
119        final Node r2 = versions.next();
120        assertEquals("Version is out of order", v2, r2);
121        final Node r3 = versions.next();
122        assertEquals("Latest version should be last.", v1, r3);
123    }
124
125    @Test
126    public void shouldConvertAUriToNodeBreadcrumbs() {
127
128        final UriInfo mockUriInfo = getUriInfoImpl();
129
130        final Map<String, String> nodeBreadcrumbs =
131            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
132                    "http://localhost/fcrepo/a/b/c").asNode());
133
134        assertEquals(of("http://localhost/fcrepo/a", "a",
135                "http://localhost/fcrepo/a/b", "b",
136                "http://localhost/fcrepo/a/b/c", "c"), nodeBreadcrumbs);
137    }
138
139    @Test
140    public void shouldRefuseToConvertAForeignUriToNodeBreadcrumbs() {
141
142        final UriInfo mockUriInfo = getUriInfoImpl();
143
144        final Map<String, String> nodeBreadcrumbs =
145            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
146                    "http://somewhere/else/a/b/c").asNode());
147
148        assertTrue(nodeBreadcrumbs.isEmpty());
149    }
150
151    @Test
152    public void testIsVersionedNode() {
153        final Graph mem = createDefaultModel().getGraph();
154        mem.add(new Triple(createURI("a/b/c"), type.asNode(), createURI(MEMENTO_TYPE)));
155        assertTrue("Node is a versioned node.", testObj.isVersionedNode(mem, createURI("a/b/c")));
156    }
157
158
159    @Test
160    public void testRdfResource() {
161        final String ns = "http://any/namespace#";
162        final String rdfType = "anyType";
163        final Graph mem = createDefaultModel().getGraph();
164        mem.add(new Triple(createURI("a/b"), type.asNode(),
165                createResource(ns + rdfType).asNode()));
166
167        assertTrue("Node is a " + rdfType + " node.",
168                testObj.isRdfResource(mem, createURI("a/b"), ns, rdfType));
169        assertFalse("Node is not a " + rdfType + " node.",
170                testObj.isRdfResource(mem, createURI("a/b"), ns, "otherType"));
171    }
172
173    @Test
174    public void shouldFindVersionRoot() {
175
176        final UriInfo mockUriInfo = getUriInfoImpl();
177
178        final String nodeUri = testObj.getVersionSubjectUrl(mockUriInfo, createResource(
179                        "http://localhost/fcrepo/a/b/fcr:versions/c").asNode());
180        assertEquals("http://localhost/fcrepo/a/b", nodeUri);
181    }
182
183    @Test
184    public void testGetVersionDate() {
185        final Graph mem = createDefaultModel().getGraph();
186        final String date_str = "20011231050505";
187        final Node subject = createURI("a/b/c/" + date_str);
188        final Instant date = Instant.from(MEMENTO_LABEL_FORMATTER.parse(date_str));
189        mem.add(new Triple(subject, CREATED_DATE.asNode(),
190            createLiteral(MEMENTO_RFC_1123_FORMATTER.format(date))));
191
192        assertEquals("Date should be available.", date, testObj.getVersionDate(mem, subject));
193    }
194
195    @Test
196    public void shouldExtractTitleFromNode() {
197        shouldExtractTitleFromNode(title);
198        shouldExtractTitleFromNode(DCTerms.title);
199        shouldExtractTitleFromNode(label);
200        shouldExtractTitleFromNode(prefLabel);
201    }
202
203    private void shouldExtractTitleFromNode( final Property property ) {
204        final Graph mem = createDefaultModel().getGraph();
205        mem.add(new Triple(createURI("a/b/c"), property.asNode(), createLiteral("abc")));
206        assertEquals("abc", testObj.getObjectTitle(mem, createURI("a/b/c")));
207    }
208
209    @Test
210    public void shouldUseTheObjectUriIfATitleIsNotAvailable() {
211        final Graph mem = createDefaultModel().getGraph();
212        mem.add(new Triple(createURI("a/b/c"), title.asNode(), createURI("d/e/f")));
213
214        assertEquals("a/b/c", testObj.getObjectTitle(mem, createURI("a/b/c")));
215
216    }
217
218    @Test
219    public void shouldUsetheBNodeIdIfItIsABNode() {
220        final Graph mem = createDefaultModel().getGraph();
221        final Node anon = createBlankNode();
222        assertEquals(anon.getBlankNodeLabel(), testObj
223                .getObjectTitle(mem, anon));
224    }
225
226    @Test
227    public void shouldJustUseTheStringIfItIsALiteral() {
228        final Graph mem = createDefaultModel().getGraph();
229        final Node lit = createLiteral("xyz");
230        assertEquals("\"xyz\"", testObj.getObjectTitle(mem, lit));
231    }
232
233    @Test
234    public void shouldConvertRdfObjectsToStrings() {
235
236        final Graph mem = createDefaultModel().getGraph();
237        mem.add(new Triple(createURI("subject"), createURI("a/b/c"),
238                NodeFactory.createLiteral("abc")));
239        mem.add(new Triple(createURI("subject"),
240                createURI("a-numeric-type"), createTypedLiteral(0).asNode()));
241        mem.add(new Triple(createURI("subject"),
242                createURI("an-empty-string"), createLiteral("")));
243        mem.add(new Triple( createURI("subject"), createURI("a-uri"),
244                createURI("some-uri")));
245
246        assertEquals("abc", testObj.getObjectsAsString(mem,
247                createURI("subject"), createResource("a/b/c"), true));
248        assertEquals("0", testObj.getObjectsAsString(mem, createURI("subject"),
249                createResource("a-numeric-type"), true));
250        assertEquals("<empty>", testObj.getObjectsAsString(mem,
251                createURI("subject"), createResource("an-empty-string"), true));
252        assertEquals("&lt;<a href=\"some-uri\">some-uri</a>&gt;", testObj
253                .getObjectsAsString(mem, createURI("subject"),
254                        createResource("a-uri"), true));
255
256        assertEquals("some-uri", testObj
257                .getObjectsAsString(mem, createURI("subject"),
258                        createResource("a-uri"), false));
259        assertEquals("", testObj.getObjectsAsString(mem, createURI("subject"),
260                createResource("a-nonexistent-uri"), true));
261
262    }
263
264    @Test
265    public void shouldExtractNamespaceAndPrefix() {
266        final Model model = createDefaultModel();
267        model.setNsPrefix("prefix", "namespace");
268
269        assertEquals("prefix:", testObj.getNamespacePrefix(model, "namespace", false));
270        assertEquals("some-other-namespace", testObj.getNamespacePrefix(model,
271                "some-other-namespace", false));
272    }
273
274    @Test
275    public void shouldSortTriplesForDisplay() {
276        final Model model = createDefaultModel();
277
278        model.setNsPrefix("prefix", "namespace");
279        final Property propertyA = model.createProperty("namespace", "a");
280        final Property propertyB = model.createProperty("namespace", "b");
281        final Property propertyC = model.createProperty("c");
282        final Literal literalA = model.createLiteral("a");
283        final Literal literalB = model.createLiteral("b");
284        final Resource resourceB = model.createResource("b");
285        model.add(resourceB, propertyA, literalA);
286
287        final Resource a = model.createResource("a");
288        model.add(a, propertyC, literalA);
289
290        model.add(a, propertyB, literalA);
291
292        model.add(a, propertyA, literalA);
293        model.add(a, propertyA, literalB);
294
295        final Iterator<Triple> iterator = model.getGraph().find(null, null, null);
296
297        final List<Triple> sortedTriples =
298            testObj.getSortedTriples(model, iterator);
299
300        sortedTriples.get(0).matches(a.asNode(), propertyA.asNode(),
301                literalA.asNode());
302        sortedTriples.get(1).matches(a.asNode(), propertyA.asNode(),
303                literalB.asNode());
304        sortedTriples.get(2).matches(a.asNode(), propertyB.asNode(),
305                literalA.asNode());
306        sortedTriples.get(3).matches(a.asNode(), propertyC.asNode(),
307                literalA.asNode());
308        sortedTriples.get(4).matches(resourceB.asNode(),
309                propertyC.asNode(), literalA.asNode());
310
311    }
312
313    @Test
314    public void shouldConvertPrefixMappingToSparqlUpdatePrefixPreamble() {
315
316        final Model model = createDefaultModel();
317
318        model.setNsPrefix("prefix", "namespace");
319
320        final String prefixPreamble = testObj.getPrefixPreamble(model);
321
322        assertEquals("PREFIX prefix: <namespace>\n\n", prefixPreamble);
323    }
324
325    @Test
326    public void shouldConvertStringLiteralsToNodes() {
327        final String uri = "fedora:resource";
328        final Literal URIRES = ResourceFactory.createPlainLiteral(uri);
329        assertEquals(URIRES.asNode(), testObj.asLiteralStringNode(uri));
330    }
331
332    @Test
333    public void testGetNumChildren() {
334        final Graph mem = createDefaultModel().getGraph();
335        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/1").asNode()));
336        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/2").asNode()));
337        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/3").asNode()));
338        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/4").asNode()));
339        assertEquals(4, testObj.getNumChildren(mem, createURI("a/b/c")));
340    }
341
342    @Test
343    public void testGetNumChildrenEmpty() {
344        final Graph mem = createDefaultModel().getGraph();
345        assertEquals(0, testObj.getNumChildren(mem, createURI("a/b/c")));
346    }
347
348    @Test
349    public void testIsRepositoryRoot() {
350        final Model model = createDefaultModel();
351        model.setNsPrefix("fedora", REPOSITORY_NAMESPACE);
352        final Graph mem = model.getGraph();
353        final Node root = createURI("http://localhost/root");
354        final Node child = createURI("http://localhost/not_root");
355
356        mem.add(new Triple(root, type.asNode(), BASIC_CONTAINER.asNode()));
357        mem.add(new Triple(root, type.asNode(), createURI(REPOSITORY_ROOT_URI)));
358        mem.add(new Triple(child, type.asNode(), BASIC_CONTAINER.asNode()));
359
360        assertTrue("Root should be a Repository Root", testObj.isRootResource(mem, root));
361        assertFalse("Child should not be a Repository Root", testObj.isRootResource(mem, child));
362    }
363}