Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: packages/intl/test/number_format_compact_test.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « packages/intl/test/number_closure_test.dart ('k') | packages/intl/test/number_format_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /// Copyright (c) 2016, 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 /// BSD-style license that can be found in the LICENSE file.
4
5 /// Tests for compact format numbers, e.g. 1.2M rather than 1,200,000
6 import 'dart:math';
7 import 'package:test/test.dart';
8 import 'package:intl/intl.dart';
9 import 'package:fixnum/fixnum.dart';
10 import 'compact_number_test_data.dart' as testdata;
11
12 /// A place to put a case that's causing a problem and have it run first when
13 /// debugging
14 var interestingCases = {
15 // "mn" : [["4321", "4.32M", "whatever"]]
16 };
17
18 main() {
19 interestingCases.forEach(validate);
20 testdata.compactNumberTestData.forEach(validate);
21
22 // ICU doesn't support compact currencies yet, so we don't have a way to
23 // generate automatic data for comparison. Hard-coded a couple of cases as a
24 // smoke test. JPY is a useful test because it has no decimalDigits and
25 // different grouping than USD, as well as a different currency symbol and
26 // suffixes.
27 testCurrency("ja", 1.2345, "¥1", "¥1");
28 testCurrency("ja", 1, "¥1", "¥1");
29 testCurrency("ja", 12, "¥12", "¥10");
30 testCurrency("ja", 123, "¥123", "¥100");
31 testCurrency("ja", 1234, "¥1230", "¥1000");
32 testCurrency("ja", 12345, "¥1.23\u4E07", "¥1\u4E07");
33 testCurrency("ja", 123456, "¥12.3\u4E07", "¥10\u4E07");
34 testCurrency("ja", 1234567, "¥123\u4e07", "¥100\u4e07");
35 testCurrency("ja", 12345678, "¥1230\u4e07", "¥1000\u4e07");
36 testCurrency("ja", 123456789, "¥1.23\u5104", "¥1\u5104");
37
38 testCurrency("ja", 0.9876, "¥1", "¥1");
39 testCurrency("ja", 9, "¥9", "¥9");
40 testCurrency("ja", 98, "¥98", "¥100");
41 testCurrency("ja", 987, "¥987", "¥1000");
42 testCurrency("ja", 9876, "¥9880", "¥1\u4E07");
43 testCurrency("ja", 98765, "¥9.88\u4E07", "¥10\u4E07");
44 testCurrency("ja", 987656, "¥98.8\u4E07", "¥100\u4E07");
45 testCurrency("ja", 9876567, "¥988\u4e07", "¥1000\u4e07");
46 testCurrency("ja", 98765678, "¥9880\u4e07", "¥1\u5104");
47 testCurrency("ja", 987656789, "¥9.88\u5104", "¥10\u5104");
48
49 testCurrency("en_US", 1.2345, r"$1.23", r"$1");
50 testCurrency("en_US", 1, r"$1.00", r"$1");
51 testCurrency("en_US", 12, r"$12.00", r"$10");
52 testCurrency("en_US", 12.3, r"$12.30", r"$10");
53 testCurrency("en_US", 123, r"$123", r"$100");
54 testCurrency("en_US", 1234, r"$1.23K", r"$1K");
55 testCurrency("en_US", 12345, r"$12.3K", r"$10K");
56 testCurrency("en_US", 123456, r"$123K", r"$100K");
57 testCurrency("en_US", 1234567, r"$1.23M", r"$1M");
58
59 // Check for order of currency symbol when currency is a suffix.
60 testCurrency("ru", 4420, "4,42\u00A0тыс.\u00A0руб.", "4\u00A0тыс.\u00A0руб.");
61
62 // Locales which don't have a suffix for thousands.
63 testCurrency("it", 442, "442\u00A0€", "400\u00A0€");
64 testCurrency("it", 4420, "4420\u00A0\$", "4000\u00A0\$", currency: 'CAD');
65 testCurrency("it", 4420000, "4,42\u00A0Mio\u00A0\$", "4\u00A0Mio\u00A0\$",
66 currency: 'USD');
67
68 test("Explicit non-default symbol with compactCurrency", () {
69 var format = new NumberFormat.compactCurrency(locale: "ja", symbol: "()");
70 var result = format.format(98765);
71 expect(result, "()9.88\u4e07");
72 });
73 }
74
75 testCurrency(String locale, num number, String expected, String expectedShort,
76 {String currency}) {
77 test("Compact simple currency for $locale, $number", () {
78 var format =
79 new NumberFormat.compactSimpleCurrency(locale: locale, name: currency);
80 var result = format.format(number);
81 expect(result, expected);
82 var shortFormat =
83 new NumberFormat.compactSimpleCurrency(locale: locale, name: currency);
84 shortFormat.significantDigits = 1;
85 var shortResult = shortFormat.format(number);
86 expect(shortResult, expectedShort);
87 });
88 test("Compact currency for $locale, $number", () {
89 var symbols = {
90 "ja": "¥",
91 "en_US": r"$",
92 "ru": "руб.",
93 "it": "€",
94 "CAD": r"$",
95 "USD": r"$"
96 };
97 var symbol = symbols[currency] ?? symbols[locale];
98 var format = new NumberFormat.compactCurrency(
99 locale: locale, name: currency, symbol: symbol);
100 var result = format.format(number);
101 expect(result, expected);
102 var shortFormat = new NumberFormat.compactCurrency(
103 locale: locale, name: currency, symbol: symbol);
104 shortFormat.significantDigits = 1;
105 var shortResult = shortFormat.format(number);
106 expect(shortResult, expectedShort);
107 });
108 }
109
110 // TODO(alanknight): Don't just skip the whole locale if there's one problem
111 // case.
112 // TODO(alanknight): Fix the problems, or at least figure out precisely where
113 // the differences are.
114 var problemLocalesShort = [
115 "am", // AM Suffixes differ, not sure why.
116 "ca", // For CA, CLDR rules are different. Jumps from 0000 to 00 prefix, so
117 // 11 digits prints as 11900.
118 "es_419", // Some odd formatting rules for these which seem to be different
119 // from CLDR. wants e.g. '160000000000k' Actual: '160 B'
120 "es_ES", // The reverse of es_419 for a few cases. We're printing a longer
121 // form.
122 "es_US", // Like es_419 but not as many of them. e.g. Expected: '87700k'
123 // Actual: '87.7 M'
124 "es_MX", // like es_419
125 "es",
126 "fa",
127 "fr_CA", // Several where PyICU isn't compacting. Expected: '988000000'
128 // Actual: '988 M'.
129 "gsw", // Suffixes disagree
130 "in", // IN not compacting 54321, looks similar to tr.
131 "id", // ID not compacting 54321, looks similar to tr.
132 "ka", // K Slight difference in the suffix
133 "kk", "mn", // We're picking the wrong pattern for 654321.
134 "lo", "mk", "my",
135 "pt_PT", // Seems to differ in appending mil or not after thousands. pt_BR
136 // does it.
137 "th", // TH Expected abbreviations as '1.09 พ.ล.' rather than '1.09 พ'
138 "tr", // TR Doesn't have a 0B format, goes directly to 00B, as a result 54321
139 // just prints as 54321
140 "ur", // UR Fails one with Expected: '15 ٹریلین' Actual: '150 کھرب'
141 ];
142
143 /// Locales that have problems in the long format.
144 ///
145 /// These are mostly minor differences in the characters, and many I can't read,
146 /// but I'm suspicious many of them are essentially the difference between
147 /// million and millions, which we don't distinguish. That's definitely the case
148 /// with e.g. DE, but our data definitely has Millionen throughout.
149 ///
150 //TODO(alanknight): Narrow these down to particular numbers. Often it's just
151 // 999999.
152 var problemLocalesLong = [
153 "ar",
154 "be", "bg", "bs",
155 "ca", "cs", "da", "de", "de_AT", "de_CH", "el", "es", "es_419", "es_ES",
156 "es_MX", "es_US", "et", "fi",
157 "fil", // FIL is different, seems like a genuine difference in suffixes
158 "fr", "fr_CA", "ga", "gl",
159 "gsw", // GSW seems like we have long forms and pyICU doesn't
160 "hr", "is", "it", "lo", // LO seems to be picking up a different pattern.
161 "lt", "lv", "mk",
162 "my", // Seems to come out in the reverse order
163 "nb", "ne", "no", "no_NO", "pl",
164 "pt", // PT has some issues with scale as well, but I think it's differences
165 // in the patterns.
166 "pt_BR", "pt_PT", "ro", "ru", "sk", "sl", "sr", "sr_Latn", "sv", "te", "tl",
167 "ur",
168 "uk",
169 ];
170
171 void validate(String locale, List<List<String>> expected) {
172 validateShort(locale, expected);
173 validateLong(locale, expected);
174 }
175
176 /// Check each bit of test data against the short compact format, both
177 /// formatting and parsing.
178 void validateShort(String locale, List<List<String>> expected) {
179 if (problemLocalesShort.contains(locale)) {
180 print("Skipping problem locale '$locale' for SHORT compact number tests");
181 return;
182 }
183 var shortFormat = new NumberFormat.compact(locale: locale);
184 for (var data in expected) {
185 var number = num.parse(data.first);
186 test("Validate $locale SHORT for ${data.first}", () {
187 validateNumber(number, shortFormat, data[1]);
188 });
189 var int64Number = new Int64(number);
190 test("Validate Int64 SHORT on $locale for ${data.first}", () {
191 validateNumber(int64Number, shortFormat, data[1]);
192 });
193 // TODO(alanknight): Make this work for MicroMoney
194 }
195 }
196
197 void validateLong(String locale, List<List<String>> expected) {
198 if (problemLocalesLong.contains(locale)) {
199 print("Skipping problem locale '$locale' for LONG compact number tests");
200 return;
201 }
202 var longFormat = new NumberFormat.compactLong(locale: locale);
203 for (var data in expected) {
204 var number = num.parse(data.first);
205 test("Validate $locale LONG for ${data.first}", () {
206 validateNumber(number, longFormat, data[2]);
207 });
208 }
209 }
210
211 void validateNumber(number, NumberFormat format, String expected) {
212 var formatted = format.format(number);
213 var ok = closeEnough(formatted, expected);
214 if (!ok) {
215 expect(
216 "$formatted ${formatted.codeUnits}", "$expected ${expected.codeUnits}");
217 }
218 var parsed = format.parse(formatted);
219 var rounded = roundForPrinting(number, format);
220 expect((parsed - rounded) / rounded < 0.001, isTrue);
221 }
222
223 /// Duplicate a bit of the logic in formatting, where if we have a
224 /// number that will round to print differently depending on the number
225 /// of significant digits, we need to check that as well, e.g.
226 /// 999999 may print as 1M.
227 roundForPrinting(number, NumberFormat format) {
228 var originalLength = NumberFormat.numberOfIntegerDigits(number);
229 var additionalDigits = originalLength - format.significantDigits;
230 if (additionalDigits > 0) {
231 var divisor = pow(10, additionalDigits);
232 // If we have an Int64, value speed over precision and make it double.
233 var rounded = (number.toDouble() / divisor).round() * divisor;
234 return rounded;
235 }
236 return number.toDouble();
237 }
238
239 final _nbsp = 0xa0;
240 final _nbspString = new String.fromCharCode(_nbsp);
241
242 /// Return true if the strings are close enough to what we
243 /// expected to consider a pass.
244 ///
245 /// In particular, there seem to be minor differences between what PyICU is
246 /// currently producing and the CLDR data. So if the strings differ only in the
247 /// presence or absence of a period at the end or of a space between the number
248 /// and the suffix, consider it close enough and return true.
249 bool closeEnough(String result, String reference) {
250 var expected = reference.replaceAll(' ', _nbspString);
251 if (result == expected) {
252 return true;
253 }
254 if ('$result.' == expected) {
255 return true;
256 }
257 if (result == '$expected.') {
258 return true;
259 }
260 if (_oneSpaceOnlyDifference(result, expected)) {
261 return true;
262 }
263 return false;
264 }
265
266 /// Do the two strings differ only by a single space being
267 /// omitted in one of them.
268 ///
269 /// We assume non-breaking spaces because we
270 /// know that's what the Intl data uses. We already know the strings aren't
271 /// equal because that's checked first in the only caller.
272 bool _oneSpaceOnlyDifference(String result, String expected) {
273 var resultWithoutSpaces =
274 new String.fromCharCodes(result.codeUnits.where((x) => x != _nbsp));
275 var expectedWithoutSpaces =
276 new String.fromCharCodes(expected.codeUnits.where((x) => x != _nbsp));
277 var resultDifference = result.length - resultWithoutSpaces.length;
278 var expectedDifference = expected.length - expectedWithoutSpaces.length;
279 return (resultWithoutSpaces == expectedWithoutSpaces &&
280 resultDifference <= 1 &&
281 expectedDifference <= 1);
282 }
OLDNEW
« no previous file with comments | « packages/intl/test/number_closure_test.dart ('k') | packages/intl/test/number_format_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698