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