• 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 <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