]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/plurults.cpp
ICU-511.34.tar.gz
[apple/icu.git] / icuSources / test / intltest / plurults.cpp
CommitLineData
46f4442e
A
1/*
2*******************************************************************************
51004dcb 3* Copyright (C) 2007-2012, International Business Machines Corporation and
46f4442e
A
4* others. All Rights Reserved.
5********************************************************************************
6
7* File PLURRULTS.cpp
8*
9********************************************************************************
10*/
11
12#include "unicode/utypes.h"
13
14#if !UCONFIG_NO_FORMATTING
15
4388f060 16#include <stdlib.h> // for strtod
46f4442e 17#include "plurults.h"
51004dcb 18#include "unicode/localpointer.h"
46f4442e
A
19#include "unicode/plurrule.h"
20
4388f060 21#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof(array[0]))
46f4442e
A
22
23void setupResult(const int32_t testSource[], char result[], int32_t* max);
51004dcb
A
24UBool checkEqual(const PluralRules &test, char *result, int32_t max);
25UBool testEquality(const PluralRules &test);
46f4442e
A
26
27// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
28// try to test the full functionality. It just calls each function in the class and
29// verifies that it works on a basic level.
30
31void PluralRulesTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
32{
33 if (exec) logln("TestSuite PluralRulesAPI");
51004dcb
A
34 TESTCASE_AUTO_BEGIN;
35 TESTCASE_AUTO(testAPI);
36 TESTCASE_AUTO(testGetUniqueKeywordValue);
37 TESTCASE_AUTO(testGetSamples);
38 TESTCASE_AUTO(testWithin);
39 TESTCASE_AUTO(testGetAllKeywordValues);
40 TESTCASE_AUTO(testOrdinal);
41 TESTCASE_AUTO_END;
46f4442e
A
42}
43
44#define PLURAL_TEST_NUM 18
45/**
46 * Test various generic API methods of PluralRules for API coverage.
47 */
48void PluralRulesTest::testAPI(/*char *par*/)
49{
50 UnicodeString pluralTestData[PLURAL_TEST_NUM] = {
51 UNICODE_STRING_SIMPLE("a: n is 1"),
52 UNICODE_STRING_SIMPLE("a: n mod 10 is 2"),
53 UNICODE_STRING_SIMPLE("a: n is not 1"),
54 UNICODE_STRING_SIMPLE("a: n mod 3 is not 1"),
55 UNICODE_STRING_SIMPLE("a: n in 2..5"),
56 UNICODE_STRING_SIMPLE("a: n within 2..5"),
57 UNICODE_STRING_SIMPLE("a: n not in 2..5"),
58 UNICODE_STRING_SIMPLE("a: n not within 2..5"),
59 UNICODE_STRING_SIMPLE("a: n mod 10 in 2..5"),
60 UNICODE_STRING_SIMPLE("a: n mod 10 within 2..5"),
61 UNICODE_STRING_SIMPLE("a: n mod 10 is 2 and n is not 12"),
62 UNICODE_STRING_SIMPLE("a: n mod 10 in 2..3 or n mod 10 is 5"),
63 UNICODE_STRING_SIMPLE("a: n mod 10 within 2..3 or n mod 10 is 5"),
64 UNICODE_STRING_SIMPLE("a: n is 1 or n is 4 or n is 23"),
65 UNICODE_STRING_SIMPLE("a: n mod 2 is 1 and n is not 3 and n in 1..11"),
66 UNICODE_STRING_SIMPLE("a: n mod 2 is 1 and n is not 3 and n within 1..11"),
67 UNICODE_STRING_SIMPLE("a: n mod 2 is 1 or n mod 5 is 1 and n is not 6"),
68 "",
69 };
70 static const int32_t pluralTestResult[PLURAL_TEST_NUM][30] = {
71 {1, 0},
72 {2,12,22, 0},
73 {0,2,3,4,5,0},
74 {0,2,3,5,6,8,9,0},
75 {2,3,4,5,0},
76 {2,3,4,5,0},
77 {0,1,6,7,8, 0},
78 {0,1,6,7,8, 0},
79 {2,3,4,5,12,13,14,15,22,23,24,25,0},
80 {2,3,4,5,12,13,14,15,22,23,24,25,0},
81 {2,22,32,42,0},
82 {2,3,5,12,13,15,22,23,25,0},
83 {2,3,5,12,13,15,22,23,25,0},
84 {1,4,23,0},
85 {1,5,7,9,11,0},
86 {1,5,7,9,11,0},
87 {1,3,5,7,9,11,13,15,16,0},
88 };
89 UErrorCode status = U_ZERO_ERROR;
90
91 // ======= Test constructors
92 logln("Testing PluralRules constructors");
4388f060
A
93
94
46f4442e 95 logln("\n start default locale test case ..\n");
4388f060
A
96
97 PluralRules defRule(status);
51004dcb
A
98 LocalPointer<PluralRules> test(new PluralRules(status));
99 LocalPointer<PluralRules> newEnPlural(test->forLocale(Locale::getEnglish(), status));
46f4442e
A
100 if(U_FAILURE(status)) {
101 dataerrln("ERROR: Could not create PluralRules (default) - exitting");
46f4442e
A
102 return;
103 }
4388f060 104
46f4442e 105 // ======= Test clone, assignment operator && == operator.
51004dcb 106 LocalPointer<PluralRules> dupRule(defRule.clone());
4388f060
A
107 if (dupRule==NULL) {
108 errln("ERROR: clone plural rules test failed!");
4388f060
A
109 return;
110 } else {
46f4442e
A
111 if ( *dupRule != defRule ) {
112 errln("ERROR: clone plural rules test failed!");
113 }
114 }
115 *dupRule = *newEnPlural;
116 if (dupRule!=NULL) {
117 if ( *dupRule != *newEnPlural ) {
118 errln("ERROR: clone plural rules test failed!");
119 }
46f4442e
A
120 }
121
4388f060 122 // ======= Test empty plural rules
46f4442e 123 logln("Testing Simple PluralRules");
4388f060 124
51004dcb 125 LocalPointer<PluralRules> empRule(test->createRules(UNICODE_STRING_SIMPLE("a:n"), status));
46f4442e
A
126 UnicodeString key;
127 for (int32_t i=0; i<10; ++i) {
128 key = empRule->select(i);
129 if ( key.charAt(0)!= 0x61 ) { // 'a'
130 errln("ERROR: empty plural rules test failed! - exitting");
131 }
132 }
4388f060
A
133
134 // ======= Test simple plural rules
46f4442e 135 logln("Testing Simple PluralRules");
4388f060 136
46f4442e
A
137 char result[100];
138 int32_t max;
4388f060 139
46f4442e 140 for (int32_t i=0; i<PLURAL_TEST_NUM-1; ++i) {
51004dcb 141 LocalPointer<PluralRules> newRules(test->createRules(pluralTestData[i], status));
46f4442e 142 setupResult(pluralTestResult[i], result, &max);
51004dcb 143 if ( !checkEqual(*newRules, result, max) ) {
46f4442e 144 errln("ERROR: simple plural rules failed! - exitting");
46f4442e
A
145 return;
146 }
46f4442e 147 }
46f4442e 148
4388f060 149 // ======= Test complex plural rules
46f4442e 150 logln("Testing Complex PluralRules");
4388f060 151 // TODO: the complex test data is hard coded. It's better to implement
46f4442e
A
152 // a parser to parse the test data.
153 UnicodeString complexRule = UNICODE_STRING_SIMPLE("a: n in 2..5; b: n in 5..8; c: n mod 2 is 1");
4388f060
A
154 UnicodeString complexRule2 = UNICODE_STRING_SIMPLE("a: n within 2..5; b: n within 5..8; c: n mod 2 is 1");
155 char cRuleResult[] =
46f4442e
A
156 {
157 0x6F, // 'o'
158 0x63, // 'c'
159 0x61, // 'a'
160 0x61, // 'a'
161 0x61, // 'a'
162 0x61, // 'a'
163 0x62, // 'b'
164 0x62, // 'b'
165 0x62, // 'b'
166 0x63, // 'c'
167 0x6F, // 'o'
168 0x63 // 'c'
169 };
51004dcb
A
170 LocalPointer<PluralRules> newRules(test->createRules(complexRule, status));
171 if ( !checkEqual(*newRules, cRuleResult, 12) ) {
46f4442e 172 errln("ERROR: complex plural rules failed! - exitting");
46f4442e 173 return;
46f4442e 174 }
51004dcb
A
175 newRules.adoptInstead(test->createRules(complexRule2, status));
176 if ( !checkEqual(*newRules, cRuleResult, 12) ) {
46f4442e 177 errln("ERROR: complex plural rules failed! - exitting");
46f4442e 178 return;
46f4442e 179 }
4388f060 180
46f4442e
A
181 // ======= Test decimal fractions plural rules
182 UnicodeString decimalRule= UNICODE_STRING_SIMPLE("a: n not in 0..100;");
183 UnicodeString KEYWORD_A = UNICODE_STRING_SIMPLE("a");
184 status = U_ZERO_ERROR;
51004dcb 185 newRules.adoptInstead(test->createRules(decimalRule, status));
46f4442e
A
186 if (U_FAILURE(status)) {
187 dataerrln("ERROR: Could not create PluralRules for testing fractions - exitting");
46f4442e
A
188 return;
189 }
190 double fData[10] = {-100, -1, -0.0, 0, 0.1, 1, 1.999, 2.0, 100, 100.001 };
4388f060 191 UBool isKeywordA[10] = {
46f4442e
A
192 TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE };
193 for (int32_t i=0; i<10; i++) {
194 if ((newRules->select(fData[i])== KEYWORD_A) != isKeywordA[i]) {
195 errln("ERROR: plural rules for decimal fractions test failed!");
196 }
197 }
4388f060 198
46f4442e
A
199 // ======= Test Equality
200 logln("Testing Equality of PluralRules");
4388f060 201
51004dcb 202 if ( !testEquality(*test) ) {
46f4442e 203 errln("ERROR: complex plural rules failed! - exitting");
46f4442e
A
204 return;
205 }
206
4388f060 207
46f4442e
A
208 // ======= Test getStaticClassID()
209 logln("Testing getStaticClassID()");
4388f060 210
46f4442e
A
211 if(test->getDynamicClassID() != PluralRules::getStaticClassID()) {
212 errln("ERROR: getDynamicClassID() didn't return the expected value");
213 }
214 // ====== Test fallback to parent locale
51004dcb
A
215 LocalPointer<PluralRules> en_UK(test->forLocale(Locale::getUK(), status));
216 LocalPointer<PluralRules> en(test->forLocale(Locale::getEnglish(), status));
217 if (en_UK.isValid() && en.isValid()) {
46f4442e
A
218 if ( *en_UK != *en ) {
219 errln("ERROR: test locale fallback failed!");
220 }
221 }
46f4442e 222
51004dcb
A
223 LocalPointer<PluralRules> zh_Hant(test->forLocale(Locale::getTaiwan(), status));
224 LocalPointer<PluralRules> zh(test->forLocale(Locale::getChinese(), status));
225 if (zh_Hant.isValid() && zh.isValid()) {
46f4442e
A
226 if ( *zh_Hant != *zh ) {
227 errln("ERROR: test locale fallback failed!");
228 }
229 }
46f4442e
A
230}
231
232void setupResult(const int32_t testSource[], char result[], int32_t* max) {
233 int32_t i=0;
234 int32_t curIndex=0;
4388f060 235
46f4442e
A
236 do {
237 while (curIndex < testSource[i]) {
238 result[curIndex++]=0x6F; //'o' other
239 }
240 result[curIndex++]=0x61; // 'a'
4388f060 241
46f4442e
A
242 } while(testSource[++i]>0);
243 *max=curIndex;
244}
245
246
51004dcb 247UBool checkEqual(const PluralRules &test, char *result, int32_t max) {
46f4442e
A
248 UnicodeString key;
249 UBool isEqual = TRUE;
250 for (int32_t i=0; i<max; ++i) {
51004dcb 251 key= test.select(i);
46f4442e
A
252 if ( key.charAt(0)!=result[i] ) {
253 isEqual = FALSE;
254 }
255 }
256 return isEqual;
257}
258
259#define MAX_EQ_ROW 2
260#define MAX_EQ_COL 5
51004dcb 261UBool testEquality(const PluralRules &test) {
46f4442e
A
262 UnicodeString testEquRules[MAX_EQ_ROW][MAX_EQ_COL] = {
263 { UNICODE_STRING_SIMPLE("a: n in 2..3"),
4388f060 264 UNICODE_STRING_SIMPLE("a: n is 2 or n is 3"),
46f4442e
A
265 UNICODE_STRING_SIMPLE( "a:n is 3 and n in 2..5 or n is 2"),
266 "",
267 },
268 { UNICODE_STRING_SIMPLE("a: n is 12; b:n mod 10 in 2..3"),
269 UNICODE_STRING_SIMPLE("b: n mod 10 in 2..3 and n is not 12; a: n in 12..12"),
270 UNICODE_STRING_SIMPLE("b: n is 13; a: n in 12..13; b: n mod 10 is 2 or n mod 10 is 3"),
271 "",
272 }
273 };
274 UErrorCode status = U_ZERO_ERROR;
275 UnicodeString key[MAX_EQ_COL];
276 UBool ret=TRUE;
277 for (int32_t i=0; i<MAX_EQ_ROW; ++i) {
278 PluralRules* rules[MAX_EQ_COL];
4388f060 279
46f4442e
A
280 for (int32_t j=0; j<MAX_EQ_COL; ++j) {
281 rules[j]=NULL;
282 }
283 int32_t totalRules=0;
284 while((totalRules<MAX_EQ_COL) && (testEquRules[i][totalRules].length()>0) ) {
51004dcb 285 rules[totalRules]=test.createRules(testEquRules[i][totalRules], status);
46f4442e
A
286 totalRules++;
287 }
288 for (int32_t n=0; n<300 && ret ; ++n) {
289 for(int32_t j=0; j<totalRules;++j) {
290 key[j] = rules[j]->select(n);
291 }
292 for(int32_t j=0; j<totalRules-1;++j) {
293 if (key[j]!=key[j+1]) {
294 ret= FALSE;
295 break;
296 }
297 }
4388f060 298
46f4442e
A
299 }
300 for (int32_t j=0; j<MAX_EQ_COL; ++j) {
301 if (rules[j]!=NULL) {
302 delete rules[j];
303 }
304 }
305 }
4388f060 306
46f4442e
A
307 return ret;
308}
46f4442e 309
4388f060
A
310void
311PluralRulesTest::assertRuleValue(const UnicodeString& rule, double expected) {
312 assertRuleKeyValue("a:" + rule, "a", expected);
313}
314
315void
316PluralRulesTest::assertRuleKeyValue(const UnicodeString& rule,
317 const UnicodeString& key, double expected) {
318 UErrorCode status = U_ZERO_ERROR;
319 PluralRules *pr = PluralRules::createRules(rule, status);
320 double result = pr->getUniqueKeywordValue(key);
321 delete pr;
322 if (expected != result) {
323 errln("expected %g but got %g", expected, result);
324 }
325}
326
327void PluralRulesTest::testGetUniqueKeywordValue() {
328 assertRuleValue("n is 1", 1);
329 assertRuleValue("n in 2..2", 2);
330 assertRuleValue("n within 2..2", 2);
331 assertRuleValue("n in 3..4", UPLRULES_NO_UNIQUE_VALUE);
332 assertRuleValue("n within 3..4", UPLRULES_NO_UNIQUE_VALUE);
333 assertRuleValue("n is 2 or n is 2", 2);
334 assertRuleValue("n is 2 and n is 2", 2);
335 assertRuleValue("n is 2 or n is 3", UPLRULES_NO_UNIQUE_VALUE);
336 assertRuleValue("n is 2 and n is 3", UPLRULES_NO_UNIQUE_VALUE);
337 assertRuleValue("n is 2 or n in 2..3", UPLRULES_NO_UNIQUE_VALUE);
338 assertRuleValue("n is 2 and n in 2..3", 2);
339 assertRuleKeyValue("a: n is 1", "not_defined", UPLRULES_NO_UNIQUE_VALUE); // key not defined
340 assertRuleKeyValue("a: n is 1", "other", UPLRULES_NO_UNIQUE_VALUE); // key matches default rule
341}
342
343void PluralRulesTest::testGetSamples() {
344 // no get functional equivalent API in ICU4C, so just
345 // test every locale...
346 UErrorCode status = U_ZERO_ERROR;
347 int32_t numLocales;
348 const Locale* locales = Locale::getAvailableLocales(numLocales);
349
350 double values[4];
351 for (int32_t i = 0; U_SUCCESS(status) && i < numLocales; ++i) {
352 PluralRules *rules = PluralRules::forLocale(locales[i], status);
353 if (U_FAILURE(status)) {
354 break;
355 }
356 StringEnumeration *keywords = rules->getKeywords(status);
357 if (U_FAILURE(status)) {
358 delete rules;
359 break;
360 }
361 const UnicodeString* keyword;
362 while (NULL != (keyword = keywords->snext(status))) {
363 int32_t count = rules->getSamples(*keyword, values, 4, status);
364 if (U_FAILURE(status)) {
365 errln(UNICODE_STRING_SIMPLE("getSamples() failed for locale ") +
366 locales[i].getName() +
367 UNICODE_STRING_SIMPLE(", keyword ") + *keyword);
368 continue;
369 }
370 if (count == 0) {
371 errln("no samples for keyword");
372 }
373 if (count > LENGTHOF(values)) {
374 errln(UNICODE_STRING_SIMPLE("getSamples()=") + count +
375 UNICODE_STRING_SIMPLE(", too many values, for locale ") +
376 locales[i].getName() +
377 UNICODE_STRING_SIMPLE(", keyword ") + *keyword);
378 count = LENGTHOF(values);
379 }
380 for (int32_t j = 0; j < count; ++j) {
381 if (values[j] == UPLRULES_NO_UNIQUE_VALUE) {
382 errln("got 'no unique value' among values");
383 } else {
384 UnicodeString resultKeyword = rules->select(values[j]);
385 if (*keyword != resultKeyword) {
386 errln("keywords don't match");
387 }
388 }
389 }
390 }
391 delete keywords;
392 delete rules;
393 }
394}
395
396void PluralRulesTest::testWithin() {
397 // goes to show you what lack of testing will do.
398 // of course, this has been broken for two years and no one has noticed...
399 UErrorCode status = U_ZERO_ERROR;
400 PluralRules *rules = PluralRules::createRules("a: n mod 10 in 5..8", status);
401 if (!rules) {
402 errln("couldn't instantiate rules");
403 return;
404 }
405
406 UnicodeString keyword = rules->select((int32_t)26);
407 if (keyword != "a") {
408 errln("expected 'a' for 26 but didn't get it.");
409 }
410
411 keyword = rules->select(26.5);
412 if (keyword != "other") {
413 errln("expected 'other' for 26.5 but didn't get it.");
414 }
415
416 delete rules;
417}
418
419void
420PluralRulesTest::testGetAllKeywordValues() {
421 const char* data[] = {
422 "a: n in 2..5", "a: 2,3,4,5; other: null; b:",
423 "a: n not in 2..5", "a: null; other: null",
424 "a: n within 2..5", "a: null; other: null",
425 "a: n not within 2..5", "a: null; other: null",
426 "a: n in 2..5 or n within 6..8", "a: null", // ignore 'other' here on out, always null
427 "a: n in 2..5 and n within 6..8", "a:",
428 "a: n in 2..5 and n within 5..8", "a: 5",
429 "a: n within 2..5 and n within 6..8", "a:", // our sampling catches these
430 "a: n within 2..5 and n within 5..8", "a: 5", // ''
431 "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5", "a: 2,4",
432 "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5 "
433 "or n within 5..6 and n within 6..7", "a: null", // but not this...
434 "a: n mod 3 is 0", "a: null",
435 "a: n mod 3 is 0 and n within 1..2", "a:",
436 "a: n mod 3 is 0 and n within 0..5", "a: 0,3",
437 "a: n mod 3 is 0 and n within 0..6", "a: null", // similarly with mod, we don't catch...
438 "a: n mod 3 is 0 and n in 3..12", "a: 3,6,9,12",
439 NULL
440 };
441
442 for (int i = 0; data[i] != NULL; i += 2) {
443 UErrorCode status = U_ZERO_ERROR;
444 UnicodeString ruleDescription(data[i], -1, US_INV);
445 const char* result = data[i+1];
446
447 logln("[%d] %s", i >> 1, data[i]);
448
449 PluralRules *p = PluralRules::createRules(ruleDescription, status);
450 if (U_FAILURE(status)) {
451 logln("could not create rules from '%s'\n", data[i]);
452 continue;
453 }
454
455 const char* rp = result;
456 while (*rp) {
457 while (*rp == ' ') ++rp;
458 if (!rp) {
459 break;
460 }
461
462 const char* ep = rp;
463 while (*ep && *ep != ':') ++ep;
464
465 status = U_ZERO_ERROR;
466 UnicodeString keyword(rp, ep - rp, US_INV);
467 double samples[4]; // no test above should have more samples than 4
468 int32_t count = p->getAllKeywordValues(keyword, &samples[0], 4, status);
469 if (U_FAILURE(status)) {
470 errln("error getting samples for %s", rp);
471 break;
472 }
473
474 if (count > 4) {
475 errln("count > 4 for keyword %s", rp);
476 count = 4;
477 }
478
479 if (*ep) {
480 ++ep; // skip colon
481 while (*ep && *ep == ' ') ++ep; // and spaces
482 }
483
484 UBool ok = TRUE;
485 if (count == -1) {
486 if (*ep != 'n') {
487 errln("expected values for keyword %s but got -1 (%s)", rp, ep);
488 ok = FALSE;
489 }
490 } else if (*ep == 'n') {
491 errln("expected count of -1, got %d, for keyword %s (%s)", count, rp, ep);
492 ok = FALSE;
493 }
494
495 // We'll cheat a bit here. The samples happend to be in order and so are our
496 // expected values, so we'll just test in order until a failure. If the
497 // implementation changes to return samples in an arbitrary order, this test
498 // must change. There's no actual restriction on the order of the samples.
499
500 for (int j = 0; ok && j < count; ++j ) { // we've verified count < 4
501 double val = samples[j];
502 if (*ep == 0 || *ep == ';') {
503 errln("got unexpected value[%d]: %g", j, val);
504 ok = FALSE;
505 break;
506 }
507 char* xp;
508 double expectedVal = strtod(ep, &xp);
509 if (xp == ep) {
510 // internal error
511 errln("yikes!");
512 ok = FALSE;
513 break;
514 }
515 ep = xp;
516 if (expectedVal != val) {
517 errln("expected %g but got %g", expectedVal, val);
518 ok = FALSE;
519 break;
520 }
521 if (*ep == ',') ++ep;
522 }
523
524 if (ok && count != -1) {
525 if (!(*ep == 0 || *ep == ';')) {
526 errln("didn't get expected value: %s", ep);
527 ok = FALSE;
528 }
529 }
530
531 while (*ep && *ep != ';') ++ep;
532 if (*ep == ';') ++ep;
533 rp = ep;
534 }
535 delete p;
536 }
537}
538
51004dcb
A
539void PluralRulesTest::testOrdinal() {
540 IcuTestErrorCode errorCode(*this, "testOrdinal");
541 LocalPointer<PluralRules> pr(PluralRules::forLocale("en", UPLURAL_TYPE_ORDINAL, errorCode));
542 if (errorCode.logIfFailureAndReset("PluralRules::forLocale(en, UPLURAL_TYPE_ORDINAL) failed")) {
543 return;
544 }
545 UnicodeString keyword = pr->select(2.);
546 if (keyword != UNICODE_STRING("two", 3)) {
547 dataerrln("PluralRules(en-ordinal).select(2) failed");
548 }
549}
550
4388f060 551#endif /* #if !UCONFIG_NO_FORMATTING */