• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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