1 /*
2  *******************************************************************************
3  * Copyright (C) 2008-2014, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.dev.test.format;
8 
9 import java.text.ParseException;
10 import java.text.ParsePosition;
11 import java.util.Locale;
12 
13 import com.ibm.icu.dev.test.TestFmwk;
14 import com.ibm.icu.math.BigDecimal;
15 import com.ibm.icu.text.MeasureFormat;
16 import com.ibm.icu.text.NumberFormat;
17 import com.ibm.icu.text.TimeUnitFormat;
18 import com.ibm.icu.util.Measure;
19 import com.ibm.icu.util.MeasureUnit;
20 import com.ibm.icu.util.TimeUnit;
21 import com.ibm.icu.util.TimeUnitAmount;
22 import com.ibm.icu.util.ULocale;
23 
24 /**
25  * @author markdavis
26  *
27  */
28 public class TimeUnitTest extends TestFmwk {
main(String[] args)29     public static void main(String[] args) throws Exception{
30         new TimeUnitTest().run(args);
31     }
32 
Test10219FractionalPlurals()33     public void Test10219FractionalPlurals() {
34         TimeUnitFormat tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
35         String[] expected = {"1 minute", "1.5 minutes", "1.58 minutes"};
36         for (int i = 2; i >= 0; i--) {
37             NumberFormat nf = NumberFormat.getNumberInstance(ULocale.ENGLISH);
38             nf.setRoundingMode(BigDecimal.ROUND_DOWN);
39             nf.setMaximumFractionDigits(i);
40             tuf.setNumberFormat(nf);
41             assertEquals("Test10219", expected[i], tuf.format(new TimeUnitAmount(1.588, TimeUnit.MINUTE)));
42         }
43     }
44 
Test10219FactionalPluralsParse()45     public void Test10219FactionalPluralsParse() throws ParseException {
46         TimeUnitFormat tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
47         ParsePosition ppos = new ParsePosition(0);
48         String parseString = "1 minutes";
49         tuf.parseObject(parseString, ppos);
50 
51         // Parsing should go all the way to the end of the string.
52         // We want the longest match, and we don't care if the plural form of the unit
53         // matches the plural form of the number.
54         assertEquals("Test10219FractionalPluralParse", parseString.length(), ppos.getIndex());
55     }
56 
TestBasic()57     public void TestBasic() {
58         String[] locales = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant"};
59         for ( int locIndex = 0; locIndex < locales.length; ++locIndex ) {
60             //System.out.println("locale: " + locales[locIndex]);
61             TimeUnitFormat[] formats = new TimeUnitFormat[] {
62                 new TimeUnitFormat(new ULocale(locales[locIndex]), TimeUnitFormat.FULL_NAME),
63                 new TimeUnitFormat(new ULocale(locales[locIndex]), TimeUnitFormat.ABBREVIATED_NAME),
64 
65             };
66             for (int style = TimeUnitFormat.FULL_NAME;
67                  style <= TimeUnitFormat.ABBREVIATED_NAME;
68                  ++style) {
69                 final TimeUnit[] values = TimeUnit.values();
70                 for (int j = 0; j < values.length; ++j) {
71                     final TimeUnit timeUnit = values[j];
72                     double[] tests = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35};
73                     for (int i = 0; i < tests.length; ++i) {
74                         TimeUnitAmount source = new TimeUnitAmount(tests[i], timeUnit);
75                         String formatted = formats[style].format(source);
76                         //System.out.println(formatted);
77                         logln(tests[i] + " => " + formatted);
78                         try {
79                             // Style should not matter when parsing.
80                             for (int parseStyle = TimeUnitFormat.FULL_NAME; parseStyle <= TimeUnitFormat.ABBREVIATED_NAME; parseStyle++) {
81                                 TimeUnitAmount result = (TimeUnitAmount) formats[parseStyle].parseObject(formatted);
82                                 if (result == null || !source.equals(result)) {
83                                     errln("No round trip: " + source + " => " + formatted + " => " + result);
84                                 }
85                             }
86                         } catch (ParseException e) {
87                             errln(e.getMessage());
88                         }
89                     }
90                 }
91             }
92         }
93     }
94 
TestAPI()95     public void TestAPI() {
96         TimeUnitFormat format = new TimeUnitFormat();
97         format.setLocale(new ULocale("pt_BR"));
98         formatParsing(format);
99         format = new TimeUnitFormat(new ULocale("de"));
100         formatParsing(format);
101         format = new TimeUnitFormat(new ULocale("ja"));
102         format.setNumberFormat(NumberFormat.getNumberInstance(new ULocale("en")));
103         formatParsing(format);
104 
105         format = new TimeUnitFormat();
106         ULocale es = new ULocale("es");
107         format.setNumberFormat(NumberFormat.getNumberInstance(es));
108         format.setLocale(es);
109         formatParsing(format);
110 
111         format.setLocale(new Locale("pt_BR"));
112         formatParsing(format);
113         format = new TimeUnitFormat(new Locale("de"));
114         formatParsing(format);
115         format = new TimeUnitFormat(new Locale("ja"));
116         format.setNumberFormat(NumberFormat.getNumberInstance(new Locale("en")));
117         formatParsing(format);
118     }
119 
TestClone()120     public void TestClone() {
121         TimeUnitFormat tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.ABBREVIATED_NAME);
122         NumberFormat nf = NumberFormat.getInstance();
123         tuf.setNumberFormat(nf);
124         TimeUnitFormat tufClone = (TimeUnitFormat) tuf.clone();
125         tuf.setLocale(Locale.GERMAN);
126         assertEquals("", "1 hr", tufClone.format(new TimeUnitAmount(1, TimeUnit.HOUR)));
127     }
128 
TestEqHashCode()129     public void TestEqHashCode() {
130         TimeUnitFormat tf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
131         MeasureFormat tfeq = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
132 
133         MeasureFormat tfne = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.ABBREVIATED_NAME);
134         MeasureFormat tfne2 = new TimeUnitFormat(ULocale.GERMAN, TimeUnitFormat.FULL_NAME);
135         verifyEqualsHashCode(tf, tfeq, tfne);
136         verifyEqualsHashCode(tf, tfeq, tfne2);
137     }
138 
TestGetLocale()139     public void TestGetLocale() {
140         TimeUnitFormat tf = new TimeUnitFormat(ULocale.GERMAN);
141         assertEquals("", ULocale.GERMAN, tf.getLocale(ULocale.VALID_LOCALE));
142     }
143 
144     /*
145      * @bug 7902
146      * This tests that requests for short unit names correctly fall back
147      * to long unit names for a locale where the locale data does not
148      * provide short unit names. As of CLDR 1.9, Greek is one such language.
149      */
TestGreek()150     public void TestGreek() {
151         String[] locales = {"el_GR", "el"};
152         final TimeUnit[] units = new TimeUnit[]{
153                 TimeUnit.SECOND,
154                 TimeUnit.MINUTE,
155                 TimeUnit.HOUR,
156                 TimeUnit.DAY,
157                 TimeUnit.WEEK,
158                 TimeUnit.MONTH,
159                 TimeUnit.YEAR};
160         int[] styles = new int[] {TimeUnitFormat.FULL_NAME, TimeUnitFormat.ABBREVIATED_NAME};
161         int[] numbers = new int[] {1, 7};
162 
163         String[] expected = {
164                 // "el_GR" 1 wide
165                 "1 δευτερόλεπτο",
166                 "1 λεπτό",
167                 "1 ώρα",
168                 "1 ημέρα",
169                 "1 εβδομάδα",
170                 "1 μήνας",
171                 "1 έτος",
172                 // "el_GR" 1 short
173                 "1 δευτ.",
174                 "1 λεπ.",
175                 "1 ώρα",
176                 "1 ημέρα",
177                 "1 εβδ.",
178                 "1 μήν.",
179                 "1 έτ.",	        // year (one)
180                 // "el_GR" 7 wide
181                 "7 δευτερόλεπτα",
182                 "7 λεπτά",
183                 "7 ώρες",
184                 "7 ημέρες",
185                 "7 εβδομάδες",
186                 "7 μήνες",
187                 "7 έτη",
188                 // "el_GR" 7 short
189                 "7 δευτ.",
190                 "7 λεπ.",
191                 "7 ώρ.",		    // hour (other)
192                 "7 ημέρες",
193                 "7 εβδ.",
194                 "7 μήν.",
195                 "7 έτ.",            // year (other)
196                 // "el" 1 wide
197                 "1 δευτερόλεπτο",
198                 "1 λεπτό",
199                 "1 ώρα",
200                 "1 ημέρα",
201                 "1 εβδομάδα",
202                 "1 μήνας",
203                 "1 έτος",
204                 // "el" 1 short
205                 "1 δευτ.",
206                 "1 λεπ.",
207                 "1 ώρα",
208                 "1 ημέρα",
209                 "1 εβδ.",
210                 "1 μήν.",
211                 "1 έτ.",	        // year (one)
212                 // "el" 7 wide
213                 "7 δευτερόλεπτα",
214                 "7 λεπτά",
215                 "7 ώρες",
216                 "7 ημέρες",
217                 "7 εβδομάδες",
218                 "7 μήνες",
219                 "7 έτη",
220                 // "el" 7 short
221                 "7 δευτ.",
222                 "7 λεπ.",
223                 "7 ώρ.",		    // hour (other)
224                 "7 ημέρες",
225                 "7 εβδ.",
226                 "7 μήν.",
227                 "7 έτ."};           // year (other
228 
229         int counter = 0;
230         TimeUnitFormat timeUnitFormat;
231         TimeUnitAmount timeUnitAmount;
232         String formatted;
233 
234         for ( int locIndex = 0; locIndex < locales.length; ++locIndex ) {
235             for( int numIndex = 0; numIndex < numbers.length; ++numIndex ) {
236                 for ( int styleIndex = 0; styleIndex < styles.length; ++styleIndex ) {
237                     for ( int unitIndex = 0; unitIndex < units.length; ++unitIndex ) {
238 
239                         timeUnitAmount = new TimeUnitAmount(numbers[numIndex], units[unitIndex]);
240                         timeUnitFormat = new TimeUnitFormat(new ULocale(locales[locIndex]), styles[styleIndex]);
241                         formatted = timeUnitFormat.format(timeUnitAmount);
242 
243                         assertEquals(
244                                 "locale: " + locales[locIndex]
245                                         + ", style: " + styles[styleIndex]
246                                                 + ", units: " + units[unitIndex]
247                                                         + ", value: " + numbers[numIndex],
248                                                 expected[counter], formatted);
249                         ++counter;
250                     }
251                 }
252             }
253         }
254     }
255 
256     /**
257      * @bug9042
258      * Performs tests for Greek.
259      * This tests that if the plural count listed in time unit format does not
260      * match those in the plural rules for the locale, those plural count in
261      * time unit format will be ingored and subsequently, fall back will kick in
262      * which is tested above.
263      * Without data sanitization, setNumberFormat() would crash.
264      * As of CLDR shiped in ICU4.8, Greek is one such language.
265      */
TestGreekWithSanitization()266     public void TestGreekWithSanitization() {
267         ULocale loc = new ULocale("el");
268         NumberFormat numfmt = NumberFormat.getInstance(loc);
269         TimeUnitFormat tuf = new TimeUnitFormat(loc);
270         tuf.parseObject("", new ParsePosition(0));
271         tuf.setNumberFormat(numfmt);
272     }
273 
274 
formatParsing(TimeUnitFormat format)275     private void formatParsing(TimeUnitFormat format) {
276         final TimeUnit[] values = TimeUnit.values();
277         for (int j = 0; j < values.length; ++j) {
278             final TimeUnit timeUnit = values[j];
279             double[] tests = {0, 0.5, 1, 2, 3, 5};
280             for (int i = 0; i < tests.length; ++i) {
281                 TimeUnitAmount source = new TimeUnitAmount(tests[i], timeUnit);
282                 String formatted = format.format(source);
283                 //System.out.println(formatted);
284                 logln(tests[i] + " => " + formatted);
285                 try {
286                     TimeUnitAmount result = (TimeUnitAmount) format.parseObject(formatted);
287                     if (result == null || !source.equals(result)) {
288                         errln("No round trip: " + source + " => " + formatted + " => " + result);
289                     }
290                 } catch (ParseException e) {
291                     errln(e.getMessage());
292                 }
293             }
294         }
295     }
296 
297     /*
298      * Tests the method public TimeUnitFormat(ULocale locale, int style), public TimeUnitFormat(Locale locale, int style)
299      */
300     @SuppressWarnings("unused")
TestTimeUnitFormat()301     public void TestTimeUnitFormat() {
302         // Tests when "if (style < FULL_NAME || style >= TOTAL_STYLES)" is true
303         // TOTAL_STYLES is 2
304         int[] cases = { TimeUnitFormat.FULL_NAME - 1, TimeUnitFormat.FULL_NAME - 2, 3 };
305         for (int i = 0; i < cases.length; i++) {
306             try {
307                 TimeUnitFormat tuf = new TimeUnitFormat(new ULocale("en_US"), cases[i]);
308                 errln("TimeUnitFormat(ULocale,int) was suppose to return an " + "exception for a style value of "
309                         + cases[i] + "passed into the constructor.");
310             } catch (Exception e) {
311             }
312         }
313         for (int i = 0; i < cases.length; i++) {
314             try {
315                 TimeUnitFormat tuf = new TimeUnitFormat(new Locale("en_US"), cases[i]);
316                 errln("TimeUnitFormat(ULocale,int) was suppose to return an " + "exception for a style value of "
317                         + cases[i] + "passed into the constructor.");
318             } catch (Exception e) {
319             }
320         }
321     }
322 
323     /*
324      * Tests the method public TimeUnitFormat setLocale(ULocale locale) public TimeUnitFormat setLocale(Locale locale)
325      */
TestSetLocale()326     public void TestSetLocale() {
327         // Tests when "if ( locale != this.locale )" is false
328         TimeUnitFormat tuf = new TimeUnitFormat(new ULocale("en_US"));
329         if (!tuf.setLocale(new ULocale("en_US")).equals(tuf) && !tuf.setLocale(new Locale("en_US")).equals(tuf)) {
330             errln("TimeUnitFormat.setLocale(ULocale) was suppose to "
331                     + "return the same TimeUnitFormat object if the same " + "ULocale is entered as a parameter.");
332         }
333     }
334 
335     /*
336      * Tests the method public TimeUnitFormat setNumberFormat(NumberFormat format)
337      */
TestSetNumberFormat()338     public void TestSetNumberFormat() {
339         TimeUnitFormat tuf = new TimeUnitFormat();
340 
341         // Tests when "if (format == this.format)" is false
342         // Tests when "if ( format == null )" is false
343         tuf.setNumberFormat(NumberFormat.getInstance());
344 
345         // Tests when "if (format == this.format)" is true
346         if (!tuf.setNumberFormat(NumberFormat.getInstance()).equals(tuf)) {
347             errln("TimeUnitFormat.setNumberFormat(NumberFormat) was suppose to "
348                     + "return the same object when the same NumberFormat is passed.");
349         }
350 
351         // Tests when "if ( format == null )" is true
352         // Tests when "if ( locale == null )" is true
353         if (!tuf.setNumberFormat(null).equals(tuf)) {
354             errln("TimeUnitFormat.setNumberFormat(NumberFormat) was suppose to "
355                     + "return the same object when null is passed.");
356         }
357 
358         TimeUnitFormat tuf1 = new TimeUnitFormat(new ULocale("en_US"));
359 
360         // Tests when "if ( locale == null )" is false
361         tuf1.setNumberFormat(NumberFormat.getInstance());
362         tuf1.setNumberFormat(null);
363     }
364 
365     /*
366      * Tests the method public StringBuffer format(Object obj, ...
367      */
TestFormat()368     public void TestFormat() {
369         TimeUnitFormat tuf = new TimeUnitFormat();
370         try {
371             tuf.format(new Integer("1"), null, null);
372             errln("TimeUnitFormat.format(Object,StringBuffer,FieldPosition) "
373                     + "was suppose to return an exception because the Object "
374                     + "parameter was not of type TimeUnitAmount.");
375         } catch (Exception e) {
376         }
377     }
378 
379     /* Tests the method private void setup() from
380      * public Object parseObject(String source, ParsePosition pos)
381      *
382      */
TestSetup()383     public void TestSetup(){
384         TimeUnitFormat tuf = new TimeUnitFormat();
385         tuf.parseObject("", new ParsePosition(0));
386 
387         TimeUnitFormat tuf1 = new TimeUnitFormat();
388         tuf1.setNumberFormat(NumberFormat.getInstance());
389         tuf1.parseObject("", new ParsePosition(0));
390     }
391 
TestStandInForMeasureFormat()392     public void TestStandInForMeasureFormat() {
393         TimeUnitFormat tuf = new TimeUnitFormat(ULocale.FRENCH, TimeUnitFormat.ABBREVIATED_NAME);
394         Measure measure = new Measure(23, MeasureUnit.CELSIUS);
395         assertEquals("23 °C", "23 °C", tuf.format(measure));
396         tuf = new TimeUnitFormat(ULocale.FRENCH, TimeUnitFormat.FULL_NAME);
397         assertEquals(
398                 "70 pied et 5,3 pouces",
399                 "70 pieds et 5,3 pouces",
400                 tuf.formatMeasures(
401                         new Measure(70, MeasureUnit.FOOT),
402                         new Measure(5.3, MeasureUnit.INCH)));
403         assertEquals("getLocale", ULocale.FRENCH, tuf.getLocale());
404         assertEquals("getNumberFormat", ULocale.FRENCH, tuf.getNumberFormat().getLocale(ULocale.VALID_LOCALE));
405         assertEquals("getWidth", MeasureFormat.FormatWidth.WIDE, tuf.getWidth());
406     }
407 
verifyEqualsHashCode(Object o, Object eq, Object ne)408     private void verifyEqualsHashCode(Object o, Object eq, Object ne) {
409         assertEquals("verifyEqualsHashCodeSame", o, o);
410         assertEquals("verifyEqualsHashCodeEq", o, eq);
411         assertNotEquals("verifyEqualsHashCodeNe", o, ne);
412         assertNotEquals("verifyEqualsHashCodeEqTrans", eq, ne);
413         assertEquals("verifyEqualsHashCodeHashEq", o.hashCode(), eq.hashCode());
414 
415         // May be a flaky test, but generally should be true.
416         // May need to comment this out later.
417         assertNotEquals("verifyEqualsHashCodeHashNe", o.hashCode(), ne.hashCode());
418     }
419 }
420