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.checklistbank;
017
018import org.gbif.api.SerdeTestUtils;
019import org.gbif.api.vocabulary.NamePart;
020import org.gbif.api.vocabulary.NameType;
021import org.gbif.api.vocabulary.Rank;
022
023import java.io.IOException;
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.assertNull;
030import static org.junit.jupiter.api.Assertions.assertTrue;
031
032public class ParsedNameTest {
033
034  @Test
035  public void testCanonicalName() {
036    ParsedName pn = new ParsedName();
037    pn.setGenusOrAbove("Abies");
038    assertEquals("Abies", pn.canonicalName());
039
040    pn.setSpecificEpithet("alba");
041    assertEquals("Abies alba", pn.canonicalName());
042
043    pn = new ParsedName();
044    pn.setGenusOrAbove("Abies");
045    pn.setSpecificEpithet("alba");
046    pn.setRank(Rank.VARIETY);
047    pn.setAuthorship("Mill.");
048    pn.setBracketAuthorship("Carl.");
049    pn.setNotho(NamePart.GENERIC);
050    pn.setInfraSpecificEpithet("alpina");
051    pn.setYear("1887");
052    pn.setSensu("Döring");
053    pn.setRemarks("lost");
054    pn.setNomStatus("nom. illeg.");
055    pn.setParsedPartially(true);
056
057    assertEquals("Abies alba alpina", pn.canonicalName());
058    assertEquals("×Abies alba var. alpina", pn.canonicalNameWithMarker());
059    assertEquals("×Abies alba var. alpina (Carl.) Mill., 1887", pn.canonicalNameComplete());
060    assertEquals("Abies alba", pn.canonicalSpeciesName());
061    assertEquals("×Abies alba var. alpina (Carl.) Mill., 1887 Döring, nom. illeg. [lost]", pn.fullName());
062
063    pn.setGenusOrAbove(null);
064    assertEquals("alba alpina", pn.canonicalName());
065    assertEquals("alba var. alpina", pn.canonicalNameWithMarker());
066    assertEquals("alba var. alpina (Carl.) Mill., 1887", pn.canonicalNameComplete());
067    assertNull(pn.canonicalSpeciesName());
068    assertEquals("alba var. alpina (Carl.) Mill., 1887 Döring, nom. illeg. [lost]", pn.fullName());
069  }
070
071  @Test
072  public void testTerminalEpithet() {
073    ParsedName pn = new ParsedName();
074    pn.setGenusOrAbove("Abies");
075    assertNull(pn.getTerminalEpithet());
076
077    pn.setInfraSpecificEpithet("abieta");
078    assertEquals("abieta", pn.getTerminalEpithet());
079
080    pn.setSpecificEpithet("vulgaris");
081    assertEquals("abieta", pn.getTerminalEpithet());
082
083    pn.setInfraSpecificEpithet(null);
084    assertEquals("vulgaris", pn.getTerminalEpithet());
085
086    pn.setGenusOrAbove(null);
087    assertEquals("vulgaris", pn.getTerminalEpithet());
088  }
089
090  @Test
091  public void testIndet() {
092    ParsedName pn = new ParsedName();
093    pn.setType(NameType.SCIENTIFIC);
094    pn.setGenusOrAbove("Abies");
095    assertFalse(pn.isIndetermined());
096
097    pn.setRank(Rank.SPECIES);
098    assertTrue(pn.isIndetermined());
099
100    for (NameType t : NameType.values()) {
101      pn.setType(t);
102      if (t.isParsable()) {
103        assertTrue(pn.isIndetermined());
104      } else {
105        assertFalse(pn.isIndetermined());
106      }
107    }
108    pn.setType(NameType.SCIENTIFIC);
109
110    pn.setSpecificEpithet("vulgaris");
111    assertFalse(pn.isIndetermined());
112
113    pn.setRank(Rank.SUBSPECIES);
114    assertTrue(pn.isIndetermined());
115
116    pn.setInfraSpecificEpithet("kingkong");
117    assertFalse(pn.isIndetermined());
118
119    for (Rank r : Rank.values()) {
120      if (r.isInfraspecific()) {
121        assertFalse(pn.isIndetermined(), r.toString());
122      }
123    }
124
125    pn.setInfraSpecificEpithet(null);
126    for (Rank r : Rank.values()) {
127      if (r.isInfraspecific()) {
128        assertTrue(pn.isIndetermined(), r.toString());
129      }
130    }
131
132    pn.setRank(Rank.SUBGENUS);
133    pn.setSpecificEpithet(null);
134    assertTrue(pn.isIndetermined());
135
136    pn.setInfraGeneric("Mysubgenus");
137    assertFalse(pn.isIndetermined());
138
139    pn = new ParsedName();
140    pn.setType(NameType.SCIENTIFIC);
141    pn.setRank(Rank.SPECIES_AGGREGATE);
142    pn.setGenusOrAbove("Achillea");
143    pn.setSpecificEpithet("millefolium");
144    pn.setAuthorship("L.");
145    assertFalse(pn.isIndetermined());
146  }
147
148  @Test
149  public void testCanonicalAscii() {
150    ParsedName pn = new ParsedName();
151    pn.setGenusOrAbove("Abies");
152    pn.setSpecificEpithet("vülgårîs");
153    pn.setInfraSpecificEpithet("æbiéñtø");
154    assertEquals("Abies vulgaris aebiento", pn.canonicalName());
155  }
156
157  @Test
158  public void testUnparsableCanonical() {
159    ParsedName pn = new ParsedName();
160    pn.setScientificName("? hostilis Gravenhorst, 1829");
161    pn.setType(NameType.PLACEHOLDER);
162    assertNull(pn.canonicalName());
163  }
164
165  /**
166   * http://dev.gbif.org/issues/browse/POR-2624
167   */
168  @Test
169  public void testSubgenus() {
170    // Brachyhypopomus (Odontohypopomus) Sullivan, Zuanon & Cox Fernandes, 2013
171    ParsedName pn = new ParsedName();
172    pn.setGenusOrAbove("Brachyhypopomus");
173    pn.setInfraGeneric("Odontohypopomus");
174    pn.setAuthorship("Sullivan, Zuanon & Cox Fernandes");
175    pn.setYear("2013");
176    assertEquals("Odontohypopomus", pn.canonicalName());
177    assertEquals("Odontohypopomus", pn.canonicalNameWithMarker());
178    assertEquals("Brachyhypopomus (Odontohypopomus) Sullivan, Zuanon & Cox Fernandes, 2013", pn.canonicalNameComplete());
179    // with given rank marker it is shown instead of brackets
180    pn.setRank(Rank.SUBGENUS);
181    assertEquals("Odontohypopomus", pn.canonicalName());
182    assertEquals("subgen. Odontohypopomus", pn.canonicalNameWithMarker());
183    assertEquals("Brachyhypopomus subgen. Odontohypopomus Sullivan, Zuanon & Cox Fernandes, 2013", pn.canonicalNameComplete());
184
185    // Achillea sect. Ptarmica (Mill.) W.D.J.Koch
186    pn = new ParsedName();
187    pn.setGenusOrAbove("Achillea");
188    pn.setInfraGeneric("Ptarmica");
189    pn.setAuthorship("W.D.J.Koch");
190    pn.setBracketAuthorship("Mill.");
191
192    assertEquals("Ptarmica", pn.canonicalName());
193    assertEquals("Achillea (Ptarmica) (Mill.) W.D.J.Koch", pn.canonicalNameComplete());
194    pn.setRank(Rank.SECTION);
195    assertEquals("Achillea sect. Ptarmica (Mill.) W.D.J.Koch", pn.canonicalNameComplete());
196  }
197
198  @Test
199  public void testBuildName() {
200    ParsedName pn = new ParsedName();
201    pn.setGenusOrAbove("Pseudomonas");
202    assertBuildName(pn, "Pseudomonas");
203
204    pn.setSpecificEpithet("syringae");
205    assertBuildName(pn, "Pseudomonas syringae");
206
207    pn.setParsedPartially(true);
208    pn.setAuthorship("Van Hall");
209    assertBuildName(pn, "Pseudomonas syringae Van Hall", "Pseudomonas syringae", "Pseudomonas syringae Van Hall", "Pseudomonas syringae");
210
211    pn.setYear("1904");
212    assertBuildName(pn, "Pseudomonas syringae Van Hall, 1904", "Pseudomonas syringae", "Pseudomonas syringae Van Hall, 1904", "Pseudomonas syringae");
213
214    pn.setBracketAuthorship("Carl.");
215    assertBuildName(pn, "Pseudomonas syringae (Carl.) Van Hall, 1904", "Pseudomonas syringae", "Pseudomonas syringae (Carl.) Van Hall, 1904", "Pseudomonas syringae");
216
217    pn.setRank(Rank.PATHOVAR);
218    pn.setInfraSpecificEpithet("aceris");
219    pn.setBracketAuthorship(null);
220    assertBuildName(pn, "Pseudomonas syringae pv. aceris Van Hall, 1904", "Pseudomonas syringae aceris", "Pseudomonas syringae pv. aceris Van Hall, 1904", "Pseudomonas syringae pv. aceris");
221
222    pn.setStrain("CFBP 2339");
223    assertBuildName(pn, "Pseudomonas syringae pv. aceris Van Hall, 1904 CFBP 2339", "Pseudomonas syringae aceris", "Pseudomonas syringae pv. aceris Van Hall, 1904 CFBP 2339", "Pseudomonas syringae pv. aceris CFBP 2339");
224
225    pn.setYear(null);
226    pn.setAuthorship(null);
227    assertBuildName(pn, "Pseudomonas syringae pv. aceris CFBP 2339", "Pseudomonas syringae aceris", "Pseudomonas syringae pv. aceris CFBP 2339", "Pseudomonas syringae pv. aceris CFBP 2339");
228
229    pn = new ParsedName();
230    pn.setGenusOrAbove("Abax");
231    pn.setSpecificEpithet("carinatus");
232    pn.setInfraSpecificEpithet("carinatus");
233    pn.setBracketAuthorship("Duftschmid");
234    pn.setBracketYear("1812");
235    pn.setRank(Rank.UNRANKED);
236    assertBuildName(pn, "Abax carinatus carinatus", "Abax carinatus carinatus", "Abax carinatus carinatus", "Abax carinatus carinatus");
237
238    pn.setRank(null);
239    assertBuildName(pn, "Abax carinatus carinatus", "Abax carinatus carinatus", "Abax carinatus carinatus", "Abax carinatus carinatus");
240
241    pn.setInfraSpecificEpithet("urinatus");
242    assertBuildName(pn, "Abax carinatus urinatus (Duftschmid, 1812)", "Abax carinatus urinatus", "Abax carinatus urinatus (Duftschmid, 1812)", "Abax carinatus urinatus");
243
244    pn.setRank(null);
245    assertBuildName(pn, "Abax carinatus urinatus (Duftschmid, 1812)", "Abax carinatus urinatus", "Abax carinatus urinatus (Duftschmid, 1812)", "Abax carinatus urinatus");
246
247    pn.setRank(Rank.SUBSPECIES);
248    assertBuildName(pn, "Abax carinatus subsp. urinatus (Duftschmid, 1812)", "Abax carinatus urinatus", "Abax carinatus subsp. urinatus (Duftschmid, 1812)", "Abax carinatus subsp. urinatus");
249
250    pn = new ParsedName();
251    pn.setGenusOrAbove("Polypodium");
252    pn.setSpecificEpithet("vulgare");
253    pn.setInfraSpecificEpithet("mantoniae");
254    pn.setBracketAuthorship("Rothm.");
255    pn.setAuthorship("Schidlay");
256    pn.setRank(Rank.SUBSPECIES);
257    pn.setNotho(NamePart.INFRASPECIFIC);
258    assertBuildName(pn, "Polypodium vulgare nothosubsp. mantoniae (Rothm.) Schidlay",
259        "Polypodium vulgare mantoniae",
260        "Polypodium vulgare nothosubsp. mantoniae (Rothm.) Schidlay",
261        "Polypodium vulgare nothosubsp. mantoniae");
262
263    pn = new ParsedName();
264    pn.setGenusOrAbove("Polypodium");
265    pn.setSpecificEpithet("vulgare");
266    pn.setInfraSpecificEpithet("mantoniae");
267    pn.setRank(Rank.INFRASPECIFIC_NAME);
268    assertBuildName(pn, "Polypodium vulgare mantoniae",
269        "Polypodium vulgare mantoniae",
270        "Polypodium vulgare mantoniae",
271        "Polypodium vulgare mantoniae");
272
273    // unparsable names
274    pn = new ParsedName();
275    for (NameType t : NameType.values()) {
276      if (!t.isParsable()) {
277        pn.setType(t);
278        pn.setScientificName("SH035824.07FU");
279        for (Rank r : Rank.values()) {
280          pn.setRank(r);
281          assertBuildName(pn, null, null, null, null);
282        }
283      }
284    }
285  }
286
287  @Test
288  public void testJsonSerde() throws IOException {
289    ParsedName pn = new ParsedName();
290    pn.setGenusOrAbove("Brachyhypopomus");
291    pn.setInfraGeneric("Odontohypopomus");
292    pn.setAuthorship("Sullivan, Zuanon & Cox Fernandes");
293    pn.setYear("2013");
294    pn.setRank(Rank.SUBGENUS);
295    SerdeTestUtils.testSerDe(pn, ParsedName.class);
296
297    pn = new ParsedName();
298    pn.setKey(123);
299    pn.setType(NameType.SCIENTIFIC);
300    pn.setGenusOrAbove("Abax");
301    pn.setSpecificEpithet("carinatus");
302    pn.setInfraSpecificEpithet("carinatus");
303    pn.setBracketAuthorship("Duftschmid");
304    pn.setBracketYear("1812");
305    pn.setRank(Rank.INFRASUBSPECIFIC_NAME);
306    SerdeTestUtils.testSerDe(pn, ParsedName.class);
307
308    pn.setAuthorship("Carlos & Kamera");
309    pn.setYear("1999");
310
311    for (Rank rank : Rank.values()) {
312      pn.setRank(rank);
313      // UNRANKED intentionally becomes null!
314      if (rank.notOtherOrUnknown()) {
315        String json = SerdeTestUtils.testSerDe(pn, ParsedName.class);
316        assertTrue(json.contains("\"rankMarker\""));
317      }
318    }
319    // check that rankMarker=null gets removed from json
320    pn.setRank(null);
321    String json = SerdeTestUtils.serialize(pn);
322    assertFalse(json.contains("\"rankMarker\""));
323  }
324
325  /**
326   * assert all build name methods return the same string
327   * @param name expected string
328   */
329  private void assertBuildName(ParsedName pn, String name) {
330    assertEquals(name, pn.fullName());
331    assertEquals(name, pn.canonicalName());
332    assertEquals(name, pn.canonicalNameComplete());
333    assertEquals(name, pn.canonicalNameWithMarker());
334  }
335
336  private void assertBuildName(ParsedName pn, String full, String canonical, String canonicalComplete, String canonicalMarker) {
337    assertEquals(canonical, pn.canonicalName(), "wrong canonicalName");
338    assertEquals(canonicalMarker, pn.canonicalNameWithMarker(), "wrong canonicalNameWithMarker");
339    assertEquals(canonicalComplete, pn.canonicalNameComplete(), "wrong canonicalNameComplete");
340    assertEquals(full, pn.fullName(), "wrong fullName");
341  }
342}