1/***********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ***********************************************************************/
6
7#include "unicode/utypes.h"
8
9#if !UCONFIG_NO_FORMATTING
10
11#include "nmfmapts.h"
12
13#include "unicode/numfmt.h"
14#include "unicode/decimfmt.h"
15#include "unicode/locid.h"
16#include "unicode/unum.h"
17#include "unicode/strenum.h"
18
19// This is an API test, not a unit test.  It doesn't test very many cases, and doesn't
20// try to test the full functionality.  It just calls each function in the class and
21// verifies that it works on a basic level.
22
23void IntlTestNumberFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
24{
25    if (exec) logln("TestSuite NumberFormatAPI");
26    switch (index) {
27        case 0: name = "NumberFormat API test";
28                if (exec) {
29                    logln("NumberFormat API test---"); logln("");
30                    UErrorCode status = U_ZERO_ERROR;
31                    Locale saveLocale;
32                    Locale::setDefault(Locale::getEnglish(), status);
33                    if(U_FAILURE(status)) {
34                        errln("ERROR: Could not set default locale, test may not give correct results");
35                    }
36                    testAPI(/* par */);
37                    Locale::setDefault(saveLocale, status);
38                }
39                break;
40        case 1: name = "NumberFormatRegistration";
41                if (exec) {
42                    logln("NumberFormat Registration test---"); logln("");
43                    UErrorCode status = U_ZERO_ERROR;
44                    Locale saveLocale;
45                    Locale::setDefault(Locale::getEnglish(), status);
46                    if(U_FAILURE(status)) {
47                        errln("ERROR: Could not set default locale, test may not give correct results");
48                    }
49                    testRegistration();
50                    Locale::setDefault(saveLocale, status);
51                }
52                break;
53        default: name = ""; break;
54    }
55}
56
57/**
58 * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
59 * NumberFormat.
60 */
61void IntlTestNumberFormatAPI::testAPI(/* char* par */)
62{
63    UErrorCode status = U_ZERO_ERROR;
64
65// ======= Test constructors
66
67    logln("Testing NumberFormat constructors");
68
69    NumberFormat *def = NumberFormat::createInstance(status);
70    if(U_FAILURE(status)) {
71        dataerrln("ERROR: Could not create NumberFormat (default) - %s", u_errorName(status));
72    }
73
74    status = U_ZERO_ERROR;
75    NumberFormat *fr = NumberFormat::createInstance(Locale::getFrench(), status);
76    if(U_FAILURE(status)) {
77        dataerrln("ERROR: Could not create NumberFormat (French) - %s", u_errorName(status));
78    }
79
80    NumberFormat *cur = NumberFormat::createCurrencyInstance(status);
81    if(U_FAILURE(status)) {
82        dataerrln("ERROR: Could not create NumberFormat (currency, default) - %s", u_errorName(status));
83    }
84
85    status = U_ZERO_ERROR;
86    NumberFormat *cur_fr = NumberFormat::createCurrencyInstance(Locale::getFrench(), status);
87    if(U_FAILURE(status)) {
88        dataerrln("ERROR: Could not create NumberFormat (currency, French) - %s", u_errorName(status));
89    }
90
91    NumberFormat *per = NumberFormat::createPercentInstance(status);
92    if(U_FAILURE(status)) {
93        dataerrln("ERROR: Could not create NumberFormat (percent, default) - %s", u_errorName(status));
94    }
95
96    status = U_ZERO_ERROR;
97    NumberFormat *per_fr = NumberFormat::createPercentInstance(Locale::getFrench(), status);
98    if(U_FAILURE(status)) {
99        dataerrln("ERROR: Could not create NumberFormat (percent, French) - %s", u_errorName(status));
100    }
101
102// ======= Test equality
103if (per_fr != NULL && cur_fr != NULL)
104{
105    logln("Testing equality operator");
106
107    if( *per_fr == *cur_fr || ! ( *per_fr != *cur_fr) ) {
108        errln("ERROR: == failed");
109    }
110}
111
112// ======= Test various format() methods
113if (cur_fr != NULL)
114{
115    logln("Testing various format() methods");
116
117    double d = -10456.0037;
118    int32_t l = 100000000;
119    Formattable fD(d);
120    Formattable fL(l);
121
122    UnicodeString res1, res2, res3, res4, res5, res6;
123    FieldPosition pos1(0), pos2(0), pos3(0), pos4(0);
124
125    res1 = cur_fr->format(d, res1);
126    logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res1);
127
128    res2 = cur_fr->format(l, res2);
129    logln((UnicodeString) "" + (int32_t) l + " formatted to " + res2);
130
131    res3 = cur_fr->format(d, res3, pos1);
132    logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res3);
133
134    res4 = cur_fr->format(l, res4, pos2);
135    logln((UnicodeString) "" + (int32_t) l + " formatted to " + res4);
136
137    status = U_ZERO_ERROR;
138    res5 = cur_fr->format(fD, res5, pos3, status);
139    if(U_FAILURE(status)) {
140        errln("ERROR: format(Formattable [double]) failed");
141    }
142    logln((UnicodeString) "" + (int32_t) fD.getDouble() + " formatted to " + res5);
143
144    status = U_ZERO_ERROR;
145    res6 = cur_fr->format(fL, res6, pos4, status);
146    if(U_FAILURE(status)) {
147        errln("ERROR: format(Formattable [long]) failed");
148    }
149    logln((UnicodeString) "" + fL.getLong() + " formatted to " + res6);
150}
151
152// ======= Test parse()
153if (fr != NULL)
154{
155    logln("Testing parse()");
156
157    double d = -10456.0037;
158    UnicodeString text("-10,456.0037");
159    Formattable result1, result2, result3;
160    ParsePosition pos(0), pos01(0);
161    fr->parseObject(text, result1, pos);
162    if(result1.getType() != Formattable::kDouble && result1.getDouble() != d) {
163        errln("ERROR: Roundtrip failed (via parse()) for " + text);
164    }
165    logln(text + " parsed into " + (int32_t) result1.getDouble());
166
167    fr->parse(text, result2, pos01);
168    if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) {
169        errln("ERROR: Roundtrip failed (via parse()) for " + text);
170    }
171    logln(text + " parsed into " + (int32_t) result2.getDouble());
172
173    status = U_ZERO_ERROR;
174    fr->parse(text, result3, status);
175    if(U_FAILURE(status)) {
176        errln("ERROR: parse() failed");
177    }
178    if(result3.getType() != Formattable::kDouble && result3.getDouble() != d) {
179        errln("ERROR: Roundtrip failed (via parse()) for " + text);
180    }
181    logln(text + " parsed into " + (int32_t) result3.getDouble());
182}
183
184// ======= Test getters and setters
185if (fr != NULL && def != NULL)
186{
187    logln("Testing getters and setters");
188
189    int32_t count = 0;
190    const Locale *locales = NumberFormat::getAvailableLocales(count);
191    logln((UnicodeString) "Got " + count + " locales" );
192    for(int32_t i = 0; i < count; i++) {
193        UnicodeString name(locales[i].getName(),"");
194        logln(name);
195    }
196
197    fr->setParseIntegerOnly( def->isParseIntegerOnly() );
198    if(fr->isParseIntegerOnly() != def->isParseIntegerOnly() ) {
199        errln("ERROR: setParseIntegerOnly() failed");
200    }
201
202    fr->setGroupingUsed( def->isGroupingUsed() );
203    if(fr->isGroupingUsed() != def->isGroupingUsed() ) {
204        errln("ERROR: setGroupingUsed() failed");
205    }
206
207    fr->setMaximumIntegerDigits( def->getMaximumIntegerDigits() );
208    if(fr->getMaximumIntegerDigits() != def->getMaximumIntegerDigits() ) {
209        errln("ERROR: setMaximumIntegerDigits() failed");
210    }
211
212    fr->setMinimumIntegerDigits( def->getMinimumIntegerDigits() );
213    if(fr->getMinimumIntegerDigits() != def->getMinimumIntegerDigits() ) {
214        errln("ERROR: setMinimumIntegerDigits() failed");
215    }
216
217    fr->setMaximumFractionDigits( def->getMaximumFractionDigits() );
218    if(fr->getMaximumFractionDigits() != def->getMaximumFractionDigits() ) {
219        errln("ERROR: setMaximumFractionDigits() failed");
220    }
221
222    fr->setMinimumFractionDigits( def->getMinimumFractionDigits() );
223    if(fr->getMinimumFractionDigits() != def->getMinimumFractionDigits() ) {
224        errln("ERROR: setMinimumFractionDigits() failed");
225    }
226}
227
228// ======= Test getStaticClassID()
229
230    logln("Testing getStaticClassID()");
231
232    status = U_ZERO_ERROR;
233    NumberFormat *test = new DecimalFormat(status);
234    if(U_FAILURE(status)) {
235        errcheckln(status, "ERROR: Couldn't create a NumberFormat - %s", u_errorName(status));
236    }
237
238    if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
239        errln("ERROR: getDynamicClassID() didn't return the expected value");
240    }
241
242    delete test;
243    delete def;
244    delete fr;
245    delete cur;
246    delete cur_fr;
247    delete per;
248    delete per_fr;
249}
250
251#if !UCONFIG_NO_SERVICE
252
253#define SRC_LOC Locale::getFrance()
254#define SWAP_LOC Locale::getUS()
255
256class NFTestFactory : public SimpleNumberFormatFactory {
257    NumberFormat* currencyStyle;
258
259public:
260    NFTestFactory()
261        : SimpleNumberFormatFactory(SRC_LOC, TRUE)
262    {
263        UErrorCode status = U_ZERO_ERROR;
264        currencyStyle = NumberFormat::createInstance(SWAP_LOC, status);
265    }
266
267    virtual ~NFTestFactory()
268    {
269        delete currencyStyle;
270    }
271
272    virtual NumberFormat* createFormat(const Locale& /* loc */, UNumberFormatStyle formatType)
273    {
274        if (formatType == UNUM_CURRENCY) {
275            return (NumberFormat*)currencyStyle->clone();
276        }
277        return NULL;
278    }
279
280   virtual inline UClassID getDynamicClassID() const
281   {
282       return (UClassID)&gID;
283   }
284
285   static inline UClassID getStaticClassID()
286   {
287        return (UClassID)&gID;
288   }
289
290private:
291   static char gID;
292};
293
294char NFTestFactory::gID = 0;
295#endif
296
297void
298IntlTestNumberFormatAPI::testRegistration()
299{
300#if !UCONFIG_NO_SERVICE
301    UErrorCode status = U_ZERO_ERROR;
302
303    LocalPointer<NumberFormat> f0(NumberFormat::createInstance(SWAP_LOC, status));
304    LocalPointer<NumberFormat> f1(NumberFormat::createInstance(SRC_LOC, status));
305    LocalPointer<NumberFormat> f2(NumberFormat::createCurrencyInstance(SRC_LOC, status));
306    URegistryKey key = NumberFormat::registerFactory(new NFTestFactory(), status);
307    LocalPointer<NumberFormat> f3(NumberFormat::createCurrencyInstance(SRC_LOC, status));
308    LocalPointer<NumberFormat> f3a(NumberFormat::createCurrencyInstance(SRC_LOC, status));
309    LocalPointer<NumberFormat> f4(NumberFormat::createInstance(SRC_LOC, status));
310
311    StringEnumeration* locs = NumberFormat::getAvailableLocales();
312
313    LocalUNumberFormatPointer uf3(unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(), NULL, &status));
314    LocalUNumberFormatPointer uf4(unum_open(UNUM_DEFAULT, NULL, 0, SRC_LOC.getName(), NULL, &status));
315
316    const UnicodeString* res;
317    for (res = locs->snext(status); res; res = locs->snext(status)) {
318        logln(*res); // service is still in synch
319    }
320
321    NumberFormat::unregister(key, status); // restore for other tests
322    LocalPointer<NumberFormat> f5(NumberFormat::createCurrencyInstance(SRC_LOC, status));
323    LocalUNumberFormatPointer uf5(unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(), NULL, &status));
324
325    if (U_FAILURE(status)) {
326        dataerrln("Error creating instnaces.");
327        return;
328    } else {
329        float n = 1234.567f;
330        UnicodeString res0, res1, res2, res3, res4, res5;
331        UChar ures3[50];
332        UChar ures4[50];
333        UChar ures5[50];
334
335        f0->format(n, res0);
336        f1->format(n, res1);
337        f2->format(n, res2);
338        f3->format(n, res3);
339        f4->format(n, res4);
340        f5->format(n, res5);
341
342        unum_formatDouble(uf3.getAlias(), n, ures3, 50, NULL, &status);
343        unum_formatDouble(uf4.getAlias(), n, ures4, 50, NULL, &status);
344        unum_formatDouble(uf5.getAlias(), n, ures5, 50, NULL, &status);
345
346        logln((UnicodeString)"f0 swap int: " + res0);
347        logln((UnicodeString)"f1 src int: " + res1);
348        logln((UnicodeString)"f2 src cur: " + res2);
349        logln((UnicodeString)"f3 reg cur: " + res3);
350        logln((UnicodeString)"f4 reg int: " + res4);
351        logln((UnicodeString)"f5 unreg cur: " + res5);
352        log("uf3 reg cur: ");
353        logln(ures3);
354        log("uf4 reg int: ");
355        logln(ures4);
356        log("uf5 ureg cur: ");
357        logln(ures5);
358
359        if (f3.getAlias() == f3a.getAlias()) {
360            errln("did not get new instance from service");
361            f3a.orphan();
362        }
363        if (res3 != res0) {
364            errln("registered service did not match");
365        }
366        if (res4 != res1) {
367            errln("registered service did not inherit");
368        }
369        if (res5 != res2) {
370            errln("unregistered service did not match original");
371        }
372
373        if (res0 != ures3) {
374            errln("registered service did not match / unum");
375        }
376        if (res1 != ures4) {
377            errln("registered service did not inherit / unum");
378        }
379        if (res2 != ures5) {
380            errln("unregistered service did not match original / unum");
381        }
382    }
383
384    for (res = locs->snext(status); res; res = locs->snext(status)) {
385        errln(*res); // service should be out of synch
386    }
387
388    locs->reset(status); // now in synch again, we hope
389    for (res = locs->snext(status); res; res = locs->snext(status)) {
390        logln(*res);
391    }
392
393    delete locs;
394#endif
395}
396
397
398#endif /* #if !UCONFIG_NO_FORMATTING */
399