Home | History | Annotate | Download | only in duration
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2007-2015, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.dev.test.duration;
     10 
     11 import java.math.BigDecimal;
     12 import java.text.FieldPosition;
     13 import java.util.Date;
     14 import java.util.HashMap;
     15 import java.util.Map;
     16 import java.util.MissingResourceException;
     17 
     18 import javax.xml.datatype.DatatypeConstants;
     19 import javax.xml.datatype.DatatypeConstants.Field;
     20 import javax.xml.datatype.Duration;
     21 
     22 import org.junit.Test;
     23 import org.junit.runner.RunWith;
     24 import org.junit.runners.JUnit4;
     25 
     26 import com.ibm.icu.dev.test.TestFmwk;
     27 import com.ibm.icu.text.DurationFormat;
     28 import com.ibm.icu.util.Calendar;
     29 import com.ibm.icu.util.ULocale;
     30 
     31 /**
     32  * @author srl
     33  *
     34  */
     35 @RunWith(JUnit4.class)
     36 public class ICUDurationTest extends TestFmwk {
     37     /**
     38      * Allows us to not depend on javax.xml.datatype.DatatypeFactory.
     39      * We need just a tiny subset of the Duration API:
     40      * The ICU DurationFormat just extracts the field values,
     41      * to convert the Duration into an internal Period type.
     42      */
     43     private static final class ICUTestDuration extends javax.xml.datatype.Duration {
     44         private final int sign;
     45         // Duration docs say BigInteger/BigDecimal but
     46         // ICU only cares about intValue() and floatValue().
     47         private final Map<Field, Number> fields;
     48 
     49         ICUTestDuration(long millis) {
     50             fields = new HashMap<Field, Number>();
     51             if (millis > 0) {
     52                 sign = 1;
     53             } else if (millis == 0) {
     54                 sign = 0;
     55                 return;
     56             } else {
     57                 sign = -1;
     58                 millis = -millis;
     59             }
     60             long d = millis / 86400000L;
     61             millis %= 86400000L;
     62             if (d > 0) {
     63                 fields.put(DatatypeConstants.DAYS, d);
     64             }
     65             long h = millis / 3600000L;
     66             millis %= 3600000L;
     67             if (h > 0) {
     68                 fields.put(DatatypeConstants.HOURS, h);
     69             }
     70             long m = millis / 60000L;
     71             millis %= 60000L;
     72             if (m > 0) {
     73                 fields.put(DatatypeConstants.MINUTES, m);
     74             }
     75             fields.put(DatatypeConstants.SECONDS, (float)millis / 1000);
     76         }
     77 
     78         /**
     79          * Pass in negative values for fields not to be set.
     80          */
     81         ICUTestDuration(int sgn, int y, int months, int d, int h, int m, float s) {
     82             sign = sgn;
     83             fields = new HashMap<Field, Number>();
     84             if (y >= 0) { fields.put(DatatypeConstants.YEARS, y); }
     85             if (months >= 0) { fields.put(DatatypeConstants.MONTHS, months); }
     86             if (d >= 0) { fields.put(DatatypeConstants.DAYS, d); }
     87             if (h >= 0) { fields.put(DatatypeConstants.HOURS, h); }
     88             if (m >= 0) { fields.put(DatatypeConstants.MINUTES, m); }
     89             if (s >= 0) { fields.put(DatatypeConstants.SECONDS, s); }
     90         }
     91 
     92         private ICUTestDuration(int sgn, Map<Field, Number> f) {
     93             sign = sgn;
     94             fields = f;
     95         }
     96 
     97         @Override
     98         public Duration add(Duration rhs) {
     99             throw new UnsupportedOperationException();
    100         }
    101 
    102         @Override
    103         public void addTo(java.util.Calendar calendar) {
    104             throw new UnsupportedOperationException();
    105         }
    106 
    107         @Override
    108         public int compare(Duration duration) {
    109             throw new UnsupportedOperationException();
    110         }
    111 
    112         @Override
    113         public Number getField(Field field) {
    114             return fields.get(field);
    115         }
    116 
    117         @Override
    118         public int getSign() {
    119             return sign;
    120         }
    121 
    122         @Override
    123         public int hashCode() {
    124             throw new UnsupportedOperationException();
    125         }
    126 
    127         @Override
    128         public boolean isSet(Field field) {
    129             return fields.containsKey(field);
    130         }
    131 
    132         @Override
    133         public Duration multiply(BigDecimal factor) {
    134             throw new UnsupportedOperationException();
    135         }
    136 
    137         @Override
    138         public Duration negate() {
    139             return new ICUTestDuration(-sign, fields);
    140         }
    141 
    142         @Override
    143         public Duration normalizeWith(java.util.Calendar startTimeInstant) {
    144             throw new UnsupportedOperationException();
    145         }
    146 
    147         @Override
    148         public String toString() {
    149             String signString = sign > 0 ? "positive" : sign == 0 ? "zero" : "negative";
    150             return signString + " fields=" + fields;
    151         }
    152     }
    153     private static final ICUTestDuration newDuration(long millis) {
    154         return new ICUTestDuration(millis);
    155     }
    156     private static final ICUTestDuration newDuration(int sgn, int d, int h, int m, float s) {
    157         return new ICUTestDuration(sgn, -1, -1, d, h, m, s);
    158     }
    159     private static final ICUTestDuration newDuration(int sgn, int h, int m, float s) {
    160         return new ICUTestDuration(sgn, -1, -1, -1, h, m, s);
    161     }
    162     private static final ICUTestDuration newDuration(int sgn, float s) {
    163         return new ICUTestDuration(sgn, -1, -1, -1, -1, -1, s);
    164     }
    165 
    166     /**
    167      *
    168      */
    169     public ICUDurationTest() {
    170     }
    171 
    172     /**
    173      * Basic test
    174      */
    175     @Test
    176     public void TestBasics() {
    177         DurationFormat df;
    178         String expect;
    179         String formatted;
    180 
    181         df = DurationFormat.getInstance(new ULocale("it"));
    182         formatted = df.formatDurationFromNow(4096);
    183         expect = "fra quattro secondi";
    184         if(!expect.equals(formatted)) {
    185             errln("Expected " + expect + " but got " + formatted);
    186         } else {
    187             logln("format duration -> " + formatted);
    188         }
    189 
    190         formatted = df.formatDurationFromNowTo(new Date(0));
    191         Calendar cal = Calendar.getInstance();
    192         int years = cal.get(Calendar.YEAR) - 1970; // year of Date(0)
    193         expect = years + " anni fa";
    194         if(!expect.equals(formatted)) {
    195             errln("Expected " + expect + " but got " + formatted);
    196         } else {
    197             logln("format date  -> " + formatted);
    198         }
    199 
    200         formatted = df.formatDurationFrom(1000*3600*24, new Date(0).getTime());
    201         expect = "fra un giorno";
    202         if(!expect.equals(formatted)) {
    203             errln("Expected " + expect + " but got " + formatted);
    204         } else {
    205             logln("format date from -> " + formatted);
    206         }
    207 
    208         formatted = df.format(new Long(1000*3600*24*2));
    209         expect = "fra due giorni";
    210         if(!expect.equals(formatted)) {
    211             errln("Expected " + expect + " but got " + formatted);
    212         } else {
    213             logln("format long obj -> " + formatted);
    214         }
    215     }
    216 
    217     @Test
    218     public void TestSimpleXMLDuration() {
    219         Duration d;
    220         DurationFormat df;
    221         String out;
    222         String expected;
    223         String expected2;
    224 
    225         // test 1
    226         d = newDuration(1, 2, 46, 40);  // "PT2H46M40S"
    227         df = DurationFormat.getInstance(new ULocale("en"));
    228         expected = "2 hours, 46 minutes, and 40 seconds";
    229         out = df.format(d);
    230         if(out.equals(expected)) {
    231             logln("out=expected: " + expected + " from " + d);
    232         } else {
    233             errln("FAIL: got " + out + " wanted " + expected + " from " + d);
    234         }
    235 
    236         // test 2
    237         d = newDuration(10000);
    238         df = DurationFormat.getInstance(new ULocale("en"));
    239         expected = "10 seconds";
    240         out = df.format(d);
    241         if(out.equals(expected)) {
    242             logln("out=expected: " + expected + " from " + d);
    243         } else {
    244             errln("FAIL: got " + out + " wanted " + expected + " from " + d);
    245         }
    246         // test 3
    247         d = newDuration(1, 0, 0, 0, 10);  // "P0DT0H0M10.0S"
    248         df = DurationFormat.getInstance(new ULocale("en"));
    249         expected = "10 seconds";
    250         out = df.format(d);
    251         if(out.equals(expected)) {
    252             logln("out=expected: " + expected + " from " + d);
    253         } else {
    254             errln("FAIL: got " + out + " wanted " + expected + " from " + d);
    255         }
    256         // test 4
    257         d = newDuration(86400000);
    258         df = DurationFormat.getInstance(new ULocale("en"));
    259         expected = "1 day, 0 hours, 0 minutes, and 0 seconds";
    260         expected2 = "1 day and 0 seconds"; // This is the expected result for Windows with IBM JRE6
    261         out = df.format(d);
    262         if(out.equals(expected)) {
    263             logln("out=expected: " + expected + " from " + d);
    264         } else {
    265             if(out.equals(expected2)){
    266                 logln("WARNING: got " + out + " wanted " + expected + " from " + d);
    267             } else{
    268                 errln("FAIL: got " + out + " wanted " + expected + " from " + d);
    269             }
    270         }
    271     }
    272 
    273     @Test
    274     public void TestXMLDuration() {
    275         final class TestCase {
    276             final String localeString;
    277             final ULocale locale;
    278             final String durationString;
    279             final Duration duration;
    280             final String expected;
    281 
    282             TestCase(String loc, String ds, Duration d, String exp) {
    283                 localeString = loc;
    284                 locale = new ULocale(loc);
    285                 durationString = ds;
    286                 duration = d;
    287                 expected = exp;
    288             }
    289         }
    290 
    291         TestCase cases[] = {
    292             new TestCase("en", "PT10.00099S",  newDuration(1, 10.00099F),  "10 seconds"),
    293             new TestCase("en", "#10000",       newDuration(10000),         "10 seconds"),
    294             new TestCase("en", "-PT10.00099S", newDuration(-1, 10.00099F), "10 seconds"),
    295             new TestCase("en", "#-10000",      newDuration(-10000),        "10 seconds"),
    296 
    297             // from BD req's
    298             new TestCase("en", "PT2H46M40S",   newDuration(1, 2, 46, 40),  "2 hours, 46 minutes, and 40 seconds"),
    299             new TestCase("it", "PT2H46M40S",   newDuration(1, 2, 46, 40),  "due ore, 46 minuti e 40 secondi"),
    300 
    301             // more cases
    302             new TestCase("en", "PT10S",        newDuration(1, 10),         "10 seconds"),
    303             new TestCase("en", "PT88M70S",     newDuration(1, -1, 88, 70), "88 minutes and 70 seconds"),
    304             new TestCase("en", "PT10.100S",    newDuration(1, 10.100F),    "10 seconds and 100 milliseconds"),
    305             new TestCase("en", "-PT10S",       newDuration(-1, 10),        "10 seconds"),
    306             new TestCase("en", "PT0H5M0S",     newDuration(1, 0, 5, 0),    "5 minutes and 0 seconds")
    307         };
    308 
    309         for (TestCase tc : cases) {
    310             String loc = tc.localeString;
    311             String from = tc.durationString;
    312             String to = tc.expected;
    313 
    314             ULocale locale = tc.locale;
    315             Duration d = tc.duration;
    316 
    317             DurationFormat df = DurationFormat.getInstance(locale);
    318             String output = df.format(d);
    319 
    320             if(output.equals(to)) {
    321                 logln("SUCCESS: locale: " + loc + ", from " + from + " ["+d.toString()+"] " +" to " + to + "= " + output);
    322             } else {
    323                 logln("FAIL: locale: " + loc + ", from " + from + " ["+d.toString()+"] " +": expected " + to + " got " + output);
    324             }
    325         }
    326     }
    327 
    328 
    329     @Test
    330     public void TestBadObjectError() {
    331         Runtime r = Runtime.getRuntime();
    332         DurationFormat df = DurationFormat.getInstance(new ULocale("en"));
    333         String output = null;
    334         try {
    335             output = df.format(r);
    336             errln("FAIL: did NOT get IllegalArgumentException! Should have. Formatted Runtime as " + output + " ???");
    337         } catch (IllegalArgumentException iae) {
    338             logln("PASS: expected: Caught iae: " + iae.toString() );
    339         }
    340         // try a second time, because it is a different code path for java < 1.5
    341         try {
    342             output = df.format(r);
    343             errln("FAIL: [#2] did NOT get IllegalArgumentException! Should have. Formatted Runtime as " + output + " ???");
    344         } catch (IllegalArgumentException iae) {
    345             logln("PASS: [#2] expected: Caught iae: " + iae.toString() );
    346         }
    347     }
    348 
    349     @Test
    350     public void TestBadLocaleError() {
    351         try {
    352             DurationFormat df = DurationFormat.getInstance(new ULocale("und"));
    353             df.format(new Date());
    354             logln("Should have thrown err.");
    355             errln("failed, should have thrown err.");
    356         } catch(MissingResourceException mre) {
    357             logln("PASS: caught missing resource exception on locale 'und'");
    358             logln(mre.toString());
    359         }
    360     }
    361 
    362     @Test
    363     public void TestResourceWithCalendar() {
    364         DurationFormat df = DurationFormat.getInstance(new ULocale("th@calendar=buddhist"));
    365         // should pass, but return a default formatter for th.
    366         if (df == null) {
    367             errln("FAIL: null DurationFormat returned.");
    368         }
    369     }
    370 
    371     /* Tests the class
    372      *      DurationFormat
    373      */
    374     @Test
    375     public void TestDurationFormat(){
    376         @SuppressWarnings("serial")
    377         class TestDurationFormat extends DurationFormat {
    378             @Override
    379             public StringBuffer format(Object object, StringBuffer toAppend, FieldPosition pos) {return null;}
    380             @Override
    381             public String formatDurationFrom(long duration, long referenceDate) {return null;}
    382             @Override
    383             public String formatDurationFromNow(long duration) {return null;}
    384             @Override
    385             public String formatDurationFromNowTo(Date targetDate) {return null;}
    386             public TestDurationFormat() {super();}
    387 
    388         }
    389 
    390         // Tests the constructor and the following method
    391         //      public Object parseObject(String source, ParsePosition pos)
    392         try{
    393             TestDurationFormat tdf = new TestDurationFormat();
    394             tdf.parseObject("",null);
    395             errln("DurationFormat.parseObjet(String,ParsePosition) was " +
    396                     "to return an exception for an unsupported operation.");
    397         } catch(Exception e){}
    398     }
    399 
    400     @Test
    401     public void TestFromNowTo() {
    402         class TestCase {
    403             ULocale locale;
    404             int diffInSeconds;
    405             String expected;
    406             TestCase(ULocale locale, int diffInSeconds, String expected) {
    407                 this.locale = locale;
    408                 this.diffInSeconds = diffInSeconds;
    409                 this.expected = expected;
    410             }
    411         }
    412         TestCase[] testCases = {
    413             new TestCase(ULocale.US, 10, "10 seconds from now"),
    414             new TestCase(ULocale.US, -10, "10 seconds ago"),
    415             new TestCase(ULocale.US, -1800, "30 minutes ago"),
    416             new TestCase(ULocale.US, 3600, "1 hour from now"),
    417             new TestCase(ULocale.US, 10000, "2 hours from now"),
    418             new TestCase(ULocale.US, -20000, "5 hours ago"),
    419             new TestCase(ULocale.FRANCE, -1800, "il y a 30 minutes"),
    420             new TestCase(ULocale.ITALY, 10000, "fra due ore"),
    421         };
    422 
    423         final long delayMS = 10;    // Safe margin - 10 milliseconds
    424                                     // See the comments below
    425         for (TestCase test : testCases) {
    426             DurationFormat df = DurationFormat.getInstance(test.locale);
    427             long target = System.currentTimeMillis() + test.diffInSeconds * 1000;
    428             // Need some adjustment because time difference is recalculated in
    429             // formatDurationFromNowTo method.
    430             target = test.diffInSeconds > 0 ? target + delayMS : target - delayMS;
    431             Date d = new Date(target);
    432             String result = df.formatDurationFromNowTo(d);
    433             assertEquals("TestFromNowTo (" + test.locale + ", " + test.diffInSeconds + "sec)",
    434                     test.expected, result);
    435         }
    436     }
    437 }
    438