1 /*
2  *******************************************************************************
3  * Copyright (C) 2004-2009, International Business Machines Corporation and         *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 
8 #include "unicode/utypes.h"
9 
10 #if !UCONFIG_NO_FORMATTING
11 
12 #include "itrbnfp.h"
13 
14 #include "unicode/umachine.h"
15 
16 #include "unicode/tblcoll.h"
17 #include "unicode/coleitr.h"
18 #include "unicode/ures.h"
19 #include "unicode/ustring.h"
20 #include "unicode/decimfmt.h"
21 
22 #include <string.h>
23 
24 // current macro not in icu1.8.1
25 #define TESTCASE(id,test)             \
26     case id:                          \
27         name = #test;                 \
28         if (exec) {                   \
29             logln(#test "---");       \
30             logln();                  \
31             test();                   \
32         }                             \
33         break
34 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)35 void IntlTestRBNFParse::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
36 {
37     if (exec) logln("TestSuite RuleBasedNumberFormatParse");
38     switch (index) {
39 #if U_HAVE_RBNF
40         TESTCASE(0, TestParse);
41 #else
42         TESTCASE(0, TestRBNFParseDisabled);
43 #endif
44     default:
45         name = "";
46         break;
47     }
48 }
49 
50 #if U_HAVE_RBNF
51 
52 void
TestParse()53 IntlTestRBNFParse::TestParse() {
54   // Try various rule parsing errors.  Shouldn't crash.
55 
56   logln("RBNF Parse test starting");
57 
58   // these rules make no sense but behave rationally
59   const char* okrules[] = {
60     "",
61     "random text",
62     "%foo:bar",
63     "%foo: bar",
64     "0:",
65     "0::",
66     ";",
67     ";;",
68     "%%foo:;",
69     ":",
70     "::",
71     ":1",
72     ":;",
73     ":;:;",
74     "-",
75     "-1",
76     "-:",
77     ".",
78     ".1",
79     "[",
80     "]",
81     "[]",
82     "[foo]",
83     "[[]",
84     "[]]",
85     "[[]]",
86     "[][]",
87     "<",
88     "<<",
89     "<<<",
90     "10:;9:;",
91     ">",
92     ">>",
93     ">>>",
94     "=",
95     "==",
96     "===",
97     "=foo=",
98 
99     NULL,
100   };
101 
102   // these rules would throw exceptions when formatting, if we could throw exceptions
103   const char* exceptrules[] = {
104     "10:", // formatting any value with a one's digit will fail
105     "11: << x", // formating a multiple of 10 causes rollback rule to fail
106     "%%foo: 0 foo; 10: =%%bar=; %%bar: 0: bar; 10: =%%foo=;",
107 
108     NULL,
109   };
110 
111   // none of these rules should crash the formatter
112   const char** allrules[] = {
113     okrules,
114     exceptrules,
115     NULL,
116   };
117 
118   for (int j = 0; allrules[j]; ++j) {
119       const char** rules = allrules[j];
120       for (int i = 0; rules[i]; ++i) {
121           const char* rule = rules[i];
122           logln("rule[%d] \"%s\"", i, rule);
123           UErrorCode status = U_ZERO_ERROR;
124           UParseError perr;
125           RuleBasedNumberFormat* formatter = new RuleBasedNumberFormat(rule, Locale::getUS(), perr, status);
126 
127           if (U_SUCCESS(status)) {
128               // format some values
129 
130               testfmt(formatter, 20, status);
131               testfmt(formatter, 1.23, status);
132               testfmt(formatter, -123, status);
133               testfmt(formatter, .123, status);
134               testfmt(formatter, 123, status);
135 
136           } else if (status == U_PARSE_ERROR) {
137               logln("perror line: %x offset: %x context: %s|%s", perr.line, perr.offset, perr.preContext, perr.postContext);
138           }
139 
140           delete formatter;
141       }
142   }
143 }
144 
145 void
testfmt(RuleBasedNumberFormat * formatter,double val,UErrorCode & status)146 IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status) {
147     UnicodeString us;
148     formatter->format((const Formattable)val, us, status);
149     if (U_SUCCESS(status)) {
150         us.insert(0, (UChar)'"');
151         us.append((UChar)'"');
152         logln(us);
153     } else {
154         logln("error: could not format %g, returned status: %d", val, status);
155     }
156 }
157 
158 void
testfmt(RuleBasedNumberFormat * formatter,int val,UErrorCode & status)159 IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status) {
160     UnicodeString us;
161     formatter->format((const Formattable)(int32_t)val, us, status);
162     if (U_SUCCESS(status)) {
163         us.insert(0, (UChar)'"');
164         us.append((UChar)'"');
165         logln(us);
166     } else {
167         logln("error: could not format %d, returned status: %d", val, status);
168     }
169 }
170 
171 
172 /* U_HAVE_RBNF */
173 #else
174 
175 void
TestRBNFParseDisabled()176 IntlTestRBNF::TestRBNFParseDisabled() {
177     errln("*** RBNF currently disabled on this platform ***\n");
178 }
179 
180 /* U_HAVE_RBNF */
181 #endif
182 
183 #endif /* #if !UCONFIG_NO_FORMATTING */
184