001/*
002 * Copyright 2020 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.common;
017
018import org.gbif.api.SerdeTestUtils;
019
020import java.io.IOException;
021import java.net.URI;
022import java.net.URLEncoder;
023import java.util.Objects;
024
025import org.junit.jupiter.api.Test;
026
027import static org.junit.jupiter.api.Assertions.assertEquals;
028import static org.junit.jupiter.api.Assertions.assertFalse;
029import static org.junit.jupiter.api.Assertions.assertTrue;
030import static org.junit.jupiter.api.Assertions.fail;
031
032public class DOITest {
033
034  @Test
035  public void testPrefixConstructor() {
036    DOI d = new DOI("10.1234", "1ASCDU");
037    assertEquals(d, new DOI("doi:10.1234/1ASCDU"));
038  }
039
040  @Test
041  public void testIsParsable() {
042    assertFalse(DOI.isParsable(null));
043    assertFalse(DOI.isParsable(""));
044    assertFalse(DOI.isParsable("10.1234.1ASCDU"));
045    assertFalse(DOI.isParsable("DOI:123"));
046    assertFalse(DOI.isParsable("   "));
047
048    assertTrue(DOI.isParsable("http://dx.doi.org/urn:doi:10.1234/1ASCDU"));
049    assertTrue(DOI.isParsable("http://doi.org/urn:doi:10.1234/1ASCDU"));
050    assertTrue(DOI.isParsable("http://dx.doi.org/doi:10.1234/1ASCDU"));
051    assertTrue(DOI.isParsable("http://doi.org/doi:10.1234/1ASCDU"));
052    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234/1ASCDU"));
053    assertTrue(DOI.isParsable("http://doi.org/10.1234/1ASCDU"));
054    assertTrue(DOI.isParsable("https://dx.doi.org/10.1234/1ASCDU"));
055    assertTrue(DOI.isParsable("https://doi.org/10.1234/1ASCDU"));
056
057    assertTrue(DOI.isParsable("doi:10.1234/1ASCDU"));
058    assertTrue(DOI.isParsable("urn:doi:10.1234/1ASCDU"));
059    assertTrue(DOI.isParsable("doi:10.1234/1ASCDU"));
060    assertTrue(DOI.isParsable("urn:doi:10.1234/1ASCDU"));
061    assertTrue(DOI.isParsable("doi:10.1234/1ascdu"));
062    assertTrue(DOI.isParsable("urn:doi:10.1234/1ascdu"));
063    assertTrue(DOI.isParsable("10.1234/1ascdu"));
064    assertTrue(DOI.isParsable("10.1234/1ASCDU"));
065
066    // This is real.
067    assertTrue(DOI.isParsable("10.1643/0045-8511(2007)2007[699:Tnvsot]2.0.Co;2"));
068    assertTrue(DOI.isParsable("doi:10.1643/0045-8511(2007)2007[699:Tnvsot]2.0.Co;2"));
069    assertTrue(DOI.isParsable("https://doi.org/10.1643/0045-8511(2007)2007%5b699%3aTnvsot%5d2.0.Co%3b2"));
070
071    // try subdivisions
072    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234.999/1ASCDU"));
073    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234.999.123/1ASCDU"));
074    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234.999.123/1ASCDU/more/and/more"));
075    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234.999.123/1ASCDU.more.and/more"));
076    assertTrue(DOI.isParsable("http://dx.doi.org/10.1234.999.123/unicode-isällöwéd_h&$e"));
077  }
078
079  @Test
080  public void testCreate() {
081    DOI d = new DOI("http://dx.doi.org/10.1234/1ASCDU");
082
083    assertSame(d, "http://dx.doi.org/urn:doi:10.1234/1ASCDU");
084    assertSame(d, "http://doi.org/urn:doi:10.1234/1ASCDU");
085    assertSame(d, "http://dx.doi.org/doi:10.1234/1ASCDU");
086    assertSame(d, "http://doi.org/doi:10.1234/1ASCDU");
087    assertSame(d, "http://dx.doi.org/10.1234/1ASCDU");
088    assertSame(d, "http://doi.org/10.1234/1ASCDU");
089    assertSame(d, "https://dx.doi.org/10.1234/1ASCDU");
090    assertSame(d, "https://doi.org/10.1234/1ASCDU");
091
092    assertSame(d, "doi:10.1234/1ASCDU");
093    assertSame(d, "urn:doi:10.1234/1ASCDU");
094    assertSame(d, "doi:10.1234/1ASCDU");
095    assertSame(d, "urn:doi:10.1234/1ASCDU");
096    assertSame(d, "doi:10.1234/1ascdu");
097    assertSame(d, "urn:doi:10.1234/1ascdu");
098    assertSame(d, "10.1234/1ascdu");
099    assertSame(d, "10.1234/1ASCDU");
100
101    new DOI("https://doi.org/10.1643/0045-8511(2007)2007%5b699%3aTnvsot%5d2.0.Co%3b2");
102
103    // try subdivisions
104    new DOI("http://dx.doi.org/10.1234.999/1ASCDU");
105    new DOI("http://dx.doi.org/10.1234.999.123/1ASCDU");
106    new DOI("http://dx.doi.org/10.1234.999.123/1ASCDU/more/and/more");
107    new DOI("http://dx.doi.org/10.1234.999.123/1ASCDU.more.and/more");
108    new DOI("http://dx.doi.org/10.1234.999.123/unicode-isällöwéd_h&$e");
109
110    // try invalid ones
111    assertInvalid("uri:doi:10.1234/1ascdu");
112    assertInvalid("doi::10.1234/1ascdu");
113    assertInvalid("10/1234/1ascdu");
114    assertInvalid("doi");
115    assertInvalid("Tim Robertson");
116    assertInvalid("http://dx.doi.org");
117    assertInvalid("http://dx.doi.org/10");
118    assertInvalid("http://doi.org");
119    assertInvalid("http://doi.org/10.453621432764678123");
120    assertInvalid("http://dx.doi.org/11.1234.999/1ASCDU");
121  }
122
123  @Test
124  public void testUrlConversion() throws Exception {
125    DOI d = new DOI("http://doi.org/10.1000/456%23789");
126    assertEquals("456%23789", d.getSuffix());
127    assertSame(d, "10.1000/456%23789");
128
129    //getUrl will be returned as https (preferred http://www.doi.org/doi_handbook/3_Resolution.html)
130    assertEquals(URI.create("https://doi.org/10.1000/" + URLEncoder.encode("456%23789", "UTF-8")), d.getUrl());
131  }
132
133  private void assertSame(DOI doi, String doi2) {
134    DOI d2 = new DOI(doi2);
135    assertEquals(d2, doi);
136  }
137
138  private void assertInvalid(String doi) {
139    try {
140      new DOI(doi);
141      fail("Invalid DOI expected: " + doi);
142    } catch (IllegalArgumentException e) {
143      // expected!
144    }
145  }
146
147  /**
148   * A container of Languages using 2 properties.
149   */
150  private static class Container {
151
152    public DOI doi1;
153    public DOI doi2; // verify that the names don't matter
154
155    public Container(DOI doi1, DOI doi2) {
156      this.doi1 = doi1;
157      this.doi2 = doi2;
158    }
159
160    // used by serializer below
161    public Container() {
162    }
163
164    @Override
165    public boolean equals(Object o) {
166      if (this == o) {
167        return true;
168      }
169      if (o == null || getClass() != o.getClass()) {
170        return false;
171      }
172      Container container = (Container) o;
173      return Objects.equals(doi1, container.doi1) &&
174        Objects.equals(doi2, container.doi2);
175    }
176
177    @Override
178    public int hashCode() {
179      return Objects.hash(doi1, doi2);
180    }
181  }
182
183  @Test
184  public void testSerDe() throws IOException {
185    DOI d = new DOI("10.1234", "1ASCDU");
186    SerdeTestUtils.testSerDe(d, DOI.class);
187
188    Container source = new Container(new DOI("doi:10.1038/nature.2014.16460"), new DOI("http://dx.doi.org/10.1034/gbif.2014.xscdf2"));
189    try {
190      String json = SerdeTestUtils.testSerDe(source, Container.class);
191      assertFalse(json.contains("doi:10."), "DOIs should be shown without a scheme");
192      assertFalse(json.contains("http"), "DOIs should not use http resolvers");
193      assertFalse(json.contains("doi.org"), "DOIs should not use http resolvers");
194      System.out.println(json);
195    } catch (Exception e) {
196      fail(e.getMessage());
197    }
198  }
199}