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