| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ******************************************************************************* |
| * Copyright (C) 2007-2015, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| ******************************************************************************* |
| */ |
| package com.ibm.icu.dev.test.duration; |
| |
| import java.math.BigDecimal; |
| import java.text.FieldPosition; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| |
| import javax.xml.datatype.DatatypeConstants; |
| import javax.xml.datatype.DatatypeConstants.Field; |
| import javax.xml.datatype.Duration; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| import com.ibm.icu.dev.test.TestFmwk; |
| import com.ibm.icu.text.DurationFormat; |
| import com.ibm.icu.util.Calendar; |
| import com.ibm.icu.util.ULocale; |
| |
| /** |
| * @author srl |
| * |
| */ |
| @RunWith(JUnit4.class) |
| public class ICUDurationTest extends TestFmwk { |
| /** |
| * Allows us to not depend on javax.xml.datatype.DatatypeFactory. |
| * We need just a tiny subset of the Duration API: |
| * The ICU DurationFormat just extracts the field values, |
| * to convert the Duration into an internal Period type. |
| */ |
| private static final class ICUTestDuration extends javax.xml.datatype.Duration { |
| private final int sign; |
| // Duration docs say BigInteger/BigDecimal but |
| // ICU only cares about intValue() and floatValue(). |
| private final Map<Field, Number> fields; |
| |
| ICUTestDuration(long millis) { |
| fields = new HashMap<Field, Number>(); |
| if (millis > 0) { |
| sign = 1; |
| } else if (millis == 0) { |
| sign = 0; |
| return; |
| } else { |
| sign = -1; |
| millis = -millis; |
| } |
| long d = millis / 86400000L; |
| millis %= 86400000L; |
| if (d > 0) { |
| fields.put(DatatypeConstants.DAYS, d); |
| } |
| long h = millis / 3600000L; |
| millis %= 3600000L; |
| if (h > 0) { |
| fields.put(DatatypeConstants.HOURS, h); |
| } |
| long m = millis / 60000L; |
| millis %= 60000L; |
| if (m > 0) { |
| fields.put(DatatypeConstants.MINUTES, m); |
| } |
| fields.put(DatatypeConstants.SECONDS, (float)millis / 1000); |
| } |
| |
| /** |
| * Pass in negative values for fields not to be set. |
| */ |
| ICUTestDuration(int sgn, int y, int months, int d, int h, int m, float s) { |
| sign = sgn; |
| fields = new HashMap<Field, Number>(); |
| if (y >= 0) { fields.put(DatatypeConstants.YEARS, y); } |
| if (months >= 0) { fields.put(DatatypeConstants.MONTHS, months); } |
| if (d >= 0) { fields.put(DatatypeConstants.DAYS, d); } |
| if (h >= 0) { fields.put(DatatypeConstants.HOURS, h); } |
| if (m >= 0) { fields.put(DatatypeConstants.MINUTES, m); } |
| if (s >= 0) { fields.put(DatatypeConstants.SECONDS, s); } |
| } |
| |
| private ICUTestDuration(int sgn, Map<Field, Number> f) { |
| sign = sgn; |
| fields = f; |
| } |
| |
| @Override |
| public Duration add(Duration rhs) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void addTo(java.util.Calendar calendar) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public int compare(Duration duration) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Number getField(Field field) { |
| return fields.get(field); |
| } |
| |
| @Override |
| public int getSign() { |
| return sign; |
| } |
| |
| @Override |
| public int hashCode() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public boolean isSet(Field field) { |
| return fields.containsKey(field); |
| } |
| |
| @Override |
| public Duration multiply(BigDecimal factor) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Duration negate() { |
| return new ICUTestDuration(-sign, fields); |
| } |
| |
| @Override |
| public Duration normalizeWith(java.util.Calendar startTimeInstant) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public String toString() { |
| String signString = sign > 0 ? "positive" : sign == 0 ? "zero" : "negative"; |
| return signString + " fields=" + fields; |
| } |
| } |
| private static final ICUTestDuration newDuration(long millis) { |
| return new ICUTestDuration(millis); |
| } |
| private static final ICUTestDuration newDuration(int sgn, int d, int h, int m, float s) { |
| return new ICUTestDuration(sgn, -1, -1, d, h, m, s); |
| } |
| private static final ICUTestDuration newDuration(int sgn, int h, int m, float s) { |
| return new ICUTestDuration(sgn, -1, -1, -1, h, m, s); |
| } |
| private static final ICUTestDuration newDuration(int sgn, float s) { |
| return new ICUTestDuration(sgn, -1, -1, -1, -1, -1, s); |
| } |
| |
| /** |
| * |
| */ |
| public ICUDurationTest() { |
| } |
| |
| /** |
| * Basic test |
| */ |
| @Test |
| public void TestBasics() { |
| DurationFormat df; |
| String expect; |
| String formatted; |
| |
| df = DurationFormat.getInstance(new ULocale("it")); |
| formatted = df.formatDurationFromNow(4096); |
| expect = "fra quattro secondi"; |
| if(!expect.equals(formatted)) { |
| errln("Expected " + expect + " but got " + formatted); |
| } else { |
| logln("format duration -> " + formatted); |
| } |
| |
| formatted = df.formatDurationFromNowTo(new Date(0)); |
| Calendar cal = Calendar.getInstance(); |
| int years = cal.get(Calendar.YEAR) - 1970; // year of Date(0) |
| expect = years + " anni fa"; |
| if(!expect.equals(formatted)) { |
| errln("Expected " + expect + " but got " + formatted); |
| } else { |
| logln("format date -> " + formatted); |
| } |
| |
| formatted = df.formatDurationFrom(1000*3600*24, new Date(0).getTime()); |
| expect = "fra un giorno"; |
| if(!expect.equals(formatted)) { |
| errln("Expected " + expect + " but got " + formatted); |
| } else { |
| logln("format date from -> " + formatted); |
| } |
| |
| formatted = df.format(new Long(1000*3600*24*2)); |
| expect = "fra due giorni"; |
| if(!expect.equals(formatted)) { |
| errln("Expected " + expect + " but got " + formatted); |
| } else { |
| logln("format long obj -> " + formatted); |
| } |
| } |
| |
| @Test |
| public void TestSimpleXMLDuration() { |
| Duration d; |
| DurationFormat df; |
| String out; |
| String expected; |
| String expected2; |
| |
| // test 1 |
| d = newDuration(1, 2, 46, 40); // "PT2H46M40S" |
| df = DurationFormat.getInstance(new ULocale("en")); |
| expected = "2 hours, 46 minutes, and 40 seconds"; |
| out = df.format(d); |
| if(out.equals(expected)) { |
| logln("out=expected: " + expected + " from " + d); |
| } else { |
| errln("FAIL: got " + out + " wanted " + expected + " from " + d); |
| } |
| |
| // test 2 |
| d = newDuration(10000); |
| df = DurationFormat.getInstance(new ULocale("en")); |
| expected = "10 seconds"; |
| out = df.format(d); |
| if(out.equals(expected)) { |
| logln("out=expected: " + expected + " from " + d); |
| } else { |
| errln("FAIL: got " + out + " wanted " + expected + " from " + d); |
| } |
| // test 3 |
| d = newDuration(1, 0, 0, 0, 10); // "P0DT0H0M10.0S" |
| df = DurationFormat.getInstance(new ULocale("en")); |
| expected = "10 seconds"; |
| out = df.format(d); |
| if(out.equals(expected)) { |
| logln("out=expected: " + expected + " from " + d); |
| } else { |
| errln("FAIL: got " + out + " wanted " + expected + " from " + d); |
| } |
| // test 4 |
| d = newDuration(86400000); |
| df = DurationFormat.getInstance(new ULocale("en")); |
| expected = "1 day, 0 hours, 0 minutes, and 0 seconds"; |
| expected2 = "1 day and 0 seconds"; // This is the expected result for Windows with IBM JRE6 |
| out = df.format(d); |
| if(out.equals(expected)) { |
| logln("out=expected: " + expected + " from " + d); |
| } else { |
| if(out.equals(expected2)){ |
| logln("WARNING: got " + out + " wanted " + expected + " from " + d); |
| } else{ |
| errln("FAIL: got " + out + " wanted " + expected + " from " + d); |
| } |
| } |
| } |
| |
| @Test |
| public void TestXMLDuration() { |
| final class TestCase { |
| final String localeString; |
| final ULocale locale; |
| final String durationString; |
| final Duration duration; |
| final String expected; |
| |
| TestCase(String loc, String ds, Duration d, String exp) { |
| localeString = loc; |
| locale = new ULocale(loc); |
| durationString = ds; |
| duration = d; |
| expected = exp; |
| } |
| } |
| |
| TestCase cases[] = { |
| new TestCase("en", "PT10.00099S", newDuration(1, 10.00099F), "10 seconds"), |
| new TestCase("en", "#10000", newDuration(10000), "10 seconds"), |
| new TestCase("en", "-PT10.00099S", newDuration(-1, 10.00099F), "10 seconds"), |
| new TestCase("en", "#-10000", newDuration(-10000), "10 seconds"), |
| |
| // from BD req's |
| new TestCase("en", "PT2H46M40S", newDuration(1, 2, 46, 40), "2 hours, 46 minutes, and 40 seconds"), |
| new TestCase("it", "PT2H46M40S", newDuration(1, 2, 46, 40), "due ore, 46 minuti e 40 secondi"), |
| |
| // more cases |
| new TestCase("en", "PT10S", newDuration(1, 10), "10 seconds"), |
| new TestCase("en", "PT88M70S", newDuration(1, -1, 88, 70), "88 minutes and 70 seconds"), |
| new TestCase("en", "PT10.100S", newDuration(1, 10.100F), "10 seconds and 100 milliseconds"), |
| new TestCase("en", "-PT10S", newDuration(-1, 10), "10 seconds"), |
| new TestCase("en", "PT0H5M0S", newDuration(1, 0, 5, 0), "5 minutes and 0 seconds") |
| }; |
| |
| for (TestCase tc : cases) { |
| String loc = tc.localeString; |
| String from = tc.durationString; |
| String to = tc.expected; |
| |
| ULocale locale = tc.locale; |
| Duration d = tc.duration; |
| |
| DurationFormat df = DurationFormat.getInstance(locale); |
| String output = df.format(d); |
| |
| if(output.equals(to)) { |
| logln("SUCCESS: locale: " + loc + ", from " + from + " ["+d.toString()+"] " +" to " + to + "= " + output); |
| } else { |
| logln("FAIL: locale: " + loc + ", from " + from + " ["+d.toString()+"] " +": expected " + to + " got " + output); |
| } |
| } |
| } |
| |
| |
| @Test |
| public void TestBadObjectError() { |
| Runtime r = Runtime.getRuntime(); |
| DurationFormat df = DurationFormat.getInstance(new ULocale("en")); |
| String output = null; |
| try { |
| output = df.format(r); |
| errln("FAIL: did NOT get IllegalArgumentException! Should have. Formatted Runtime as " + output + " ???"); |
| } catch (IllegalArgumentException iae) { |
| logln("PASS: expected: Caught iae: " + iae.toString() ); |
| } |
| // try a second time, because it is a different code path for java < 1.5 |
| try { |
| output = df.format(r); |
| errln("FAIL: [#2] did NOT get IllegalArgumentException! Should have. Formatted Runtime as " + output + " ???"); |
| } catch (IllegalArgumentException iae) { |
| logln("PASS: [#2] expected: Caught iae: " + iae.toString() ); |
| } |
| } |
| |
| @Test |
| public void TestBadLocaleError() { |
| try { |
| DurationFormat df = DurationFormat.getInstance(new ULocale("und")); |
| df.format(new Date()); |
| logln("Should have thrown err."); |
| errln("failed, should have thrown err."); |
| } catch(MissingResourceException mre) { |
| logln("PASS: caught missing resource exception on locale 'und'"); |
| logln(mre.toString()); |
| } |
| } |
| |
| @Test |
| public void TestResourceWithCalendar() { |
| DurationFormat df = DurationFormat.getInstance(new ULocale("th@calendar=buddhist")); |
| // should pass, but return a default formatter for th. |
| if (df == null) { |
| errln("FAIL: null DurationFormat returned."); |
| } |
| } |
| |
| /* Tests the class |
| * DurationFormat |
| */ |
| @Test |
| public void TestDurationFormat(){ |
| @SuppressWarnings("serial") |
| class TestDurationFormat extends DurationFormat { |
| @Override |
| public StringBuffer format(Object object, StringBuffer toAppend, FieldPosition pos) {return null;} |
| @Override |
| public String formatDurationFrom(long duration, long referenceDate) {return null;} |
| @Override |
| public String formatDurationFromNow(long duration) {return null;} |
| @Override |
| public String formatDurationFromNowTo(Date targetDate) {return null;} |
| public TestDurationFormat() {super();} |
| |
| } |
| |
| // Tests the constructor and the following method |
| // public Object parseObject(String source, ParsePosition pos) |
| try{ |
| TestDurationFormat tdf = new TestDurationFormat(); |
| tdf.parseObject("",null); |
| errln("DurationFormat.parseObjet(String,ParsePosition) was " + |
| "to return an exception for an unsupported operation."); |
| } catch(Exception e){} |
| } |
| |
| @Test |
| public void TestFromNowTo() { |
| class TestCase { |
| ULocale locale; |
| int diffInSeconds; |
| String expected; |
| TestCase(ULocale locale, int diffInSeconds, String expected) { |
| this.locale = locale; |
| this.diffInSeconds = diffInSeconds; |
| this.expected = expected; |
| } |
| } |
| TestCase[] testCases = { |
| new TestCase(ULocale.US, 10, "10 seconds from now"), |
| new TestCase(ULocale.US, -10, "10 seconds ago"), |
| new TestCase(ULocale.US, -1800, "30 minutes ago"), |
| new TestCase(ULocale.US, 3600, "1 hour from now"), |
| new TestCase(ULocale.US, 10000, "2 hours from now"), |
| new TestCase(ULocale.US, -20000, "5 hours ago"), |
| new TestCase(ULocale.FRANCE, -1800, "il y a 30 minutes"), |
| new TestCase(ULocale.ITALY, 10000, "fra due ore"), |
| }; |
| |
| final long delayMS = 10; // Safe margin - 10 milliseconds |
| // See the comments below |
| for (TestCase test : testCases) { |
| DurationFormat df = DurationFormat.getInstance(test.locale); |
| long target = System.currentTimeMillis() + test.diffInSeconds * 1000; |
| // Need some adjustment because time difference is recalculated in |
| // formatDurationFromNowTo method. |
| target = test.diffInSeconds > 0 ? target + delayMS : target - delayMS; |
| Date d = new Date(target); |
| String result = df.formatDurationFromNowTo(d); |
| assertEquals("TestFromNowTo (" + test.locale + ", " + test.diffInSeconds + "sec)", |
| test.expected, result); |
| } |
| } |
| } |