Intensive model change for referenceBase and subclass, smaller model changes for...
[cdmlib.git] / cdmlib-model / src / test / java / eu / etaxonomy / cdm / strategy / merge / DefaultMergeStrategyTest.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.cdm.strategy.merge;
12
13 import java.util.HashSet;
14 import java.util.Set;
15 import java.util.UUID;
16
17 import org.apache.log4j.Logger;
18 import org.joda.time.DateTime;
19 import org.junit.After;
20 import org.junit.AfterClass;
21 import org.junit.Assert;
22 import org.junit.Before;
23 import org.junit.BeforeClass;
24 import org.junit.Ignore;
25 import org.junit.Test;
26
27 import eu.etaxonomy.cdm.model.agent.Address;
28 import eu.etaxonomy.cdm.model.agent.Contact;
29 import eu.etaxonomy.cdm.model.agent.Institution;
30 import eu.etaxonomy.cdm.model.agent.InstitutionalMembership;
31 import eu.etaxonomy.cdm.model.agent.Person;
32 import eu.etaxonomy.cdm.model.agent.Team;
33 import eu.etaxonomy.cdm.model.common.Annotation;
34 import eu.etaxonomy.cdm.model.common.DefaultTermInitializer;
35 import eu.etaxonomy.cdm.model.common.Keyword;
36 import eu.etaxonomy.cdm.model.common.LSID;
37 import eu.etaxonomy.cdm.model.common.TimePeriod;
38 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
39 import eu.etaxonomy.cdm.model.location.Point;
40 import eu.etaxonomy.cdm.model.location.ReferenceSystem;
41 import eu.etaxonomy.cdm.model.location.WaterbodyOrCountry;
42 import eu.etaxonomy.cdm.model.name.BotanicalName;
43 import eu.etaxonomy.cdm.model.name.NameRelationship;
44 import eu.etaxonomy.cdm.model.name.NameRelationshipType;
45 import eu.etaxonomy.cdm.model.name.Rank;
46 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
47 import eu.etaxonomy.cdm.model.occurrence.Specimen;
48 import eu.etaxonomy.cdm.model.reference.Book;
49 import eu.etaxonomy.cdm.model.reference.PrintSeries;
50 import eu.etaxonomy.cdm.model.reference.Thesis;
51 import eu.etaxonomy.cdm.model.taxon.Taxon;
52 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
53 import eu.etaxonomy.cdm.strategy.cache.reference.INomenclaturalReferenceCacheStrategy;
54
55 /**
56 * @author a.mueller
57 * @created 03.08.2009
58 * @version 1.0
59 */
60 public class DefaultMergeStrategyTest {
61 @SuppressWarnings("unused")
62 private static final Logger logger = Logger.getLogger(DefaultMergeStrategyTest.class);
63
64 private DefaultMergeStrategy bookMergeStrategy;
65 private Book book1;
66 private String editionString1 ="Ed.1";
67 private String volumeString1 ="Vol.1";
68 private Team team1;
69 private PrintSeries printSeries1;
70 private Annotation annotation1;
71 private String title1 = "Title1";
72 private TimePeriod datePublished1 = TimePeriod.NewInstance(2000);
73 private int hasProblem1 = 1;
74 private LSID lsid1;
75
76 private Book book2;
77 private String editionString2 ="Ed.2";
78 private String volumeString2 ="Vol.2";
79 private Team team2;
80 private PrintSeries printSeries2;
81 private Annotation annotation2;
82 private String annotationString2;
83 private String title2 = "Title2";
84 private DateTime created2 = new DateTime(1999, 3, 1, 0, 0, 0, 0);
85 private TimePeriod datePublished2 = TimePeriod.NewInstance(2002);
86 private int hasProblem2 = 1;
87 private LSID lsid2;
88
89
90 private Book book3;
91
92 /**
93 * @throws java.lang.Exception
94 */
95 @BeforeClass
96 public static void setUpBeforeClass() throws Exception {
97 DefaultTermInitializer termInitializer = new DefaultTermInitializer();
98 termInitializer.initialize();
99 }
100
101 /**
102 * @throws java.lang.Exception
103 */
104 @AfterClass
105 public static void tearDownAfterClass() throws Exception {
106 }
107
108 /**
109 * @throws java.lang.Exception
110 */
111 @Before
112 public void setUp() throws Exception {
113 bookMergeStrategy = DefaultMergeStrategy.NewInstance(Book.class);
114 team1 = Team.NewInstance();
115 team1.setTitleCache("Team1");
116 team2 = Team.NewInstance();
117 team2.setTitleCache("Team2");
118 printSeries1 = PrintSeries.NewInstance("Series1");
119 printSeries2 = PrintSeries.NewInstance("Series2");
120 annotation1 = Annotation.NewInstance("Annotation1", null);
121 annotationString2 = "Annotation2";
122 annotation2 = Annotation.NewInstance(annotationString2, null);
123
124 book1 = Book.NewInstance();
125 book1.setAuthorTeam(team1);
126 book1.setTitle(title1);
127 book1.setEdition(editionString1);
128 book1.setVolume(volumeString1);
129 book1.setInSeries(printSeries1);
130 book1.addAnnotation(annotation1);
131 book1.setDatePublished(datePublished1);
132 book1.setParsingProblem(hasProblem1);
133 lsid1 = new LSID("authority1", "namespace1", "object1", "revision1");
134 book1.setLsid(lsid1);
135 book1.setNomenclaturallyRelevant(false);
136
137 book2 = Book.NewInstance();
138 book2.setAuthorTeam(team2);
139 book2.setTitle(title2);
140 book2.setEdition(editionString2);
141 book2.setVolume(volumeString2);
142 book2.setInSeries(printSeries2);
143 book2.addAnnotation(annotation2);
144 book2.setCreated(created2);
145 book2.setDatePublished(datePublished2);
146 book2.setParsingProblem(hasProblem2);
147 lsid2 = new LSID("authority2", "namespace2", "object2", "revision2");
148 book2.setLsid(lsid2);
149 book2.setNomenclaturallyRelevant(true);
150
151 }
152
153 /**
154 * @throws java.lang.Exception
155 */
156 @After
157 public void tearDown() throws Exception {
158 }
159
160 //********************* TEST *********************************************/
161
162 /**
163 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#NewInstance(java.lang.Class)}.
164 */
165 @Test
166 public void testNewInstance() {
167 Assert.assertNotNull(bookMergeStrategy);
168 Assert.assertEquals(Book.class, bookMergeStrategy.getMergeClass());
169 }
170
171 /**
172 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#getMergeMode(java.lang.String)}.
173 */
174 @Test
175 public void testGetMergeMode() {
176 Assert.assertEquals("Merge mode for title should be MergeMode.FIRST", MergeMode.FIRST, bookMergeStrategy.getMergeMode("title"));
177 }
178
179 /**
180 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#getMergeMode(java.lang.String)}.
181 */
182 @Test
183 public void testGetSetMergeMode() {
184 //legal value
185 try {
186 bookMergeStrategy.setMergeMode("edition", MergeMode.SECOND);
187 Assert.assertEquals("Merge mode for edition should be", MergeMode.SECOND, bookMergeStrategy.getMergeMode("edition"));
188 } catch (MergeException e1) {
189 Assert.fail();
190 }
191 //illegalValue
192 try {
193 bookMergeStrategy.setMergeMode("xxx", MergeMode.SECOND);
194 Assert.fail("A property name must exist, otherwise an exception must be thrown");
195 } catch (Exception e) {
196 //ok
197 }
198 //illegalValue
199 try {
200 bookMergeStrategy.setMergeMode("cacheStrategy", MergeMode.SECOND);
201 Assert.fail("CacheStrategy is transient and therefore not a legal merge parameter");
202 } catch (Exception e) {
203 //ok
204 }
205 //illegalValue
206 try {
207 bookMergeStrategy.setMergeMode("id", MergeMode.SECOND);
208 Assert.fail("Identifier merge mode must always be MergeMode.FIRST");
209 } catch (Exception e) {
210 //ok
211 }
212 //illegalValue
213 try {
214 bookMergeStrategy.setMergeMode("uuid", MergeMode.SECOND);
215 Assert.fail("Identifier merge mode must always be MergeMode.FIRST");
216 } catch (Exception e) {
217 //ok
218 }
219
220
221 }
222
223
224 /**
225 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#invoke(eu.etaxonomy.cdm.strategy.merge.IMergable, eu.etaxonomy.cdm.strategy.merge.IMergable)}.
226 * @throws MergeException
227 */
228 @Test
229 public void testInvokeReferences() throws MergeException {
230 INomenclaturalReferenceCacheStrategy<Book> cacheStrategy1 = book1.getCacheStrategy();
231 int id = book1.getId();
232 UUID uuid = book1.getUuid();
233 try {
234 bookMergeStrategy.setMergeMode("edition", MergeMode.SECOND);
235 bookMergeStrategy.setMergeMode("volume", MergeMode.NULL);
236 bookMergeStrategy.setMergeMode("authorTeam", MergeMode.SECOND);
237 bookMergeStrategy.setMergeMode("created", MergeMode.SECOND);
238 bookMergeStrategy.setMergeMode("updated",MergeMode.NULL);
239 bookMergeStrategy.setMergeMode("datePublished", MergeMode.SECOND);
240 bookMergeStrategy.setMergeMode("parsingProblem", MergeMode.SECOND);
241 bookMergeStrategy.setMergeMode("inReference", MergeMode.SECOND);
242 bookMergeStrategy.setMergeMode("lsid", MergeMode.SECOND);
243
244 bookMergeStrategy.invoke(book1, book2);
245 } catch (MergeException e) {
246 throw e;
247 //Assert.fail("An unexpected merge exception occurred: " + e.getMessage() + ";" + e.getCause().getMessage());
248 }
249 Assert.assertEquals("Title should stay the same", title1, book1.getTitle());
250 Assert.assertEquals("Edition should become edition 2", editionString2, book1.getEdition());
251 Assert.assertNull("Volume should be null", book1.getVolume());
252
253 //Boolean
254 Assert.assertEquals("Has problem must be hasProblem2", hasProblem2, book1.getParsingProblem());
255 Assert.assertEquals("nomenclaturally relevant must have value true (AND semantics)", true, book1.isNomenclaturallyRelevant() );
256
257
258 //CdmBase
259 Assert.assertSame("AuthorTeam must be the one of book2", team2, book1.getAuthorTeam());
260 Assert.assertSame("In Series must be the one of book2", printSeries2, book1.getInSeries());
261
262 //Transient
263 Assert.assertSame("Cache strategy is transient and shouldn't change therefore", cacheStrategy1, book1.getCacheStrategy());
264
265
266 //UserType
267 Assert.assertSame("Created must be created2", created2, book1.getCreated());
268 //TODO updated should have the actual date if any value has changed
269 Assert.assertSame("Created must be created2", null, book1.getUpdated());
270 Assert.assertSame("Created must be datePublsihed2", datePublished2, book1.getDatePublished());
271 //TODO this may not be correct
272 Assert.assertSame("LSID must be LSID2", lsid2, book1.getLsid());
273
274
275 //TODO
276 // book1.setProblemEnds(end);
277 // book1.setProtectedTitleCache(protectedTitleCache);
278
279 //annotations -> ADD_CLONE
280 Assert.assertEquals("Annotations should contain annotations of both books", 2, book1.getAnnotations().size());
281 boolean cloneExists = false;
282 for (Annotation annotation : book1.getAnnotations()){
283 if (annotation == this.annotation2){
284 //Hibernate will not persist the exact same object. Probably this is a bug (the according row in the
285 //M:M table is not deleted and a unique constraints does not allow adding 2 rows with the same annotation_id
286 //This test can be changed once this bug does not exist anymore
287 Assert.fail("Book1 should contain a clone of annotation2 but contains annotation2 itself");
288 }else if (annotationString2.equals(annotation.getText())){
289 cloneExists = true;
290 }
291 }
292 Assert.assertTrue("Book1 should contain a clone of annotation2", cloneExists);
293 // Assert.assertEquals("Annotations from book2 should be deleted", 0, book2.getAnnotations().size());
294
295 //identifier
296 Assert.assertSame("Identifier must never be changed", id, book1.getId());
297 Assert.assertSame("Identifier must never be changed", uuid, book1.getUuid());
298
299 //Test Thesis
300 Institution school1 = Institution.NewInstance();
301 Institution school2 = Institution.NewInstance();
302
303 Thesis thesis1 = Thesis.NewInstance(school1);
304 Thesis thesis2 = Thesis.NewInstance(school2);
305 DefaultMergeStrategy thesisStrategy = DefaultMergeStrategy.NewInstance(Thesis.class);
306
307 thesisStrategy.setMergeMode("school", MergeMode.SECOND);
308 thesisStrategy.invoke(thesis1, thesis2);
309 Assert.assertSame("school must be school2", school2, thesis1.getSchool());
310 }
311
312
313 /**
314 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#invoke(eu.etaxonomy.cdm.strategy.merge.IMergable, eu.etaxonomy.cdm.strategy.merge.IMergable)}.
315 * @throws MergeException
316 */
317 @Test
318 @Ignore
319 public void testInvokeTxonNames() throws MergeException {
320 IMergeStrategy botNameMergeStrategy = DefaultMergeStrategy.NewInstance(BotanicalName.class);
321 BotanicalName botName1 = BotanicalName.NewInstance(Rank.SPECIES());
322 BotanicalName botName2 = BotanicalName.NewInstance(Rank.SPECIES());
323 BotanicalName botName3 = BotanicalName.NewInstance(Rank.SPECIES());
324
325 botName1.setGenusOrUninomial("Genus1");
326 botName1.setSpecificEpithet("species1");
327 botName1.setAnamorphic(true);
328
329 botName2.setGenusOrUninomial("Genus2");
330 botName2.setSpecificEpithet("species2");
331 botName2.setAnamorphic(false);
332
333 //name relations
334 botName2.addBasionym(botName3, book1, "p.22", null);
335 Specimen specimen1 = Specimen.NewInstance();
336 botName2.addSpecimenTypeDesignation(specimen1, SpecimenTypeDesignationStatus.HOLOTYPE(), book2, "p.56", "originalNameString", false, true);
337
338 //descriptions
339 TaxonNameDescription description1 = TaxonNameDescription.NewInstance();
340 botName1.addDescription(description1);
341 TaxonNameDescription description2 = TaxonNameDescription.NewInstance();
342 botName2.addDescription(description2);
343
344 //authors
345 Team team1 = Team.NewInstance();
346 Team team2 = Team.NewInstance();
347 Person person1 = Person.NewInstance();
348 botName1.setCombinationAuthorTeam(team1);
349 botName2.setCombinationAuthorTeam(team2);
350
351 //taxa
352 TaxonBase taxon1= Taxon.NewInstance(botName1, book1);
353 TaxonBase taxon2= Taxon.NewInstance(botName2, book2);
354
355 try {
356 botNameMergeStrategy.setMergeMode("combinationAuthorTeam", MergeMode.SECOND);
357 botNameMergeStrategy.setMergeMode("anamorphic", MergeMode.AND);
358
359 // botNameMergeStrategy.invoke(botName1, botName2);
360 } catch (MergeException e) {
361 throw e;
362 //Assert.fail("An unexpected merge exception occurred: " + e.getMessage() + ";" + e.getCause().getMessage());
363 }
364
365 //Boolean
366 Assert.assertEquals("Is anamorphic must be false", true && false, botName1.isAnamorphic());
367
368 //NameRelations
369 Set<NameRelationship> toRelations = botName1.getRelationsToThisName();
370 Set<NameRelationship> basionymRelations = new HashSet<NameRelationship>();
371 for (NameRelationship toRelation : toRelations){
372 if (toRelation.getType().equals(NameRelationshipType.BASIONYM())){
373 basionymRelations.add(toRelation);
374 }
375 }
376 Assert.assertEquals("Number of basionyms must be 1", 1, basionymRelations.size());
377 Assert.assertEquals("Basionym must have same reference", book1, basionymRelations.iterator().next().getCitation());
378 //TODO merge relation if matches() = true
379
380 //Types
381 Assert.assertEquals("Number of specimen type designations must be 1", 1, botName1.getSpecimenTypeDesignations().size());
382 //TODO add to all names etc.
383
384 //Description
385 Assert.assertEquals("Number of descriptions must be 2", 2, botName1.getDescriptions().size());
386
387 //AuthorTeams
388 Assert.assertEquals("Combination author must be combination author 2", team2, botName1.getCombinationAuthorTeam());
389
390 //Taxa
391 Assert.assertEquals("TaxonName of taxon1 must be name1", botName1, taxon1.getName());
392 Assert.assertEquals("TaxonName of taxon2 must be name1", botName1, taxon2.getName());
393
394 }
395
396 /**
397 * Test method for {@link eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy#invoke(eu.etaxonomy.cdm.strategy.merge.IMergable, eu.etaxonomy.cdm.strategy.merge.IMergable)}.
398 * @throws MergeException
399 */
400 @Test
401 public void testInvokeAgents() throws MergeException {
402 IMergeStrategy teamMergeStrategy = DefaultMergeStrategy.NewInstance(Team.class);
403
404 Team team1 = Team.NewInstance();
405 Team team2 = Team.NewInstance();
406 Team team3 = Team.NewInstance();
407
408 Person person1 = Person.NewTitledInstance("person1");
409 Person person2 = Person.NewTitledInstance("person2");
410 Person person3 = Person.NewTitledInstance("person3");
411
412 team1.setTitleCache("Team1");
413 team1.setNomenclaturalTitle("T.1");
414 String street1 = "Strasse1";
415 team1.setContact(Contact.NewInstance(street1, "12345", "Berlin", WaterbodyOrCountry.ARGENTINA_ARGENTINE_REPUBLIC(),"pobox" , "Region", "a@b.de", "f12345", "+49-30-123456", "www.abc.de", Point.NewInstance(2.4, 3.2, ReferenceSystem.WGS84(), 3)));
416 team2.setContact(Contact.NewInstance("Street2", null, "London", null, null, null, null, "874599873", null, null, null));
417 String street3 = "Street3";
418 team2.addAddress(street3, null, null, null, null, null, Point.NewInstance(1.1, 2.2, null, 4));
419 String emailAddress1 = "Email1";
420 team1.addEmailAddress(emailAddress1);
421
422 team2.addTeamMember(person1);
423 team2.addTeamMember(person2);
424 String emailAddress2 = "Email2";
425 team2.addEmailAddress(emailAddress2);
426
427 team3.addTeamMember(person3);
428 team3.addEmailAddress("emailAddress3");
429
430 teamMergeStrategy.invoke(team2, team3);
431
432 Assert.assertEquals("Team2 must have 3 persons as members",3, team2.getTeamMembers().size());
433 Assert.assertTrue("Team2 must have person3 as new member", team2.getTeamMembers().contains(person3));
434 Assert.assertSame("Team2 must have person3 as third member",person3, team2.getTeamMembers().get(2));
435
436 //Contact
437 teamMergeStrategy.invoke(team2, team1);
438 Contact team2Contact = team2.getContact();
439 Assert.assertNotNull("team2Contact must not be null", team2Contact);
440 Assert.assertNotNull("Addresses must not be null", team2Contact.getAddresses());
441 Assert.assertEquals("Number of addresses must be 3", 3, team2Contact.getAddresses().size());
442 Assert.assertEquals("Number of email addresses must be 4", 4, team2Contact.getEmailAddresses().size());
443
444 boolean street1Exists = false;
445 boolean street3Exists = false;
446 boolean country1Exists = false;
447 for (Address address : team2Contact.getAddresses()){
448 if (street1.equals(address.getStreet())){
449 street1Exists = true;
450 }
451 if (street3.equals(address.getStreet())){
452 street3Exists = true;
453 }
454 if (WaterbodyOrCountry.ARGENTINA_ARGENTINE_REPUBLIC() == address.getCountry()){
455 country1Exists = true;
456 }
457 }
458 Assert.assertTrue("Street1 must be one of the streets in team2's addresses", street1Exists);
459 Assert.assertTrue("Street3 must be one of the streets in team2's addressesss", street3Exists);
460 Assert.assertTrue("Argentina must be one of the countries in team2's addresses", country1Exists);
461
462 //Person
463 Institution institution1 = Institution.NewInstance();
464 institution1.setTitleCache("inst1");
465 Institution institution2 = Institution.NewInstance();
466 institution2.setTitleCache("inst2");
467
468 TimePeriod period1 = TimePeriod.NewInstance(2002, 2004);
469 TimePeriod period2 = TimePeriod.NewInstance(2004, 2006);
470
471 person1.addInstitutionalMembership(institution1, period1, "departement1", "role1");
472 person2.addInstitutionalMembership(institution2, period2, "departement2", "role2");
473
474 Keyword keyword1 = Keyword.NewInstance("K1", "K1", "K1");
475 person1.addKeyword(keyword1);
476
477 Keyword keyword2 = Keyword.NewInstance("K2", "K2", "K2");
478 person2.addKeyword(keyword2);
479
480 IMergeStrategy personMergeStrategy = DefaultMergeStrategy.NewInstance(Person.class);
481 personMergeStrategy.invoke(person1, person2);
482
483 Assert.assertEquals("Number of institutional memberships must be 2", 2, person1.getInstitutionalMemberships().size());
484 Assert.assertEquals("Number of keywords must be 2", 2, person1.getKeywords().size());
485 for (InstitutionalMembership institutionalMembership : person1.getInstitutionalMemberships()){
486 Assert.assertSame("Person of institutional memebership must be person1", person1, institutionalMembership.getPerson());
487 }
488
489 }
490
491 }