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