169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/***********************************************************************
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * COPYRIGHT:
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (c) 1997-2011, International Business Machines Corporation
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * and others. All Rights Reserved.
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ***********************************************************************/
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/utypes.h"
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#if !UCONFIG_NO_FORMATTING
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "msfmrgts.h"
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/format.h"
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/decimfmt.h"
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/locid.h"
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/msgfmt.h"
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/numfmt.h"
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/choicfmt.h"
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "unicode/gregocal.h"
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "putilimp.h"
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// *****************************************************************************
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// class MessageFormatRegressionTest
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// *****************************************************************************
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid
2969e17611504376e4d4603925f8528dfc890fd2c6Luis SigalMessageFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal{
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO_BEGIN;
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4074764)
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //TESTCASE_AUTO(Test4058973)  -- disabled/obsolete in ICU 4.8
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4031438)
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4052223)
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4104976)
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4106659)
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4106660)
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4111739)
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4114743)
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4116444)
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4114739)
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4113018)
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4106661)
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4094906)
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4118592)
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4118594)
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4105380)
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4120552)
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4142938)
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(TestChoicePatternQuote)
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(Test4112104)
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO(TestAPI)
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    TESTCASE_AUTO_END;
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5769e17611504376e4d4603925f8528dfc890fd2c6Luis SigalUBool
5869e17611504376e4d4603925f8528dfc890fd2c6Luis SigalMessageFormatRegressionTest::failure(UErrorCode status, const char* msg, UBool possibleDataError)
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal{
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    if(U_FAILURE(status)) {
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (possibleDataError) {
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dataerrln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else {
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return TRUE;
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    return FALSE;
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* @bug 4074764
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Null exception when formatting pattern with MessageFormat
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with no parameters.
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid MessageFormatRegressionTest::Test4074764() {
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UnicodeString pattern [] = {
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        "Message without param",
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        "Message with param:{0}",
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        "Longer Message with param {0}"
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    };
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //difference between the two param strings are that
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //in the first one, the param position is within the
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //length of the string without param while it is not so
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //in the other case.
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UErrorCode status = U_ZERO_ERROR;
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    MessageFormat *messageFormatter = new MessageFormat("", status);
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    failure(status, "couldn't create MessageFormat");
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    //try {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //Apply pattern with param and print the result
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        messageFormatter->applyPattern(pattern[1], status);
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        failure(status, "messageFormat->applyPattern");
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //Object[] params = {new UnicodeString("BUG"), new Date()};
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Formattable params [] = {
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Formattable(UnicodeString("BUG")),
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Formattable(0, Formattable::kIsDate)
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        };
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        UnicodeString tempBuffer;
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        FieldPosition pos(FieldPosition::DONT_CARE);
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status);
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if( tempBuffer != "Message with param:BUG" || failure(status, "messageFormat->format"))
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            errln("MessageFormat with one param test failed.");
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        logln("Formatted with one extra param : " + tempBuffer);
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //Apply pattern without param and print the result
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        messageFormatter->applyPattern(pattern[0], status);
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        failure(status, "messageFormatter->applyPattern");
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // {sfb} how much does this apply in C++?
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // do we want to verify that the Formattable* array is not NULL,
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // or is that the user's responsibility?
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // additionally, what should be the item count?
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // for bug testing purposes, assume that something was set to
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // NULL by mistake, and that the length should be non-zero
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //tempBuffer = messageFormatter->format(NULL, 1, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status);
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        tempBuffer.remove();
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        tempBuffer = messageFormatter->format(NULL, 0, tempBuffer, pos, status);
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if( tempBuffer != "Message without param" || failure(status, "messageFormat->format"))
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            errln("MessageFormat with no param test failed.");
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        logln("Formatted with no params : " + tempBuffer);
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        tempBuffer.remove();
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status);
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         if (tempBuffer != "Message without param" || failure(status, "messageFormat->format"))
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            errln("Formatted with arguments > subsitution failed. result = " + tempBuffer);
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         logln("Formatted with extra params : " + tempBuffer);
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //This statement gives an exception while formatting...
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //If we use pattern[1] for the message with param,
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //we get an NullPointerException in MessageFormat.java(617)
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //If we use pattern[2] for the message with param,
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //Both are due to maxOffset not being reset to -1
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //in applyPattern() when the pattern does not
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        //contain any param.
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /*} catch (Exception foo) {
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        errln("Exception when formatting with no params.");
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }*/
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    delete messageFormatter;
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* @bug 4058973
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * MessageFormat.toPattern has weird rounding behavior.
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * ICU 4.8: This test is commented out because toPattern() has been changed to return
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the original pattern string, rather than reconstituting a new (equivalent) one.
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This trivially eliminates issues with rounding or any other pattern string differences.
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid MessageFormatRegressionTest::Test4058973()
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal{
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UErrorCode status = U_ZERO_ERROR;
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    MessageFormat *fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}", status);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    failure(status, "new MessageFormat");
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UnicodeString pat;
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    pat = fmt->toPattern(pat);
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UnicodeString exp("{0,choice,0#no files|1#one file|1< {0,number,integer} files}");
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    if (pat != exp) {
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        errln("MessageFormat.toPattern failed");
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        errln("Exp: " + exp);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        errln("Got: " + pat);
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    delete fmt;
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}*/
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* @bug 4031438
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * More robust message formats.
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid MessageFormatRegressionTest::Test4031438()
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal{
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    UErrorCode status = U_ZERO_ERROR;
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
179    UnicodeString pattern1("Impossible {1} has occurred -- status code is {0} and message is {2}.");
180    UnicodeString pattern2("Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.");
181
182    MessageFormat *messageFormatter = new MessageFormat("", status);
183    failure(status, "new MessageFormat");
184
185    const UBool possibleDataError = TRUE;
186
187    //try {
188        logln("Apply with pattern : " + pattern1);
189        messageFormatter->applyPattern(pattern1, status);
190        failure(status, "messageFormat->applyPattern");
191        //Object[] params = {new Integer(7)};
192        Formattable params []= {
193            Formattable((int32_t)7)
194        };
195        UnicodeString tempBuffer;
196        FieldPosition pos(FieldPosition::DONT_CARE);
197        tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status);
198        if(tempBuffer != "Impossible {1} has occurred -- status code is 7 and message is {2}." || failure(status, "MessageFormat::format"))
199            dataerrln("Tests arguments < substitution failed");
200        logln("Formatted with 7 : " + tempBuffer);
201        ParsePosition pp(0);
202        int32_t count = 0;
203        Formattable *objs = messageFormatter->parse(tempBuffer, pp, count);
204        //if(objs[7/*params.length*/] != NULL)
205        //    errln("Parse failed with more than expected arguments");
206
207        NumberFormat *fmt = 0;
208        UnicodeString temp, temp1;
209
210        for (int i = 0; i < count; i++) {
211
212            // convert to string if not already
213            Formattable obj = objs[i];
214            temp.remove();
215            if(obj.getType() == Formattable::kString)
216                temp = obj.getString(temp);
217            else {
218                fmt = NumberFormat::createInstance(status);
219                switch (obj.getType()) {
220                case Formattable::kLong: fmt->format(obj.getLong(), temp); break;
221                case Formattable::kInt64: fmt->format(obj.getInt64(), temp); break;
222                case Formattable::kDouble: fmt->format(obj.getDouble(), temp); break;
223                default: break;
224                }
225            }
226
227            // convert to string if not already
228            Formattable obj1 = params[i];
229            temp1.remove();
230            if(obj1.getType() == Formattable::kString)
231                temp1 = obj1.getString(temp1);
232            else {
233                fmt = NumberFormat::createInstance(status);
234                switch (obj1.getType()) {
235                case Formattable::kLong: fmt->format(obj1.getLong(), temp1); break;
236                case Formattable::kInt64: fmt->format(obj1.getInt64(), temp1); break;
237                case Formattable::kDouble: fmt->format(obj1.getDouble(), temp1); break;
238                default: break;
239                }
240            }
241
242            //if (objs[i] != NULL && objs[i].getString(temp1) != params[i].getString(temp2)) {
243            if (temp != temp1) {
244                errln("Parse failed on object " + objs[i].getString(temp1) + " at index : " + i);
245            }
246        }
247
248        delete fmt;
249        delete [] objs;
250
251        // {sfb} does this apply?  no way to really pass a null Formattable,
252        // only a null array
253
254        /*tempBuffer = messageFormatter->format(null, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status);
255        if (tempBuffer != "Impossible {1} has occurred -- status code is {0} and message is {2}." || failure(status, "messageFormat->format"))
256            errln("Tests with no arguments failed");
257        logln("Formatted with null : " + tempBuffer);*/
258        logln("Apply with pattern : " + pattern2);
259        messageFormatter->applyPattern(pattern2, status);
260        failure(status, "messageFormatter->applyPattern", possibleDataError);
261        tempBuffer.remove();
262        tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status);
263        if (tempBuffer != "Double ' Quotes 7 test and quoted {1} test plus 'other {2} stuff'.")
264            dataerrln("quote format test (w/ params) failed. - %s", u_errorName(status));
265        logln("Formatted with params : " + tempBuffer);
266
267        /*tempBuffer = messageFormatter->format(null);
268        if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))
269            errln("quote format test (w/ null) failed.");
270        logln("Formatted with null : " + tempBuffer);
271        logln("toPattern : " + messageFormatter.toPattern());*/
272    /*} catch (Exception foo) {
273        errln("Exception when formatting in bug 4031438. "+foo.getMessage());
274    }*/
275        delete messageFormatter;
276}
277
278void MessageFormatRegressionTest::Test4052223()
279{
280
281    ParsePosition pos(0);
282    if (pos.getErrorIndex() != -1) {
283        errln("ParsePosition.getErrorIndex initialization failed.");
284    }
285
286    UErrorCode status = U_ZERO_ERROR;
287    MessageFormat *fmt = new MessageFormat("There are {0} apples growing on the {1} tree.", status);
288    failure(status, "new MessageFormat");
289    UnicodeString str("There is one apple growing on the peach tree.");
290
291    int32_t count = 0;
292    fmt->parse(str, pos, count);
293
294    logln(UnicodeString("unparsable string , should fail at ") + pos.getErrorIndex());
295    if (pos.getErrorIndex() == -1)
296        errln("Bug 4052223 failed : parsing string " + str);
297    pos.setErrorIndex(4);
298    if (pos.getErrorIndex() != 4)
299        errln(UnicodeString("setErrorIndex failed, got ") + pos.getErrorIndex() + " instead of 4");
300
301    ChoiceFormat *f = new ChoiceFormat(
302        "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.", status);
303    failure(status, "new ChoiceFormat");
304    pos.setIndex(0);
305    pos.setErrorIndex(-1);
306    Formattable obj;
307    f->parse("are negative", obj, pos);
308    if (pos.getErrorIndex() != -1 && obj.getDouble() == -1.0)
309        errln(UnicodeString("Parse with \"are negative\" failed, at ") + pos.getErrorIndex());
310    pos.setIndex(0);
311    pos.setErrorIndex(-1);
312    f->parse("are no or fraction ", obj, pos);
313    if (pos.getErrorIndex() != -1 && obj.getDouble() == 0.0)
314        errln(UnicodeString("Parse with \"are no or fraction\" failed, at ") + pos.getErrorIndex());
315    pos.setIndex(0);
316    pos.setErrorIndex(-1);
317    f->parse("go postal", obj, pos);
318    if (pos.getErrorIndex() == -1 && ! uprv_isNaN(obj.getDouble()))
319        errln(UnicodeString("Parse with \"go postal\" failed, at ") + pos.getErrorIndex());
320
321    delete fmt;
322    delete f;
323}
324/* @bug 4104976
325 * ChoiceFormat.equals(null) throws NullPointerException
326 */
327
328// {sfb} not really applicable in C++?? (kind of silly)
329
330void MessageFormatRegressionTest::Test4104976()
331{
332    double limits [] = {1, 20};
333    UnicodeString formats [] = {
334        UnicodeString("xyz"),
335        UnicodeString("abc")
336    };
337    int32_t formats_length = (int32_t)(sizeof(formats)/sizeof(formats[0]));
338    UErrorCode status = U_ZERO_ERROR;
339    ChoiceFormat *cf = new ChoiceFormat(limits, formats, formats_length);
340    failure(status, "new ChoiceFormat");
341    //try {
342        log("Compares to null is always false, returned : ");
343        logln(cf == NULL ? "TRUE" : "FALSE");
344    /*} catch (Exception foo) {
345        errln("ChoiceFormat.equals(null) throws exception.");
346    }*/
347
348    delete cf;
349}
350
351/* @bug 4106659
352 * ChoiceFormat.ctor(double[], String[]) doesn't check
353 * whether lengths of input arrays are equal.
354 */
355
356// {sfb} again, not really applicable in C++
357
358void MessageFormatRegressionTest::Test4106659()
359{
360    /*
361    double limits [] = {
362        1, 2, 3
363    };
364    UnicodeString formats [] = {
365        "one", "two"
366    };
367    ChoiceFormat *cf = NULL;
368    //try {
369    //    cf = new ChoiceFormat(limits, formats, 3);
370    //} catch (Exception foo) {
371    //    logln("ChoiceFormat constructor should check for the array lengths");
372    //    cf = null;
373    //}
374    //if (cf != null)
375    //    errln(cf->format(5));
376    //
377    delete cf;
378    */
379}
380
381/* @bug 4106660
382 * ChoiceFormat.ctor(double[], String[]) allows unordered double array.
383 * This is not a bug, added javadoc to emphasize the use of limit
384 * array must be in ascending order.
385 */
386void MessageFormatRegressionTest::Test4106660()
387{
388    double limits [] = {3, 1, 2};
389    UnicodeString formats [] = {
390        UnicodeString("Three"),
391            UnicodeString("One"),
392            UnicodeString("Two")
393    };
394    ChoiceFormat *cf = new ChoiceFormat(limits, formats, 3);
395    double d = 5.0;
396    UnicodeString str;
397    FieldPosition pos(FieldPosition::DONT_CARE);
398    str = cf->format(d, str, pos);
399    if (str != "Two")
400        errln( (UnicodeString) "format(" + d + ") = " + str);
401
402    delete cf;
403}
404
405/* @bug 4111739
406 * MessageFormat is incorrectly serialized/deserialized.
407 */
408
409// {sfb} doesn't apply in C++
410
411void MessageFormatRegressionTest::Test4111739()
412{
413    /*MessageFormat format1 = null;
414    MessageFormat format2 = null;
415    ObjectOutputStream ostream = null;
416    ByteArrayOutputStream baos = null;
417    ObjectInputStream istream = null;
418
419    try {
420        baos = new ByteArrayOutputStream();
421        ostream = new ObjectOutputStream(baos);
422    } catch(IOException e) {
423        errln("Unexpected exception : " + e.getMessage());
424        return;
425    }
426
427    try {
428        format1 = new MessageFormat("pattern{0}");
429        ostream.writeObject(format1);
430        ostream.flush();
431
432        byte bytes[] = baos.toByteArray();
433
434        istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
435        format2 = (MessageFormat)istream.readObject();
436    } catch(Exception e) {
437        errln("Unexpected exception : " + e.getMessage());
438    }
439
440    if (!format1.equals(format2)) {
441        errln("MessageFormats before and after serialization are not" +
442            " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +
443            format2 + "(" + format2.toPattern() + ")");
444    } else {
445        logln("Serialization for MessageFormat is OK.");
446    }*/
447}
448/* @bug 4114743
449 * MessageFormat.applyPattern allows illegal patterns.
450 */
451void MessageFormatRegressionTest::Test4114743()
452{
453    UnicodeString originalPattern("initial pattern");
454    UErrorCode status = U_ZERO_ERROR;
455    MessageFormat *mf = new MessageFormat(originalPattern, status);
456    failure(status, "new MessageFormat");
457    //try {
458        UnicodeString illegalPattern("ab { '}' de");
459        mf->applyPattern(illegalPattern, status);
460        if( ! U_FAILURE(status))
461            errln("illegal pattern: \"" + illegalPattern + "\"");
462    /*} catch (IllegalArgumentException foo) {
463        if (!originalPattern.equals(mf.toPattern()))
464            errln("pattern after: \"" + mf.toPattern() + "\"");
465    }*/
466    delete mf;
467}
468
469/* @bug 4116444
470 * MessageFormat.parse has different behavior in case of null.
471 */
472void MessageFormatRegressionTest::Test4116444()
473{
474    UnicodeString patterns [] = {
475        (UnicodeString)"",
476        (UnicodeString)"one",
477        (UnicodeString) "{0,date,short}"
478    };
479
480    UErrorCode status = U_ZERO_ERROR;
481    MessageFormat *mf = new MessageFormat("", status);
482    failure(status, "new MessageFormat");
483
484    for (int i = 0; i < 3; i++) {
485        UnicodeString pattern = patterns[i];
486        mf->applyPattern(pattern, status);
487        failure(status, "mf->applyPattern", TRUE);
488
489        //try {
490        int32_t count = 0;
491        ParsePosition pp(0);
492        Formattable *array = mf->parse(UnicodeString(""), pp, count);
493            logln("pattern: \"" + pattern + "\"");
494            log(" parsedObjects: ");
495            if (array != NULL) {
496                log("{");
497                for (int j = 0; j < count; j++) {
498                    //if (array[j] != null)
499                    UnicodeString dummy;
500                    dataerrln("\"" + array[j].getString(dummy) + "\"");
501                    //else
502                     //   log("null");
503                    if (j < count- 1)
504                        log(",");
505                }
506                log("}") ;
507                delete[] array;
508            } else {
509                log("null");
510            }
511            logln("");
512        /*} catch (Exception e) {
513            errln("pattern: \"" + pattern + "\"");
514            errln("  Exception: " + e.getMessage());
515        }*/
516    }
517
518    delete mf;
519}
520/* @bug 4114739 (FIX and add javadoc)
521 * MessageFormat.format has undocumented behavior about empty format objects.
522 */
523
524// {sfb} doesn't apply in C++?
525void MessageFormatRegressionTest::Test4114739()
526{
527
528    UErrorCode status = U_ZERO_ERROR;
529    MessageFormat *mf = new MessageFormat("<{0}>", status);
530    failure(status, "new MessageFormat");
531
532    Formattable *objs1 = NULL;
533    //Formattable objs2 [] = {};
534    //Formattable *objs3 [] = {NULL};
535    //try {
536    UnicodeString pat;
537    UnicodeString res;
538        logln("pattern: \"" + mf->toPattern(pat) + "\"");
539        log("format(null) : ");
540        FieldPosition pos(FieldPosition::DONT_CARE);
541        logln("\"" + mf->format(objs1, 0, res, pos, status) + "\"");
542        failure(status, "mf->format");
543        /*log("format({})   : ");
544        logln("\"" + mf->format(objs2, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\"");
545        failure(status, "mf->format");
546        log("format({null}) :");
547        logln("\"" + mf->format(objs3, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\"");
548        failure(status, "mf->format");*/
549    /*} catch (Exception e) {
550        errln("Exception thrown for null argument tests.");
551    }*/
552
553    delete mf;
554}
555
556/* @bug 4113018
557 * MessageFormat.applyPattern works wrong with illegal patterns.
558 */
559void MessageFormatRegressionTest::Test4113018()
560{
561    UnicodeString originalPattern("initial pattern");
562    UErrorCode status = U_ZERO_ERROR;
563    MessageFormat *mf = new MessageFormat(originalPattern, status);
564    failure(status, "new messageFormat");
565    UnicodeString illegalPattern("format: {0, xxxYYY}");
566    UnicodeString pat;
567    logln("pattern before: \"" + mf->toPattern(pat) + "\"");
568    logln("illegal pattern: \"" + illegalPattern + "\"");
569    //try {
570        mf->applyPattern(illegalPattern, status);
571        if( ! U_FAILURE(status))
572            errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);
573    /*} catch (IllegalArgumentException e) {
574        if (!originalPattern.equals(mf.toPattern()))
575            errln("pattern after: \"" + mf.toPattern() + "\"");
576    }*/
577    delete mf;
578}
579
580/* @bug 4106661
581 * ChoiceFormat is silent about the pattern usage in javadoc.
582 */
583void MessageFormatRegressionTest::Test4106661()
584{
585    UErrorCode status = U_ZERO_ERROR;
586    ChoiceFormat *fmt = new ChoiceFormat(
587      "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.", status);
588    failure(status, "new ChoiceFormat");
589    UnicodeString pat;
590    logln("Formatter Pattern : " + fmt->toPattern(pat));
591
592    FieldPosition bogus(FieldPosition::DONT_CARE);
593    UnicodeString str;
594
595    // Will this work for -inf?
596    logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status));
597    failure(status, "fmt->format");
598    str.remove();
599    logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
600    failure(status, "fmt->format");
601    str.remove();
602    logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
603    failure(status, "fmt->format");
604    str.remove();
605    logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status));
606    failure(status, "fmt->format");
607    str.remove();
608    logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status));
609    failure(status, "fmt->format");
610    str.remove();
611    logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status));
612    failure(status, "fmt->format");
613    str.remove();
614    logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status));
615    failure(status, "fmt->format");
616    str.remove();
617    logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status));
618    failure(status, "fmt->format");
619    str.remove();
620    logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status));
621    failure(status, "fmt->format");
622    str.remove();
623    logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status));
624    failure(status, "fmt->format");
625    str.remove();
626    logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status));
627    failure(status, "fmt->format");
628
629    delete fmt;
630}
631
632/* @bug 4094906
633 * ChoiceFormat should accept \u221E as eq. to INF.
634 */
635void MessageFormatRegressionTest::Test4094906()
636{
637    UErrorCode status = U_ZERO_ERROR;
638    UnicodeString pattern("-");
639    pattern += (UChar) 0x221E;
640    pattern += "<are negative|0<are no or fraction|1#is one|1<is 1+|";
641    pattern += (UChar) 0x221E;
642    pattern += "<are many.";
643
644    ChoiceFormat *fmt = new ChoiceFormat(pattern, status);
645    failure(status, "new ChoiceFormat");
646    UnicodeString pat;
647    if (fmt->toPattern(pat) != pattern) {
648        errln( (UnicodeString) "Formatter Pattern : " + pat);
649        errln( (UnicodeString) "Expected Pattern  : " + pattern);
650    }
651    FieldPosition bogus(FieldPosition::DONT_CARE);
652    UnicodeString str;
653
654    // Will this work for -inf?
655    logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status));
656    failure(status, "fmt->format");
657    str.remove();
658    logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
659    failure(status, "fmt->format");
660    str.remove();
661    logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
662    failure(status, "fmt->format");
663    str.remove();
664    logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status));
665    failure(status, "fmt->format");
666    str.remove();
667    logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status));
668    failure(status, "fmt->format");
669    str.remove();
670    logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status));
671    failure(status, "fmt->format");
672    str.remove();
673    logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status));
674    failure(status, "fmt->format");
675    str.remove();
676    logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status));
677    failure(status, "fmt->format");
678    str.remove();
679    logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status));
680    failure(status, "fmt->format");
681    str.remove();
682    logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status));
683    failure(status, "fmt->format");
684    str.remove();
685    logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status));
686    failure(status, "fmt->format");
687
688    delete fmt;
689}
690
691/* @bug 4118592
692 * MessageFormat.parse fails with ChoiceFormat.
693 */
694void MessageFormatRegressionTest::Test4118592()
695{
696    UErrorCode status = U_ZERO_ERROR;
697    MessageFormat *mf = new MessageFormat("", status);
698    failure(status, "new messageFormat");
699    UnicodeString pattern("{0,choice,1#YES|2#NO}");
700    UnicodeString prefix("");
701    Formattable *objs = 0;
702
703    for (int i = 0; i < 5; i++) {
704        UnicodeString formatted;
705        formatted = prefix + "YES";
706        mf->applyPattern(prefix + pattern, status);
707        failure(status, "mf->applyPattern");
708        prefix += "x";
709        //Object[] objs = mf.parse(formatted, new ParsePosition(0));
710        int32_t count = 0;
711        ParsePosition pp(0);
712        objs = mf->parse(formatted, pp, count);
713        UnicodeString pat;
714        logln(UnicodeString("") + i + ". pattern :\"" + mf->toPattern(pat) + "\"");
715        log(" \"" + formatted + "\" parsed as ");
716        if (objs == NULL)
717            logln("  null");
718        else {
719            UnicodeString temp;
720            if(objs[0].getType() == Formattable::kString)
721                logln((UnicodeString)"  " + objs[0].getString(temp));
722            else
723                logln((UnicodeString)"  " + (objs[0].getType() == Formattable::kLong ? objs[0].getLong() : objs[0].getDouble()));
724            delete[] objs;
725
726        }
727    }
728
729    delete mf;
730}
731/* @bug 4118594
732 * MessageFormat.parse fails for some patterns.
733 */
734void MessageFormatRegressionTest::Test4118594()
735{
736    UErrorCode status = U_ZERO_ERROR;
737    const UBool possibleDataError = TRUE;
738    MessageFormat *mf = new MessageFormat("{0}, {0}, {0}", status);
739    failure(status, "new MessageFormat");
740    UnicodeString forParsing("x, y, z");
741    //Object[] objs = mf.parse(forParsing, new ParsePosition(0));
742    int32_t count = 0;
743    ParsePosition pp(0);
744    Formattable *objs = mf->parse(forParsing, pp, count);
745    UnicodeString pat;
746    logln("pattern: \"" + mf->toPattern(pat) + "\"");
747    logln("text for parsing: \"" + forParsing + "\"");
748    UnicodeString str;
749    if (objs[0].getString(str) != "z")
750        errln("argument0: \"" + objs[0].getString(str) + "\"");
751    mf->applyPattern("{0,number,#.##}, {0,number,#.#}", status);
752    failure(status, "mf->applyPattern", possibleDataError);
753    //Object[] oldobjs = {new Double(3.1415)};
754    Formattable oldobjs [] = {Formattable(3.1415)};
755    UnicodeString result;
756    FieldPosition pos(FieldPosition::DONT_CARE);
757    result = mf->format( oldobjs, 1, result, pos, status );
758    failure(status, "mf->format", possibleDataError);
759    pat.remove();
760    logln("pattern: \"" + mf->toPattern(pat) + "\"");
761    logln("text for parsing: \"" + result + "\"");
762    // result now equals "3.14, 3.1"
763    if (result != "3.14, 3.1")
764        dataerrln("result = " + result + " - " + u_errorName(status));
765    //Object[] newobjs = mf.parse(result, new ParsePosition(0));
766    int32_t count1 = 0;
767    pp.setIndex(0);
768    Formattable *newobjs = mf->parse(result, pp, count1);
769    // newobjs now equals {new Double(3.1)}
770    if (newobjs == NULL) {
771        dataerrln("Error calling MessageFormat::parse");
772    } else {
773        if (newobjs[0].getDouble() != 3.1)
774            errln( UnicodeString("newobjs[0] = ") + newobjs[0].getDouble());
775    }
776
777    delete [] objs;
778    delete [] newobjs;
779    delete mf;
780}
781/* @bug 4105380
782 * When using ChoiceFormat, MessageFormat is not good for I18n.
783 */
784void MessageFormatRegressionTest::Test4105380()
785{
786    UnicodeString patternText1("The disk \"{1}\" contains {0}.");
787    UnicodeString patternText2("There are {0} on the disk \"{1}\"");
788    UErrorCode status = U_ZERO_ERROR;
789    const UBool possibleDataError = TRUE;
790    MessageFormat *form1 = new MessageFormat(patternText1, status);
791    failure(status, "new MessageFormat");
792    MessageFormat *form2 = new MessageFormat(patternText2, status);
793    failure(status, "new MessageFormat");
794    double filelimits [] = {0,1,2};
795    UnicodeString filepart [] = {
796        (UnicodeString)"no files",
797            (UnicodeString)"one file",
798            (UnicodeString)"{0,number} files"
799    };
800    ChoiceFormat *fileform = new ChoiceFormat(filelimits, filepart, 3);
801    form1->setFormat(1, *fileform);
802    form2->setFormat(0, *fileform);
803    //Object[] testArgs = {new Long(12373), "MyDisk"};
804    Formattable testArgs [] = {
805        Formattable((int32_t)12373),
806            Formattable((UnicodeString)"MyDisk")
807    };
808
809    FieldPosition bogus(FieldPosition::DONT_CARE);
810
811    UnicodeString result;
812    logln(form1->format(testArgs, 2, result, bogus, status));
813    failure(status, "form1->format", possibleDataError);
814    result.remove();
815    logln(form2->format(testArgs, 2, result, bogus, status));
816    failure(status, "form1->format", possibleDataError);
817
818    delete form1;
819    delete form2;
820    delete fileform;
821}
822/* @bug 4120552
823 * MessageFormat.parse incorrectly sets errorIndex.
824 */
825void MessageFormatRegressionTest::Test4120552()
826{
827    UErrorCode status = U_ZERO_ERROR;
828    MessageFormat *mf = new MessageFormat("pattern", status);
829    failure(status, "new MessageFormat");
830    UnicodeString texts[] = {
831        (UnicodeString)"pattern",
832            (UnicodeString)"pat",
833            (UnicodeString)"1234"
834    };
835    UnicodeString pat;
836    logln("pattern: \"" + mf->toPattern(pat) + "\"");
837    for (int i = 0; i < 3; i++) {
838        ParsePosition pp(0);
839        //Object[] objs = mf.parse(texts[i], pp);
840        int32_t count = 0;
841        Formattable *objs = mf->parse(texts[i], pp, count);
842        log("  text for parsing: \"" + texts[i] + "\"");
843        if (objs == NULL) {
844            logln("  (incorrectly formatted string)");
845            if (pp.getErrorIndex() == -1)
846                errln(UnicodeString("Incorrect error index: ") + pp.getErrorIndex());
847        } else {
848            logln("  (correctly formatted string)");
849            delete[] objs;
850        }
851    }
852    delete mf;
853}
854
855/**
856 * @bug 4142938
857 * MessageFormat handles single quotes in pattern wrong.
858 * This is actually a problem in ChoiceFormat; it doesn't
859 * understand single quotes.
860 */
861void MessageFormatRegressionTest::Test4142938()
862{
863    UnicodeString pat = CharsToUnicodeString("''Vous'' {0,choice,0#n''|1#}avez s\\u00E9lectionn\\u00E9 "
864        "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} "
865        "personnel{0,choice,0#s|1#|2#s}.");
866    UErrorCode status = U_ZERO_ERROR;
867    MessageFormat *mf = new MessageFormat(pat, status);
868    failure(status, "new MessageFormat");
869
870    UnicodeString PREFIX [] = {
871        CharsToUnicodeString("'Vous' n'avez s\\u00E9lectionn\\u00E9 aucun clients personnels."),
872        CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 "),
873        CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 ")
874    };
875    UnicodeString SUFFIX [] = {
876        UnicodeString(),
877        UNICODE_STRING(" client personnel.", 18),
878        UNICODE_STRING(" clients personnels.", 20)
879    };
880
881    for (int i=0; i<3; i++) {
882        UnicodeString out;
883        //out = mf->format(new Object[]{new Integer(i)});
884        Formattable objs [] = {
885            Formattable((int32_t)i)
886        };
887        FieldPosition pos(FieldPosition::DONT_CARE);
888        out = mf->format(objs, 1, out, pos, status);
889        if (!failure(status, "mf->format", TRUE)) {
890            if (SUFFIX[i] == "") {
891                if (out != PREFIX[i])
892                    errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");
893            }
894            else {
895                if (!out.startsWith(PREFIX[i]) ||
896                    !out.endsWith(SUFFIX[i]))
897                    errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +
898                          SUFFIX[i] + "\"");
899            }
900        }
901    }
902
903    delete mf;
904}
905
906/**
907 * @bug 4142938
908 * Test the applyPattern and toPattern handling of single quotes
909 * by ChoiceFormat.  (This is in here because this was a bug reported
910 * against MessageFormat.)  The single quote is used to quote the
911 * pattern characters '|', '#', '<', and '\u2264'.  Two quotes in a row
912 * is a quote literal.
913 */
914void MessageFormatRegressionTest::TestChoicePatternQuote()
915{
916    // ICU 4.8 ChoiceFormat (like PluralFormat & SelectFormat)
917    // returns the chosen string unmodified, so that it is usable in a MessageFormat.
918    // We modified the test strings accordingly.
919    // Note: Without further formatting/trimming/etc., it is not possible
920    // to get a single apostrophe as the last character of a non-final choice sub-message
921    // because the single apostrophe before the pipe '|' would start quoted text.
922    // Normally, ChoiceFormat is used inside a MessageFormat, where a double apostrophe
923    // can be used in that case and will be formatted as a single one.
924    // (Better: Use a "real" apostrophe, U+2019.)
925    UnicodeString DATA [] = {
926        // Pattern                  0 value           1 value
927        // {sfb} hacked - changed \u2264 to = (copied from Character Map)
928        "0#can't|1#can",            "can't",          "can",
929        "0#pound(#)='#''|1#xyz",    "pound(#)='#''",  "xyz",
930        "0#1<2 '| 1=1'|1#'",        "1<2 '| 1=1'",    "'",
931    };
932    for (int i=0; i<9; i+=3) {
933        //try {
934            UErrorCode status = U_ZERO_ERROR;
935            ChoiceFormat *cf = new ChoiceFormat(DATA[i], status);
936            failure(status, "new ChoiceFormat");
937            for (int j=0; j<=1; ++j) {
938                UnicodeString out;
939                FieldPosition pos(FieldPosition::DONT_CARE);
940                out = cf->format((double)j, out, pos);
941                if (out != DATA[i+1+j])
942                    errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +
943                          out + "; want \"" + DATA[i+1+j] + "\"");
944            }
945            UnicodeString pat;
946            pat = cf->toPattern(pat);
947            UnicodeString pat2;
948            ChoiceFormat *cf2 = new ChoiceFormat(pat, status);
949            pat2 = cf2->toPattern(pat2);
950            if (pat != pat2)
951                errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + "\"");
952            else
953                logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + "\"");
954        /*}
955        catch (IllegalArgumentException e) {
956            errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e);
957        }*/
958
959        delete cf;
960        delete cf2;
961    }
962}
963
964/**
965 * @bug 4112104
966 * MessageFormat.equals(null) throws a NullPointerException.  The JLS states
967 * that it should return false.
968 */
969void MessageFormatRegressionTest::Test4112104()
970{
971    UErrorCode status = U_ZERO_ERROR;
972    MessageFormat *format = new MessageFormat("", status);
973    failure(status, "new MessageFormat");
974    //try {
975        // This should NOT throw an exception
976        if (format == NULL) {
977            // It also should return false
978            errln("MessageFormat.equals(null) returns false");
979        }
980    /*}
981    catch (NullPointerException e) {
982        errln("MessageFormat.equals(null) throws " + e);
983    }*/
984    delete format;
985}
986
987void MessageFormatRegressionTest::TestAPI() {
988    UErrorCode status = U_ZERO_ERROR;
989    MessageFormat *format = new MessageFormat("", status);
990    failure(status, "new MessageFormat");
991
992    // Test adoptFormat
993    MessageFormat *fmt = new MessageFormat("",status);
994    format->adoptFormat("some_name",fmt,status);  // Must at least pass a valid identifier.
995    failure(status, "adoptFormat");
996
997    // Test getFormat
998    format->setFormat((int32_t)0,*fmt);
999    format->getFormat("some_other_name",status);  // Must at least pass a valid identifier.
1000    failure(status, "getFormat");
1001    delete format;
1002}
1003
1004#endif /* #if !UCONFIG_NO_FORMATTING */
1005