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