LEFT | RIGHT |
(no file at all) | |
| 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) 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.lang.reflect.Field; |
| 12 import java.lang.reflect.InvocationTargetException; |
| 13 import java.lang.reflect.Method; |
| 14 import java.util.HashMap; |
| 15 import java.util.HashSet; |
| 16 import java.util.Map; |
| 17 |
| 18 import com.ibm.icu.math.BigDecimal; |
| 19 import com.ibm.icu.text.DecimalFormat; |
| 20 import com.ibm.icu.text.NumberFormat; |
| 21 import com.ibm.icu.util.Currency; |
| 22 import com.ibm.icu.util.ULocale; |
| 23 |
| 24 /** |
| 25 * A representation of a single NumberFormat specification test from a data driv
en test file. |
| 26 * <p> |
| 27 * The purpose of this class is to hide the details of the data driven test file
from the |
| 28 * main testing code. |
| 29 * <p> |
| 30 * This class contains fields describing an attribute of the test that may or ma
y |
| 31 * not be set. The name of each attribute corresponds to the name used in the |
| 32 * data driven test file. |
| 33 * <p> |
| 34 * <b>Adding new attributes</b> |
| 35 * <p> |
| 36 * Each attribute name is lower case. Moreover, for each attribute there is also
a |
| 37 * setXXX method for that attribute that is used to initialize the attribute fro
m a |
| 38 * String value read from the data file. For example, there is a setLocale(Strin
g) method |
| 39 * for the locale attribute and a setCurrency(String) method for the currency at
tribute. |
| 40 * In general, for an attribute named abcd, the setter will be setAbcd(String). |
| 41 * This naming rule must be strictly followed or else the test runner will not k
now how to |
| 42 * initialize instances of this class. |
| 43 * <p> |
| 44 * In addition each attribute is listed in the fieldOrdering static array which
specifies |
| 45 * The order that attributes are printed whenever there is a test failure. |
| 46 * <p> |
| 47 * To add a new attribute, first create a public field for it. |
| 48 * Next, add the attribute name to the fieldOrdering array. |
| 49 * Finally, create a setter method for it. |
| 50 * |
| 51 * @author rocketman |
| 52 */ |
| 53 public class DataDrivenNumberFormatTestData { |
| 54 |
| 55 /** |
| 56 * The locale. |
| 57 */ |
| 58 public ULocale locale = null; |
| 59 |
| 60 /** |
| 61 * The currency. |
| 62 */ |
| 63 public Currency currency = null; |
| 64 |
| 65 /** |
| 66 * The pattern to initialize the formatter, for example 0.00" |
| 67 */ |
| 68 public String pattern = null; |
| 69 |
| 70 /** |
| 71 * The value to format as a string. For example 1234.5 would be "1234.5" |
| 72 */ |
| 73 public String format = null; |
| 74 |
| 75 /** |
| 76 * The formatted value. |
| 77 */ |
| 78 public String output = null; |
| 79 |
| 80 /** |
| 81 * Field for arbitrary comments. |
| 82 */ |
| 83 public String comment = null; |
| 84 |
| 85 public Integer minIntegerDigits = null; |
| 86 public Integer maxIntegerDigits = null; |
| 87 public Integer minFractionDigits = null; |
| 88 public Integer maxFractionDigits = null; |
| 89 public Integer minGroupingDigits = null; |
| 90 public Integer useSigDigits = null; |
| 91 public Integer minSigDigits = null; |
| 92 public Integer maxSigDigits = null; |
| 93 public Integer useGrouping = null; |
| 94 public Integer multiplier = null; |
| 95 public Double roundingIncrement = null; |
| 96 public Integer formatWidth = null; |
| 97 public String padCharacter = null; |
| 98 public Integer useScientific = null; |
| 99 public Integer grouping = null; |
| 100 public Integer grouping2 = null; |
| 101 public Integer roundingMode = null; |
| 102 public Currency.CurrencyUsage currencyUsage = null; |
| 103 public Integer minimumExponentDigits = null; |
| 104 public Integer exponentSignAlwaysShown = null; |
| 105 public Integer decimalSeparatorAlwaysShown = null; |
| 106 public Integer padPosition = null; |
| 107 public String positivePrefix = null; |
| 108 public String positiveSuffix = null; |
| 109 public String negativePrefix = null; |
| 110 public String negativeSuffix = null; |
| 111 public String localizedPattern = null; |
| 112 public String toPattern = null; |
| 113 public String toLocalizedPattern = null; |
| 114 public Integer style = null; |
| 115 public String parse = null; |
| 116 public Integer lenient = null; |
| 117 public String plural = null; |
| 118 public Integer parseIntegerOnly = null; |
| 119 public Integer decimalPatternMatchRequired = null; |
| 120 public Integer parseCaseSensitive = null; |
| 121 public Integer parseNoExponent = null; |
| 122 public String outputCurrency = null; |
| 123 |
| 124 |
| 125 |
| 126 /** |
| 127 * nothing or empty means that test ought to work for both C and JAVA; |
| 128 * "C" means test is known to fail in C. "J" means test is known to fail in
JAVA. |
| 129 * "CJ" means test is known to fail for both languages. |
| 130 */ |
| 131 public String breaks = null; |
| 132 |
| 133 private static Map<String, Integer> roundingModeMap = |
| 134 new HashMap<String, Integer>(); |
| 135 |
| 136 static { |
| 137 roundingModeMap.put("ceiling", BigDecimal.ROUND_CEILING); |
| 138 roundingModeMap.put("floor", BigDecimal.ROUND_FLOOR); |
| 139 roundingModeMap.put("down", BigDecimal.ROUND_DOWN); |
| 140 roundingModeMap.put("up", BigDecimal.ROUND_UP); |
| 141 roundingModeMap.put("halfEven", BigDecimal.ROUND_HALF_EVEN); |
| 142 roundingModeMap.put("halfDown", BigDecimal.ROUND_HALF_DOWN); |
| 143 roundingModeMap.put("halfUp", BigDecimal.ROUND_HALF_UP); |
| 144 roundingModeMap.put("unnecessary", BigDecimal.ROUND_UNNECESSARY); |
| 145 } |
| 146 |
| 147 private static Map<String, Currency.CurrencyUsage> currencyUsageMap = |
| 148 new HashMap<String, Currency.CurrencyUsage>(); |
| 149 |
| 150 static { |
| 151 currencyUsageMap.put("standard", Currency.CurrencyUsage.STANDARD); |
| 152 currencyUsageMap.put("cash", Currency.CurrencyUsage.CASH); |
| 153 } |
| 154 |
| 155 private static Map<String, Integer> padPositionMap = |
| 156 new HashMap<String, Integer>(); |
| 157 |
| 158 static { |
| 159 // TODO: Fix so that it doesn't depend on DecimalFormat. |
| 160 padPositionMap.put("beforePrefix", DecimalFormat.PAD_BEFORE_PREFIX); |
| 161 padPositionMap.put("afterPrefix", DecimalFormat.PAD_AFTER_PREFIX); |
| 162 padPositionMap.put("beforeSuffix", DecimalFormat.PAD_BEFORE_SUFFIX); |
| 163 padPositionMap.put("afterSuffix", DecimalFormat.PAD_AFTER_SUFFIX); |
| 164 } |
| 165 |
| 166 private static Map<String, Integer> formatStyleMap = |
| 167 new HashMap<String, Integer>(); |
| 168 |
| 169 static { |
| 170 formatStyleMap.put("decimal", NumberFormat.NUMBERSTYLE); |
| 171 formatStyleMap.put("currency", NumberFormat.CURRENCYSTYLE); |
| 172 formatStyleMap.put("percent", NumberFormat.PERCENTSTYLE); |
| 173 formatStyleMap.put("scientific", NumberFormat.SCIENTIFICSTYLE); |
| 174 formatStyleMap.put("currencyIso", NumberFormat.ISOCURRENCYSTYLE); |
| 175 formatStyleMap.put("currencyPlural", NumberFormat.PLURALCURRENCYSTYLE); |
| 176 formatStyleMap.put("currencyAccounting", NumberFormat.ACCOUNTINGCURRENCY
STYLE); |
| 177 formatStyleMap.put("cashCurrency", NumberFormat.CASHCURRENCYSTYLE); |
| 178 } |
| 179 |
| 180 // Add any new fields here. On test failures, fields are printed in the same
order they |
| 181 // appear here. |
| 182 private static String[] fieldOrdering = { |
| 183 "locale", |
| 184 "currency", |
| 185 "pattern", |
| 186 "format", |
| 187 "output", |
| 188 "comment", |
| 189 "minIntegerDigits", |
| 190 "maxIntegerDigits", |
| 191 "minFractionDigits", |
| 192 "maxFractionDigits", |
| 193 "minGroupingDigits", |
| 194 "breaks", |
| 195 "useSigDigits", |
| 196 "minSigDigits", |
| 197 "maxSigDigits", |
| 198 "useGrouping", |
| 199 "multiplier", |
| 200 "roundingIncrement", |
| 201 "formatWidth", |
| 202 "padCharacter", |
| 203 "useScientific", |
| 204 "grouping", |
| 205 "grouping2", |
| 206 "roundingMode", |
| 207 "currencyUsage", |
| 208 "minimumExponentDigits", |
| 209 "exponentSignAlwaysShown", |
| 210 "decimalSeparatorAlwaysShown", |
| 211 "padPosition", |
| 212 "positivePrefix", |
| 213 "positiveSuffix", |
| 214 "negativePrefix", |
| 215 "negativeSuffix", |
| 216 "localizedPattern", |
| 217 "toPattern", |
| 218 "toLocalizedPattern", |
| 219 "style", |
| 220 "parse", |
| 221 "lenient", |
| 222 "plural", |
| 223 "parseIntegerOnly", |
| 224 "decimalPatternMatchRequired", |
| 225 "parseNoExponent", |
| 226 "outputCurrency" |
| 227 }; |
| 228 |
| 229 static { |
| 230 HashSet<String> set = new HashSet<String>(); |
| 231 for (String s : fieldOrdering) { |
| 232 if (!set.add(s)) { |
| 233 throw new ExceptionInInitializerError(s + "is a duplicate field.
"); |
| 234 } |
| 235 } |
| 236 } |
| 237 |
| 238 private static <T> T fromString(Map<String, T> map, String key) { |
| 239 T value = map.get(key); |
| 240 if (value == null) { |
| 241 throw new IllegalArgumentException("Bad value: "+ key); |
| 242 } |
| 243 return value; |
| 244 } |
| 245 |
| 246 // start field setters. |
| 247 // add setter for each new field in this block. |
| 248 |
| 249 public void setLocale(String value) { |
| 250 locale = new ULocale(value); |
| 251 } |
| 252 |
| 253 public void setCurrency(String value) { |
| 254 currency = Currency.getInstance(value); |
| 255 } |
| 256 |
| 257 public void setPattern(String value) { |
| 258 pattern = value; |
| 259 } |
| 260 |
| 261 public void setFormat(String value) { |
| 262 format = value; |
| 263 } |
| 264 |
| 265 public void setOutput(String value) { |
| 266 output = value; |
| 267 } |
| 268 |
| 269 public void setComment(String value) { |
| 270 comment = value; |
| 271 } |
| 272 |
| 273 public void setMinIntegerDigits(String value) { |
| 274 minIntegerDigits = Integer.valueOf(value); |
| 275 } |
| 276 |
| 277 public void setMaxIntegerDigits(String value) { |
| 278 maxIntegerDigits = Integer.valueOf(value); |
| 279 } |
| 280 |
| 281 public void setMinFractionDigits(String value) { |
| 282 minFractionDigits = Integer.valueOf(value); |
| 283 } |
| 284 |
| 285 public void setMaxFractionDigits(String value) { |
| 286 maxFractionDigits = Integer.valueOf(value); |
| 287 } |
| 288 |
| 289 public void setMinGroupingDigits(String value) { |
| 290 minGroupingDigits = Integer.valueOf(value); |
| 291 } |
| 292 |
| 293 public void setBreaks(String value) { |
| 294 breaks = value; |
| 295 } |
| 296 |
| 297 public void setUseSigDigits(String value) { |
| 298 useSigDigits = Integer.valueOf(value); |
| 299 } |
| 300 |
| 301 public void setMinSigDigits(String value) { |
| 302 minSigDigits = Integer.valueOf(value); |
| 303 } |
| 304 |
| 305 public void setMaxSigDigits(String value) { |
| 306 maxSigDigits = Integer.valueOf(value); |
| 307 } |
| 308 |
| 309 public void setUseGrouping(String value) { |
| 310 useGrouping = Integer.valueOf(value); |
| 311 } |
| 312 |
| 313 public void setMultiplier(String value) { |
| 314 multiplier = Integer.valueOf(value); |
| 315 } |
| 316 |
| 317 public void setRoundingIncrement(String value) { |
| 318 roundingIncrement = Double.valueOf(value); |
| 319 } |
| 320 |
| 321 public void setFormatWidth(String value) { |
| 322 formatWidth = Integer.valueOf(value); |
| 323 } |
| 324 |
| 325 public void setPadCharacter(String value) { |
| 326 padCharacter = value; |
| 327 } |
| 328 |
| 329 public void setUseScientific(String value) { |
| 330 useScientific = Integer.valueOf(value); |
| 331 } |
| 332 |
| 333 public void setGrouping(String value) { |
| 334 grouping = Integer.valueOf(value); |
| 335 } |
| 336 |
| 337 public void setGrouping2(String value) { |
| 338 grouping2 = Integer.valueOf(value); |
| 339 } |
| 340 |
| 341 public void setRoundingMode(String value) { |
| 342 roundingMode = fromString(roundingModeMap, value); |
| 343 } |
| 344 |
| 345 public void setCurrencyUsage(String value) { |
| 346 currencyUsage = fromString(currencyUsageMap, value); |
| 347 } |
| 348 |
| 349 public void setMinimumExponentDigits(String value) { |
| 350 minimumExponentDigits = Integer.valueOf(value); |
| 351 } |
| 352 |
| 353 public void setExponentSignAlwaysShown(String value) { |
| 354 exponentSignAlwaysShown = Integer.valueOf(value); |
| 355 } |
| 356 |
| 357 public void setDecimalSeparatorAlwaysShown(String value) { |
| 358 decimalSeparatorAlwaysShown = Integer.valueOf(value); |
| 359 } |
| 360 |
| 361 public void setPadPosition(String value) { |
| 362 padPosition = fromString(padPositionMap, value); |
| 363 } |
| 364 |
| 365 public void setPositivePrefix(String value) { |
| 366 positivePrefix = value; |
| 367 } |
| 368 |
| 369 public void setPositiveSuffix(String value) { |
| 370 positiveSuffix = value; |
| 371 } |
| 372 |
| 373 public void setNegativePrefix(String value) { |
| 374 negativePrefix = value; |
| 375 } |
| 376 |
| 377 public void setNegativeSuffix(String value) { |
| 378 negativeSuffix = value; |
| 379 } |
| 380 |
| 381 public void setLocalizedPattern(String value) { |
| 382 localizedPattern = value; |
| 383 } |
| 384 |
| 385 public void setToPattern(String value) { |
| 386 toPattern = value; |
| 387 } |
| 388 |
| 389 public void setToLocalizedPattern(String value) { |
| 390 toLocalizedPattern = value; |
| 391 } |
| 392 |
| 393 public void setStyle(String value) { |
| 394 style = fromString(formatStyleMap, value); |
| 395 } |
| 396 |
| 397 public void setParse(String value) { |
| 398 parse = value; |
| 399 } |
| 400 |
| 401 public void setLenient(String value) { |
| 402 lenient = Integer.valueOf(value); |
| 403 } |
| 404 |
| 405 public void setPlural(String value) { |
| 406 plural = value; |
| 407 } |
| 408 |
| 409 public void setParseIntegerOnly(String value) { |
| 410 parseIntegerOnly = Integer.valueOf(value); |
| 411 } |
| 412 |
| 413 public void setParseCaseSensitive(String value) { |
| 414 parseCaseSensitive = Integer.valueOf(value); |
| 415 } |
| 416 |
| 417 public void setDecimalPatternMatchRequired(String value) { |
| 418 decimalPatternMatchRequired = Integer.valueOf(value); |
| 419 } |
| 420 |
| 421 public void setParseNoExponent(String value) { |
| 422 parseNoExponent = Integer.valueOf(value); |
| 423 } |
| 424 |
| 425 public void setOutputCurrency(String value) { |
| 426 outputCurrency = value; |
| 427 } |
| 428 |
| 429 // end field setters. |
| 430 |
| 431 // start of field clearers |
| 432 // Add clear methods that can be set in one test and cleared |
| 433 // in the next i.e the breaks field. |
| 434 |
| 435 public void clearBreaks() { |
| 436 breaks = null; |
| 437 } |
| 438 |
| 439 public void clearUseGrouping() { |
| 440 useGrouping = null; |
| 441 } |
| 442 |
| 443 public void clearGrouping2() { |
| 444 grouping2 = null; |
| 445 } |
| 446 |
| 447 public void clearGrouping() { |
| 448 grouping = null; |
| 449 } |
| 450 |
| 451 public void clearMinGroupingDigits() { |
| 452 minGroupingDigits = null; |
| 453 } |
| 454 |
| 455 public void clearUseScientific() { |
| 456 useScientific = null; |
| 457 } |
| 458 |
| 459 public void clearDecimalSeparatorAlwaysShown() { |
| 460 decimalSeparatorAlwaysShown = null; |
| 461 } |
| 462 |
| 463 // end field clearers |
| 464 |
| 465 public void setField(String fieldName, String valueString) |
| 466 throws NoSuchMethodException { |
| 467 Method m = getClass().getMethod( |
| 468 fieldToSetter(fieldName), String.class); |
| 469 try { |
| 470 m.invoke(this, valueString); |
| 471 } catch (IllegalAccessException e) { |
| 472 throw new RuntimeException(e); |
| 473 } catch (InvocationTargetException e) { |
| 474 throw new RuntimeException(e); |
| 475 } |
| 476 } |
| 477 |
| 478 public void clearField(String fieldName) |
| 479 throws NoSuchMethodException { |
| 480 Method m = getClass().getMethod(fieldToClearer(fieldName)); |
| 481 try { |
| 482 m.invoke(this); |
| 483 } catch (IllegalAccessException e) { |
| 484 throw new RuntimeException(e); |
| 485 } catch (InvocationTargetException e) { |
| 486 throw new RuntimeException(e); |
| 487 } |
| 488 } |
| 489 |
| 490 @Override |
| 491 public String toString() { |
| 492 StringBuilder result = new StringBuilder(); |
| 493 result.append("{"); |
| 494 boolean first = true; |
| 495 for (String fieldName : fieldOrdering) { |
| 496 try { |
| 497 Field field = getClass().getField(fieldName); |
| 498 Object optionalValue = field.get(this); |
| 499 if (optionalValue == null) { |
| 500 continue; |
| 501 } |
| 502 if (!first) { |
| 503 result.append(", "); |
| 504 } |
| 505 first = false; |
| 506 result.append(fieldName); |
| 507 result.append(": "); |
| 508 result.append(optionalValue); |
| 509 } catch (NoSuchFieldException e) { |
| 510 throw new RuntimeException(e); |
| 511 } catch (SecurityException e) { |
| 512 throw new RuntimeException(e); |
| 513 } catch (IllegalAccessException e) { |
| 514 throw new RuntimeException(e); |
| 515 } |
| 516 } |
| 517 result.append("}"); |
| 518 return result.toString(); |
| 519 } |
| 520 |
| 521 private static String fieldToSetter(String fieldName) { |
| 522 return "set" |
| 523 + Character.toUpperCase(fieldName.charAt(0)) |
| 524 + fieldName.substring(1); |
| 525 } |
| 526 |
| 527 private static String fieldToClearer(String fieldName) { |
| 528 return "clear" |
| 529 + Character.toUpperCase(fieldName.charAt(0)) |
| 530 + fieldName.substring(1); |
| 531 } |
| 532 |
| 533 } |
LEFT | RIGHT |