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.kernel.api.identifiers;
007
008import static org.fcrepo.kernel.api.FedoraTypes.FCR_ACL;
009import static org.fcrepo.kernel.api.FedoraTypes.FCR_METADATA;
010import static org.fcrepo.kernel.api.FedoraTypes.FCR_TOMBSTONE;
011import static org.fcrepo.kernel.api.FedoraTypes.FCR_VERSIONS;
012import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_ID_PREFIX;
013import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_LABEL_FORMATTER;
014import static org.junit.Assert.assertEquals;
015import static org.junit.Assert.assertFalse;
016import static org.junit.Assert.assertTrue;
017import static org.junit.Assert.fail;
018
019import java.time.Instant;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.List;
023
024import org.fcrepo.kernel.api.FedoraTypes;
025import org.fcrepo.kernel.api.exception.InvalidMementoPathException;
026import org.fcrepo.kernel.api.exception.InvalidResourceIdentifierException;
027
028import org.junit.Test;
029
030/**
031 * @author pwinckles
032 */
033public class FedoraIdTest {
034
035    @Test
036    public void testMissingPrefix() throws Exception {
037        final FedoraId fedoraID = FedoraId.create("this-is-a-test/ok");
038        final String testID = FEDORA_ID_PREFIX + "/this-is-a-test/ok";
039        assertResource(fedoraID, "NORMAL", testID, testID);
040    }
041
042    @Test
043    public void testRepositoryRoot() throws Exception {
044        final FedoraId fedoraID = FedoraId.create(FEDORA_ID_PREFIX);
045        assertResource(fedoraID, "ROOT", FEDORA_ID_PREFIX, FEDORA_ID_PREFIX);
046    }
047
048    @Test
049    public void testNormal() throws Exception {
050        final String testID = FEDORA_ID_PREFIX + "/first-object";
051        final FedoraId fedoraID = FedoraId.create(testID);
052        assertResource(fedoraID, "NORMAL", testID, testID);
053    }
054
055    @Test(expected = InvalidResourceIdentifierException.class)
056    public void testEmptyPath() throws Exception {
057        final String testID = FEDORA_ID_PREFIX + "/first-object//second-object";
058        FedoraId.create(testID);
059    }
060
061    @Test
062    public void testNormalAcl() throws Exception {
063        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_ACL;
064        final FedoraId fedoraID = FedoraId.create(testID);
065        assertResource(fedoraID, "ACL", testID, FEDORA_ID_PREFIX + "/first-object");
066    }
067
068    @Test(expected = InvalidResourceIdentifierException.class)
069    public void testNormalAclException() throws Exception {
070        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_ACL + "/garbage";
071        FedoraId.create(testID);
072    }
073
074    @Test
075    public void testNormalDescription() throws Exception {
076        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA;
077        final FedoraId fedoraID = FedoraId.create(testID);
078        assertResource(fedoraID, "METADATA", testID, FEDORA_ID_PREFIX + "/first-object");
079    }
080
081    @Test(expected = InvalidResourceIdentifierException.class)
082    public void testNormalDescriptionException() throws Exception {
083        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/test-garbage";
084        FedoraId.create(testID);
085    }
086
087    @Test
088    public void testNormalTimemap() throws Exception {
089        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS;
090        final FedoraId fedoraID = FedoraId.create(testID);
091        assertResource(fedoraID, "TIMEMAP", testID, FEDORA_ID_PREFIX + "/first-object");
092    }
093
094    @Test
095    public void testNormalMemento() throws Exception {
096        final String mementoString = "20001221010304";
097        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" + mementoString;
098        final FedoraId fedoraID = FedoraId.create(testID);
099        assertResource(fedoraID, "MEMENTO", testID, FEDORA_ID_PREFIX + "/first-object");
100        assertEquals(mementoString, fedoraID.getMementoString());
101        final Instant mementoInstant = Instant.from(MEMENTO_LABEL_FORMATTER.parse(mementoString));
102        assertEquals(mementoInstant, fedoraID.getMementoInstant());
103    }
104
105    @Test(expected = InvalidMementoPathException.class)
106    public void testNormalMementoException() throws Exception {
107        final String mementoString = "00001221010304";
108        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" + mementoString;
109        FedoraId.create(testID);
110    }
111
112    @Test(expected = InvalidMementoPathException.class)
113    public void testNormalMementoException2() throws Exception {
114        final String mementoString = "other-text";
115        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" + mementoString;
116        FedoraId.create(testID);
117    }
118
119    @Test(expected = InvalidResourceIdentifierException.class)
120    public void testMetadataAcl() throws Exception {
121        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_ACL;
122        FedoraId.create(testID);
123    }
124
125
126    @Test(expected = InvalidResourceIdentifierException.class)
127    public void testMetadataAclException() throws Exception {
128        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_ACL + "/garbage";
129        FedoraId.create(testID);
130    }
131
132    @Test
133    public void testMetadataTimemap() throws Exception {
134        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS;
135        final FedoraId fedoraID = FedoraId.create(testID);
136        assertResource(fedoraID, Arrays.asList("METADATA", "TIMEMAP"), testID, FEDORA_ID_PREFIX +
137                "/first-object");
138    }
139
140    @Test
141    public void testMetadataMemento() throws Exception {
142        final String mementoString = "20101109231256";
143        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "/" +
144                mementoString;
145        final FedoraId fedoraID = FedoraId.create(testID);
146        assertResource(fedoraID, Arrays.asList("METADATA", "MEMENTO"), testID, FEDORA_ID_PREFIX +
147                "/first-object");
148        assertEquals(mementoString, fedoraID.getMementoString());
149        final Instant mementoInstant = Instant.from(MEMENTO_LABEL_FORMATTER.parse(mementoString));
150        assertEquals(mementoInstant, fedoraID.getMementoInstant());
151    }
152
153
154    @Test
155    public void testNormalWithHash() throws Exception {
156        final String testID = FEDORA_ID_PREFIX + "/first-object#hashURI";
157        final FedoraId fedoraID = FedoraId.create(testID);
158        assertResource(fedoraID, "HASH", testID, FEDORA_ID_PREFIX + "/first-object");
159        assertEquals("hashURI", fedoraID.getHashUri());
160    }
161
162    @Test
163    public void testAclWithHash() throws Exception {
164        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_ACL + "#hashURI";
165        final FedoraId fedoraID = FedoraId.create(testID);
166        assertResource(fedoraID, Arrays.asList("HASH", "ACL"), testID, FEDORA_ID_PREFIX + "/first-object");
167        assertEquals("hashURI", fedoraID.getHashUri());
168    }
169
170
171    @Test(expected = InvalidResourceIdentifierException.class)
172    public void testAclWithHashException() throws Exception {
173        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_ACL + "/garbage#hashURI";
174        final FedoraId fedoraID = FedoraId.create(testID);
175    }
176
177    @Test
178    public void testMetadataWithHash() throws Exception {
179        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "#hashURI";
180        final FedoraId fedoraID = FedoraId.create(testID);
181        assertResource(fedoraID, Arrays.asList("HASH", "METADATA"), testID, FEDORA_ID_PREFIX + "/first-object");
182        assertEquals("hashURI", fedoraID.getHashUri());
183    }
184
185    @Test(expected = InvalidResourceIdentifierException.class)
186    public void testMetadataAclWithHash() throws Exception {
187        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_ACL + "#hashURI";
188        final FedoraId fedoraID = FedoraId.create(testID);
189        assertResource(fedoraID, Arrays.asList("HASH", "METADATA", "ACL"), testID, FEDORA_ID_PREFIX +
190                "/first-object");
191        assertEquals("hashURI", fedoraID.getHashUri());
192    }
193
194    @Test(expected = InvalidResourceIdentifierException.class)
195    public void testMetadataAclWithHashException() throws Exception {
196        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_ACL + "/garbage#hashURI";
197        final FedoraId fedoraID = FedoraId.create(testID);
198    }
199
200    @Test
201    public void testTimemapWithHash() throws Exception {
202        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "#hashURI";
203        final FedoraId fedoraID = FedoraId.create(testID);
204        assertResource(fedoraID, Arrays.asList("HASH", "TIMEMAP"), testID, FEDORA_ID_PREFIX + "/first-object");
205        assertEquals("hashURI", fedoraID.getHashUri());
206    }
207
208    @Test
209    public void testMementoWithHash() throws Exception {
210        final String mementoString = "20101109231256";
211        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" +
212                mementoString + "#hashURI";
213        final FedoraId fedoraID = FedoraId.create(testID);
214        assertResource(fedoraID, Arrays.asList("HASH", "MEMENTO"), testID, FEDORA_ID_PREFIX + "/first-object");
215        assertEquals("hashURI", fedoraID.getHashUri());
216        assertEquals(mementoString, fedoraID.getMementoString());
217        final Instant mementoInstant = Instant.from(MEMENTO_LABEL_FORMATTER.parse(mementoString));
218        assertEquals(mementoInstant, fedoraID.getMementoInstant());
219    }
220
221    @Test(expected = InvalidMementoPathException.class)
222    public void testMementoWithHashException() throws Exception {
223        final String mementoString = "00001221010304";
224        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" + mementoString + "#hashURI";
225        final FedoraId fedoraID = FedoraId.create(testID);
226    }
227
228    @Test(expected = InvalidMementoPathException.class)
229    public void testMementoWithHashException2() throws Exception {
230        final String mementoString = "test-garbage";
231        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_VERSIONS + "/" + mementoString + "#hashURI";
232        final FedoraId fedoraID = FedoraId.create(testID);
233    }
234
235    @Test
236    public void testMetadataTimemapWithHash() throws Exception {
237        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "#hashURI";
238        final FedoraId fedoraID = FedoraId.create(testID);
239        assertResource(fedoraID, Arrays.asList("HASH", "METADATA", "TIMEMAP"), testID, FEDORA_ID_PREFIX +
240                "/first-object");
241        assertEquals("hashURI", fedoraID.getHashUri());
242    }
243
244    @Test
245    public void testMetadataMementoWithHash() throws Exception {
246        final String mementoString = "20101109231256";
247        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "/" +
248                mementoString + "#hashURI";
249        final FedoraId fedoraID = FedoraId.create(testID);
250        assertResource(fedoraID, Arrays.asList("HASH", "METADATA", "MEMENTO"), testID, FEDORA_ID_PREFIX +
251                "/first-object");
252        assertEquals("hashURI", fedoraID.getHashUri());
253        assertEquals(mementoString, fedoraID.getMementoString());
254        final Instant mementoInstant = Instant.from(MEMENTO_LABEL_FORMATTER.parse(mementoString));
255        assertEquals(mementoInstant, fedoraID.getMementoInstant());
256    }
257
258    @Test(expected = InvalidMementoPathException.class)
259    public void testMetadataMementoWithHashException() throws Exception {
260        final String mementoString = "00001221010304";
261        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "/" +
262                mementoString + "#hashURI";
263        final FedoraId fedoraID = FedoraId.create(testID);
264    }
265
266    @Test(expected = InvalidMementoPathException.class)
267    public void testMetadataMementoWithHashException1() throws Exception {
268        final String mementoString = "test-garbage";
269        final String testID = FEDORA_ID_PREFIX + "/first-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "/" +
270                mementoString + "#hashURI";
271        final FedoraId fedoraID = FedoraId.create(testID);
272    }
273
274    @Test
275    public void testCreateNull() {
276        final FedoraId fedoraID = FedoraId.create(null);
277        assertTrue(fedoraID.isRepositoryRoot());
278        assertEquals(FEDORA_ID_PREFIX, fedoraID.getFullId());
279    }
280
281    @Test
282    public void testCreateEmpty() {
283        final FedoraId fedoraID = FedoraId.create("");
284        assertTrue(fedoraID.isRepositoryRoot());
285        assertEquals(FEDORA_ID_PREFIX, fedoraID.getFullId());
286    }
287
288    @Test
289    public void testStringConcatenation() {
290        final FedoraId fedoraID = FedoraId.create("object1", "object2", "object3");
291        assertEquals(FEDORA_ID_PREFIX + "/object1/object2/object3", fedoraID.getFullId());
292    }
293
294    @Test
295    public void testResourceIdAddition() {
296        final FedoraId fedoraID = FedoraId.create("core-object", FCR_VERSIONS);
297        final FedoraId fedoraId1 = fedoraID.asAcl();
298        assertEquals(FEDORA_ID_PREFIX + "/core-object/" + FCR_ACL, fedoraId1.getFullId());
299    }
300
301    @Test
302    public void testFullIdAddition() {
303        final FedoraId fedoraID = FedoraId.create("core-object");
304        final FedoraId fedoraId1 = fedoraID.asMemento("20200401101900");
305        assertEquals(FEDORA_ID_PREFIX + "/core-object/" + FCR_VERSIONS + "/20200401101900", fedoraId1.getFullId());
306    }
307
308    @Test
309    public void testResourceIdAdditionMultiple() {
310        final FedoraId fedoraID = FedoraId.create("core-object", FCR_ACL);
311        final FedoraId fedoraId1 = fedoraID.asMemento("20200401110400");
312        assertEquals(FEDORA_ID_PREFIX + "/core-object/" + FCR_VERSIONS + "/20200401110400", fedoraId1.getFullId());
313    }
314
315    @Test
316    public void testFullIdAdditionMultiple() {
317        final FedoraId fedoraID = FedoraId.create("core-object", FCR_METADATA);
318        final FedoraId fedoraId1 = fedoraID.asMemento("20200401110400");
319        assertEquals(FEDORA_ID_PREFIX + "/core-object/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401110400",
320                fedoraId1.getFullId());
321    }
322
323    @Test(expected = IllegalArgumentException.class)
324    public void testResolveBlank() {
325        final FedoraId fedoraId = FedoraId.create("core-object");
326        fedoraId.resolve(null);
327    }
328
329    @Test(expected = IllegalArgumentException.class)
330    public void testResolveEmptyString() {
331        final FedoraId fedoraId = FedoraId.create("core-object");
332        fedoraId.resolve("");
333    }
334
335    @Test(expected = InvalidResourceIdentifierException.class)
336    public void testDoubleAcl() {
337        FedoraId.create("core-object/" + FCR_ACL + "/" + FCR_ACL);
338    }
339
340    @Test
341    public void testAsMemento() {
342        assertAsMemento("original/" + FCR_METADATA + "/" + FCR_VERSIONS,
343                "original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101900");
344        assertAsMemento("original/" + FCR_METADATA + "#blah",
345                "original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101900#blah");
346        assertAsMemento("original/" + FCR_VERSIONS,
347                "original/" + FCR_VERSIONS + "/20200401101900");
348        assertAsMemento("original/" + FCR_TOMBSTONE,
349                "original/" + FCR_VERSIONS + "/20200401101900");
350        assertAsMemento("original/" + FCR_ACL,
351                "original/" + FCR_VERSIONS + "/20200401101900");
352        assertAsMemento("original/" + FCR_VERSIONS + "/20200401101901",
353                "original/" + FCR_VERSIONS + "/20200401101901");
354        assertAsMemento("original/child",
355                "original/child/" + FCR_VERSIONS + "/20200401101900");
356        assertAsMemento("original/child#sad",
357                "original/child/" + FCR_VERSIONS + "/20200401101900#sad");
358    }
359
360    @Test
361    public void testAsTimemap() {
362        assertAsTimemap("original/" + FCR_METADATA + "/" + FCR_VERSIONS,
363                "original/" + FCR_METADATA + "/" + FCR_VERSIONS);
364        assertAsTimemap("original/" + FCR_METADATA + "#blah",
365                "original/" + FCR_METADATA + "/" + FCR_VERSIONS);
366        assertAsTimemap("original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901",
367                "original/" + FCR_METADATA + "/" + FCR_VERSIONS);
368        assertAsTimemap("original/" + FCR_VERSIONS,
369                "original/" + FCR_VERSIONS);
370        assertAsTimemap("original/" + FCR_TOMBSTONE,
371                "original/" + FCR_VERSIONS);
372        assertAsTimemap("original/" + FCR_ACL,
373                "original/" + FCR_VERSIONS);
374        assertAsTimemap("original/" + FCR_VERSIONS + "/20200401101900",
375                "original/" + FCR_VERSIONS);
376        assertAsTimemap("original/child",
377                "original/child/" + FCR_VERSIONS);
378        assertAsTimemap("original/child#sad",
379                "original/child/" + FCR_VERSIONS);
380    }
381
382    @Test
383    public void testAsDescription() {
384        assertAsDescription("original/" + FCR_METADATA + "/" + FCR_VERSIONS,
385                "original/" + FCR_METADATA + "/" + FCR_VERSIONS);
386        assertAsDescription("original/" + FCR_METADATA + "#blah",
387                "original/" + FCR_METADATA + "#blah");
388        assertAsDescription("original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901",
389                "original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901");
390        assertAsDescription("original/" + FCR_VERSIONS,
391                "original/" + FCR_METADATA + "/" + FCR_VERSIONS);
392        assertAsDescription("original/" + FCR_TOMBSTONE,
393                "original/" + FCR_METADATA);
394        assertAsDescription("original/" + FCR_ACL,
395                "original/" + FCR_METADATA);
396        assertAsDescription("original/" + FCR_VERSIONS + "/20200401101900",
397                "original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101900");
398        assertAsDescription("original/child",
399                "original/child/" + FCR_METADATA);
400        assertAsDescription("original/child#sad",
401                "original/child/" + FCR_METADATA + "#sad");
402    }
403
404    @Test
405    public void testAsTombstone() {
406        final var tombstone = "original/" + FCR_TOMBSTONE;
407        assertAsTombstone("original/" + FCR_METADATA + "/" + FCR_VERSIONS, tombstone);
408        assertAsTombstone("original/" + FCR_METADATA + "#blah", tombstone);
409        assertAsTombstone("original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901", tombstone);
410        assertAsTombstone("original/" + FCR_VERSIONS, tombstone);
411        assertAsTombstone("original/" + FCR_TOMBSTONE, tombstone);
412        assertAsTombstone("original/" + FCR_ACL, tombstone);
413        assertAsTombstone("original/" + FCR_VERSIONS + "/20200401101900", tombstone);
414        assertAsTombstone("original/child", "original/child/" + FCR_TOMBSTONE);
415        assertAsTombstone("original/child#sad", "original/child/" + FCR_TOMBSTONE);
416    }
417
418    @Test
419    public void testAsAcl() {
420        final var acl = "original/" + FCR_ACL;
421        assertAsAcl("original/" + FCR_METADATA + "/" + FCR_VERSIONS, acl);
422        assertAsAcl("original/" + FCR_METADATA + "#blah", acl);
423        assertAsAcl("original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901", acl);
424        assertAsAcl("original/" + FCR_VERSIONS, acl);
425        assertAsAcl("original/" + FCR_TOMBSTONE, acl);
426        assertAsAcl("original/" + FCR_ACL, acl);
427        assertAsAcl("original/" + FCR_VERSIONS + "/20200401101900", acl);
428        assertAsAcl("original/child", "original/child/" + FCR_ACL);
429        assertAsAcl("original/child#sad", "original/child/" + FCR_ACL);
430    }
431
432    @Test
433    public void testEncodedId() {
434        // Slashes are not encoded.
435        final String normal = "/object/child";
436        final var normalId = FedoraId.create(normal);
437        assertEquals(FEDORA_ID_PREFIX + normal, normalId.getEncodedFullId());
438        assertEquals(FEDORA_ID_PREFIX + normal, normalId.getFullId());
439        // Colons are not encoded.
440        final String withColon = "/object/test:prefix";
441        final var withColonId = FedoraId.create(withColon);
442        assertEquals(FEDORA_ID_PREFIX + withColon, withColonId.getEncodedFullId());
443        assertEquals(FEDORA_ID_PREFIX + withColon, withColonId.getFullId());
444        // Hashes are not encoded.
445        final String withHash = "/object/with#hash";
446        final var withHashId = FedoraId.create(withHash);
447        assertEquals(FEDORA_ID_PREFIX + withHash, withHashId.getEncodedFullId());
448        assertEquals(FEDORA_ID_PREFIX + withHash, withHashId.getFullId());
449        // Query string characters (? & =) are not encoded.
450        final String withQueryString = "/object/with?query=parameters&for=uris";
451        final var withQueryStringId = FedoraId.create(withQueryString);
452        assertEquals(FEDORA_ID_PREFIX + withQueryString, withQueryStringId.getEncodedFullId());
453        assertEquals(FEDORA_ID_PREFIX + withQueryString, withQueryStringId.getFullId());
454        // Plus and minus (hyphens) signs are not encoded
455        final String plus_sign = "/object/one+two/three-four";
456        final var plus_signId = FedoraId.create(plus_sign);
457        assertEquals(FEDORA_ID_PREFIX + plus_sign, plus_signId.getEncodedFullId());
458        assertEquals(FEDORA_ID_PREFIX + plus_sign, plus_signId.getFullId());
459        // Remaining URI sub-deliminators are not encoded
460        final String sub_delims = "/object/with!/some$weird/possibly'unstable/group(ing)/all*/comma,comma/and;this";
461        final var sub_delimsId = FedoraId.create(sub_delims);
462        assertEquals(FEDORA_ID_PREFIX + sub_delims, sub_delimsId.getEncodedFullId());
463        assertEquals(FEDORA_ID_PREFIX + sub_delims, sub_delimsId.getFullId());
464
465        // Spaces ARE encoded.
466        final String with_space = "/object/has a space";
467        final var with_space_id = FedoraId.create(with_space);
468        assertEquals(FEDORA_ID_PREFIX + "/object/has%20a%20space", with_space_id.getEncodedFullId());
469        assertEquals(FEDORA_ID_PREFIX + with_space, with_space_id.getFullId());
470
471        // Encoded spaces are double encoded
472        final String with_encoded_space = "/object/has%20a%20space";
473        final var with_encoded_space_id = FedoraId.create(with_encoded_space);
474        assertEquals(FEDORA_ID_PREFIX + "/object/has%2520a%2520space", with_encoded_space_id.getEncodedFullId());
475        assertEquals(FEDORA_ID_PREFIX + with_encoded_space, with_encoded_space_id.getFullId());
476    }
477
478    @Test
479    public void verifyStorageNamingRestrictions() {
480        assertIdStringConstraint(".fcrepo");
481        assertIdStringConstraint("fcr-root");
482        assertIdStringConstraint("fcr-container.nt");
483
484        assertIdSuffixConstraint("~fcr-desc");
485        assertIdSuffixConstraint("~fcr-acl");
486        assertIdSuffixConstraint("~fcr-desc.nt");
487        assertIdSuffixConstraint("~fcr-acl.nt");
488    }
489
490    @Test
491    public void testAsDescribedId() {
492        assertAsDescribedId("original" + "/" + FCR_METADATA + "/" + FCR_VERSIONS,
493                "original/" + FCR_VERSIONS);
494        assertAsDescribedId("original/" + FCR_METADATA + "#blah",
495                "original" + "#blah");
496        assertAsDescribedId("original/" + FCR_METADATA + "/" + FCR_VERSIONS + "/20200401101901",
497                "original/" + FCR_VERSIONS + "/20200401101901");
498        assertAsDescribedId("original/" + FCR_VERSIONS,
499                "original/" + FCR_VERSIONS);
500        assertAsDescribedId("original/" + FCR_VERSIONS + "/20200401101900",
501                "original/" + FCR_VERSIONS + "/20200401101900");
502        assertAsDescribedId("original/" + FCR_TOMBSTONE,
503                "original/" + FCR_TOMBSTONE);
504        assertAsDescribedId("original/" + FCR_ACL,
505                "original/" + FCR_ACL);
506        assertAsDescribedId("original/child/" + FCR_METADATA,
507                "original/child");
508        assertAsDescribedId("original/child/" + FCR_METADATA + "#sad",
509                "original/child#sad");
510    }
511
512    private void assertAsMemento(final String original, final String expected) {
513        final var id = FedoraId.create(original);
514        assertEquals(FedoraTypes.FEDORA_ID_PREFIX + "/" + expected,
515                id.asMemento("20200401101900").getFullId());
516    }
517
518    private void assertAsTimemap(final String original, final String expected) {
519        final var id = FedoraId.create(original);
520        assertEquals(FedoraTypes.FEDORA_ID_PREFIX + "/" + expected,
521                id.asTimemap().getFullId());
522    }
523
524    private void assertAsTombstone(final String original, final String expected) {
525        final var id = FedoraId.create(original);
526        assertEquals(FedoraTypes.FEDORA_ID_PREFIX + "/" + expected,
527                id.asTombstone().getFullId());
528    }
529
530    private void assertAsAcl(final String original, final String expected) {
531        final var id = FedoraId.create(original);
532        assertEquals(FedoraTypes.FEDORA_ID_PREFIX + "/" + expected,
533                id.asAcl().getFullId());
534    }
535
536    private void assertAsDescription(final String original, final String expected) {
537        final var id = FedoraId.create(original);
538        assertEquals(FedoraTypes.FEDORA_ID_PREFIX + "/" + expected,
539                id.asDescription().getFullId());
540    }
541
542    private void assertAsDescribedId(final String original, final String expected) {
543        final var id = FedoraId.create(original);
544        assertEquals(FEDORA_ID_PREFIX + "/" + expected,
545                id.getFullDescribedId());
546    }
547
548    /**
549     * Utility to test a FedoraId against expectations.
550     * @param fedoraID The FedoraId object to test.
551     * @param type A string type of "ROOT", "ACL", "METADATA", "TIMEMAP", "MEMENTO" and "HASH"
552     * @param fullID The expected full ID.
553     * @param shortID The expected short ID.
554     */
555    private void assertResource(final FedoraId fedoraID, final String type, final String fullID, final String shortID) {
556        assertResource(fedoraID, Collections.singletonList(type), fullID, shortID);
557    }
558
559    /**
560     * Utility to test a FedoraId against expectations.
561     * @param fedoraID The FedoraId object to test.
562     * @param type A list of string type of "ROOT", "ACL", "METADATA", "TIMEMAP", "MEMENTO" and "HASH"
563     * @param fullID The expected full ID.
564     * @param shortID The expected short ID.
565     */
566    private void assertResource(final FedoraId fedoraID, final List<String> type, final String fullID,
567                                final String shortID) {
568        if (type.contains("ROOT")) {
569            assertTrue(fedoraID.isRepositoryRoot());
570        } else {
571            assertFalse(fedoraID.isRepositoryRoot());
572        }
573        if (type.contains("ACL")) {
574            assertTrue(fedoraID.isAcl());
575        } else {
576            assertFalse(fedoraID.isAcl());
577        }
578        if (type.contains("METADATA")) {
579            assertTrue(fedoraID.isDescription());
580        } else {
581            assertFalse(fedoraID.isDescription());
582        }
583        if (type.contains("HASH")) {
584            assertTrue(fedoraID.isHashUri());
585        } else {
586            assertFalse(fedoraID.isHashUri());
587        }
588        if (type.contains("MEMENTO")) {
589            assertTrue(fedoraID.isMemento());
590        } else {
591            assertFalse(fedoraID.isMemento());
592        }
593        if (type.contains("TIMEMAP")) {
594            assertTrue(fedoraID.isTimemap());
595        } else {
596            assertFalse(fedoraID.isTimemap());
597        }
598        assertEquals(fullID, fedoraID.getFullId());
599        assertEquals(shortID, fedoraID.getBaseId());
600    }
601
602    private void assertIdStringConstraint(final String id) {
603        assertInvalidId(id);
604        FedoraId.create(id + "-suffix");
605        FedoraId.create("prefix-" + id);
606    }
607
608    private void assertIdSuffixConstraint(final String suffix) {
609        assertInvalidId("prefix" + suffix);
610        FedoraId.create(suffix);
611        FedoraId.create(suffix + "-suffix");
612    }
613
614    private void assertInvalidId(final String id) {
615        try {
616            FedoraId.create(id);
617            fail("should have thrown an exception creating id: " + id);
618        } catch (final InvalidResourceIdentifierException e) {
619            // expected exception
620        }
621    }
622
623}