• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * Copyright (c) 2016, International Business Machines Corporation
5  * and others. All Rights Reserved.
6  ********************************************************************/
7 /* C API TEST FOR DATE INTERVAL FORMAT */
8 
9 #include "unicode/utypes.h"
10 
11 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION
12 
13 #include <stdbool.h>
14 
15 #include "unicode/ureldatefmt.h"
16 #include "unicode/unum.h"
17 #include "unicode/udisplaycontext.h"
18 #include "unicode/ustring.h"
19 #include "cintltst.h"
20 #include "cmemory.h"
21 #include "cformtst.h"
22 
23 static void TestRelDateFmt(void);
24 static void TestNumericField(void);
25 static void TestCombineDateTime(void);
26 static void TestFields(void);
27 
28 void addRelativeDateFormatTest(TestNode** root);
29 
30 #define TESTCASE(x) addTest(root, &x, "tsformat/crelativedateformattest/" #x)
31 
addRelativeDateFormatTest(TestNode ** root)32 void addRelativeDateFormatTest(TestNode** root)
33 {
34     TESTCASE(TestRelDateFmt);
35     TESTCASE(TestNumericField);
36     TESTCASE(TestCombineDateTime);
37     TESTCASE(TestFields);
38 }
39 
40 static const double offsets[] = { -5.0, -2.2, -2.0, -1.0, -0.7, -0.0, 0.0, 0.7, 1.0, 2.0, 5.0 };
41 enum { kNumOffsets = UPRV_LENGTHOF(offsets) };
42 
43 typedef struct {
44     int32_t field;
45     int32_t beginPos;
46     int32_t endPos;
47 } FieldsDat;
48 
49 static const char* en_decDef_long_midSent_sec[kNumOffsets*2] = {
50 /*  text                    numeric */
51     "5 seconds ago",        "5 seconds ago",      /* -5   */
52     "2.2 seconds ago",      "2.2 seconds ago",    /* -2.2 */
53     "2 seconds ago",        "2 seconds ago",      /* -2   */
54     "1 second ago",         "1 second ago",       /* -1   */
55     "0.7 seconds ago",      "0.7 seconds ago",    /* -0.7 */
56     "now",                  "0 seconds ago",      /*  -0  */
57     "now",                  "in 0 seconds",       /*  0   */
58     "in 0.7 seconds",       "in 0.7 seconds",     /*  0.7 */
59     "in 1 second",          "in 1 second",        /*  1   */
60     "in 2 seconds",         "in 2 seconds",       /*  2   */
61     "in 5 seconds",         "in 5 seconds"        /*  5   */
62 };
63 
64 static const FieldsDat en_attrDef_long_midSent_sec[kNumOffsets*2] = {
65 /*  text           numeric           text                    numeric */
66     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 seconds ago",        "5 seconds ago",       -5   */
67     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "2.2 seconds ago",      "2.2 seconds ago",     -2.2 */
68     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 seconds ago",        "2 seconds ago",       -2   */
69     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "1 second ago",         "1 second ago",        -1   */
70     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "0.7 seconds ago",      "0.7 seconds ago",     -0.7 */
71     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "now",                  "0 seconds ago",        -0  */
72     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "now",                  "in 0 seconds",         0   */
73     {UDAT_REL_NUMERIC_FIELD,  3,  6}, {UDAT_REL_NUMERIC_FIELD,  3,  6}, /* "in 0.7 seconds",       "in 0.7 seconds",       0.7 */
74     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 1 second",          "in 1 second",          1   */
75     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 seconds",         "in 2 seconds",         2   */
76     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 seconds",         "in 5 seconds"          5   */
77 };
78 
79 static const char* en_decDef_long_midSent_week[kNumOffsets*2] = {
80 /*  text                    numeric */
81     "5 weeks ago",          "5 weeks ago",        /* -5   */
82     "2.2 weeks ago",        "2.2 weeks ago",      /* -2.2 */
83     "2 weeks ago",          "2 weeks ago",        /* -2   */
84     "last week",            "1 week ago",         /* -1   */
85     "0.7 weeks ago",        "0.7 weeks ago",      /* -0.7 */
86     "this week",            "0 weeks ago",        /*  -0  */
87     "this week",            "in 0 weeks",         /*  0   */
88     "in 0.7 weeks",         "in 0.7 weeks",       /*  0.7 */
89     "next week",            "in 1 week",          /*  1   */
90     "in 2 weeks",           "in 2 weeks",         /*  2   */
91     "in 5 weeks",           "in 5 weeks"          /*  5   */
92 };
93 
94 static const FieldsDat en_attrDef_long_midSent_week[kNumOffsets*2] = {
95 /*  text           numeric           text                    numeric */
96     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 weeks ago",          "5 weeks ago",         -5   */
97     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "2.2 weeks ago",        "2.2 weeks ago",       -2.2 */
98     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 weeks ago",          "2 weeks ago",         -2   */
99     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "last week",            "1 week ago",          -1   */
100     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "0.7 weeks ago",        "0.7 weeks ago",       -0.7 */
101     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "this week",            "0 weeks ago",          -0  */
102     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "this week",            "in 0 weeks",           0   */
103     {UDAT_REL_NUMERIC_FIELD,  3,  6}, {UDAT_REL_NUMERIC_FIELD,  3,  6}, /* "in 0.7 weeks",         "in 0.7 weeks",         0.7 */
104     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "next week",            "in 1 week",            1   */
105     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 weeks",           "in 2 weeks",           2   */
106     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 weeks",           "in 5 weeks"            5   */
107 };
108 
109 static const char* en_dec0_long_midSent_week[kNumOffsets*2] = {
110 /*  text                    numeric */
111     "5 weeks ago",          "5 weeks ago",        /* -5   */
112     "2 weeks ago",          "2 weeks ago",        /* -2.2 */
113     "2 weeks ago",          "2 weeks ago",        /* -2  */
114     "last week",            "1 week ago",         /* -1   */
115     "0 weeks ago",          "0 weeks ago",        /* -0.7 */
116     "this week",            "0 weeks ago",        /* -0  */
117     "this week",            "in 0 weeks",         /*  0   */
118     "in 0 weeks",           "in 0 weeks",         /*  0.7 */
119     "next week",            "in 1 week",          /*  1   */
120     "in 2 weeks",           "in 2 weeks",         /*  2   */
121     "in 5 weeks",           "in 5 weeks"          /*  5   */
122 };
123 
124 static const FieldsDat en_attr0_long_midSent_week[kNumOffsets*2] = {
125 /*  text           numeric           text                    numeric */
126     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 weeks ago",          "5 weeks ago",         -5   */
127     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 weeks ago",          "2 weeks ago",         -2.2 */
128     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 weeks ago",          "2 weeks ago",         -2  */
129     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "last week",            "1 week ago",          -1   */
130     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "0 weeks ago",          "0 weeks ago",         -0.7 */
131     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "this week",            "0 weeks ago",         -0  */
132     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "this week",            "in 0 weeks",           0   */
133     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 0 weeks",           "in 0 weeks",           0.7 */
134     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "next week",            "in 1 week",            1   */
135     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 weeks",           "in 2 weeks",           2   */
136     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 weeks",           "in 5 weeks"            5   */
137 };
138 
139 static const char* en_decDef_short_midSent_week[kNumOffsets*2] = {
140 /*  text                    numeric */
141     "5 wk. ago",            "5 wk. ago",          /* -5   */
142     "2.2 wk. ago",          "2.2 wk. ago",        /* -2.2 */
143     "2 wk. ago",            "2 wk. ago",          /* -2   */
144     "last wk.",             "1 wk. ago",          /* -1   */
145     "0.7 wk. ago",          "0.7 wk. ago",        /* -0.7 */
146     "this wk.",             "0 wk. ago",          /* -0   */
147     "this wk.",             "in 0 wk.",           /*  0   */
148     "in 0.7 wk.",           "in 0.7 wk.",         /*  0.7 */
149     "next wk.",             "in 1 wk.",           /*  1   */
150     "in 2 wk.",             "in 2 wk.",           /*  2   */
151     "in 5 wk.",             "in 5 wk."            /*  5   */
152 };
153 
154 static const FieldsDat en_attrDef_short_midSent_week[kNumOffsets*2] = {
155 /*  text           numeric           text                    numeric */
156     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 wk. ago",            "5 wk. ago",           -5   */
157     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "2.2 wk. ago",          "2.2 wk. ago",         -2.2 */
158     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 wk. ago",            "2 wk. ago",           -2   */
159     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "last wk.",             "1 wk. ago",           -1   */
160     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "0.7 wk. ago",          "0.7 wk. ago",         -0.7 */
161     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "this wk.",             "0 wk. ago",           -0   */
162     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "this wk.",             "in 0 wk.",             0   */
163     {UDAT_REL_NUMERIC_FIELD,  3,  6}, {UDAT_REL_NUMERIC_FIELD,  3,  6}, /* "in 0.7 wk.",           "in 0.7 wk.",           0.7 */
164     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "next wk.",             "in 1 wk.",             1   */
165     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 wk.",             "in 2 wk.",             2   */
166     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 wk.",             "in 5 wk."              5   */
167 };
168 
169 static const char* en_decDef_long_midSent_min[kNumOffsets*2] = {
170 /*  text                    numeric */
171     "5 minutes ago",        "5 minutes ago",      /* -5   */
172     "2.2 minutes ago",      "2.2 minutes ago",    /* -2.2 */
173     "2 minutes ago",        "2 minutes ago",      /* -2   */
174     "1 minute ago",         "1 minute ago",       /* -1   */
175     "0.7 minutes ago",      "0.7 minutes ago",    /* -0.7 */
176     "this minute",          "0 minutes ago",      /* -0   */
177     "this minute",          "in 0 minutes",       /*  0   */
178     "in 0.7 minutes",       "in 0.7 minutes",     /*  0.7 */
179     "in 1 minute",          "in 1 minute",        /*  1   */
180     "in 2 minutes",         "in 2 minutes",       /*  2   */
181     "in 5 minutes",         "in 5 minutes"        /*  5   */
182 };
183 
184 static const FieldsDat en_attrDef_long_midSent_min[kNumOffsets*2] = {
185 /*  text           numeric           text                    numeric */
186     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 minutes ago",        "5 minutes ago",       -5   */
187     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "2.2 minutes ago",      "2.2 minutes ago",     -2.2 */
188     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 minutes ago",        "2 minutes ago",       -2   */
189     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "1 minute ago",         "1 minute ago",        -1   */
190     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "0.7 minutes ago",      "0.7 minutes ago",     -0.7 */
191     {-1,  -1,  -1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "this minute",        "0 minutes ago",       -0   */
192     {-1,  -1,  -1}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "this minute",         "in 0 minutes",         0   */
193     {UDAT_REL_NUMERIC_FIELD,  3,  6}, {UDAT_REL_NUMERIC_FIELD,  3,  6}, /* "in 0.7 minutes",       "in 0.7 minutes",       0.7 */
194     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 1 minute",          "in 1 minute",          1   */
195     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 minutes",         "in 2 minutes",         2   */
196     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 minutes",         "in 5 minutes"          5   */
197 };
198 
199 static const char* en_dec0_long_midSent_tues[kNumOffsets*2] = {
200 /*  text                    numeric */
201     "5 Tuesdays ago",       "5 Tuesdays ago",     /* -5   */
202     "2.2 Tuesdays ago",     "2.2 Tuesdays ago",   /* -2.2 */
203     "2 Tuesdays ago",       "2 Tuesdays ago",     /* -2   */
204     "last Tuesday",         "1 Tuesday ago",      /* -1   */
205     "0.7 Tuesdays ago",     "0.7 Tuesdays ago",   /* -0.7 */
206     "this Tuesday",         "0 Tuesdays ago",     /* -0   */
207     "this Tuesday",         "in 0 Tuesdays",      /*  0   */
208     "in 0.7 Tuesdays",      "in 0.7 Tuesdays",    /*  0.7 */
209     "next Tuesday",         "in 1 Tuesday",       /*  1   */
210     "in 2 Tuesdays",        "in 2 Tuesdays",      /*  2   */
211     "in 5 Tuesdays",        "in 5 Tuesdays",      /*  5   */
212 };
213 
214 static const FieldsDat en_attr0_long_midSent_tues[kNumOffsets*2] = {
215 /*  text           numeric           text                    numeric */
216     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "5 Tuesdays ago",       "5 Tuesdays ago",      -5   */
217     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "2.2 Tuesdays ago",     "2.2 Tuesdays ago",    -2.2 */
218     {UDAT_REL_NUMERIC_FIELD,  0,  1}, {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "2 Tuesdays ago",       "2 Tuesdays ago",      -2   */
219     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "last Tuesday",         "1 Tuesday ago",       -1   */
220     {UDAT_REL_NUMERIC_FIELD,  0,  3}, {UDAT_REL_NUMERIC_FIELD,  0,  3}, /* "0.7 Tuesdays ago",     "0.7 Tuesdays ago",    -0.7 */
221     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  0,  1}, /* "this Tuesday",         "0 Tuesdays ago",      -0   */
222     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "this Tuesday",         "in 0 Tuesdays",        0   */
223     {UDAT_REL_NUMERIC_FIELD,  3,  6}, {UDAT_REL_NUMERIC_FIELD,  3,  6}, /* "in 0.7 Tuesdays",      "in 0.7 Tuesdays",      0.7 */
224     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "next Tuesday",         "in 1 Tuesday",         1   */
225     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 2 Tuesdays",        "in 2 Tuesdays",        2   */
226     {UDAT_REL_NUMERIC_FIELD,  3,  4}, {UDAT_REL_NUMERIC_FIELD,  3,  4}, /* "in 5 Tuesdays",        "in 5 Tuesdays",        5   */
227 };
228 
229 static const char* fr_decDef_long_midSent_day[kNumOffsets*2] = {
230 /*  text                    numeric */
231     "il y a 5 jours",       "il y a 5 jours",     /* -5   */
232     "il y a 2,2 jours",     "il y a 2,2 jours",   /* -2.2 */
233     "avant-hier",           "il y a 2 jours",     /* -2   */
234     "hier",                 "il y a 1 jour",      /* -1   */
235     "il y a 0,7 jour",      "il y a 0,7 jour",    /* -0.7 */
236     "aujourd\\u2019hui",    "il y a 0 jour",      /* -0   */
237     "aujourd\\u2019hui",    "dans 0 jour",        /*  0   */
238     "dans 0,7 jour",        "dans 0,7 jour",      /*  0.7 */
239     "demain",               "dans 1 jour",        /*  1   */
240     "apr\\u00E8s-demain",   "dans 2 jours",       /*  2   */
241     "dans 5 jours",         "dans 5 jours"        /*  5   */
242 };
243 
244 static const FieldsDat fr_attrDef_long_midSent_day[kNumOffsets*2] = {
245 /*  text           numeric           text                    numeric */
246     {UDAT_REL_NUMERIC_FIELD,  7,  8}, {UDAT_REL_NUMERIC_FIELD,  7,  8}, /* "il y a 5 jours",       "il y a 5 jours",      -5   */
247     {UDAT_REL_NUMERIC_FIELD,  7, 10}, {UDAT_REL_NUMERIC_FIELD,  7, 10}, /* "il y a 2,2 jours",     "il y a 2,2 jours",    -2.2 */
248     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  7,  8}, /* "avant-hier",           "il y a 2 jours",      -2   */
249     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  7,  8}, /* "hier",                 "il y a 1 jour",       -1   */
250     {UDAT_REL_NUMERIC_FIELD,  7, 10}, {UDAT_REL_NUMERIC_FIELD,  7, 10}, /* "il y a 0,7 jour",      "il y a 0,7 jour",     -0.7 */
251     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  7,  8}, /* "aujourd\\u2019hui",    "il y a 0 jour",       -0   */
252     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  5,  6}, /* "aujourd\\u2019hui",    "dans 0 jour",          0   */
253     {UDAT_REL_NUMERIC_FIELD,  5,  8}, {UDAT_REL_NUMERIC_FIELD,  5,  8}, /* "dans 0,7 jour",        "dans 0,7 jour",        0.7 */
254     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  5,  6}, /* "demain",               "dans 1 jour",          1   */
255     { -1, -1, -1},                    {UDAT_REL_NUMERIC_FIELD,  5,  6}, /* "apr\\u00E8s-demain",   "dans 2 jours",         2   */
256     {UDAT_REL_NUMERIC_FIELD,  5,  6}, {UDAT_REL_NUMERIC_FIELD,  5,  6}, /* "dans 5 jours",         "dans 5 jours"          5   */
257 };
258 
259 static const char* ak_decDef_long_stdAlon_sec[kNumOffsets*2] = { // falls back to root
260 /*  text                    numeric */
261     "nnibuo 5 a atwam",     "nnibuo 5 a atwam",               /* -5   */
262     "nnibuo 2.2 a atwam",   "nnibuo 2.2 a atwam",             /* -2.2 */
263     "nnibuo 2 a atwam",     "nnibuo 2 a atwam",               /* -2   */
264     "anibuo 1 a atwam",     "anibuo 1 a atwam",               /* -1   */
265     "nnibuo 0.7 a atwam",   "nnibuo 0.7 a atwam",             /* -0.7 */
266     "seesei",               "anibuo 0 a atwam",               /*  -0  */
267     "seesei",               "anibuo 0 mu",               /*  0   */
268     "nnibuo 0.7 mu",        "nnibuo 0.7 mu",             /*  0.7 */
269     "anibuo 1 mu",          "anibuo 1 mu",               /*  1   */
270     "nnibuo 2 mu",          "nnibuo 2 mu",               /*  2   */
271     "nnibuo 5 mu",          "nnibuo 5 mu",               /*  5   */
272 };
273 
274 static const FieldsDat ak_attrDef_long_stdAlon_sec[kNumOffsets*2] = {
275     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
276     {UDAT_REL_NUMERIC_FIELD, 7, 10}, {UDAT_REL_NUMERIC_FIELD, 7, 10},
277     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
278     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
279     {UDAT_REL_NUMERIC_FIELD, 7, 10}, {UDAT_REL_NUMERIC_FIELD, 7, 10},
280     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 7, 8},
281     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 7, 8},
282     {UDAT_REL_NUMERIC_FIELD, 7, 10}, {UDAT_REL_NUMERIC_FIELD, 7, 10},
283     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
284     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
285     {UDAT_REL_NUMERIC_FIELD, 7, 8}, {UDAT_REL_NUMERIC_FIELD, 7, 8},
286 };
287 
288 static const char* enIN_decDef_short_midSent_weds[kNumOffsets*2] = {
289 /*  text                    numeric */
290     "5 Wed ago",            "5 Wed ago",          /* -5   */
291     "2.2 Wed ago",          "2.2 Wed ago",        /* -2.2 */
292     "2 Wed ago",            "2 Wed ago",          /* -2   */
293     "last Wed",             "1 Wed ago",          /* -1   */
294     "0.7 Wed ago",          "0.7 Wed ago",        /* -0.7 */
295     "this Wed",             "0 Wed ago",          /*  -0  */
296     "this Wed",             "in 0 Wed",           /*  0   */
297     "in 0.7 Wed",           "in 0.7 Wed",         /*  0.7 */
298     "next Wed",             "in 1 Wed",           /*  1   */ // in 1 Wed. missing in logical group
299     "in 2 Wed",             "in 2 Wed",           /*  2   */
300     "in 5 Wed",             "in 5 Wed"            /*  5   */
301 };
302 
303 static const FieldsDat enIN_attrDef_short_midSent_weds[kNumOffsets*2] = {
304     {UDAT_REL_NUMERIC_FIELD, 0, 1}, {UDAT_REL_NUMERIC_FIELD, 0, 1},
305     {UDAT_REL_NUMERIC_FIELD, 0, 3}, {UDAT_REL_NUMERIC_FIELD, 0, 3},
306     {UDAT_REL_NUMERIC_FIELD, 0, 1}, {UDAT_REL_NUMERIC_FIELD, 0, 1},
307     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 0, 1},
308     {UDAT_REL_NUMERIC_FIELD, 0, 3}, {UDAT_REL_NUMERIC_FIELD, 0, 3},
309     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 0, 1},
310     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 3, 4},
311     {UDAT_REL_NUMERIC_FIELD, 3, 6}, {UDAT_REL_NUMERIC_FIELD, 3, 6},
312     { -1, -1, -1},                  {UDAT_REL_NUMERIC_FIELD, 3, 4},
313     {UDAT_REL_NUMERIC_FIELD, 3, 4}, {UDAT_REL_NUMERIC_FIELD, 3, 4},
314     {UDAT_REL_NUMERIC_FIELD, 3, 4}, {UDAT_REL_NUMERIC_FIELD, 3, 4},
315 };
316 
317 typedef struct {
318     const char*                         locale;
319     int32_t                             decPlaces; /* fixed decimal places; -1 to use default num formatter */
320     UDateRelativeDateTimeFormatterStyle width;
321     UDisplayContext                     capContext;
322     URelativeDateTimeUnit               unit;
323     const char **                       expectedResults; /* for the various offsets */
324     const FieldsDat*                    expectedAttributes;
325 } RelDateTimeFormatTestItem;
326 
327 static const RelDateTimeFormatTestItem fmtTestItems[] = {
328     { "en", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_SECOND,
329       en_decDef_long_midSent_sec,   en_attrDef_long_midSent_sec },
330     { "en", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK,
331       en_decDef_long_midSent_week,  en_attrDef_long_midSent_week},
332     { "en",  0, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK,
333       en_dec0_long_midSent_week,    en_attr0_long_midSent_week},
334     { "en", -1, UDAT_STYLE_SHORT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK,
335       en_decDef_short_midSent_week, en_attrDef_short_midSent_week},
336     { "en", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_MINUTE,
337       en_decDef_long_midSent_min,   en_attrDef_long_midSent_min},
338     { "en", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_TUESDAY,
339       en_dec0_long_midSent_tues,    en_attr0_long_midSent_tues},
340     { "fr", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_DAY,
341       fr_decDef_long_midSent_day,   fr_attrDef_long_midSent_day},
342     { "ak", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_STANDALONE,         UDAT_REL_UNIT_SECOND,
343       ak_decDef_long_stdAlon_sec,   ak_attrDef_long_stdAlon_sec},
344     { "en_IN", -1, UDAT_STYLE_SHORT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEDNESDAY,
345       enIN_decDef_short_midSent_weds, enIN_attrDef_short_midSent_weds},
346     { "en@calendar=iso8601", -1, UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_SECOND,
347       en_decDef_long_midSent_sec,   en_attrDef_long_midSent_sec },
348     { NULL,  0, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, (URelativeDateTimeUnit)0, NULL, NULL } /* terminator */
349 };
350 
351 enum { kUBufMax = 64, kBBufMax = 256 };
352 
TestRelDateFmt(void)353 static void TestRelDateFmt(void)
354 {
355     const RelDateTimeFormatTestItem *itemPtr;
356     log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n");
357     for (itemPtr = fmtTestItems; itemPtr->locale != NULL; itemPtr++) {
358         URelativeDateTimeFormatter *reldatefmt = NULL;
359         UNumberFormat* nfToAdopt = NULL;
360         UErrorCode status = U_ZERO_ERROR;
361         int32_t iOffset;
362 
363         if (itemPtr->decPlaces >= 0) {
364             nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status);
365             if ( U_FAILURE(status) ) {
366                 log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status));
367                 continue;
368             }
369 		    unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces);
370 		    unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces);
371 		    unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN);
372         }
373         reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status);
374         if ( U_FAILURE(status) ) {
375             log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n",
376                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
377                     myErrorName(status) );
378             continue;
379         }
380 
381         for (iOffset = 0; iOffset < kNumOffsets; iOffset++) {
382             UChar ubufget[kUBufMax];
383             int32_t ulenget;
384 
385             status = U_ZERO_ERROR;
386             ulenget = ureldatefmt_format(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status);
387             if ( U_FAILURE(status) ) {
388                 log_err("FAIL: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
389                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
390                     offsets[iOffset], (int)itemPtr->unit, myErrorName(status) );
391             } else {
392                 UChar ubufexp[kUBufMax];
393                 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2], ubufexp, kUBufMax);
394                 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) {
395                     char  bbufget[kBBufMax];
396                     u_austrncpy(bbufget, ubufget, kUBufMax);
397                     log_err("ERROR: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n      expected %s\n      get      %s\n",
398                         itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
399                         offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2], bbufget );
400                 }
401             }
402 
403             status = U_ZERO_ERROR;
404             ulenget = ureldatefmt_formatNumeric(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status);
405             if ( U_FAILURE(status) ) {
406                 log_err("FAIL: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
407                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
408                     offsets[iOffset], (int)itemPtr->unit, myErrorName(status) );
409             } else {
410                 UChar ubufexp[kUBufMax];
411                 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2 + 1], ubufexp, kUBufMax);
412                 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) {
413                     char  bbufget[kBBufMax];
414                     u_austrncpy(bbufget, ubufget, kUBufMax);
415                     log_err("ERROR: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n      expected %s\n      get      %s\n",
416                         itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
417                         offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2 + 1], bbufget );
418                 }
419             }
420         }
421 
422         ureldatefmt_close(reldatefmt);
423     }
424 }
425 
TestNumericField(void)426 static void TestNumericField(void)
427 {
428     const RelDateTimeFormatTestItem *itemPtr;
429     log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_formatForFields(), ureldatefmt_formatNumericForFields() with various parameters\n");
430     for (itemPtr = fmtTestItems; itemPtr->locale != NULL; itemPtr++) {
431         URelativeDateTimeFormatter *reldatefmt = NULL;
432         UNumberFormat* nfToAdopt = NULL;
433         UErrorCode status = U_ZERO_ERROR;
434         int32_t iOffset;
435 
436         if (itemPtr->decPlaces >= 0) {
437             nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status);
438             if ( U_FAILURE(status) ) {
439                 log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status));
440                 continue;
441             }
442             unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces);
443             unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces);
444             unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN);
445         }
446         reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status);
447         if ( U_FAILURE(status) ) {
448             log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n",
449                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
450                     myErrorName(status) );
451             continue;
452         }
453 
454         for (iOffset = 0; iOffset < kNumOffsets; iOffset++) {
455             /* Depend on the next one to verify the data */
456             status = U_ZERO_ERROR;
457             UFormattedRelativeDateTime* fv = ureldatefmt_openResult(&status);
458             if ( U_FAILURE(status) ) {
459                 log_err("ureldatefmt_openResult fails, status %s\n", u_errorName(status));
460                 continue;
461             }
462             ureldatefmt_formatToResult(reldatefmt, offsets[iOffset], itemPtr->unit, fv, &status);
463             if ( U_FAILURE(status) ) {
464                 log_err("FAIL: ureldatefmt_formatForFields() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
465                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
466                     offsets[iOffset], (int)itemPtr->unit, myErrorName(status) );
467             } else {
468                 UChar ubufexp[kUBufMax];
469                 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2], ubufexp, kUBufMax);
470                 int32_t ulenget;
471                 const UChar* ubufget = ufmtval_getString(ureldatefmt_resultAsValue(fv, &status), &ulenget, &status);
472                 assertUEquals("String content", ubufexp, ubufget);
473                 assertIntEquals("String length", ulenexp, ulenget);
474 
475                 FieldsDat expectedAttr = itemPtr->expectedAttributes[iOffset*2];
476                 UConstrainedFieldPosition* cfpos = ucfpos_open(&status);
477                 UBool foundNumeric = false;
478                 while (true) {
479                     foundNumeric = ufmtval_nextPosition(ureldatefmt_resultAsValue(fv, &status), cfpos, &status);
480                     if (!foundNumeric) {
481                         break;
482                     }
483                     if (ucfpos_getCategory(cfpos, &status) == UFIELD_CATEGORY_RELATIVE_DATETIME
484                         && ucfpos_getField(cfpos, &status) == UDAT_REL_NUMERIC_FIELD) {
485                         break;
486                     }
487                 }
488                 assertSuccess("Looking for numeric", &status);
489                 int32_t beginPos, endPos;
490                 ucfpos_getIndexes(cfpos, &beginPos, &endPos, &status);
491                 if (expectedAttr.field == -1) {
492                     if (foundNumeric) {
493                         log_err("ureldatefmt_formatForFields as \"%s\"; expect no field, but got %d\n",
494                                 itemPtr->expectedResults[iOffset*2],
495                                 ucfpos_getField(cfpos, &status));
496                     }
497                 } else {
498                     if (!foundNumeric ||
499                         beginPos != expectedAttr.beginPos ||
500                         endPos != expectedAttr.endPos) {
501                         log_err("ureldatefmt_formatForFields as \"%s\"; expect field %d range %d-%d, get range %d-%d\n",
502                                 itemPtr->expectedResults[iOffset*2],
503                                 expectedAttr.field, expectedAttr.beginPos, expectedAttr.endPos,
504                                 beginPos, endPos);
505                     }
506                 }
507                 ucfpos_close(cfpos);
508             }
509 
510             /* Depend on the next one to verify the data */
511             status = U_ZERO_ERROR;
512             ureldatefmt_formatNumericToResult(reldatefmt, offsets[iOffset], itemPtr->unit, fv, &status);
513             if ( U_FAILURE(status) ) {
514                 log_err("FAIL: ureldatefmt_formatNumericForFields() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
515                     itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext,
516                     offsets[iOffset], (int)itemPtr->unit, myErrorName(status) );
517             } else {
518                 UChar ubufexp[kUBufMax];
519                 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2 + 1], ubufexp, kUBufMax);
520                 int32_t ulenget;
521                 const UChar* ubufget = ufmtval_getString(ureldatefmt_resultAsValue(fv, &status), &ulenget, &status);
522                 assertUEquals("String content", ubufexp, ubufget);
523                 assertIntEquals("String length", ulenexp, ulenget);
524 
525                 FieldsDat expectedAttr = itemPtr->expectedAttributes[iOffset*2 + 1];
526                 UConstrainedFieldPosition* cfpos = ucfpos_open(&status);
527                 UBool foundNumeric = false;
528                 while (true) {
529                     foundNumeric = ufmtval_nextPosition(ureldatefmt_resultAsValue(fv, &status), cfpos, &status);
530                     if (!foundNumeric) {
531                         break;
532                     }
533                     if (ucfpos_getCategory(cfpos, &status) == UFIELD_CATEGORY_RELATIVE_DATETIME
534                         && ucfpos_getField(cfpos, &status) == UDAT_REL_NUMERIC_FIELD) {
535                         break;
536                     }
537                 }
538                 assertSuccess("Looking for numeric", &status);
539                 int32_t beginPos, endPos;
540                 ucfpos_getIndexes(cfpos, &beginPos, &endPos, &status);
541                 if (expectedAttr.field == -1) {
542                     if (foundNumeric) {
543                         log_err("ureldatefmt_formatForFields as \"%s\"; expect no field, but got %d rang %d-%d\n",
544                                 itemPtr->expectedResults[iOffset*2],
545                                 ucfpos_getField(cfpos, &status), beginPos, endPos);
546                     }
547                 } else {
548                     if (!foundNumeric ||
549                         (beginPos != expectedAttr.beginPos || endPos != expectedAttr.endPos)) {
550                         log_err("ureldatefmt_formatForFields as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
551                                 itemPtr->expectedResults[iOffset*2 + 1],
552                                 expectedAttr.field, expectedAttr.beginPos, expectedAttr.endPos,
553                                 ucfpos_getField(cfpos, &status), beginPos, endPos);
554                     }
555                 }
556                 ucfpos_close(cfpos);
557             }
558             ureldatefmt_closeResult(fv);
559         }
560 
561         ureldatefmt_close(reldatefmt);
562     }
563 }
564 
565 typedef struct {
566     const char*                         locale;
567     UDateRelativeDateTimeFormatterStyle width;
568     UDisplayContext                     capContext;
569     const char *                        relativeDateString;
570     const char *                        timeString;
571     const char *                        expectedResult;
572 } CombineDateTimeTestItem;
573 
574 static const CombineDateTimeTestItem combTestItems[] = {
575     { "en",  UDAT_STYLE_LONG,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "yesterday",  "3:45 PM",  "yesterday, 3:45 PM" },
576     { NULL,  (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, NULL, NULL, NULL } /* terminator */
577 };
578 
TestCombineDateTime(void)579 static void TestCombineDateTime(void)
580 {
581     const CombineDateTimeTestItem *itemPtr;
582     log_verbose("\nTesting ureldatefmt_combineDateAndTime() with various parameters\n");
583     for (itemPtr = combTestItems; itemPtr->locale != NULL; itemPtr++) {
584         URelativeDateTimeFormatter *reldatefmt = NULL;
585         UErrorCode status = U_ZERO_ERROR;
586         UChar ubufreldate[kUBufMax];
587         UChar ubuftime[kUBufMax];
588         UChar ubufget[kUBufMax];
589         int32_t ulenreldate, ulentime, ulenget;
590 
591         reldatefmt = ureldatefmt_open(itemPtr->locale, NULL, itemPtr->width, itemPtr->capContext, &status);
592         if ( U_FAILURE(status) ) {
593             log_data_err("FAIL: ureldatefmt_open() for locale %s, width %d, capContext %d: %s\n",
594                     itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) );
595             continue;
596         }
597 
598         ulenreldate = u_unescape(itemPtr->relativeDateString, ubufreldate, kUBufMax);
599         ulentime    = u_unescape(itemPtr->timeString,         ubuftime,    kUBufMax);
600         ulenget     = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, ubufget, kUBufMax, &status);
601         if ( U_FAILURE(status) ) {
602             log_err("FAIL: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d: %s\n",
603                 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) );
604         } else {
605             UChar ubufexp[kUBufMax];
606             int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax);
607             if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) {
608                 char  bbufget[kBBufMax];
609                 u_austrncpy(bbufget, ubufget, kUBufMax);
610                 log_err("ERROR: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d;\n      expected %s\n      get      %s\n",
611                     itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, itemPtr->expectedResult, bbufget );
612             }
613         }
614         // preflight test
615         status = U_ZERO_ERROR;
616         ulenget = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, NULL, 0, &status);
617         if ( status != U_BUFFER_OVERFLOW_ERROR) {
618             log_err("FAIL: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d: expected U_BUFFER_OVERFLOW_ERROR, got %s\n",
619                 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) );
620         } else {
621             UChar ubufexp[kUBufMax];
622             int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax);
623             if (ulenget != ulenexp) {
624                 log_err("ERROR: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d;\n      expected len %d, get len %d\n",
625                     itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, ulenexp, ulenget );
626             }
627         }
628 
629         ureldatefmt_close(reldatefmt);
630     }
631 }
632 
TestFields(void)633 static void TestFields(void) {
634     UErrorCode ec = U_ZERO_ERROR;
635     URelativeDateTimeFormatter* fmt = ureldatefmt_open(
636         "en-us",
637         NULL,
638         UDAT_STYLE_SHORT,
639         UDISPCTX_CAPITALIZATION_NONE,
640         &ec);
641     assertSuccess("Creating RelDTFmt", &ec);
642     UFormattedRelativeDateTime* frdt = ureldatefmt_openResult(&ec);
643     assertSuccess("Creating FmtVal", &ec);
644 
645     ureldatefmt_formatNumericToResult(fmt, -50, UDAT_REL_UNIT_SATURDAY, frdt, &ec);
646     assertSuccess("formatNumeric", &ec);
647     {
648         const UFormattedValue* fv = ureldatefmt_resultAsValue(frdt, &ec);
649         assertSuccess("Should convert without error", &ec);
650         static const UFieldPositionWithCategory expectedFieldPositions[] = {
651             // category, field, begin index, end index
652             {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD, 0, 2},
653             {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD, 0, 2},
654             {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD, 3, 11}};
655         checkMixedFormattedValue(
656             "FormattedRelativeDateTime as FormattedValue (numeric)",
657             fv,
658             u"50 Sat. ago",
659             expectedFieldPositions,
660             UPRV_LENGTHOF(expectedFieldPositions));
661     }
662 
663     ureldatefmt_formatToResult(fmt, -1, UDAT_REL_UNIT_WEEK, frdt, &ec);
664     assertSuccess("format", &ec);
665     {
666         const UFormattedValue* fv = ureldatefmt_resultAsValue(frdt, &ec);
667         assertSuccess("Should convert without error", &ec);
668         static const UFieldPositionWithCategory expectedFieldPositions[] = {
669             // category, field, begin index, end index
670             {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD, 0, 8}};
671         checkMixedFormattedValue(
672             "FormattedRelativeDateTime as FormattedValue (relative)",
673             fv,
674             u"last wk.",
675             expectedFieldPositions,
676             UPRV_LENGTHOF(expectedFieldPositions));
677     }
678 
679     ureldatefmt_closeResult(frdt);
680     ureldatefmt_close(fmt);
681 }
682 
683 #endif /* #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */
684