1 // © 2016 and later: Unicode, Inc. and others. 
   2 // License & terms of use: http://www.unicode.org/copyright.html 
   3 /******************************************************************** 
   5  * Copyright (c) 1997-2014, International Business Machines Corporation and 
   6  * others. All Rights Reserved. 
   7  ********************************************************************/ 
  10  * IntlTestCollator is the medium level test class for everything in the directory "collate". 
  13 /*********************************************************************** 
  14 * Modification history 
  15 * Date        Name        Description 
  16 * 02/14/2001  synwee      Compare with cintltst and commented away tests  
  18 ***********************************************************************/ 
  20 #include "unicode/utypes.h" 
  22 #if !UCONFIG_NO_COLLATION 
  24 #include "unicode/localpointer.h" 
  25 #include "unicode/sortkey.h" 
  26 #include "unicode/uchar.h" 
  27 #include "unicode/ustring.h" 
  52 #include "alphaindextst.h" 
  54 // Set to 1 to test offsets in backAndForth() 
  55 #define TEST_OFFSETS 0 
  57 extern IntlTest 
*createCollationTest(); 
  59 void IntlTestCollator::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* par 
) 
  62         logln("TestSuite Collator: "); 
  66     TESTCASE_AUTO_CLASS(CollationEnglishTest
); 
  67     TESTCASE_AUTO_CLASS(CollationFrenchTest
); 
  68     TESTCASE_AUTO_CLASS(CollationGermanTest
); 
  69     TESTCASE_AUTO_CLASS(CollationSpanishTest
); 
  70     TESTCASE_AUTO_CLASS(CollationKanaTest
); 
  71     TESTCASE_AUTO_CLASS(CollationTurkishTest
); 
  72     TESTCASE_AUTO_CLASS(CollationDummyTest
); 
  73     TESTCASE_AUTO_CLASS(G7CollationTest
); 
  74     TESTCASE_AUTO_CLASS(CollationMonkeyTest
); 
  75     TESTCASE_AUTO_CLASS(CollationAPITest
); 
  76     TESTCASE_AUTO_CLASS(CollationRegressionTest
); 
  77     TESTCASE_AUTO_CLASS(CollationCurrencyTest
); 
  78     TESTCASE_AUTO_CLASS(CollationIteratorTest
); 
  79     TESTCASE_AUTO_CLASS(CollationThaiTest
); 
  80     TESTCASE_AUTO_CLASS(LotusCollationKoreanTest
); 
  81     TESTCASE_AUTO_CLASS(StringSearchTest
); 
  82     TESTCASE_AUTO_CLASS(UCAConformanceTest
); 
  83     TESTCASE_AUTO_CLASS(CollationServiceTest
); 
  84     TESTCASE_AUTO_CLASS(CollationFinnishTest
); // removed by weiv - we have changed Finnish collation 
  85     TESTCASE_AUTO_CLASS(SSearchTest
); 
  86 #if !UCONFIG_NO_NORMALIZATION 
  87     TESTCASE_AUTO_CLASS(AlphabeticIndexTest
); 
  89     TESTCASE_AUTO_CREATE_CLASS(CollationTest
); 
  94 IntlTestCollator::compareUsingPartials(UCollator 
*coll
, const UChar source
[], int32_t sLen
, const UChar target
[], int32_t tLen
, int32_t pieceSize
, UErrorCode 
&status
) { 
  95   int32_t partialSKResult 
= 0; 
  96   uint8_t sBuf
[512], tBuf
[512]; 
  97   UCharIterator sIter
, tIter
; 
  98   uint32_t sState
[2], tState
[2]; 
  99   int32_t sSize 
= pieceSize
, tSize 
= pieceSize
; 
 101   status 
= U_ZERO_ERROR
; 
 102   sState
[0] = 0; sState
[1] = 0; 
 103   tState
[0] = 0; tState
[1] = 0; 
 104   while(sSize 
== pieceSize 
&& tSize 
== pieceSize 
&& partialSKResult 
== 0) { 
 105     uiter_setString(&sIter
, source
, sLen
); 
 106     uiter_setString(&tIter
, target
, tLen
); 
 107     sSize 
= ucol_nextSortKeyPart(coll
, &sIter
, sState
, sBuf
, pieceSize
, &status
); 
 108     tSize 
= ucol_nextSortKeyPart(coll
, &tIter
, tState
, tBuf
, pieceSize
, &status
); 
 110     if(sState
[0] != 0 || tState
[0] != 0) { 
 111       log("State != 0 : %08X %08X\n", sState
[0], tState
[0]); 
 115     partialSKResult 
= memcmp(sBuf
, tBuf
, pieceSize
); 
 118   if(partialSKResult 
< 0) { 
 120   } else if(partialSKResult 
> 0) { 
 128 IntlTestCollator::doTestVariant(Collator
* col
, const UnicodeString 
&source
, const UnicodeString 
&target
, Collator::EComparisonResult result
) 
 130   UErrorCode status 
= U_ZERO_ERROR
; 
 132   UCollator 
*myCollation 
= col
->toUCollator(); 
 134   Collator::EComparisonResult compareResult 
= col
->compare(source
, target
); 
 136   CollationKey srckey
, tgtkey
; 
 137   col
->getCollationKey(source
, srckey
, status
); 
 138   col
->getCollationKey(target
, tgtkey
, status
); 
 139   if (U_FAILURE(status
)){ 
 140     errln("Creation of collation keys failed\n"); 
 142   Collator::EComparisonResult keyResult 
= srckey
.compareTo(tgtkey
); 
 144   reportCResult(source
, target
, srckey
, tgtkey
, compareResult
, keyResult
, result
, result
); 
 146     UColAttributeValue norm 
= ucol_getAttribute(myCollation
, UCOL_NORMALIZATION_MODE
, &status
); 
 148     int32_t sLen 
= source
.length(), tLen 
= target
.length(); 
 149     const UChar
* src 
= source
.getBuffer(); 
 150     const UChar
* trg 
= target
.getBuffer(); 
 151     UCollationResult compareResultIter 
= (UCollationResult
)result
; 
 154       UCharIterator sIter
, tIter
; 
 155       uiter_setString(&sIter
, src
, sLen
); 
 156       uiter_setString(&tIter
, trg
, tLen
); 
 157       compareResultIter 
= ucol_strcollIter(myCollation
, &sIter
, &tIter
, &status
); 
 158       if(compareResultIter 
!= (UCollationResult
)result
) { 
 159         errln("Different result for iterative comparison "+source
+" "+target
); 
 162     /* convert the strings to UTF-8 and do try comparing with char iterator */ 
 163     if(!quick
) { /*!QUICK*/ 
 164       char utf8Source
[256], utf8Target
[256]; 
 165       int32_t utf8SourceLen 
= 0, utf8TargetLen 
= 0; 
 166       u_strToUTF8(utf8Source
, 256, &utf8SourceLen
, src
, sLen
, &status
); 
 167       if(U_FAILURE(status
)) { /* probably buffer is not big enough */ 
 168         log("Src UTF-8 buffer too small! Will not compare!\n"); 
 170         u_strToUTF8(utf8Target
, 256, &utf8TargetLen
, trg
, tLen
, &status
); 
 171         if(U_SUCCESS(status
)) { /* probably buffer is not big enough */ 
 172           UCollationResult compareResultUTF8 
= (UCollationResult
)result
, compareResultUTF8Norm 
= (UCollationResult
)result
; 
 173           UCharIterator sIter
, tIter
; 
 174           /*log_verbose("Strings converted to UTF-8:%s, %s\n", aescstrdup(source,-1), aescstrdup(target,-1));*/ 
 175           uiter_setUTF8(&sIter
, utf8Source
, utf8SourceLen
); 
 176           uiter_setUTF8(&tIter
, utf8Target
, utf8TargetLen
); 
 177        /*uiter_setString(&sIter, source, sLen); 
 178       uiter_setString(&tIter, target, tLen);*/ 
 179           compareResultUTF8 
= ucol_strcollIter(myCollation
, &sIter
, &tIter
, &status
); 
 180           ucol_setAttribute(myCollation
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
); 
 181           sIter
.move(&sIter
, 0, UITER_START
); 
 182           tIter
.move(&tIter
, 0, UITER_START
); 
 183           compareResultUTF8Norm 
= ucol_strcollIter(myCollation
, &sIter
, &tIter
, &status
); 
 184           ucol_setAttribute(myCollation
, UCOL_NORMALIZATION_MODE
, norm
, &status
); 
 185           if(compareResultUTF8 
!= compareResultIter
) { 
 186             errln("different results in iterative comparison for UTF-16 and UTF-8 encoded strings. "+source
+", "+target
); 
 188           if(compareResultUTF8 
!= compareResultUTF8Norm
) { 
 189             errln("different results in iterative when normalization is turned on with UTF-8 strings. "+source
+", "+target
); 
 192           log("Target UTF-8 buffer too small! Did not compare!\n"); 
 194         if(U_FAILURE(status
)) { 
 195           log("UTF-8 strcoll failed! Ignoring result\n"); 
 200     /* testing the partial sortkeys */ 
 202       int32_t partialSizes
[] = { 3, 1, 2, 4, 8, 20, 80 }; /* just size 3 in the quick mode */ 
 203       int32_t partialSizesSize 
= 1; 
 205         partialSizesSize 
= 7; 
 208       log("partial sortkey test piecesize="); 
 209       for(i 
= 0; i 
< partialSizesSize
; i
++) { 
 210         UCollationResult partialSKResult 
= (UCollationResult
)result
, partialNormalizedSKResult 
= (UCollationResult
)result
; 
 211         log("%i ", partialSizes
[i
]); 
 213         partialSKResult 
= compareUsingPartials(myCollation
, src
, sLen
, trg
, tLen
, partialSizes
[i
], status
); 
 214         if(partialSKResult 
!= (UCollationResult
)result
) { 
 215           errln("Partial sortkey comparison returned wrong result: "+source
+", "+target
+" (size "+partialSizes
[i
]+")");            
 218         if(norm 
!= UCOL_ON 
&& !quick
) { 
 220           ucol_setAttribute(myCollation
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
); 
 221           partialNormalizedSKResult 
= compareUsingPartials(myCollation
, src
, sLen
, trg
, tLen
, partialSizes
[i
], status
); 
 222           ucol_setAttribute(myCollation
, UCOL_NORMALIZATION_MODE
, norm
, &status
); 
 223           if(partialSKResult 
!= partialNormalizedSKResult
) { 
 224             errln("Partial sortkey comparison gets different result when normalization is on: "+source
+", "+target
+" (size "+partialSizes
[i
]+")");            
 231   if (compareResult != result) { 
 232     errln("String comparison failed in variant test\n"); 
 234   if (keyResult != result) { 
 235     errln("Collation key comparison failed in variant test\n"); 
 241 IntlTestCollator::doTest(Collator
* col
, const UChar 
*source
, const UChar 
*target
, Collator::EComparisonResult result
) { 
 242   doTest(col
, UnicodeString(source
), UnicodeString(target
), result
); 
 246 IntlTestCollator::doTest(Collator
* col
, const UnicodeString 
&source
, const UnicodeString 
&target
, Collator::EComparisonResult result
) 
 249     doTestVariant(col
, source
, target
, result
); 
 250     if(result 
== Collator::LESS
) { 
 251       doTestVariant(col
, target
, source
, Collator::GREATER
); 
 252     } else if (result 
== Collator::GREATER
) { 
 253       doTestVariant(col
, target
, source
, Collator::LESS
); 
 256     UErrorCode status 
= U_ZERO_ERROR
; 
 257     LocalPointer
<CollationElementIterator
> c(((RuleBasedCollator 
*)col
)->createCollationElementIterator(source
)); 
 258     logln("Testing iterating source: "+source
); 
 260     c
->setText(target
, status
); 
 261     logln("Testing iterating target: "+target
); 
 267 // used for collation result reporting, defined here for convenience 
 268 // (maybe moved later) 
 270 IntlTestCollator::reportCResult( const UnicodeString 
&source
, const UnicodeString 
&target
, 
 271              CollationKey 
&sourceKey
, CollationKey 
&targetKey
, 
 272              Collator::EComparisonResult compareResult
, 
 273              Collator::EComparisonResult keyResult
, 
 274                                 Collator::EComparisonResult incResult
, 
 275                          Collator::EComparisonResult expectedResult 
) 
 277     if (expectedResult 
< -1 || expectedResult 
> 1) 
 279         errln("***** invalid call to reportCResult ****"); 
 283     UBool ok1 
= (compareResult 
== expectedResult
); 
 284     UBool ok2 
= (keyResult 
== expectedResult
); 
 285     UBool ok3 
= (incResult 
== expectedResult
); 
 288     if (ok1 
&& ok2 
&& ok3 
&& !verbose
) { 
 289         // Keep non-verbose, passing tests fast 
 292         UnicodeString 
msg1(ok1 
? "Ok: compare(" : "FAIL: compare("); 
 293         UnicodeString 
msg2(", "), msg3(") returned "), msg4("; expected "); 
 294         UnicodeString prettySource
, prettyTarget
, sExpect
, sResult
; 
 296         IntlTest::prettify(source
, prettySource
); 
 297         IntlTest::prettify(target
, prettyTarget
); 
 298         appendCompareResult(compareResult
, sResult
); 
 299         appendCompareResult(expectedResult
, sExpect
); 
 302             logln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult
); 
 304             errln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult 
+ msg4 
+ sExpect
); 
 307         msg1 
= UnicodeString(ok2 
? "Ok: key(" : "FAIL: key("); 
 308         msg2 
= ").compareTo(key("; 
 309         msg3 
= ")) returned "; 
 311         appendCompareResult(keyResult
, sResult
); 
 314             logln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult
); 
 316             errln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult 
+ msg4 
+ sExpect
); 
 321             prettify(sourceKey
, prettySource
); 
 322             prettify(targetKey
, prettyTarget
); 
 324             errln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget
); 
 326         msg1 
= UnicodeString (ok3 
? "Ok: incCompare(" : "FAIL: incCompare("); 
 328         msg3 
= ") returned "; 
 330         appendCompareResult(incResult
, sResult
); 
 333             logln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult
); 
 335             errln(msg1 
+ prettySource 
+ msg2 
+ prettyTarget 
+ msg3 
+ sResult 
+ msg4 
+ sExpect
); 
 341 IntlTestCollator::appendCompareResult(Collator::EComparisonResult result
, 
 342                   UnicodeString
& target
) 
 344     if (result 
== Collator::LESS
) 
 348     else if (result 
== Collator::EQUAL
) 
 352     else if (result 
== Collator::GREATER
) 
 358         UnicodeString huh 
= "?"; 
 360         target 
+= (huh 
+ (int32_t)result
); 
 366 // Produce a printable representation of a CollationKey 
 367 UnicodeString 
&IntlTestCollator::prettify(const CollationKey 
&source
, UnicodeString 
&target
) 
 369     int32_t i
, byteCount
; 
 370     const uint8_t *bytes 
= source
.getByteArray(byteCount
); 
 375     for (i 
= 0; i 
< byteCount
; i 
+= 1) 
 380         appendHex(bytes
[i
], 2, target
); 
 388 void IntlTestCollator::backAndForth(CollationElementIterator 
&iter
) 
 390     // Run through the iterator forwards and stick it into an array 
 391     int32_t orderLength 
= 0; 
 392     LocalArray
<Order
> orders(getOrders(iter
, orderLength
)); 
 393     UErrorCode status 
= U_ZERO_ERROR
; 
 395     // Now go through it backwards and make sure we get the same values 
 396     int32_t index 
= orderLength
; 
 399     // reset the iterator 
 402     while ((o 
= iter
.previous(status
)) != CollationElementIterator::NULLORDER
) 
 404         /*int32_t offset = */iter
.getOffset(); 
 409           } else { // this is an error, orders exhausted but there are non-ignorable CEs from 
 411             errln("Backward iteration returned a non ignorable after orders are exhausted"); 
 417         if (o 
!= orders
[index
].order
) { 
 421                 while (index 
> 0 && orders
[--index
].order 
== 0) { 
 425                 if (o 
!= orders
[index
].order
) { 
 426                     errln("Mismatched order at index %d: 0x%0:8X vs. 0x%0:8X", index
, 
 427                     orders
[index
].order
, o
); 
 435         if (offset 
!= orders
[index
].offset
) { 
 436           errln("Mismatched offset at index %d: %d vs. %d", index
, 
 437             orders
[index
].offset
, offset
); 
 445     while (index 
!= 0 && orders
[index 
- 1].order 
== 0) 
 452         UnicodeString 
msg("Didn't get back to beginning - index is "); 
 457         while ((o 
= iter
.next(status
)) != CollationElementIterator::NULLORDER
) 
 459             UnicodeString 
hexString("0x"); 
 461             appendHex(o
, 8, hexString
); 
 468         while ((o 
= iter
.previous(status
)) != CollationElementIterator::NULLORDER
) 
 470             UnicodeString 
hexString("0x"); 
 472             appendHex(o
, 8, hexString
); 
 482  * Return an integer array containing all of the collation orders 
 483  * returned by calls to next on the specified iterator 
 485 IntlTestCollator::Order 
*IntlTestCollator::getOrders(CollationElementIterator 
&iter
, int32_t &orderLength
) 
 487     int32_t maxSize 
= 100; 
 489     LocalArray
<Order
> orders(new Order
[maxSize
]); 
 490     UErrorCode status 
= U_ZERO_ERROR
; 
 491     int32_t offset 
= iter
.getOffset(); 
 494     while ((order 
= iter
.next(status
)) != CollationElementIterator::NULLORDER
) 
 499             Order 
*temp 
= new Order
[maxSize
]; 
 501             uprv_memcpy(temp
, orders
.getAlias(), size 
* sizeof(Order
)); 
 502             orders
.adoptInstead(temp
); 
 505         orders
[size
].order  
= order
; 
 506         orders
[size
].offset 
= offset
; 
 508         offset 
= iter
.getOffset(); 
 511     if (U_FAILURE(status
)) { 
 512         errln("CollationElementIterator.next() failed - %s", 
 513               u_errorName(status
)); 
 518         Order 
*temp 
= new Order
[size
]; 
 520         uprv_memcpy(temp
, orders
.getAlias(), size 
* sizeof(Order
)); 
 521         orders
.adoptInstead(temp
); 
 525     return orders
.orphan(); 
 528 #endif /* #if !UCONFIG_NO_COLLATION */