1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.text; 18 19 import java.math.BigInteger; 20 import java.math.RoundingMode; 21 import java.text.DecimalFormat; 22 import java.text.DecimalFormatSymbols; 23 import java.text.FieldPosition; 24 import java.text.NumberFormat; 25 import java.text.ParsePosition; 26 import java.util.Currency; 27 import java.util.Locale; 28 29 public class NumberFormatTest extends junit.framework.TestCase { 30 // NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls doubleValue for 31 // custom Number subclasses. 32 public void test_custom_Number_gets_longValue() throws Exception { 33 class MyNumber extends Number { 34 public byte byteValue() { throw new UnsupportedOperationException(); } 35 public double doubleValue() { return 123; } 36 public float floatValue() { throw new UnsupportedOperationException(); } 37 public int intValue() { throw new UnsupportedOperationException(); } 38 public long longValue() { throw new UnsupportedOperationException(); } 39 public short shortValue() { throw new UnsupportedOperationException(); } 40 public String toString() { throw new UnsupportedOperationException(); } 41 } 42 NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); 43 assertEquals("123", nf.format(new MyNumber())); 44 } 45 46 // NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls longValue for 47 // any BigInteger with a bitLength strictly less than 64. 48 public void test_small_BigInteger_gets_longValue() throws Exception { 49 class MyNumberFormat extends NumberFormat { 50 public StringBuffer format(double value, StringBuffer b, FieldPosition f) { 51 b.append("double"); 52 return b; 53 } 54 public StringBuffer format(long value, StringBuffer b, FieldPosition f) { 55 b.append("long"); 56 return b; 57 } 58 public Number parse(String string, ParsePosition p) { 59 throw new UnsupportedOperationException(); 60 } 61 } 62 NumberFormat nf = new MyNumberFormat(); 63 assertEquals("long", nf.format(BigInteger.valueOf(Long.MAX_VALUE))); 64 assertEquals("double", nf.format(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE))); 65 assertEquals("long", nf.format(BigInteger.valueOf(Long.MIN_VALUE))); 66 assertEquals("double", nf.format(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE))); 67 } 68 69 public void test_getIntegerInstance_ar() throws Exception { 70 // Previous versions of android use just the positive format string (ICU4C) although now we 71 // use '<positive_format>;<negative_format>' because of ICU4J denormalization. 72 NumberFormat numberFormat = NumberFormat.getNumberInstance(new Locale("ar")); 73 String patternNI = ((DecimalFormat) numberFormat).toPattern(); 74 assertTrue("#,##0.###;-#,##0.###".equals(patternNI) || "#,##0.###".equals(patternNI)); 75 NumberFormat integerFormat = NumberFormat.getIntegerInstance(new Locale("ar")); 76 String patternII = ((DecimalFormat) integerFormat).toPattern(); 77 assertTrue("#,##0;-#,##0".equals(patternII) || "#,##0".equals(patternII)); 78 } 79 80 public void test_numberLocalization() throws Exception { 81 Locale arabic = new Locale("ar"); 82 NumberFormat nf = NumberFormat.getNumberInstance(arabic); 83 assertEquals('\u0660', new DecimalFormatSymbols(arabic).getZeroDigit()); 84 assertEquals("", nf.format(1234567890)); 85 } 86 87 // Formatting percentages is confusing but deliberate. 88 // Ensure we don't accidentally "fix" this. 89 // https://code.google.com/p/android/issues/detail?id=10333 90 public void test_10333() throws Exception { 91 NumberFormat nf = NumberFormat.getPercentInstance(Locale.US); 92 assertEquals("15%", nf.format(0.15)); 93 assertEquals("1,500%", nf.format(15)); 94 try { 95 nf.format("15"); 96 fail(); 97 } catch (IllegalArgumentException expected) { 98 } 99 } 100 101 public void testPercentageRounding() throws Exception { 102 NumberFormat nf = NumberFormat.getPercentInstance(Locale.US); 103 assertEquals("15%", nf.format(0.149)); 104 assertEquals("14%", nf.format(0.142)); 105 106 nf.setRoundingMode(RoundingMode.UP); 107 assertEquals("15%", nf.format(0.142)); 108 109 nf.setRoundingMode(RoundingMode.DOWN); 110 assertEquals("14%", nf.format(0.149)); 111 112 nf.setMaximumFractionDigits(1); 113 assertEquals("14.9%", nf.format(0.149)); 114 } 115 116 // https://code.google.com/p/android/issues/detail?id=62269 117 public void test_62269() throws Exception { 118 NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); 119 try { 120 nf.parse(null); 121 fail(); 122 } catch (NullPointerException expected) { 123 } 124 } 125 126 public void test_nullLocales() { 127 try { 128 NumberFormat.getInstance(null); 129 fail(); 130 } catch (NullPointerException expected) {} 131 132 try { 133 NumberFormat.getIntegerInstance(null); 134 fail(); 135 } catch (NullPointerException expected) {} 136 137 try { 138 NumberFormat.getCurrencyInstance(null); 139 fail(); 140 } catch (NullPointerException expected) {} 141 142 try { 143 NumberFormat.getPercentInstance(null); 144 fail(); 145 } catch (NullPointerException expected) {} 146 147 try { 148 NumberFormat.getNumberInstance(null); 149 fail(); 150 } catch (NullPointerException expected) {} 151 } 152 153 // https://code.google.com/p/android/issues/detail?id=79925\ 154 // When switching currency after having initialised a DecimalFormat instance to a currency, 155 // the symbols are missing. 156 public void test_issue79925() { 157 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US); 158 nf.setCurrency(Currency.getInstance("EUR")); 159 assertEquals("50.00", nf.format(50.0)); 160 161 DecimalFormatSymbols decimalFormatSymbols = ((DecimalFormat) nf).getDecimalFormatSymbols(); 162 decimalFormatSymbols.setCurrencySymbol(""); 163 ((DecimalFormat) nf).setDecimalFormatSymbols(decimalFormatSymbols); 164 assertEquals("50.00", nf.format(50.0)); 165 166 nf.setCurrency(Currency.getInstance("SGD")); 167 assertEquals("SGD50.00", nf.format(50.0)); 168 169 nf.setCurrency(Currency.getInstance("SGD")); 170 assertEquals("SGD50.00", nf.format(50.00)); 171 172 nf.setCurrency(Currency.getInstance("USD")); 173 assertEquals("$50.00", nf.format(50.0)); 174 175 nf.setCurrency(Currency.getInstance("SGD")); 176 assertEquals("SGD50.00", nf.format(50.0)); 177 } 178 179 // Test to ensure explicitly setting a currency symbol will overwrite the defaults. 180 public void test_customCurrencySymbol() { 181 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US); 182 DecimalFormatSymbols dfs = ((DecimalFormat) nf).getDecimalFormatSymbols(); 183 dfs.setCurrencySymbol("SPECIAL"); 184 ((DecimalFormat) nf).setDecimalFormatSymbols(dfs); 185 assertEquals("SPECIAL3.14", nf.format(3.14)); 186 187 // Setting the currency again should reset the symbols. 188 nf.setCurrency(Currency.getInstance("USD")); 189 assertEquals("$3.14", nf.format(3.14)); 190 191 // Setting it back again should work. 192 dfs.setCurrencySymbol("NEW"); 193 ((DecimalFormat) nf).setDecimalFormatSymbols(dfs); 194 assertEquals("NEW3.14", nf.format(3.14)); 195 } 196 197 // Test to ensure currency formatting from specified locale works. 198 public void test_currencyFromLocale() { 199 // French locale formats with "," as separator and Euro symbol after a non-breaking space. 200 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.FRANCE); 201 assertEquals("50,00\u00a0", nf.format(50)); 202 203 // British locale uses pound sign with no spacing. 204 nf = NumberFormat.getCurrencyInstance(Locale.UK); 205 assertEquals("50.00", nf.format(50)); 206 } 207 208 // Test the currency symbol is correctly taken from ICU. Verifies that the fractional digits 209 // are not updated because DecimalFormat.setCurrency agrees not to change it. 210 public void test_setCurrency() throws Exception { 211 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US); 212 213 // The Armenian Dram is a special case where the fractional digits are 0. 214 Currency amd = Currency.getInstance("AMD"); 215 assertEquals(0, amd.getDefaultFractionDigits()); 216 217 // Armenian Dram ISO 4217 code. 218 nf.setCurrency(amd); 219 assertEquals(2, nf.getMinimumFractionDigits()); // Check DecimalFormat has not taken the 220 assertEquals(2, nf.getMaximumFractionDigits()); // currency specific fractional digits. 221 assertEquals("AMD50.00", nf.format(50.00)); 222 223 // Try and explicitly request fractional digits for the specified currency. 224 nf.setMaximumFractionDigits(amd.getDefaultFractionDigits()); 225 assertEquals("AMD50", nf.format(50.00)); 226 227 nf = NumberFormat.getCurrencyInstance(Locale.US); 228 229 // Euro sign. 230 nf.setCurrency(Currency.getInstance("EUR")); 231 assertEquals("50.00", nf.format(50.00)); 232 233 // Japanese Yen symbol. 234 nf.setCurrency(Currency.getInstance("JPY")); 235 assertEquals("50.00", nf.format(50.00)); 236 237 // Swiss Franc ISO 4217 code. 238 nf.setCurrency(Currency.getInstance("CHF")); 239 assertEquals("CHF50.00", nf.format(50.00)); 240 } 241 242 // Test the setting of locale specific patterns which have different fractional digits. 243 public void test_currencyWithPatternDigits() throws Exception { 244 // Japanese Yen 0 fractional digits. 245 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.JAPAN); 246 assertEquals("50", nf.format(50.00)); 247 248 // Armenian Dram 0 fractional digits. 249 nf = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("hy-AM")); 250 assertEquals("50\u00a0", nf.format(50.00)); 251 252 // Swiss Francs 2 fractional digits. 253 nf = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("de-CH")); 254 assertEquals("CHF\u00a050.00", nf.format(50.00)); 255 } 256 257 // http://b/28893763 258 public void test_setCurrency_leavesFractionDigitsUntouched() { 259 NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US); 260 format.setMinimumFractionDigits(0); 261 format.setCurrency(Currency.getInstance("USD")); 262 assertEquals("$10", format.format(10d)); 263 } 264 } 265