1 package org.collectionspace.services.structureddate;
3 import java.lang.reflect.Array;
4 import java.lang.reflect.InvocationTargetException;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Iterator;
10 import java.util.Stack;
12 import org.apache.commons.beanutils.PropertyUtils;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15 import org.testng.Assert;
16 import org.testng.annotations.BeforeClass;
17 import org.testng.annotations.Test;
18 import org.yaml.snakeyaml.Yaml;
20 public class StructuredDateEvaluatorTest {
21 public static final String TEST_CASE_FILE = "/test-dates.yaml";
22 public static final List<String> YAML_DATE_SPEC = Arrays.asList("year", "month", "day", "era", "certainty", "qualifierType", "qualifierValue", "qualifierUnit");
24 final Logger logger = LoggerFactory.getLogger(StructuredDateEvaluatorTest.class);
33 Yaml yaml = new Yaml();
34 Map<String, Object> testCases = (Map<String, Object>) yaml.load(getClass().getResourceAsStream(TEST_CASE_FILE));
36 for (String displayDate : testCases.keySet()) {
37 logger.debug("Testing input: " + displayDate);
39 Map<String, Object> expectedStructuredDateFields = (Map<String, Object>) testCases.get(displayDate);
41 StructuredDateInternal expectedStructuredDate = createStructuredDateFromYamlSpec(displayDate, expectedStructuredDateFields);
42 StructuredDateInternal actualStructuredDate = null;
45 actualStructuredDate = StructuredDateInternal.parse(displayDate);
47 catch(StructuredDateFormatException e) {
48 logger.debug(e.getMessage());
51 Assert.assertEquals(actualStructuredDate, expectedStructuredDate);
55 private StructuredDateInternal createStructuredDateFromYamlSpec(String displayDate, Map<String, Object> structuredDateFields) {
56 StructuredDateInternal structuredDate = null;
58 if (structuredDateFields != null && structuredDateFields.containsKey("latestDate")) {
59 Object latestDate = structuredDateFields.get("latestDate");
60 if (latestDate instanceof String) {
61 Date currentDate = DateUtils.getCurrentDate();
62 ArrayList latestDateItems = new ArrayList<>();
63 if (latestDate.equals("current date")) {
64 latestDateItems.add(currentDate.getYear());
65 latestDateItems.add(currentDate.getMonth());
66 latestDateItems.add(currentDate.getDay());
67 latestDateItems.add(currentDate.getEra() == Era.BCE ? "BCE" : "CE");
68 structuredDateFields.put("latestDate", latestDateItems);
70 if (latestDate.equals("uncalibrated latest date")) {
71 Stack<ArrayList> results = calculateUncalibratedDate(displayDate, currentDate.getYear());
72 structuredDateFields.put("latestDate", results.pop());
73 structuredDateFields.put("earliestSingleDate", results.pop());
78 if (structuredDateFields != null) {
79 structuredDate = new StructuredDateInternal();
81 for (String propertyName : structuredDateFields.keySet()) {
82 Object value = structuredDateFields.get(propertyName);
85 Class propertyType = PropertyUtils.getPropertyType(structuredDate, propertyName);
87 if (propertyType.equals(Date.class)) {
88 value = createDateFromYamlSpec((List<Object>) value);
91 PropertyUtils.setProperty(structuredDate, propertyName, value);
93 catch(NoSuchMethodException e) {
94 logger.warn(propertyName + " is not a property");
96 catch(InvocationTargetException e) {
97 logger.error(propertyName + " accessor threw an exception");
99 catch(IllegalAccessException e) {
100 logger.error("could not access property " + propertyName);
104 if (structuredDate.getDisplayDate() == null) {
105 structuredDate.setDisplayDate(displayDate);
109 return structuredDate;
114 * Calculates the uncalibrated date, since the yalm expected dates need to be dynamic
115 * as they will change from year to year.
116 * @param displayDate The current test's display date
117 * @param currentYear The current year
119 * @return a stack consisting of two ArrayLists, each containing the expected dates
121 public Stack<ArrayList> calculateUncalibratedDate(String displayDate, Integer currentYear) {
122 Stack<ArrayList> stack = new Stack<ArrayList>();
123 ArrayList latestDate = new ArrayList<>();
124 ArrayList earliestDate = new ArrayList<>();
127 String reg = "±|\\+/-";
128 String[] splitDateTokens = displayDate.split(reg);
129 String[] tokensPartTwo = splitDateTokens[1].split(" ");
131 Integer mainYear = Integer.parseInt(splitDateTokens[0].replaceAll("\\s|,", ""));
135 offset = Integer.parseInt(tokensPartTwo[0]);
136 } catch (Exception e) {
137 offset = Integer.parseInt(tokensPartTwo[1].replaceAll("\\s|,", ""));
140 Integer earliestYear = currentYear - (mainYear + offset);
141 Integer latestYear = currentYear - (mainYear - offset);
143 String earliestEra = earliestYear < 0 ? "BCE" : "CE";
144 String latestEra = latestYear < 0 ? "BCE" : "CE";
146 earliestYear = Math.abs(earliestYear);
147 latestYear = Math.abs(latestYear);
149 latestDate.add(latestYear);
151 latestDate.add(DateUtils.getDaysInMonth(12, latestYear, null));
152 latestDate.add(latestEra);
154 earliestDate.add(earliestYear);
157 earliestDate.add(earliestEra);
159 stack.push(earliestDate);
160 stack.push(latestDate);
165 private Date createDateFromYamlSpec(List<Object> dateFields) {
166 Date date = new Date();
167 Iterator<Object> fieldIterator = dateFields.iterator();
169 for (String propertyName : YAML_DATE_SPEC) {
170 Object value = fieldIterator.hasNext() ? fieldIterator.next() : null;
173 Class propertyType = PropertyUtils.getPropertyType(date, propertyName);
175 if (value != null && Enum.class.isAssignableFrom(propertyType)) {
176 value = Enum.valueOf(propertyType, (String) value);
179 PropertyUtils.setProperty(date, propertyName, value);
181 catch(NoSuchMethodException e) {
182 logger.warn(propertyName + " is not a property");
184 catch(InvocationTargetException e) {
185 logger.error(propertyName + " accessor threw an exception");
187 catch(IllegalAccessException e) {
188 logger.error("could not access property " + propertyName);