// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
* Copyright (C) 2004-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "itrbnfp.h"
#include "unicode/umachine.h"
#include "unicode/tblcoll.h"
#include "unicode/coleitr.h"
#include "unicode/ures.h"
#include "unicode/ustring.h"
#include "unicode/decimfmt.h"
#include <string.h>
// current macro not in icu1.8.1
#define TESTCASE(id,test) \
case id: \
name = #test; \
if (exec) { \
logln(#test "---"); \
logln(); \
test(); \
} \
break
void IntlTestRBNFParse::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
{
if (exec) logln("TestSuite RuleBasedNumberFormatParse");
switch (index) {
#if U_HAVE_RBNF
TESTCASE(0, TestParse);
#else
TESTCASE(0, TestRBNFParseDisabled);
#endif
default:
name = "";
break;
}
}
#if U_HAVE_RBNF
void
IntlTestRBNFParse::TestParse() {
// Try various rule parsing errors. Shouldn't crash.
logln("RBNF Parse test starting");
// these rules make no sense but behave rationally
const char* okrules[] = {
"",
"random text",
"%foo:bar",
"%foo: bar",
"0:",
"0::",
";",
";;",
"%%foo:;",
":",
"::",
":1",
":;",
":;:;",
"-",
"-1",
"-:",
".",
".1",
"[",
"]",
"[]",
"[foo]",
"[[]",
"[]]",
"[[]]",
"[][]",
"<",
"<<",
"<<<",
"10:;9:;",
">",
">>",
">>>",
"=",
"==",
"===",
"=foo=",
NULL,
};
// these rules would throw exceptions when formatting, if we could throw exceptions
const char* exceptrules[] = {
"10:", // formatting any value with a one's digit will fail
"11: << x", // formating a multiple of 10 causes rollback rule to fail
"%%foo: 0 foo; 10: =%%bar=; %%bar: 0: bar; 10: =%%foo=;",
NULL,
};
// none of these rules should crash the formatter
const char** allrules[] = {
okrules,
exceptrules,
NULL,
};
for (int j = 0; allrules[j]; ++j) {
const char** rules = allrules[j];
for (int i = 0; rules[i]; ++i) {
const char* rule = rules[i];
logln("rule[%d] \"%s\"", i, rule);
UErrorCode status = U_ZERO_ERROR;
UParseError perr;
RuleBasedNumberFormat* formatter = new RuleBasedNumberFormat(rule, Locale::getUS(), perr, status);
if (U_SUCCESS(status)) {
// format some values
testfmt(formatter, 20, status);
testfmt(formatter, 1.23, status);
testfmt(formatter, -123, status);
testfmt(formatter, .123, status);
testfmt(formatter, 123, status);
} else if (status == U_PARSE_ERROR) {
logln("perror line: %x offset: %x context: %s|%s", perr.line, perr.offset, perr.preContext, perr.postContext);
}
delete formatter;
}
}
}
void
IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status) {
UnicodeString us;
formatter->format((const Formattable)val, us, status);
if (U_SUCCESS(status)) {
us.insert(0, (UChar)'"');
us.append((UChar)'"');
logln(us);
} else {
logln("error: could not format %g, returned status: %d", val, status);
}
}
void
IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status) {
UnicodeString us;
formatter->format((const Formattable)(int32_t)val, us, status);
if (U_SUCCESS(status)) {
us.insert(0, (UChar)'"');
us.append((UChar)'"');
logln(us);
} else {
logln("error: could not format %d, returned status: %d", val, status);
}
}
/* U_HAVE_RBNF */
#else
void
IntlTestRBNF::TestRBNFParseDisabled() {
errln("*** RBNF currently disabled on this platform ***\n");
}
/* U_HAVE_RBNF */
#endif
#endif /* #if !UCONFIG_NO_FORMATTING */