OLD | NEW |
1 /** | 1 /// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 * Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 /// for details. All rights reserved. Use of this source code is governed by a |
3 * for details. All rights reserved. Use of this source code is governed by a | 3 /// BSD-style license that can be found in the LICENSE file. |
4 * BSD-style license that can be found in the LICENSE file. | |
5 */ | |
6 | 4 |
7 library number_format_test; | 5 library number_format_test; |
8 | 6 |
9 import 'package:unittest/unittest.dart'; | 7 import 'package:test/test.dart'; |
10 import 'package:intl/number_symbols_data.dart'; | 8 import 'package:intl/number_symbols_data.dart'; |
11 import 'package:intl/intl.dart'; | 9 import 'package:intl/intl.dart'; |
12 import 'number_test_data.dart'; | 10 import 'number_test_data.dart'; |
13 import 'dart:math'; | 11 import 'dart:math'; |
14 | 12 |
15 /** | 13 /// Tests the Numeric formatting library in dart. |
16 * Tests the Numeric formatting library in dart. | |
17 */ | |
18 var testNumbersWeCanReadBack = { | 14 var testNumbersWeCanReadBack = { |
19 "-1": -1, | 15 "-1": -1, |
20 "-2": -2.0, | 16 "-2": -2.0, |
21 "-0.01": -0.01, | 17 "-0.01": -0.01, |
| 18 "-1.23": -1.23, |
22 "0.001": 0.001, | 19 "0.001": 0.001, |
23 "0.01": 0.01, | 20 "0.01": 0.01, |
24 "0.1": 0.1, | 21 "0.1": 0.1, |
25 "1": 1, | 22 "1": 1, |
26 "2": 2.0, | 23 "2": 2.0, |
27 "10": 10, | 24 "10": 10, |
28 "100": 100, | 25 "100": 100, |
29 "1,000": 1000, | 26 "1,000": 1000, |
30 "2,000,000,000,000": 2000000000000, | 27 "2,000,000,000,000": 2000000000000, |
31 "0.123": 0.123, | 28 "0.123": 0.123, |
32 "1,234": 1234.0, | 29 "1,234": 1234.0, |
33 "1.234": 1.234, | 30 "1.234": 1.234, |
34 "1.23": 1.230, | 31 "1.23": 1.230, |
35 "NaN": double.NAN, | 32 "NaN": double.NAN, |
36 "∞": double.INFINITY, | 33 "∞": double.INFINITY, |
37 "-∞": double.NEGATIVE_INFINITY, | 34 "-∞": double.NEGATIVE_INFINITY, |
38 }; | 35 }; |
39 | 36 |
40 /** Test numbers that we can't parse because we lose precision in formatting.*/ | 37 /// Test numbers that we can't parse because we lose precision in formatting. |
41 var testNumbersWeCannotReadBack = {"3.142": PI,}; | 38 var testNumbersWeCannotReadBack = { |
| 39 "3.142": PI, |
| 40 "-1.234": -1.2342, |
| 41 "-1.235": -1.2348, |
| 42 "1.234": 1.2342, |
| 43 "1.235": 1.2348 |
| 44 }; |
42 | 45 |
43 /** Test numbers that won't work in Javascript because they're too big. */ | 46 /// Test numbers that won't work in Javascript because they're too big. |
44 var testNumbersOnlyForTheVM = { | 47 var testNumbersOnlyForTheVM = { |
45 "10,000,000,000,000,000,000,000,000,000,000": | 48 "10,000,000,000,000,000,000,000,000,000,000": |
46 10000000000000000000000000000000, | 49 10000000000000000000000000000000, |
47 }; | 50 }; |
48 | 51 |
49 get allTestNumbers => new Map.from(testNumbersWeCanReadBack) | 52 get allTestNumbers => new Map.from(testNumbersWeCanReadBack) |
50 ..addAll(testNumbersWeCannotReadBack) | 53 ..addAll(testNumbersWeCannotReadBack) |
51 ..addAll(inJavaScript() ? {} : testNumbersOnlyForTheVM); | 54 ..addAll(inJavaScript() ? {} : testNumbersOnlyForTheVM); |
52 | 55 |
53 var testExponential = const {"1E-3": 0.001, "1E-2": 0.01, "1.23E0": 1.23}; | 56 var testExponential = const {"1E-3": 0.001, "1E-2": 0.01, "1.23E0": 1.23}; |
(...skipping 17 matching lines...) Expand all Loading... |
71 // For data from a list of locales, run each locale's data as a separate | 74 // For data from a list of locales, run each locale's data as a separate |
72 // test so we can see exactly which ones pass or fail. The test data is | 75 // test so we can see exactly which ones pass or fail. The test data is |
73 // hard-coded as printing 123, -12.3, %12,300, -1,230% in each locale. | 76 // hard-coded as printing 123, -12.3, %12,300, -1,230% in each locale. |
74 var mainList = numberTestData; | 77 var mainList = numberTestData; |
75 var sortedLocales = new List.from(numberFormatSymbols.keys); | 78 var sortedLocales = new List.from(numberFormatSymbols.keys); |
76 sortedLocales.sort((a, b) => a.compareTo(b)); | 79 sortedLocales.sort((a, b) => a.compareTo(b)); |
77 for (var locale in sortedLocales) { | 80 for (var locale in sortedLocales) { |
78 var testFormats = standardFormats(locale); | 81 var testFormats = standardFormats(locale); |
79 var testLength = (testFormats.length * 3) + 1; | 82 var testLength = (testFormats.length * 3) + 1; |
80 var list = mainList.take(testLength).iterator; | 83 var list = mainList.take(testLength).iterator; |
| 84 list.moveNext(); |
81 mainList = mainList.skip(testLength); | 85 mainList = mainList.skip(testLength); |
82 var nextLocaleFromList = (list..moveNext()).current; | 86 if (locale == list.current) { |
83 test("Test against ICU data for $locale", () { | 87 testAgainstIcu(locale, testFormats, list); |
84 expect(locale, nextLocaleFromList); | 88 } |
85 for (var format in testFormats) { | |
86 var formatted = format.format(123); | |
87 var negative = format.format(-12.3); | |
88 var large = format.format(1234567890); | |
89 var expected = (list..moveNext()).current; | |
90 expect(formatted, expected); | |
91 var expectedNegative = (list..moveNext()).current; | |
92 // Some of these results from CLDR have a leading LTR/RTL indicator, | |
93 // which we don't want. We also treat the difference between Unicode | |
94 // minus sign (2212) and hyphen-minus (45) as not significant. | |
95 expectedNegative = expectedNegative | |
96 .replaceAll("\u200e", "") | |
97 .replaceAll("\u200f", "") | |
98 .replaceAll("\u2212", "-"); | |
99 expect(negative, expectedNegative); | |
100 var expectedLarge = (list..moveNext()).current; | |
101 expect(large, expectedLarge); | |
102 var readBack = format.parse(formatted); | |
103 expect(readBack, 123); | |
104 var readBackNegative = format.parse(negative); | |
105 expect(readBackNegative, -12.3); | |
106 var readBackLarge = format.parse(large); | |
107 expect(readBackLarge, 1234567890); | |
108 } | |
109 }); | |
110 } | 89 } |
111 | 90 |
112 test('Simple set of numbers', () { | 91 test('Simple set of numbers', () { |
113 var number = new NumberFormat(); | 92 var number = new NumberFormat(); |
114 for (var x in allTestNumbers.keys) { | 93 for (var x in allTestNumbers.keys) { |
115 var formatted = number.format(allTestNumbers[x]); | 94 var formatted = number.format(allTestNumbers[x]); |
116 expect(formatted, x); | 95 expect(formatted, x); |
117 if (!testNumbersWeCannotReadBack.containsKey(x)) { | 96 if (!testNumbersWeCannotReadBack.containsKey(x)) { |
118 var readBack = number.parse(formatted); | 97 var readBack = number.parse(formatted); |
119 // Even among ones we can read back, we can't test NaN for equality. | 98 // Even among ones we can read back, we can't test NaN for equality. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 var modified = {"12%": 0.12, "12\u2030": 0.012}; | 131 var modified = {"12%": 0.12, "12\u2030": 0.012}; |
153 modified.addAll(testExponential); | 132 modified.addAll(testExponential); |
154 for (var x in modified.keys) { | 133 for (var x in modified.keys) { |
155 var parsed = number.parse(x); | 134 var parsed = number.parse(x); |
156 expect(parsed, modified[x]); | 135 expect(parsed, modified[x]); |
157 } | 136 } |
158 }); | 137 }); |
159 | 138 |
160 test('Explicit currency name', () { | 139 test('Explicit currency name', () { |
161 var amount = 1000000.32; | 140 var amount = 1000000.32; |
162 var usConvention = new NumberFormat.currencyPattern('en_US', '€'); | 141 var usConvention = new NumberFormat.currency(locale: 'en_US', symbol: '€'); |
163 var formatted = usConvention.format(amount); | 142 var formatted = usConvention.format(amount); |
164 expect(formatted, '€1,000,000.32'); | 143 expect(formatted, '€1,000,000.32'); |
165 var readBack = usConvention.parse(formatted); | 144 var readBack = usConvention.parse(formatted); |
166 expect(readBack, amount); | 145 expect(readBack, amount); |
167 var swissConvention = new NumberFormat.currencyPattern('de_CH', r'$'); | 146 var swissConvention = new NumberFormat.currencyPattern('de_CH', r'$'); |
168 formatted = swissConvention.format(amount); | 147 formatted = swissConvention.format(amount); |
169 var nbsp = new String.fromCharCode(0xa0); | 148 var nbsp = new String.fromCharCode(0xa0); |
170 expect(formatted, r"$" + nbsp + "1'000'000.32"); | 149 expect(formatted, r"$" + nbsp + "1'000'000.32"); |
171 readBack = swissConvention.parse(formatted); | 150 readBack = swissConvention.parse(formatted); |
172 expect(readBack, amount); | 151 expect(readBack, amount); |
173 | 152 |
174 /// Verify we can leave off the currency and it gets filled in. | 153 /// Verify we can leave off the currency and it gets filled in. |
175 var plainSwiss = new NumberFormat.currencyPattern('de_CH'); | 154 var plainSwiss = new NumberFormat.currency(locale: 'de_CH'); |
176 formatted = plainSwiss.format(amount); | 155 formatted = plainSwiss.format(amount); |
177 expect(formatted, r"CHF" + nbsp + "1'000'000.32"); | 156 expect(formatted, r"CHF" + nbsp + "1'000'000.32"); |
178 readBack = plainSwiss.parse(formatted); | 157 readBack = plainSwiss.parse(formatted); |
179 expect(readBack, amount); | 158 expect(readBack, amount); |
180 | 159 |
181 // Verify that we can pass null in order to specify the currency symbol | 160 // Verify that we can pass null in order to specify the currency symbol |
182 // but use the default locale. | 161 // but use the default locale. |
183 var defaultLocale = new NumberFormat.currencyPattern(null, 'Smurfs'); | 162 var defaultLocale = new NumberFormat.currencyPattern(null, 'Smurfs'); |
184 formatted = defaultLocale.format(amount); | 163 formatted = defaultLocale.format(amount); |
185 // We don't know what the exact format will be, but it should have Smurfs. | 164 // We don't know what the exact format will be, but it should have Smurfs. |
186 expect(formatted.contains('Smurfs'), isTrue); | 165 expect(formatted.contains('Smurfs'), isTrue); |
187 readBack = defaultLocale.parse(formatted); | 166 readBack = defaultLocale.parse(formatted); |
188 expect(readBack, amount); | 167 expect(readBack, amount); |
189 }); | 168 }); |
190 | 169 |
191 test("Delta percent format", () { | 170 test("Delta percent format", () { |
192 var f = new NumberFormat("+#,##0%;-#,##0%"); | 171 var f = new NumberFormat("+#,##0%;-#,##0%"); |
193 expect(f.format(-0.07), "-7%"); | 172 expect(f.format(-0.07), "-7%"); |
194 expect(f.format(0.12), "+12%"); | 173 expect(f.format(0.12), "+12%"); |
195 }); | 174 }); |
196 | 175 |
197 test('Unparseable', () { | 176 test('Unparseable', () { |
198 var format = new NumberFormat.currencyPattern(); | 177 var format = new NumberFormat.currency(); |
199 expect(() => format.parse("abcdefg"), throwsFormatException); | 178 expect(() => format.parse("abcdefg"), throwsFormatException); |
200 expect(() => format.parse(""), throwsFormatException); | 179 expect(() => format.parse(""), throwsFormatException); |
201 expect(() => format.parse("1.0zzz"), throwsFormatException); | 180 expect(() => format.parse("1.0zzz"), throwsFormatException); |
202 expect(() => format.parse("-∞+1"), throwsFormatException); | 181 expect(() => format.parse("-∞+1"), throwsFormatException); |
203 }); | 182 }); |
| 183 |
| 184 var digitsCheck = { |
| 185 0: "@4", |
| 186 1: "@4.3", |
| 187 2: "@4.32", |
| 188 3: "@4.322", |
| 189 4: "@4.3220", |
| 190 }; |
| 191 |
| 192 test('Decimal digits', () { |
| 193 var amount = 4.3219876; |
| 194 for (var digits in digitsCheck.keys) { |
| 195 var f = new NumberFormat.currency( |
| 196 locale: 'en_US', symbol: '@', decimalDigits: digits); |
| 197 var formatted = f.format(amount); |
| 198 expect(formatted, digitsCheck[digits]); |
| 199 } |
| 200 var defaultFormat = new NumberFormat.currency(locale: 'en_US', symbol: '@'); |
| 201 var formatted = defaultFormat.format(amount); |
| 202 expect(formatted, digitsCheck[2]); |
| 203 |
| 204 var jpyUs = |
| 205 new NumberFormat.currency(locale: 'en_US', name: 'JPY', symbol: '@'); |
| 206 formatted = jpyUs.format(amount); |
| 207 expect(formatted, digitsCheck[0]); |
| 208 |
| 209 var jpyJa = |
| 210 new NumberFormat.currency(locale: 'ja', name: 'JPY', symbol: '@'); |
| 211 formatted = jpyJa.format(amount); |
| 212 expect(formatted, digitsCheck[0]); |
| 213 |
| 214 var jpySimple = new NumberFormat.simpleCurrency(locale: 'ja', name: 'JPY'); |
| 215 formatted = jpySimple.format(amount); |
| 216 expect(formatted, "¥4"); |
| 217 |
| 218 var jpyLower = |
| 219 new NumberFormat.currency(locale: 'en_US', name: 'jpy', symbol: '@'); |
| 220 formatted = jpyLower.format(amount); |
| 221 expect(formatted, digitsCheck[0]); |
| 222 |
| 223 var tnd = new NumberFormat.currency(name: 'TND', symbol: '@'); |
| 224 formatted = tnd.format(amount); |
| 225 expect(formatted, digitsCheck[3]); |
| 226 }); |
| 227 |
| 228 testSimpleCurrencySymbols(); |
204 } | 229 } |
| 230 |
| 231 String stripExtras(String input) { |
| 232 // Some of these results from CLDR have a leading LTR/RTL indicator, |
| 233 // and/or Arabic letter indicator, |
| 234 // which we don't want. We also treat the difference between Unicode |
| 235 // minus sign (2212) and hyphen-minus (45) as not significant. |
| 236 return input |
| 237 .replaceAll("\u200e", "") |
| 238 .replaceAll("\u200f", "") |
| 239 .replaceAll("\u061c", "") |
| 240 .replaceAll("\u2212", "-"); |
| 241 } |
| 242 |
| 243 void testAgainstIcu(locale, List<NumberFormat> testFormats, list) { |
| 244 test("Test against ICU data for $locale", () { |
| 245 for (var format in testFormats) { |
| 246 var formatted = format.format(123); |
| 247 var negative = format.format(-12.3); |
| 248 var large = format.format(1234567890); |
| 249 var expected = (list..moveNext()).current; |
| 250 expect(formatted, expected); |
| 251 var expectedNegative = (list..moveNext()).current; |
| 252 expect(stripExtras(negative), stripExtras(expectedNegative)); |
| 253 var expectedLarge = (list..moveNext()).current; |
| 254 expect(large, expectedLarge); |
| 255 var readBack = format.parse(formatted); |
| 256 expect(readBack, 123); |
| 257 var readBackNegative = format.parse(negative); |
| 258 expect(readBackNegative, -12.3); |
| 259 var readBackLarge = format.parse(large); |
| 260 expect(readBackLarge, 1234567890); |
| 261 } |
| 262 }); |
| 263 } |
| 264 |
| 265 testSimpleCurrencySymbols() { |
| 266 var currencies = ['USD', 'CAD', 'EUR', 'CRC', null]; |
| 267 // Note that these print using the simple symbol as if we were in a |
| 268 // a locale where that currency symbol is well understood. So we |
| 269 // expect Canadian dollars printed as $, even though our locale is |
| 270 // en_US, and this would confuse users. |
| 271 var simple = currencies.map((currency) => |
| 272 new NumberFormat.simpleCurrency(locale: 'en_US', name: currency)); |
| 273 var expectedSimple = [r'$', r'$', '\u20ac', '\u20a1', r'$']; |
| 274 // These will always print as the global name, regardless of locale |
| 275 var global = currencies.map( |
| 276 (currency) => new NumberFormat.currency(locale: 'en_US', name: currency)); |
| 277 var expectedGlobal = currencies.map((curr) => curr ?? 'USD').toList(); |
| 278 |
| 279 testCurrencySymbolsFor(expectedGlobal, global, "global"); |
| 280 testCurrencySymbolsFor(expectedSimple, simple, "simple"); |
| 281 } |
| 282 |
| 283 testCurrencySymbolsFor(expected, formats, name) { |
| 284 var amount = 1000000.32; |
| 285 new Map.fromIterables(expected, formats) |
| 286 .forEach((expected, NumberFormat format) { |
| 287 test("Test $name ${format.currencyName}", () { |
| 288 // We have to allow for currencies with different fraction digits, e.g. CR
C. |
| 289 var maxDigits = format.maximumFractionDigits; |
| 290 var rounded = maxDigits == 0 ? amount.round() : amount; |
| 291 var fractionDigits = (amount - rounded) < 0.00001 ? '.32' : ''; |
| 292 var formatted = format.format(rounded); |
| 293 expect(formatted, "${expected}1,000,000$fractionDigits"); |
| 294 var parsed = format.parse(formatted); |
| 295 expect(parsed, rounded); |
| 296 }); |
| 297 }); |
| 298 } |
OLD | NEW |