1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 #include "unicode/utypes.h"
5
6 #if !UCONFIG_NO_FORMATTING
7
8 // Allow implicit conversion from char16_t* to UnicodeString for this file:
9 // Helpful in toString methods and elsewhere.
10 #define UNISTR_FROM_STRING_EXPLICIT
11
12 #include <stdio.h>
13 #include "unicode/unumberformatter.h"
14 #include "unicode/unumberrangeformatter.h"
15 #include "unicode/umisc.h"
16 #include "unicode/unum.h"
17 #include "unicode/ustring.h"
18 #include "cformtst.h"
19 #include "cintltst.h"
20 #include "cmemory.h"
21
22 static void TestExampleCode(void);
23
24 static void TestFormattedValue(void);
25
26 static void TestSkeletonParseError(void);
27
28 static void TestGetDecimalNumbers(void);
29
30 void addUNumberRangeFormatterTest(TestNode** root);
31
32 #define TESTCASE(x) addTest(root, &x, "tsformat/unumberrangeformatter/" #x)
33
addUNumberRangeFormatterTest(TestNode ** root)34 void addUNumberRangeFormatterTest(TestNode** root) {
35 TESTCASE(TestExampleCode);
36 TESTCASE(TestFormattedValue);
37 TESTCASE(TestSkeletonParseError);
38 TESTCASE(TestGetDecimalNumbers);
39 }
40
41
42 #define CAPACITY 30
43
44
TestExampleCode()45 static void TestExampleCode() {
46 // This is the example code given in unumberrangeformatter.h.
47
48 // Setup:
49 UErrorCode ec = U_ZERO_ERROR;
50 UNumberRangeFormatter* uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
51 u"currency/USD precision-integer",
52 -1,
53 UNUM_RANGE_COLLAPSE_AUTO,
54 UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
55 "en-US",
56 NULL,
57 &ec);
58 UFormattedNumberRange* uresult = unumrf_openResult(&ec);
59 assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
60
61 // Format a double range:
62 unumrf_formatDoubleRange(uformatter, 3.0, 5.0, uresult, &ec);
63 assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
64
65 // Get the result string:
66 int32_t len;
67 const UChar* str = ufmtval_getString(unumrf_resultAsValue(uresult, &ec), &len, &ec);
68 assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
69 assertUEquals("Should produce expected string result", u"$3 – $5", str);
70 int32_t resultLength = str != NULL ? u_strlen(str) : 0;
71 assertIntEquals("Length should be as expected", resultLength, len);
72
73 // Cleanup:
74 unumrf_close(uformatter);
75 unumrf_closeResult(uresult);
76 }
77
78
TestFormattedValue()79 static void TestFormattedValue() {
80 UErrorCode ec = U_ZERO_ERROR;
81 UNumberRangeFormatter* uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
82 u"K",
83 -1,
84 UNUM_RANGE_COLLAPSE_AUTO,
85 UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
86 "en-US",
87 NULL,
88 &ec);
89 assertSuccessCheck("Should create without error", &ec, TRUE);
90 UFormattedNumberRange* uresult = unumrf_openResult(&ec);
91 assertSuccess("Should create result without error", &ec);
92
93 // Test the decimal number code path, too
94 unumrf_formatDecimalRange(uformatter, "5.5e4", -1, "1.5e5", -1, uresult, &ec);
95
96 if (assertSuccessCheck("Should format without error", &ec, TRUE)) {
97 const UFormattedValue* fv = unumrf_resultAsValue(uresult, &ec);
98 assertSuccess("Should convert without error", &ec);
99 static const UFieldPositionWithCategory expectedFieldPositions[] = {
100 // category, field, begin index, end index
101 {UFIELD_CATEGORY_NUMBER_RANGE_SPAN, 0, 0, 3},
102 {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD, 0, 2},
103 {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD, 2, 3},
104 {UFIELD_CATEGORY_NUMBER_RANGE_SPAN, 1, 6, 10},
105 {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD, 6, 9},
106 {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD, 9, 10}};
107 checkMixedFormattedValue(
108 "FormattedNumber as FormattedValue",
109 fv,
110 u"55K – 150K",
111 expectedFieldPositions,
112 UPRV_LENGTHOF(expectedFieldPositions));
113 }
114
115 assertIntEquals("Identity result should match",
116 UNUM_IDENTITY_RESULT_NOT_EQUAL,
117 unumrf_resultGetIdentityResult(uresult, &ec));
118
119 // cleanup:
120 unumrf_closeResult(uresult);
121 unumrf_close(uformatter);
122 }
123
124
TestSkeletonParseError()125 static void TestSkeletonParseError() {
126 UErrorCode ec = U_ZERO_ERROR;
127 UNumberRangeFormatter* uformatter;
128 UParseError perror;
129
130 // The UParseError can be null. The following should not segfault.
131 uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
132 u".00 measure-unit/typo",
133 -1,
134 UNUM_RANGE_COLLAPSE_AUTO,
135 UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
136 "en",
137 NULL,
138 &ec);
139 unumrf_close(uformatter);
140
141 // Now test the behavior.
142 ec = U_ZERO_ERROR;
143 uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
144 u".00 measure-unit/typo",
145 -1,
146 UNUM_RANGE_COLLAPSE_AUTO,
147 UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
148 "en",
149 &perror,
150 &ec);
151
152 assertIntEquals("Should have set error code", U_NUMBER_SKELETON_SYNTAX_ERROR, ec);
153 assertIntEquals("Should have correct skeleton error offset", 17, perror.offset);
154 assertUEquals("Should have correct pre context", u"0 measure-unit/", perror.preContext);
155 assertUEquals("Should have correct post context", u"typo", perror.postContext);
156
157 // cleanup:
158 unumrf_close(uformatter);
159 }
160
161
TestGetDecimalNumbers()162 static void TestGetDecimalNumbers() {
163 UErrorCode ec = U_ZERO_ERROR;
164 UNumberRangeFormatter* uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
165 u"currency/USD",
166 -1,
167 UNUM_RANGE_COLLAPSE_AUTO,
168 UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
169 "en-US",
170 NULL,
171 &ec);
172 assertSuccessCheck("Should create without error", &ec, TRUE);
173 UFormattedNumberRange* uresult = unumrf_openResult(&ec);
174 assertSuccess("Should create result without error", &ec);
175
176 unumrf_formatDoubleRange(uformatter, 3.0, 5.0, uresult, &ec);
177 const UChar* str = ufmtval_getString(unumrf_resultAsValue(uresult, &ec), NULL, &ec);
178 assertSuccessCheck("Formatting should succeed", &ec, TRUE);
179 assertUEquals("Should produce expected string result", u"$3.00 \u2013 $5.00", str);
180
181 char buffer[CAPACITY];
182
183 int32_t len = unumrf_resultGetFirstDecimalNumber(uresult, buffer, CAPACITY, &ec);
184 assertIntEquals("First len should be as expected", strlen(buffer), len);
185 assertEquals("First decimal should be as expected", "3", buffer);
186
187 len = unumrf_resultGetSecondDecimalNumber(uresult, buffer, CAPACITY, &ec);
188 assertIntEquals("Second len should be as expected", strlen(buffer), len);
189 assertEquals("Second decimal should be as expected", "5", buffer);
190
191 // cleanup:
192 unumrf_closeResult(uresult);
193 unumrf_close(uformatter);
194 }
195
196 #endif /* #if !UCONFIG_NO_FORMATTING */
197