001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.http.commons.responses;
007
008import static com.google.common.collect.ImmutableMap.of;
009import static org.apache.jena.graph.NodeFactory.createBlankNode;
010import static org.apache.jena.graph.NodeFactory.createLiteral;
011import static org.apache.jena.graph.NodeFactory.createURI;
012import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
013import static org.apache.jena.rdf.model.ResourceFactory.createResource;
014import static org.apache.jena.rdf.model.ResourceFactory.createTypedLiteral;
015import static org.apache.jena.vocabulary.DC.title;
016import static org.apache.jena.vocabulary.RDF.type;
017import static org.apache.jena.vocabulary.RDFS.label;
018import static org.apache.jena.vocabulary.SKOS.prefLabel;
019import static org.fcrepo.http.commons.test.util.TestHelpers.getUriInfoImpl;
020import static org.fcrepo.kernel.api.RdfLexicon.CONTAINS;
021import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
022import static org.fcrepo.kernel.api.RdfLexicon.MEMENTO_TYPE;
023import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
024import static org.fcrepo.kernel.api.RdfLexicon.BASIC_CONTAINER;
025import static org.fcrepo.kernel.api.FedoraTypes.FCR_VERSIONS;
026import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_ROOT;
027import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_LABEL_FORMATTER;
028import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_RFC_1123_FORMATTER;
029import static org.junit.Assert.assertEquals;
030import static org.junit.Assert.assertFalse;
031import static org.junit.Assert.assertTrue;
032import java.time.Instant;
033import java.util.Iterator;
034import java.util.List;
035import java.util.Map;
036
037import javax.ws.rs.core.UriInfo;
038
039import org.apache.jena.graph.Graph;
040import org.apache.jena.graph.Triple;
041import org.junit.Before;
042import org.junit.Test;
043
044import org.apache.jena.graph.Node;
045import org.apache.jena.graph.NodeFactory;
046import org.apache.jena.rdf.model.Literal;
047import org.apache.jena.rdf.model.Model;
048import org.apache.jena.rdf.model.Property;
049import org.apache.jena.rdf.model.Resource;
050import org.apache.jena.rdf.model.ResourceFactory;
051import org.apache.jena.vocabulary.DCTerms;
052
053/**
054 * <p>ViewHelpersTest class.</p>
055 *
056 * @author awoods
057 */
058public class ViewHelpersTest {
059
060    private ViewHelpers testObj;
061
062    @Before
063    public void setUp() {
064        testObj = ViewHelpers.getInstance();
065    }
066
067    @Test
068    public void testGetVersions() {
069        final Graph mem = createDefaultModel().getGraph();
070        final String resource_version = "http://localhost/fcrepo/abc/" + FCR_VERSIONS;
071        final Instant recent = Instant.now();
072        final Node version = createURI(resource_version + "/" + MEMENTO_LABEL_FORMATTER.format(recent));
073        mem.add(new Triple(createURI(resource_version), CONTAINS.asNode(), version));
074        mem.add(new Triple(version, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(recent))));
075        assertEquals("Version should be available.",
076            version, testObj.getVersions(mem, createURI(resource_version)).next());
077    }
078
079    @Test
080    public void testGetOrderedVersions() {
081        final Node resource_version = createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS);
082        final Instant recent = Instant.now();
083        final Instant past = recent.minus(3, java.time.temporal.ChronoUnit.DAYS);
084        final Instant way_past = recent.minus(60, java.time.temporal.ChronoUnit.DAYS);
085        final Node v1 =
086            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(recent));
087        final Node v2 =
088            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(past));
089        final Node v3 =
090            createURI("http://localhost/fcrepo/abc/" + FCR_VERSIONS + "/" + MEMENTO_LABEL_FORMATTER.format(way_past));
091
092        final Graph mem = createDefaultModel().getGraph();
093        mem.add(new Triple(resource_version, CONTAINS.asNode(), v1));
094        mem.add(new Triple(resource_version, CONTAINS.asNode(), v2));
095        mem.add(new Triple(resource_version, CONTAINS.asNode(), v3));
096        mem.add(new Triple(v1, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(recent))));
097        mem.add(new Triple(v2, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(past))));
098        mem.add(new Triple(v3, CREATED_DATE.asNode(), createLiteral(MEMENTO_RFC_1123_FORMATTER.format(way_past))));
099
100        final Iterator<Node> versions = testObj.getOrderedVersions(mem, resource_version, CONTAINS);
101        assertTrue(versions.hasNext());
102        final Node r1 = versions.next();
103        assertEquals("Version is out of order", v3, r1);
104        final Node r2 = versions.next();
105        assertEquals("Version is out of order", v2, r2);
106        final Node r3 = versions.next();
107        assertEquals("Latest version should be last.", v1, r3);
108    }
109
110    @Test
111    public void shouldConvertAUriToNodeBreadcrumbs() {
112
113        final UriInfo mockUriInfo = getUriInfoImpl();
114
115        final Map<String, String> nodeBreadcrumbs =
116            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
117                    "http://localhost/fcrepo/a/b/c").asNode());
118
119        assertEquals(of("http://localhost/fcrepo/a", "a",
120                "http://localhost/fcrepo/a/b", "b",
121                "http://localhost/fcrepo/a/b/c", "c"), nodeBreadcrumbs);
122    }
123
124    @Test
125    public void shouldRefuseToConvertAForeignUriToNodeBreadcrumbs() {
126
127        final UriInfo mockUriInfo = getUriInfoImpl();
128
129        final Map<String, String> nodeBreadcrumbs =
130            testObj.getNodeBreadcrumbs(mockUriInfo, createResource(
131                    "http://somewhere/else/a/b/c").asNode());
132
133        assertTrue(nodeBreadcrumbs.isEmpty());
134    }
135
136    @Test
137    public void testIsVersionedNode() {
138        final Graph mem = createDefaultModel().getGraph();
139        mem.add(new Triple(createURI("a/b/c"), type.asNode(), createURI(MEMENTO_TYPE)));
140        assertTrue("Node is a versioned node.", testObj.isVersionedNode(mem, createURI("a/b/c")));
141    }
142
143
144    @Test
145    public void testRdfResource() {
146        final String ns = "http://any/namespace#";
147        final String rdfType = "anyType";
148        final Graph mem = createDefaultModel().getGraph();
149        mem.add(new Triple(createURI("a/b"), type.asNode(),
150                createResource(ns + rdfType).asNode()));
151
152        assertTrue("Node is a " + rdfType + " node.",
153                testObj.isRdfResource(mem, createURI("a/b"), ns, rdfType));
154        assertFalse("Node is not a " + rdfType + " node.",
155                testObj.isRdfResource(mem, createURI("a/b"), ns, "otherType"));
156    }
157
158    @Test
159    public void shouldFindVersionRoot() {
160
161        final UriInfo mockUriInfo = getUriInfoImpl();
162
163        final String nodeUri = testObj.getVersionSubjectUrl(mockUriInfo, createResource(
164                        "http://localhost/fcrepo/a/b/fcr:versions/c").asNode());
165        assertEquals("http://localhost/fcrepo/a/b", nodeUri);
166    }
167
168    @Test
169    public void testGetVersionDate() {
170        final Graph mem = createDefaultModel().getGraph();
171        final String date_str = "20011231050505";
172        final Node subject = createURI("a/b/c/" + date_str);
173        final Instant date = Instant.from(MEMENTO_LABEL_FORMATTER.parse(date_str));
174        mem.add(new Triple(subject, CREATED_DATE.asNode(),
175            createLiteral(MEMENTO_RFC_1123_FORMATTER.format(date))));
176
177        assertEquals("Date should be available.", date, testObj.getVersionDate(mem, subject));
178    }
179
180    @Test
181    public void shouldExtractTitleFromNode() {
182        shouldExtractTitleFromNode(title);
183        shouldExtractTitleFromNode(DCTerms.title);
184        shouldExtractTitleFromNode(label);
185        shouldExtractTitleFromNode(prefLabel);
186    }
187
188    private void shouldExtractTitleFromNode( final Property property ) {
189        final Graph mem = createDefaultModel().getGraph();
190        mem.add(new Triple(createURI("a/b/c"), property.asNode(), createLiteral("abc")));
191        assertEquals("abc", testObj.getObjectTitle(mem, createURI("a/b/c")));
192    }
193
194    @Test
195    public void shouldUseTheObjectUriIfATitleIsNotAvailable() {
196        final Graph mem = createDefaultModel().getGraph();
197        mem.add(new Triple(createURI("a/b/c"), title.asNode(), createURI("d/e/f")));
198
199        assertEquals("a/b/c", testObj.getObjectTitle(mem, createURI("a/b/c")));
200
201    }
202
203    @Test
204    public void shouldUsetheBNodeIdIfItIsABNode() {
205        final Graph mem = createDefaultModel().getGraph();
206        final Node anon = createBlankNode();
207        assertEquals(anon.getBlankNodeLabel(), testObj
208                .getObjectTitle(mem, anon));
209    }
210
211    @Test
212    public void shouldJustUseTheStringIfItIsALiteral() {
213        final Graph mem = createDefaultModel().getGraph();
214        final Node lit = createLiteral("xyz");
215        assertEquals("\"xyz\"", testObj.getObjectTitle(mem, lit));
216    }
217
218    @Test
219    public void shouldConvertRdfObjectsToStrings() {
220
221        final Graph mem = createDefaultModel().getGraph();
222        mem.add(new Triple(createURI("subject"), createURI("a/b/c"),
223                NodeFactory.createLiteral("abc")));
224        mem.add(new Triple(createURI("subject"),
225                createURI("a-numeric-type"), createTypedLiteral(0).asNode()));
226        mem.add(new Triple(createURI("subject"),
227                createURI("an-empty-string"), createLiteral("")));
228        mem.add(new Triple( createURI("subject"), createURI("a-uri"),
229                createURI("some-uri")));
230
231        assertEquals("abc", testObj.getObjectsAsString(mem,
232                createURI("subject"), createResource("a/b/c"), true));
233        assertEquals("0", testObj.getObjectsAsString(mem, createURI("subject"),
234                createResource("a-numeric-type"), true));
235        assertEquals("<empty>", testObj.getObjectsAsString(mem,
236                createURI("subject"), createResource("an-empty-string"), true));
237        assertEquals("&lt;<a href=\"some-uri\">some-uri</a>&gt;", testObj
238                .getObjectsAsString(mem, createURI("subject"),
239                        createResource("a-uri"), true));
240
241        assertEquals("some-uri", testObj
242                .getObjectsAsString(mem, createURI("subject"),
243                        createResource("a-uri"), false));
244        assertEquals("", testObj.getObjectsAsString(mem, createURI("subject"),
245                createResource("a-nonexistent-uri"), true));
246
247    }
248
249    @Test
250    public void shouldExtractNamespaceAndPrefix() {
251        final Model model = createDefaultModel();
252        model.setNsPrefix("prefix", "namespace");
253
254        assertEquals("prefix:", testObj.getNamespacePrefix(model, "namespace", false));
255        assertEquals("some-other-namespace", testObj.getNamespacePrefix(model,
256                "some-other-namespace", false));
257    }
258
259    @Test
260    public void shouldSortTriplesForDisplay() {
261        final Model model = createDefaultModel();
262
263        model.setNsPrefix("prefix", "namespace");
264        final Property propertyA = model.createProperty("namespace", "a");
265        final Property propertyB = model.createProperty("namespace", "b");
266        final Property propertyC = model.createProperty("c");
267        final Literal literalA = model.createLiteral("a");
268        final Literal literalB = model.createLiteral("b");
269        final Resource resourceB = model.createResource("b");
270        model.add(resourceB, propertyA, literalA);
271
272        final Resource a = model.createResource("a");
273        model.add(a, propertyC, literalA);
274
275        model.add(a, propertyB, literalA);
276
277        model.add(a, propertyA, literalA);
278        model.add(a, propertyA, literalB);
279
280        final Iterator<Triple> iterator = model.getGraph().find(null, null, null);
281
282        final List<Triple> sortedTriples =
283            testObj.getSortedTriples(model, iterator);
284
285        sortedTriples.get(0).matches(a.asNode(), propertyA.asNode(),
286                literalA.asNode());
287        sortedTriples.get(1).matches(a.asNode(), propertyA.asNode(),
288                literalB.asNode());
289        sortedTriples.get(2).matches(a.asNode(), propertyB.asNode(),
290                literalA.asNode());
291        sortedTriples.get(3).matches(a.asNode(), propertyC.asNode(),
292                literalA.asNode());
293        sortedTriples.get(4).matches(resourceB.asNode(),
294                propertyC.asNode(), literalA.asNode());
295
296    }
297
298    @Test
299    public void shouldConvertPrefixMappingToSparqlUpdatePrefixPreamble() {
300
301        final Model model = createDefaultModel();
302
303        model.setNsPrefix("prefix", "namespace");
304
305        final String prefixPreamble = testObj.getPrefixPreamble(model);
306
307        assertEquals("PREFIX prefix: <namespace>\n\n", prefixPreamble);
308    }
309
310    @Test
311    public void shouldConvertStringLiteralsToNodes() {
312        final String uri = "fedora:resource";
313        final Literal URIRES = ResourceFactory.createPlainLiteral(uri);
314        assertEquals(URIRES.asNode(), testObj.asLiteralStringNode(uri));
315    }
316
317    @Test
318    public void testGetNumChildren() {
319        final Graph mem = createDefaultModel().getGraph();
320        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/1").asNode()));
321        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/2").asNode()));
322        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/3").asNode()));
323        mem.add(new Triple(createURI("a/b/c"), CONTAINS.asNode(), createResource("a/b/c/4").asNode()));
324        assertEquals(4, testObj.getNumChildren(mem, createURI("a/b/c")));
325    }
326
327    @Test
328    public void testGetNumChildrenEmpty() {
329        final Graph mem = createDefaultModel().getGraph();
330        assertEquals(0, testObj.getNumChildren(mem, createURI("a/b/c")));
331    }
332
333    @Test
334    public void testIsRepositoryRoot() {
335        final Model model = createDefaultModel();
336        model.setNsPrefix("fedora", REPOSITORY_NAMESPACE);
337        final Graph mem = model.getGraph();
338        final Node root = createURI("http://localhost/root");
339        final Node child = createURI("http://localhost/not_root");
340
341        mem.add(new Triple(root, type.asNode(), BASIC_CONTAINER.asNode()));
342        mem.add(new Triple(root, type.asNode(), REPOSITORY_ROOT.asNode()));
343        mem.add(new Triple(child, type.asNode(), BASIC_CONTAINER.asNode()));
344
345        assertTrue("Root should be a Repository Root", testObj.isRootResource(mem, root));
346        assertFalse("Child should not be a Repository Root", testObj.isRootResource(mem, child));
347    }
348}