Home | History | Annotate | Download | only in intltest
      1 /*
      2  **********************************************************************
      3  *   Copyright (C) 2005-2010, International Business Machines
      4  *   Corporation and others.  All Rights Reserved.
      5  **********************************************************************
      6  */
      7 
      8 
      9 #include "unicode/utypes.h"
     10 
     11 #if !UCONFIG_NO_COLLATION
     12 
     13 #include "unicode/unistr.h"
     14 #include "unicode/putil.h"
     15 #include "unicode/usearch.h"
     16 
     17 #include "cmemory.h"
     18 #include "unicode/coll.h"
     19 #include "unicode/tblcoll.h"
     20 #include "unicode/coleitr.h"
     21 #include "unicode/ucoleitr.h"
     22 
     23 #include "unicode/regex.h"        // TODO: make conditional on regexp being built.
     24 
     25 #include "unicode/uniset.h"
     26 #include "unicode/uset.h"
     27 #include "unicode/ustring.h"
     28 #include "hash.h"
     29 #include "uhash.h"
     30 #include "ucol_imp.h"
     31 
     32 #include "intltest.h"
     33 #include "ssearch.h"
     34 
     35 #include "unicode/colldata.h"
     36 #include "unicode/bmsearch.h"
     37 #include "unicode/bms.h"
     38 
     39 #include "xmlparser.h"
     40 #include "ucbuf.h"
     41 
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <stdio.h>
     45 
     46 char testId[100];
     47 
     48 #define TEST_ASSERT(x) {if (!(x)) { \
     49     errln("Failure in file %s, line %d, test ID = \"%s\"", __FILE__, __LINE__, testId);}}
     50 
     51 #define TEST_ASSERT_M(x, m) {if (!(x)) { \
     52     errln("Failure in file %s, line %d.   \"%s\"", __FILE__, __LINE__, m);return;}}
     53 
     54 #define TEST_ASSERT_SUCCESS(errcode) {if (U_FAILURE(errcode)) { \
     55     dataerrln("Failure in file %s, line %d, test ID \"%s\", status = \"%s\"", \
     56           __FILE__, __LINE__, testId, u_errorName(errcode));}}
     57 
     58 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
     59 #define NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type))
     60 #define DELETE_ARRAY(array) uprv_free((void *) (array))
     61 
     62 //---------------------------------------------------------------------------
     63 //
     64 //  Test class boilerplate
     65 //
     66 //---------------------------------------------------------------------------
     67 SSearchTest::SSearchTest()
     68 {
     69 }
     70 
     71 SSearchTest::~SSearchTest()
     72 {
     73 }
     74 
     75 void SSearchTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char *params )
     76 {
     77     if (exec) logln("TestSuite SSearchTest: ");
     78     switch (index) {
     79 #if !UCONFIG_NO_BREAK_ITERATION
     80        case 0: name = "searchTest";
     81             if (exec) searchTest();
     82             break;
     83 
     84         case 1: name = "offsetTest";
     85             if (exec) offsetTest();
     86             break;
     87 
     88         case 2: name = "monkeyTest";
     89             if (exec) monkeyTest(params);
     90             break;
     91 
     92         case 3: name = "bmMonkeyTest";
     93             if (exec) bmMonkeyTest(params);
     94             break;
     95 
     96         case 4: name = "boyerMooreTest";
     97             if (exec) boyerMooreTest();
     98             break;
     99 
    100         case 5: name = "goodSuffixTest";
    101             if (exec) goodSuffixTest();
    102             break;
    103 
    104         case 6: name = "searchTime";
    105             if (exec) searchTime();
    106             break;
    107 
    108         case 7: name = "bmsTest";
    109             if (exec) bmsTest();
    110             break;
    111 
    112         case 8: name = "bmSearchTest";
    113             if (exec) bmSearchTest();
    114             break;
    115 
    116         case 9: name = "udhrTest";
    117             if (exec) udhrTest();
    118             break;
    119         case 10: name = "stringListTest";
    120             if (exec) stringListTest();
    121             break;
    122 #endif
    123         default: name = "";
    124             break; //needed to end loop
    125     }
    126 }
    127 
    128 
    129 #if !UCONFIG_NO_BREAK_ITERATION
    130 
    131 #define PATH_BUFFER_SIZE 2048
    132 const char *SSearchTest::getPath(char buffer[2048], const char *filename) {
    133     UErrorCode status = U_ZERO_ERROR;
    134     const char *testDataDirectory = IntlTest::getSourceTestData(status);
    135 
    136     if (U_FAILURE(status) || strlen(testDataDirectory) + strlen(filename) + 1 >= PATH_BUFFER_SIZE) {
    137         errln("ERROR: getPath() failed - %s", u_errorName(status));
    138         return NULL;
    139     }
    140 
    141     strcpy(buffer, testDataDirectory);
    142     strcat(buffer, filename);
    143     return buffer;
    144 }
    145 
    146 
    147 void SSearchTest::searchTest()
    148 {
    149 #if !UCONFIG_NO_REGULAR_EXPRESSIONS && !UCONFIG_NO_FILE_IO
    150     UErrorCode status = U_ZERO_ERROR;
    151     char path[PATH_BUFFER_SIZE];
    152     const char *testFilePath = getPath(path, "ssearch.xml");
    153 
    154     if (testFilePath == NULL) {
    155         return; /* Couldn't get path: error message already output. */
    156     }
    157 
    158     LocalPointer<UXMLParser> parser(UXMLParser::createParser(status));
    159     TEST_ASSERT_SUCCESS(status);
    160     LocalPointer<UXMLElement> root(parser->parseFile(testFilePath, status));
    161     TEST_ASSERT_SUCCESS(status);
    162     if (U_FAILURE(status)) {
    163         return;
    164     }
    165 
    166     const UnicodeString *debugTestCase = root->getAttribute("debug");
    167     if (debugTestCase != NULL) {
    168 //       setenv("USEARCH_DEBUG", "1", 1);
    169     }
    170 
    171 
    172     const UXMLElement *testCase;
    173     int32_t tc = 0;
    174 
    175     while((testCase = root->nextChildElement(tc)) != NULL) {
    176 
    177         if (testCase->getTagName().compare("test-case") != 0) {
    178             errln("ssearch, unrecognized XML Element in test file");
    179             continue;
    180         }
    181         const UnicodeString *id       = testCase->getAttribute("id");
    182         *testId = 0;
    183         if (id != NULL) {
    184             id->extract(0, id->length(), testId,  sizeof(testId), US_INV);
    185         }
    186 
    187         // If debugging test case has been specified and this is not it, skip to next.
    188         if (id!=NULL && debugTestCase!=NULL && *id != *debugTestCase) {
    189             continue;
    190         }
    191         //
    192         //  Get the requested collation strength.
    193         //    Default is tertiary if the XML attribute is missing from the test case.
    194         //
    195         const UnicodeString *strength = testCase->getAttribute("strength");
    196         UColAttributeValue collatorStrength = UCOL_PRIMARY;
    197         if      (strength==NULL)          { collatorStrength = UCOL_TERTIARY;}
    198         else if (*strength=="PRIMARY")    { collatorStrength = UCOL_PRIMARY;}
    199         else if (*strength=="SECONDARY")  { collatorStrength = UCOL_SECONDARY;}
    200         else if (*strength=="TERTIARY")   { collatorStrength = UCOL_TERTIARY;}
    201         else if (*strength=="QUATERNARY") { collatorStrength = UCOL_QUATERNARY;}
    202         else if (*strength=="IDENTICAL")  { collatorStrength = UCOL_IDENTICAL;}
    203         else {
    204             // Bogus value supplied for strength.  Shouldn't happen, even from
    205             //  typos, if the  XML source has been validated.
    206             //  This assert is a little deceiving in that strength can be
    207             //   any of the allowed values, not just TERTIARY, but it will
    208             //   do the job of getting the error output.
    209             TEST_ASSERT(*strength=="TERTIARY")
    210         }
    211 
    212         //
    213         // Get the collator normalization flag.  Default is UCOL_OFF.
    214         //
    215         UColAttributeValue normalize = UCOL_OFF;
    216         const UnicodeString *norm = testCase->getAttribute("norm");
    217         TEST_ASSERT (norm==NULL || *norm=="ON" || *norm=="OFF");
    218         if (norm!=NULL && *norm=="ON") {
    219             normalize = UCOL_ON;
    220         }
    221 
    222         //
    223         // Get the alternate_handling flag. Default is UCOL_NON_IGNORABLE.
    224         //
    225         UColAttributeValue alternateHandling = UCOL_NON_IGNORABLE;
    226         const UnicodeString *alt = testCase->getAttribute("alternate_handling");
    227         TEST_ASSERT (alt == NULL || *alt == "SHIFTED" || *alt == "NON_IGNORABLE");
    228         if (alt != NULL && *alt == "SHIFTED") {
    229             alternateHandling = UCOL_SHIFTED;
    230         }
    231 
    232         const UnicodeString defLocale("en");
    233         char  clocale[100];
    234         const UnicodeString *locale   = testCase->getAttribute("locale");
    235         if (locale == NULL || locale->length()==0) {
    236             locale = &defLocale;
    237         };
    238         locale->extract(0, locale->length(), clocale, sizeof(clocale), NULL);
    239 
    240 
    241         UnicodeString  text;
    242         UnicodeString  target;
    243         UnicodeString  pattern;
    244         int32_t        expectedMatchStart = -1;
    245         int32_t        expectedMatchLimit = -1;
    246         const UXMLElement  *n;
    247         int32_t                nodeCount = 0;
    248 
    249         n = testCase->getChildElement("pattern");
    250         TEST_ASSERT(n != NULL);
    251         if (n==NULL) {
    252             continue;
    253         }
    254         text = n->getText(FALSE);
    255         text = text.unescape();
    256         pattern.append(text);
    257         nodeCount++;
    258 
    259         n = testCase->getChildElement("pre");
    260         if (n!=NULL) {
    261             text = n->getText(FALSE);
    262             text = text.unescape();
    263             target.append(text);
    264             nodeCount++;
    265         }
    266 
    267         n = testCase->getChildElement("m");
    268         if (n!=NULL) {
    269             expectedMatchStart = target.length();
    270             text = n->getText(FALSE);
    271             text = text.unescape();
    272             target.append(text);
    273             expectedMatchLimit = target.length();
    274             nodeCount++;
    275         }
    276 
    277         n = testCase->getChildElement("post");
    278         if (n!=NULL) {
    279             text = n->getText(FALSE);
    280             text = text.unescape();
    281             target.append(text);
    282             nodeCount++;
    283         }
    284 
    285         //  Check that there weren't extra things in the XML
    286         TEST_ASSERT(nodeCount == testCase->countChildren());
    287 
    288         // Open a collator and StringSearch based on the parameters
    289         //   obtained from the XML.
    290         //
    291         status = U_ZERO_ERROR;
    292         LocalUCollatorPointer collator(ucol_open(clocale, &status));
    293         ucol_setStrength(collator.getAlias(), collatorStrength);
    294         ucol_setAttribute(collator.getAlias(), UCOL_NORMALIZATION_MODE, normalize, &status);
    295         ucol_setAttribute(collator.getAlias(), UCOL_ALTERNATE_HANDLING, alternateHandling, &status);
    296         LocalUStringSearchPointer uss(usearch_openFromCollator(pattern.getBuffer(), pattern.length(),
    297                                                                target.getBuffer(), target.length(),
    298                                                                collator.getAlias(),
    299                                                                NULL,     // the break iterator
    300                                                                &status));
    301 
    302         TEST_ASSERT_SUCCESS(status);
    303         if (U_FAILURE(status)) {
    304             continue;
    305         }
    306 
    307         int32_t foundStart = 0;
    308         int32_t foundLimit = 0;
    309         UBool   foundMatch;
    310 
    311         //
    312         // Do the search, check the match result against the expected results.
    313         //
    314         foundMatch= usearch_search(uss.getAlias(), 0, &foundStart, &foundLimit, &status);
    315         TEST_ASSERT_SUCCESS(status);
    316         if ((foundMatch && expectedMatchStart<0) ||
    317             (foundStart != expectedMatchStart)   ||
    318             (foundLimit != expectedMatchLimit)) {
    319                 TEST_ASSERT(FALSE);   //  ouput generic error position
    320                 infoln("Found, expected match start = %d, %d \n"
    321                        "Found, expected match limit = %d, %d",
    322                 foundStart, expectedMatchStart, foundLimit, expectedMatchLimit);
    323         }
    324 
    325         // In case there are other matches...
    326         // (should we only do this if the test case passed?)
    327         while (foundMatch) {
    328             expectedMatchStart = foundStart;
    329             expectedMatchLimit = foundLimit;
    330 
    331             foundMatch = usearch_search(uss.getAlias(), foundLimit, &foundStart, &foundLimit, &status);
    332         }
    333 
    334         uss.adoptInstead(usearch_openFromCollator(pattern.getBuffer(), pattern.length(),
    335             target.getBuffer(), target.length(),
    336             collator.getAlias(),
    337             NULL,
    338             &status));
    339 
    340         //
    341         // Do the backwards search, check the match result against the expected results.
    342         //
    343         foundMatch= usearch_searchBackwards(uss.getAlias(), target.length(), &foundStart, &foundLimit, &status);
    344         TEST_ASSERT_SUCCESS(status);
    345         if ((foundMatch && expectedMatchStart<0) ||
    346             (foundStart != expectedMatchStart)   ||
    347             (foundLimit != expectedMatchLimit)) {
    348                 TEST_ASSERT(FALSE);   //  ouput generic error position
    349                 infoln("Found, expected backwards match start = %d, %d \n"
    350                        "Found, expected backwards match limit = %d, %d",
    351                 foundStart, expectedMatchStart, foundLimit, expectedMatchLimit);
    352         }
    353     }
    354 #endif
    355 }
    356 
    357 struct UdhrTestCase
    358 {
    359     const char *locale;
    360     const char *file;
    361 };
    362 
    363 void SSearchTest::udhrTest()
    364 {
    365     UErrorCode status = U_ZERO_ERROR;
    366     char path[PATH_BUFFER_SIZE];
    367     const char *udhrPath = getPath(path, "udhr");
    368 
    369     if (udhrPath == NULL) {
    370         // couldn't get path: error message already output...
    371         return;
    372     }
    373 
    374     UdhrTestCase testCases[] = {
    375         {"en", "udhr_eng.txt"},
    376         {"de", "udhr_deu_1996.txt"},
    377         {"fr", "udhr_fra.txt"},
    378         {"ru", "udhr_rus.txt"},
    379         {"th", "udhr_tha.txt"},
    380         {"ja", "udhr_jpn.txt"},
    381         {"ko", "udhr_kor.txt"},
    382         {"zh", "udhr_cmn_hans.txt"},
    383         {"zh_Hant", "udhr_cmn_hant.txt"}
    384     };
    385 
    386     int32_t testCount = ARRAY_SIZE(testCases);
    387 
    388     for (int32_t t = 0; t < testCount; t += 1) {
    389         int32_t len = 0;
    390         char *resolvedFileName = NULL;
    391         const char *encoding = NULL;
    392         UCHARBUF *ucharBuf = NULL;
    393 
    394         ucbuf_resolveFileName(udhrPath, testCases[t].file, NULL, &len, &status);
    395         resolvedFileName = NEW_ARRAY(char, len);
    396 
    397         if(resolvedFileName == NULL){
    398             continue;
    399         }
    400 
    401         if(status == U_BUFFER_OVERFLOW_ERROR){
    402             status = U_ZERO_ERROR;
    403         }
    404 
    405         ucbuf_resolveFileName(udhrPath, testCases[t].file, resolvedFileName, &len, &status);
    406         ucharBuf = ucbuf_open(resolvedFileName, &encoding, TRUE, FALSE, &status);
    407 
    408         DELETE_ARRAY(resolvedFileName);
    409 
    410         if(U_FAILURE(status)){
    411             infoln("Could not open the input file %s. Test skipped\n", testCases[t].file);
    412             continue;
    413         }
    414 
    415         int32_t targetLen = 0;
    416         const UChar *target = ucbuf_getBuffer(ucharBuf, &targetLen, &status);
    417 
    418         /* The first line of the file contains the pattern */
    419         int32_t start = 0, end = 0, plen = 0;
    420 
    421         for(end = start; ; end += 1) {
    422             UChar ch = target[end];
    423 
    424             if (ch == 0x000A || ch == 0x000D || ch == 0x2028) {
    425                 break;
    426             }
    427         }
    428 
    429         plen = end - start;
    430 
    431         UChar *pattern = NEW_ARRAY(UChar, plen);
    432         for (int32_t i = 0; i < plen; i += 1) {
    433             pattern[i] =  target[start++];
    434         }
    435 
    436         int32_t offset = 0;
    437         UCollator *coll = ucol_open(testCases[t].locale, &status);
    438         UCD *ucd = NULL;
    439         BMS *bms = NULL;
    440 
    441         if (U_FAILURE(status)) {
    442             errln("Could not open collator for %s", testCases[t].locale);
    443             goto delete_collator;
    444         }
    445 
    446         ucd = ucd_open(coll, &status);
    447 
    448         if (U_FAILURE(status)) {
    449             errln("Could not open CollData object for %s", testCases[t].locale);
    450             goto delete_ucd;
    451         }
    452 
    453         bms = bms_open(ucd, pattern, plen, target, targetLen, &status);
    454 
    455         if (U_FAILURE(status)) {
    456             errln("Could not open search object for %s", testCases[t].locale);
    457             goto delete_bms;
    458         }
    459 
    460         start = end = -1;
    461         while (bms_search(bms, offset, &start, &end)) {
    462             offset = end;
    463         }
    464 
    465         if (offset == 0) {
    466             errln("Could not find pattern - locale: %s, file: %s ", testCases[t].locale, testCases[t].file);
    467         }
    468 
    469 delete_bms:
    470         bms_close(bms);
    471 
    472 delete_ucd:
    473         ucd_close(ucd);
    474 
    475 delete_collator:
    476         ucol_close(coll);
    477 
    478         DELETE_ARRAY(pattern);
    479         ucbuf_close(ucharBuf);
    480     }
    481 
    482     ucd_flushCache();
    483 }
    484 
    485 void SSearchTest::bmSearchTest()
    486 {
    487 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
    488     UErrorCode status = U_ZERO_ERROR;
    489     char path[PATH_BUFFER_SIZE];
    490     const char *testFilePath = getPath(path, "ssearch.xml");
    491 
    492     if (testFilePath == NULL) {
    493         return; /* Couldn't get path: error message already output. */
    494     }
    495 
    496     UXMLParser  *parser = UXMLParser::createParser(status);
    497     TEST_ASSERT_SUCCESS(status);
    498     UXMLElement *root   = parser->parseFile(testFilePath, status);
    499     TEST_ASSERT_SUCCESS(status);
    500     if (U_FAILURE(status)) {
    501         return;
    502     }
    503 
    504     const UnicodeString *debugTestCase = root->getAttribute("debug");
    505     if (debugTestCase != NULL) {
    506 //       setenv("USEARCH_DEBUG", "1", 1);
    507     }
    508 
    509 
    510     const UXMLElement *testCase;
    511     int32_t tc = 0;
    512 
    513     while((testCase = root->nextChildElement(tc)) != NULL) {
    514 
    515         if (testCase->getTagName().compare("test-case") != 0) {
    516             errln("ssearch, unrecognized XML Element in test file");
    517             continue;
    518         }
    519         const UnicodeString *id       = testCase->getAttribute("id");
    520         *testId = 0;
    521         if (id != NULL) {
    522             id->extract(0, id->length(), testId,  sizeof(testId), US_INV);
    523         }
    524 
    525         // If debugging test case has been specified and this is not it, skip to next.
    526         if (id!=NULL && debugTestCase!=NULL && *id != *debugTestCase) {
    527             continue;
    528         }
    529         //
    530         //  Get the requested collation strength.
    531         //    Default is tertiary if the XML attribute is missing from the test case.
    532         //
    533         const UnicodeString *strength = testCase->getAttribute("strength");
    534         UColAttributeValue collatorStrength = UCOL_PRIMARY;
    535         if      (strength==NULL)          { collatorStrength = UCOL_TERTIARY;}
    536         else if (*strength=="PRIMARY")    { collatorStrength = UCOL_PRIMARY;}
    537         else if (*strength=="SECONDARY")  { collatorStrength = UCOL_SECONDARY;}
    538         else if (*strength=="TERTIARY")   { collatorStrength = UCOL_TERTIARY;}
    539         else if (*strength=="QUATERNARY") { collatorStrength = UCOL_QUATERNARY;}
    540         else if (*strength=="IDENTICAL")  { collatorStrength = UCOL_IDENTICAL;}
    541         else {
    542             // Bogus value supplied for strength.  Shouldn't happen, even from
    543             //  typos, if the  XML source has been validated.
    544             //  This assert is a little deceiving in that strength can be
    545             //   any of the allowed values, not just TERTIARY, but it will
    546             //   do the job of getting the error output.
    547             TEST_ASSERT(*strength=="TERTIARY")
    548         }
    549 
    550         //
    551         // Get the collator normalization flag.  Default is UCOL_OFF.
    552         //
    553         UColAttributeValue normalize = UCOL_OFF;
    554         const UnicodeString *norm = testCase->getAttribute("norm");
    555         TEST_ASSERT (norm==NULL || *norm=="ON" || *norm=="OFF");
    556         if (norm!=NULL && *norm=="ON") {
    557             normalize = UCOL_ON;
    558         }
    559 
    560         //
    561         // Get the alternate_handling flag. Default is UCOL_NON_IGNORABLE.
    562         //
    563         UColAttributeValue alternateHandling = UCOL_NON_IGNORABLE;
    564         const UnicodeString *alt = testCase->getAttribute("alternate_handling");
    565         TEST_ASSERT (alt == NULL || *alt == "SHIFTED" || *alt == "NON_IGNORABLE");
    566         if (alt != NULL && *alt == "SHIFTED") {
    567             alternateHandling = UCOL_SHIFTED;
    568         }
    569 
    570         const UnicodeString defLocale("en");
    571         char  clocale[100];
    572         const UnicodeString *locale   = testCase->getAttribute("locale");
    573         if (locale == NULL || locale->length()==0) {
    574             locale = &defLocale;
    575         };
    576         locale->extract(0, locale->length(), clocale, sizeof(clocale), NULL);
    577 
    578 
    579         UnicodeString  text;
    580         UnicodeString  target;
    581         UnicodeString  pattern;
    582         int32_t        expectedMatchStart = -1;
    583         int32_t        expectedMatchLimit = -1;
    584         const UXMLElement  *n;
    585         int32_t                nodeCount = 0;
    586 
    587         n = testCase->getChildElement("pattern");
    588         TEST_ASSERT(n != NULL);
    589         if (n==NULL) {
    590             continue;
    591         }
    592         text = n->getText(FALSE);
    593         text = text.unescape();
    594         pattern.append(text);
    595         nodeCount++;
    596 
    597         n = testCase->getChildElement("pre");
    598         if (n!=NULL) {
    599             text = n->getText(FALSE);
    600             text = text.unescape();
    601             target.append(text);
    602             nodeCount++;
    603         }
    604 
    605         n = testCase->getChildElement("m");
    606         if (n!=NULL) {
    607             expectedMatchStart = target.length();
    608             text = n->getText(FALSE);
    609             text = text.unescape();
    610             target.append(text);
    611             expectedMatchLimit = target.length();
    612             nodeCount++;
    613         }
    614 
    615         n = testCase->getChildElement("post");
    616         if (n!=NULL) {
    617             text = n->getText(FALSE);
    618             text = text.unescape();
    619             target.append(text);
    620             nodeCount++;
    621         }
    622 
    623         //  Check that there weren't extra things in the XML
    624         TEST_ASSERT(nodeCount == testCase->countChildren());
    625 
    626         // Open a collator and StringSearch based on the parameters
    627         //   obtained from the XML.
    628         //
    629         status = U_ZERO_ERROR;
    630         UCollator *collator = ucol_open(clocale, &status);
    631         ucol_setStrength(collator, collatorStrength);
    632         ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, normalize, &status);
    633         ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, alternateHandling, &status);
    634         UCD *ucd = ucd_open(collator, &status);
    635         BMS *bms = bms_open(ucd, pattern.getBuffer(), pattern.length(), target.getBuffer(), target.length(), &status);
    636 
    637         TEST_ASSERT_SUCCESS(status);
    638         if (U_FAILURE(status)) {
    639             bms_close(bms);
    640             ucd_close(ucd);
    641             ucol_close(collator);
    642             continue;
    643         }
    644 
    645         int32_t foundStart = 0;
    646         int32_t foundLimit = 0;
    647         UBool   foundMatch;
    648 
    649         //
    650         // Do the search, check the match result against the expected results.
    651         //
    652         foundMatch = bms_search(bms, 0, &foundStart, &foundLimit);
    653       //TEST_ASSERT_SUCCESS(status);
    654         if ((foundMatch && expectedMatchStart < 0) ||
    655             (foundStart != expectedMatchStart)     ||
    656             (foundLimit != expectedMatchLimit)) {
    657                 TEST_ASSERT(FALSE);   //  ouput generic error position
    658                 infoln("Found, expected match start = %d, %d \n"
    659                        "Found, expected match limit = %d, %d",
    660                 foundStart, expectedMatchStart, foundLimit, expectedMatchLimit);
    661         }
    662 
    663         bms_close(bms);
    664         ucd_close(ucd);
    665         ucol_close(collator);
    666     }
    667 
    668     ucd_flushCache();
    669     delete root;
    670     delete parser;
    671 #endif
    672 }
    673 
    674 struct Order
    675 {
    676     int32_t order;
    677     int32_t lowOffset;
    678     int32_t highOffset;
    679 };
    680 
    681 class OrderList
    682 {
    683 public:
    684     OrderList();
    685     OrderList(UCollator *coll, const UnicodeString &string, int32_t stringOffset = 0);
    686     ~OrderList();
    687 
    688     int32_t size(void) const;
    689     void add(int32_t order, int32_t low, int32_t high);
    690     const Order *get(int32_t index) const;
    691     int32_t getLowOffset(int32_t index) const;
    692     int32_t getHighOffset(int32_t index) const;
    693     int32_t getOrder(int32_t index) const;
    694     void reverse(void);
    695     UBool compare(const OrderList &other) const;
    696     UBool matchesAt(int32_t offset, const OrderList &other) const;
    697 
    698 private:
    699     Order *list;
    700     int32_t listMax;
    701     int32_t listSize;
    702 };
    703 
    704 OrderList::OrderList()
    705   : list(NULL),  listMax(16), listSize(0)
    706 {
    707     list = new Order[listMax];
    708 }
    709 
    710 OrderList::OrderList(UCollator *coll, const UnicodeString &string, int32_t stringOffset)
    711     : list(NULL), listMax(16), listSize(0)
    712 {
    713     UErrorCode status = U_ZERO_ERROR;
    714     UCollationElements *elems = ucol_openElements(coll, string.getBuffer(), string.length(), &status);
    715     uint32_t strengthMask = 0;
    716     int32_t order, low, high;
    717 
    718     switch (ucol_getStrength(coll))
    719     {
    720     default:
    721         strengthMask |= UCOL_TERTIARYORDERMASK;
    722         /* fall through */
    723 
    724     case UCOL_SECONDARY:
    725         strengthMask |= UCOL_SECONDARYORDERMASK;
    726         /* fall through */
    727 
    728     case UCOL_PRIMARY:
    729         strengthMask |= UCOL_PRIMARYORDERMASK;
    730     }
    731 
    732     list = new Order[listMax];
    733 
    734     ucol_setOffset(elems, stringOffset, &status);
    735 
    736     do {
    737         low   = ucol_getOffset(elems);
    738         order = ucol_next(elems, &status);
    739         high  = ucol_getOffset(elems);
    740 
    741         if (order != UCOL_NULLORDER) {
    742             order &= strengthMask;
    743         }
    744 
    745         if (order != UCOL_IGNORABLE) {
    746             add(order, low, high);
    747         }
    748     } while (order != UCOL_NULLORDER);
    749 
    750     ucol_closeElements(elems);
    751 }
    752 
    753 OrderList::~OrderList()
    754 {
    755     delete[] list;
    756 }
    757 
    758 void OrderList::add(int32_t order, int32_t low, int32_t high)
    759 {
    760     if (listSize >= listMax) {
    761         listMax *= 2;
    762 
    763         Order *newList = new Order[listMax];
    764 
    765         uprv_memcpy(newList, list, listSize * sizeof(Order));
    766         delete[] list;
    767         list = newList;
    768     }
    769 
    770     list[listSize].order      = order;
    771     list[listSize].lowOffset  = low;
    772     list[listSize].highOffset = high;
    773 
    774     listSize += 1;
    775 }
    776 
    777 const Order *OrderList::get(int32_t index) const
    778 {
    779     if (index >= listSize) {
    780         return NULL;
    781     }
    782 
    783     return &list[index];
    784 }
    785 
    786 int32_t OrderList::getLowOffset(int32_t index) const
    787 {
    788     const Order *order = get(index);
    789 
    790     if (order != NULL) {
    791         return order->lowOffset;
    792     }
    793 
    794     return -1;
    795 }
    796 
    797 int32_t OrderList::getHighOffset(int32_t index) const
    798 {
    799     const Order *order = get(index);
    800 
    801     if (order != NULL) {
    802         return order->highOffset;
    803     }
    804 
    805     return -1;
    806 }
    807 
    808 int32_t OrderList::getOrder(int32_t index) const
    809 {
    810     const Order *order = get(index);
    811 
    812     if (order != NULL) {
    813         return order->order;
    814     }
    815 
    816     return UCOL_NULLORDER;
    817 }
    818 
    819 int32_t OrderList::size() const
    820 {
    821     return listSize;
    822 }
    823 
    824 void OrderList::reverse()
    825 {
    826     for(int32_t f = 0, b = listSize - 1; f < b; f += 1, b -= 1) {
    827         Order swap = list[b];
    828 
    829         list[b] = list[f];
    830         list[f] = swap;
    831     }
    832 }
    833 
    834 UBool OrderList::compare(const OrderList &other) const
    835 {
    836     if (listSize != other.listSize) {
    837         return FALSE;
    838     }
    839 
    840     for(int32_t i = 0; i < listSize; i += 1) {
    841         if (list[i].order  != other.list[i].order ||
    842             list[i].lowOffset != other.list[i].lowOffset ||
    843             list[i].highOffset != other.list[i].highOffset) {
    844                 return FALSE;
    845         }
    846     }
    847 
    848     return TRUE;
    849 }
    850 
    851 UBool OrderList::matchesAt(int32_t offset, const OrderList &other) const
    852 {
    853     // NOTE: sizes include the NULLORDER, which we don't want to compare.
    854     int32_t otherSize = other.size() - 1;
    855 
    856     if (listSize - 1 - offset < otherSize) {
    857         return FALSE;
    858     }
    859 
    860     for (int32_t i = offset, j = 0; j < otherSize; i += 1, j += 1) {
    861         if (getOrder(i) != other.getOrder(j)) {
    862             return FALSE;
    863         }
    864     }
    865 
    866     return TRUE;
    867 }
    868 
    869 static char *printOffsets(char *buffer, OrderList &list)
    870 {
    871     int32_t size = list.size();
    872     char *s = buffer;
    873 
    874     for(int32_t i = 0; i < size; i += 1) {
    875         const Order *order = list.get(i);
    876 
    877         if (i != 0) {
    878             s += sprintf(s, ", ");
    879         }
    880 
    881         s += sprintf(s, "(%d, %d)", order->lowOffset, order->highOffset);
    882     }
    883 
    884     return buffer;
    885 }
    886 
    887 static char *printOrders(char *buffer, OrderList &list)
    888 {
    889     int32_t size = list.size();
    890     char *s = buffer;
    891 
    892     for(int32_t i = 0; i < size; i += 1) {
    893         const Order *order = list.get(i);
    894 
    895         if (i != 0) {
    896             s += sprintf(s, ", ");
    897         }
    898 
    899         s += sprintf(s, "%8.8X", order->order);
    900     }
    901 
    902     return buffer;
    903 }
    904 
    905 void SSearchTest::offsetTest()
    906 {
    907     static const UVersionInfo icu47 = { 4, 7, 0, 0 };
    908     const char *test[] = {
    909         // The sequence \u0FB3\u0F71\u0F71\u0F80 contains a discontiguous
    910         // contraction (\u0FB3\u0F71\u0F80) logically followed by \u0F71.
    911         "\\u1E33\\u0FB3\\u0F71\\u0F71\\u0F80\\uD835\\uDF6C\\u01B0",
    912 
    913         "\\ua191\\u16ef\\u2036\\u017a",
    914 
    915 #if 0
    916         // This results in a complex interaction between contraction,
    917         // expansion and normalization that confuses the backwards offset fixups.
    918         "\\u0F7F\\u0F80\\u0F81\\u0F82\\u0F83\\u0F84\\u0F85",
    919 #endif
    920 
    921         "\\u0F80\\u0F81\\u0F82\\u0F83\\u0F84\\u0F85",
    922         "\\u07E9\\u07EA\\u07F1\\u07F2\\u07F3",
    923 
    924         "\\u02FE\\u02FF"
    925         "\\u0300\\u0301\\u0302\\u0303\\u0304\\u0305\\u0306\\u0307\\u0308\\u0309\\u030A\\u030B\\u030C\\u030D\\u030E\\u030F"
    926         "\\u0310\\u0311\\u0312\\u0313\\u0314\\u0315\\u0316\\u0317\\u0318\\u0319\\u031A\\u031B\\u031C\\u031D\\u031E\\u031F"
    927         "\\u0320\\u0321\\u0322\\u0323\\u0324\\u0325\\u0326\\u0327\\u0328\\u0329\\u032A\\u032B\\u032C\\u032D\\u032E\\u032F"
    928         "\\u0330\\u0331\\u0332\\u0333\\u0334\\u0335\\u0336\\u0337\\u0338\\u0339\\u033A\\u033B\\u033C\\u033D\\u033E\\u033F"
    929         "\\u0340\\u0341\\u0342\\u0343\\u0344\\u0345\\u0346\\u0347\\u0348\\u0349\\u034A\\u034B\\u034C\\u034D\\u034E", // currently not working, see #8081
    930 
    931         "\\u02FE\\u02FF\\u0300\\u0301\\u0302\\u0303\\u0316\\u0317\\u0318", // currently not working, see #8081
    932         "a\\u02FF\\u0301\\u0316", // currently not working, see #8081
    933         "a\\u02FF\\u0316\\u0301",
    934         "a\\u0430\\u0301\\u0316",
    935         "a\\u0430\\u0316\\u0301",
    936         "abc\\u0E41\\u0301\\u0316",
    937         "abc\\u0E41\\u0316\\u0301",
    938         "\\u0E41\\u0301\\u0316",
    939         "\\u0E41\\u0316\\u0301",
    940         "a\\u0301\\u0316",
    941         "a\\u0316\\u0301",
    942         "\\uAC52\\uAC53",
    943         "\\u34CA\\u34CB",
    944         "\\u11ED\\u11EE",
    945         "\\u30C3\\u30D0",
    946         "p\\u00E9ch\\u00E9",
    947         "a\\u0301\\u0325",
    948         "a\\u0300\\u0325",
    949         "a\\u0325\\u0300",
    950         "A\\u0323\\u0300B",
    951         "A\\u0300\\u0323B",
    952         "A\\u0301\\u0323B",
    953         "A\\u0302\\u0301\\u0323B",
    954         "abc",
    955         "ab\\u0300c",
    956         "ab\\u0300\\u0323c",
    957         " \\uD800\\uDC00\\uDC00",
    958         "a\\uD800\\uDC00\\uDC00",
    959         "A\\u0301\\u0301",
    960         "A\\u0301\\u0323",
    961         "A\\u0301\\u0323B",
    962         "B\\u0301\\u0323C",
    963         "A\\u0300\\u0323B",
    964         "\\u0301A\\u0301\\u0301",
    965         "abcd\\r\\u0301",
    966         "p\\u00EAche",
    967         "pe\\u0302che",
    968     };
    969 
    970     int32_t testCount = ARRAY_SIZE(test);
    971     UErrorCode status = U_ZERO_ERROR;
    972     RuleBasedCollator *col = (RuleBasedCollator *) Collator::createInstance(Locale::getEnglish(), status);
    973     if (U_FAILURE(status)) {
    974         errcheckln(status, "Failed to create collator in offsetTest! - %s", u_errorName(status));
    975         return;
    976     }
    977     char buffer[4096];  // A bit of a hack... just happens to be long enough for all the test cases...
    978                         // We could allocate one that's the right size by (CE_count * 10) + 2
    979                         // 10 chars is enough room for 8 hex digits plus ", ". 2 extra chars for "[" and "]"
    980 
    981     col->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
    982 
    983     for(int32_t i = 0; i < testCount; i += 1) {
    984         if (!isICUVersionAtLeast(icu47) && i>=4 && i<=6) {
    985             continue; // timebomb until ticket #8080 is resolved
    986         }
    987         UnicodeString ts = CharsToUnicodeString(test[i]);
    988         CollationElementIterator *iter = col->createCollationElementIterator(ts);
    989         OrderList forwardList;
    990         OrderList backwardList;
    991         int32_t order, low, high;
    992 
    993         do {
    994             low   = iter->getOffset();
    995             order = iter->next(status);
    996             high  = iter->getOffset();
    997 
    998             forwardList.add(order, low, high);
    999         } while (order != CollationElementIterator::NULLORDER);
   1000 
   1001         iter->reset();
   1002         iter->setOffset(ts.length(), status);
   1003 
   1004         backwardList.add(CollationElementIterator::NULLORDER, iter->getOffset(), iter->getOffset());
   1005 
   1006         do {
   1007             high  = iter->getOffset();
   1008             order = iter->previous(status);
   1009             low   = iter->getOffset();
   1010 
   1011             if (order == CollationElementIterator::NULLORDER) {
   1012                 break;
   1013             }
   1014 
   1015             backwardList.add(order, low, high);
   1016         } while (TRUE);
   1017 
   1018         backwardList.reverse();
   1019 
   1020         if (forwardList.compare(backwardList)) {
   1021             logln("Works with \"%s\"", test[i]);
   1022             logln("Forward offsets:  [%s]", printOffsets(buffer, forwardList));
   1023 //          logln("Backward offsets: [%s]", printOffsets(buffer, backwardList));
   1024 
   1025             logln("Forward CEs:  [%s]", printOrders(buffer, forwardList));
   1026 //          logln("Backward CEs: [%s]", printOrders(buffer, backwardList));
   1027 
   1028             logln();
   1029         } else {
   1030             errln("Fails with \"%s\"", test[i]);
   1031             infoln("Forward offsets:  [%s]", printOffsets(buffer, forwardList));
   1032             infoln("Backward offsets: [%s]", printOffsets(buffer, backwardList));
   1033 
   1034             infoln("Forward CEs:  [%s]", printOrders(buffer, forwardList));
   1035             infoln("Backward CEs: [%s]", printOrders(buffer, backwardList));
   1036 
   1037             infoln();
   1038         }
   1039         delete iter;
   1040     }
   1041     delete col;
   1042 }
   1043 
   1044 #if 0
   1045 static UnicodeString &escape(const UnicodeString &string, UnicodeString &buffer)
   1046 {
   1047     for(int32_t i = 0; i < string.length(); i += 1) {
   1048         UChar32 ch = string.char32At(i);
   1049 
   1050         if (ch >= 0x0020 && ch <= 0x007F) {
   1051             if (ch == 0x005C) {
   1052                 buffer.append("\\\\");
   1053             } else {
   1054                 buffer.append(ch);
   1055             }
   1056         } else {
   1057             char cbuffer[12];
   1058 
   1059             if (ch <= 0xFFFFL) {
   1060                 sprintf(cbuffer, "\\u%4.4X", ch);
   1061             } else {
   1062                 sprintf(cbuffer, "\\U%8.8X", ch);
   1063             }
   1064 
   1065             buffer.append(cbuffer);
   1066         }
   1067 
   1068         if (ch >= 0x10000L) {
   1069             i += 1;
   1070         }
   1071     }
   1072 
   1073     return buffer;
   1074 }
   1075 #endif
   1076 
   1077 #if 1
   1078 
   1079 struct PCE
   1080 {
   1081     uint64_t ce;
   1082     int32_t  lowOffset;
   1083     int32_t  highOffset;
   1084 };
   1085 
   1086 class PCEList
   1087 {
   1088 public:
   1089     PCEList(UCollator *coll, const UnicodeString &string);
   1090     ~PCEList();
   1091 
   1092     int32_t size() const;
   1093 
   1094     const PCE *get(int32_t index) const;
   1095 
   1096     int32_t getLowOffset(int32_t index) const;
   1097     int32_t getHighOffset(int32_t index) const;
   1098     uint64_t getOrder(int32_t index) const;
   1099 
   1100     UBool matchesAt(int32_t offset, const PCEList &other) const;
   1101 
   1102     uint64_t operator[](int32_t index) const;
   1103 
   1104 private:
   1105     void add(uint64_t ce, int32_t low, int32_t high);
   1106 
   1107     PCE *list;
   1108     int32_t listMax;
   1109     int32_t listSize;
   1110 };
   1111 
   1112 PCEList::PCEList(UCollator *coll, const UnicodeString &string)
   1113 {
   1114     UErrorCode status = U_ZERO_ERROR;
   1115     UCollationElements *elems = ucol_openElements(coll, string.getBuffer(), string.length(), &status);
   1116     uint64_t order;
   1117     int32_t low, high;
   1118 
   1119     list = new PCE[listMax];
   1120 
   1121     ucol_setOffset(elems, 0, &status);
   1122 
   1123     do {
   1124         order = ucol_nextProcessed(elems, &low, &high, &status);
   1125         add(order, low, high);
   1126     } while (order != UCOL_PROCESSED_NULLORDER);
   1127 
   1128     ucol_closeElements(elems);
   1129 }
   1130 
   1131 PCEList::~PCEList()
   1132 {
   1133     delete[] list;
   1134 }
   1135 
   1136 void PCEList::add(uint64_t order, int32_t low, int32_t high)
   1137 {
   1138     if (listSize >= listMax) {
   1139         listMax *= 2;
   1140 
   1141         PCE *newList = new PCE[listMax];
   1142 
   1143         uprv_memcpy(newList, list, listSize * sizeof(Order));
   1144         delete[] list;
   1145         list = newList;
   1146     }
   1147 
   1148     list[listSize].ce         = order;
   1149     list[listSize].lowOffset  = low;
   1150     list[listSize].highOffset = high;
   1151 
   1152     listSize += 1;
   1153 }
   1154 
   1155 const PCE *PCEList::get(int32_t index) const
   1156 {
   1157     if (index >= listSize) {
   1158         return NULL;
   1159     }
   1160 
   1161     return &list[index];
   1162 }
   1163 
   1164 int32_t PCEList::getLowOffset(int32_t index) const
   1165 {
   1166     const PCE *pce = get(index);
   1167 
   1168     if (pce != NULL) {
   1169         return pce->lowOffset;
   1170     }
   1171 
   1172     return -1;
   1173 }
   1174 
   1175 int32_t PCEList::getHighOffset(int32_t index) const
   1176 {
   1177     const PCE *pce = get(index);
   1178 
   1179     if (pce != NULL) {
   1180         return pce->highOffset;
   1181     }
   1182 
   1183     return -1;
   1184 }
   1185 
   1186 uint64_t PCEList::getOrder(int32_t index) const
   1187 {
   1188     const PCE *pce = get(index);
   1189 
   1190     if (pce != NULL) {
   1191         return pce->ce;
   1192     }
   1193 
   1194     return UCOL_PROCESSED_NULLORDER;
   1195 }
   1196 
   1197 int32_t PCEList::size() const
   1198 {
   1199     return listSize;
   1200 }
   1201 
   1202 UBool PCEList::matchesAt(int32_t offset, const PCEList &other) const
   1203 {
   1204     // NOTE: sizes include the NULLORDER, which we don't want to compare.
   1205     int32_t otherSize = other.size() - 1;
   1206 
   1207     if (listSize - 1 - offset < otherSize) {
   1208         return FALSE;
   1209     }
   1210 
   1211     for (int32_t i = offset, j = 0; j < otherSize; i += 1, j += 1) {
   1212         if (getOrder(i) != other.getOrder(j)) {
   1213             return FALSE;
   1214         }
   1215     }
   1216 
   1217     return TRUE;
   1218 }
   1219 
   1220 uint64_t PCEList::operator[](int32_t index) const
   1221 {
   1222     return getOrder(index);
   1223 }
   1224 
   1225 void SSearchTest::boyerMooreTest()
   1226 {
   1227     UErrorCode status = U_ZERO_ERROR;
   1228     UCollator *coll = NULL;
   1229     CollData *data = NULL;
   1230     const CEList* ce = NULL;
   1231     const CEList* ce1 = NULL;
   1232     UnicodeString lp  = "fuss";
   1233     UnicodeString sp = "fu\\u00DF";
   1234     BoyerMooreSearch *longPattern = NULL;
   1235     BoyerMooreSearch *shortPattern = NULL;
   1236     UnicodeString targets[]  = {"fu\\u00DF", "fu\\u00DFball", "1fu\\u00DFball", "12fu\\u00DFball", "123fu\\u00DFball", "1234fu\\u00DFball",
   1237                                 "ffu\\u00DF", "fufu\\u00DF", "fusfu\\u00DF",
   1238                                 "fuss", "ffuss", "fufuss", "fusfuss", "1fuss", "12fuss", "123fuss", "1234fuss", "fu\\u00DF", "1fu\\u00DF", "12fu\\u00DF", "123fu\\u00DF", "1234fu\\u00DF"};
   1239     int32_t start = -1, end = -1;
   1240 
   1241     coll = ucol_openFromShortString("LEN_S1", FALSE, NULL, &status);
   1242     if (U_FAILURE(status)) {
   1243         errcheckln(status, "Could not open collator. - %s", u_errorName(status));
   1244         return;
   1245     }
   1246 
   1247     data = CollData::open(coll, status);
   1248     if (U_FAILURE(status)) {
   1249         errln("Could not open CollData object.");
   1250         goto close_data;
   1251     }
   1252 
   1253     data->getDynamicClassID();
   1254     if (U_FAILURE(status)) {
   1255         errln("Could not get dynamic class ID of CollData.");
   1256         goto close_patterns;
   1257     }
   1258 
   1259     data->getStaticClassID();
   1260     if (U_FAILURE(status)) {
   1261         errln("Could not get static class ID of CollData.");
   1262         goto close_patterns;
   1263     }
   1264 
   1265     longPattern = new BoyerMooreSearch(data, lp.unescape(), NULL, status);
   1266     shortPattern = new BoyerMooreSearch(data, sp.unescape(), NULL, status);
   1267     if (U_FAILURE(status)) {
   1268         errln("Could not create pattern objects.");
   1269         goto close_patterns;
   1270     }
   1271 
   1272     longPattern->getBadCharacterTable();
   1273     shortPattern->getBadCharacterTable();
   1274     if (U_FAILURE(status)) {
   1275         errln("Could not get bad character table.");
   1276         goto close_patterns;
   1277     }
   1278 
   1279     longPattern->getGoodSuffixTable();
   1280     shortPattern->getGoodSuffixTable();
   1281     if (U_FAILURE(status)) {
   1282         errln("Could not get good suffix table.");
   1283         goto close_patterns;
   1284     }
   1285 
   1286     longPattern->getDynamicClassID();
   1287     shortPattern->getDynamicClassID();
   1288     if (U_FAILURE(status)) {
   1289         errln("Could not get dynamic class ID of BoyerMooreSearch.");
   1290         goto close_patterns;
   1291     }
   1292 
   1293     longPattern->getStaticClassID();
   1294     shortPattern->getStaticClassID();
   1295     if (U_FAILURE(status)) {
   1296         errln("Could not get static class ID of BoyerMooreSearch.");
   1297         goto close_patterns;
   1298     }
   1299 
   1300     longPattern->getData();
   1301     shortPattern->getData();
   1302     if (U_FAILURE(status)) {
   1303         errln("Could not get collate data.");
   1304         goto close_patterns;
   1305     }
   1306 
   1307     ce = longPattern->getPatternCEs();
   1308     ce1 = shortPattern->getPatternCEs();
   1309     if (U_FAILURE(status)) {
   1310         errln("Could not get pattern CEs.");
   1311         goto close_patterns;
   1312     }
   1313 
   1314     ce->getDynamicClassID();
   1315     ce1->getDynamicClassID();
   1316     if (U_FAILURE(status)) {
   1317         errln("Could not get dynamic class ID of CEList.");
   1318         goto close_patterns;
   1319     }
   1320 
   1321     ce->getStaticClassID();
   1322     ce1->getStaticClassID();
   1323     if (U_FAILURE(status)) {
   1324         errln("Could not get static class ID of CEList.");
   1325         goto close_patterns;
   1326     }
   1327 
   1328     if(data->minLengthInChars(ce,0) != 3){
   1329         errln("Minimal Length in Characters for 'data' with 'ce' was suppose to give 3.");
   1330         goto close_patterns;
   1331     }
   1332 
   1333     if(data->minLengthInChars(ce1,0) != 3){
   1334         errln("Minimal Length in Characters for 'data' with 'ce1' was suppose to give 3.");
   1335         goto close_patterns;
   1336     }
   1337 
   1338     for (uint32_t t = 0; t < (sizeof(targets)/sizeof(targets[0])); t += 1) {
   1339         UnicodeString target = targets[t].unescape();
   1340 
   1341         longPattern->setTargetString(&target, status);
   1342         if (longPattern->search(0, start, end)) {
   1343             logln("Test %d: found long pattern at [%d, %d].", t, start, end);
   1344         } else {
   1345             errln("Test %d: did not find long pattern.", t);
   1346         }
   1347 
   1348         shortPattern->setTargetString(&target, status);
   1349         if (shortPattern->search(0, start, end)) {
   1350             logln("Test %d: found short pattern at [%d, %d].", t, start, end);
   1351         } else {
   1352             errln("Test %d: did not find short pattern.", t);
   1353         }
   1354 
   1355         if(longPattern->empty()){
   1356             errln("Test %d: Long pattern should not have been empty.");
   1357         }
   1358 
   1359         if(shortPattern->empty()){
   1360             errln("Test %d: Short pattern should not have been empty.");
   1361         }
   1362     }
   1363 
   1364 close_patterns:
   1365     delete shortPattern;
   1366     delete longPattern;
   1367 
   1368 close_data:
   1369     CollData::close(data);
   1370     ucol_close(coll);
   1371 }
   1372 
   1373 void SSearchTest::bmsTest()
   1374 {
   1375     UErrorCode status = U_ZERO_ERROR;
   1376     UCollator *coll = NULL;
   1377     UCD *data = NULL;
   1378     UnicodeString lp  = "fuss";
   1379     UnicodeString lpu = lp.unescape();
   1380     UnicodeString sp  = "fu\\u00DF";
   1381     UnicodeString spu = sp.unescape();
   1382     BMS *longPattern = NULL;
   1383     BMS *shortPattern = NULL;
   1384     UnicodeString targets[]  = {"fu\\u00DF", "fu\\u00DFball", "1fu\\u00DFball", "12fu\\u00DFball", "123fu\\u00DFball", "1234fu\\u00DFball",
   1385                                 "ffu\\u00DF", "fufu\\u00DF", "fusfu\\u00DF",
   1386                                 "fuss", "ffuss", "fufuss", "fusfuss", "1fuss", "12fuss", "123fuss", "1234fuss", "fu\\u00DF", "1fu\\u00DF", "12fu\\u00DF", "123fu\\u00DF", "1234fu\\u00DF"};
   1387     int32_t start = -1, end = -1;
   1388 
   1389     coll = ucol_openFromShortString("LEN_S1", FALSE, NULL, &status);
   1390     if (U_FAILURE(status)) {
   1391         errcheckln(status, "Could not open collator. - %s", u_errorName(status));
   1392         return;
   1393     }
   1394 
   1395     data = ucd_open(coll, &status);
   1396     if (U_FAILURE(status)) {
   1397         errln("Could not open CollData object.");
   1398         goto close_data;
   1399     }
   1400 
   1401     longPattern = bms_open(data, lpu.getBuffer(), lpu.length(), NULL, 0, &status);
   1402     shortPattern = bms_open(data, spu.getBuffer(), spu.length(), NULL, 0, &status);
   1403     if (U_FAILURE(status)) {
   1404         errln("Couldn't open pattern objects.");
   1405         goto close_patterns;
   1406     }
   1407 
   1408     for (uint32_t t = 0; t < (sizeof(targets)/sizeof(targets[0])); t += 1) {
   1409         UnicodeString target = targets[t].unescape();
   1410 
   1411         bms_setTargetString(longPattern, target.getBuffer(), target.length(), &status);
   1412         if (bms_search(longPattern, 0, &start, &end)) {
   1413             logln("Test %d: found long pattern at [%d, %d].", t, start, end);
   1414         } else {
   1415             errln("Test %d: did not find long pattern.", t);
   1416         }
   1417 
   1418         bms_setTargetString(shortPattern, target.getBuffer(), target.length(), &status);
   1419         if (bms_search(shortPattern, 0, &start, &end)) {
   1420             logln("Test %d: found short pattern at [%d, %d].", t, start, end);
   1421         } else {
   1422             errln("Test %d: did not find short pattern.", t);
   1423         }
   1424     }
   1425 
   1426     /* Add better coverage for bms code. */
   1427     if(bms_empty(longPattern)) {
   1428         errln("FAIL: longgPattern is empty.");
   1429     }
   1430 
   1431     if (!bms_getData(longPattern)) {
   1432         errln("FAIL: bms_getData returned NULL.");
   1433     }
   1434 
   1435     if (!ucd_getCollator(data)) {
   1436         errln("FAIL: ucd_getCollator returned NULL.");
   1437     }
   1438 
   1439 close_patterns:
   1440     bms_close(shortPattern);
   1441     bms_close(longPattern);
   1442 
   1443 close_data:
   1444     ucd_close(data);
   1445     ucd_freeCache();
   1446     ucol_close(coll);
   1447 }
   1448 
   1449 void SSearchTest::goodSuffixTest()
   1450 {
   1451     UErrorCode status = U_ZERO_ERROR;
   1452     UCollator *coll = NULL;
   1453     CollData *data = NULL;
   1454     UnicodeString pat = /*"gcagagag"*/ "fxeld";
   1455     UnicodeString target = /*"gcatcgcagagagtatacagtacg"*/ "cloveldfxeld";
   1456     BoyerMooreSearch *pattern = NULL;
   1457     int32_t start = -1, end = -1;
   1458 
   1459     coll = ucol_open(NULL, &status);
   1460     if (U_FAILURE(status)) {
   1461         errcheckln(status, "Couldn't open collator. - %s", u_errorName(status));
   1462         return;
   1463     }
   1464 
   1465     data = CollData::open(coll, status);
   1466     if (U_FAILURE(status)) {
   1467         errln("Couldn't open CollData object.");
   1468         goto close_data;
   1469     }
   1470 
   1471     pattern = new BoyerMooreSearch(data, pat, &target, status);
   1472     if (U_FAILURE(status)) {
   1473         errln("Couldn't open pattern object.");
   1474         goto close_pattern;
   1475     }
   1476 
   1477     if (pattern->search(0, start, end)) {
   1478         logln("Found pattern at [%d, %d].", start, end);
   1479     } else {
   1480         errln("Did not find pattern.");
   1481     }
   1482 
   1483 close_pattern:
   1484     delete pattern;
   1485 
   1486 close_data:
   1487     CollData::close(data);
   1488     ucol_close(coll);
   1489 }
   1490 
   1491 //
   1492 //  searchTime()    A quick and dirty performance test for string search.
   1493 //                  Probably  doesn't really belong as part of intltest, but it
   1494 //                  does check that the search succeeds, and gets the right result,
   1495 //                  so it serves as a functionality test also.
   1496 //
   1497 //                  To run as a perf test, up the loop count, select by commenting
   1498 //                  and uncommenting in the code the operation to be measured,
   1499 //                  rebuild, and measure the running time of this test alone.
   1500 //
   1501 //                     time LD_LIBRARY_PATH=whatever  ./intltest  collate/SSearchTest/searchTime
   1502 //
   1503 void SSearchTest::searchTime() {
   1504     static const char *longishText =
   1505 "Whylom, as olde stories tellen us,\n"
   1506 "Ther was a duk that highte Theseus:\n"
   1507 "Of Athenes he was lord and governour,\n"
   1508 "And in his tyme swich a conquerour,\n"
   1509 "That gretter was ther noon under the sonne.\n"
   1510 "Ful many a riche contree hadde he wonne;\n"
   1511 "What with his wisdom and his chivalrye,\n"
   1512 "He conquered al the regne of Femenye,\n"
   1513 "That whylom was y-cleped Scithia;\n"
   1514 "And weddede the quene Ipolita,\n"
   1515 "And broghte hir hoom with him in his contree\n"
   1516 "With muchel glorie and greet solempnitee,\n"
   1517 "And eek hir yonge suster Emelye.\n"
   1518 "And thus with victorie and with melodye\n"
   1519 "Lete I this noble duk to Athenes ryde,\n"
   1520 "And al his hoost, in armes, him bisyde.\n"
   1521 "And certes, if it nere to long to here,\n"
   1522 "I wolde han told yow fully the manere,\n"
   1523 "How wonnen was the regne of Femenye\n"
   1524 "By Theseus, and by his chivalrye;\n"
   1525 "And of the grete bataille for the nones\n"
   1526 "Bitwixen Athen's and Amazones;\n"
   1527 "And how asseged was Ipolita,\n"
   1528 "The faire hardy quene of Scithia;\n"
   1529 "And of the feste that was at hir weddinge,\n"
   1530 "And of the tempest at hir hoom-cominge;\n"
   1531 "But al that thing I moot as now forbere.\n"
   1532 "I have, God woot, a large feeld to ere,\n"
   1533 "And wayke been the oxen in my plough.\n"
   1534 "The remenant of the tale is long y-nough.\n"
   1535 "I wol nat letten eek noon of this route;\n"
   1536 "Lat every felawe telle his tale aboute,\n"
   1537 "And lat see now who shal the soper winne;\n"
   1538 "And ther I lefte, I wol ageyn biginne.\n"
   1539 "This duk, of whom I make mencioun,\n"
   1540 "When he was come almost unto the toun,\n"
   1541 "In al his wele and in his moste pryde,\n"
   1542 "He was war, as he caste his eye asyde,\n"
   1543 "Wher that ther kneled in the hye weye\n"
   1544 "A companye of ladies, tweye and tweye,\n"
   1545 "Ech after other, clad in clothes blake; \n"
   1546 "But swich a cry and swich a wo they make,\n"
   1547 "That in this world nis creature livinge,\n"
   1548 "That herde swich another weymentinge;\n"
   1549 "And of this cry they nolde never stenten,\n"
   1550 "Til they the reynes of his brydel henten.\n"
   1551 "'What folk ben ye, that at myn hoomcominge\n"
   1552 "Perturben so my feste with cryinge'?\n"
   1553 "Quod Theseus, 'have ye so greet envye\n"
   1554 "Of myn honour, that thus compleyne and crye? \n"
   1555 "Or who hath yow misboden, or offended?\n"
   1556 "And telleth me if it may been amended;\n"
   1557 "And why that ye ben clothed thus in blak'?\n"
   1558 "The eldest lady of hem alle spak,\n"
   1559 "When she hadde swowned with a deedly chere,\n"
   1560 "That it was routhe for to seen and here,\n"
   1561 "And seyde: 'Lord, to whom Fortune hath yiven\n"
   1562 "Victorie, and as a conquerour to liven,\n"
   1563 "Noght greveth us your glorie and your honour;\n"
   1564 "But we biseken mercy and socour.\n"
   1565 "Have mercy on our wo and our distresse.\n"
   1566 "Som drope of pitee, thurgh thy gentilesse,\n"
   1567 "Up-on us wrecched wommen lat thou falle.\n"
   1568 "For certes, lord, ther nis noon of us alle,\n"
   1569 "That she nath been a duchesse or a quene;\n"
   1570 "Now be we caitifs, as it is wel sene:\n"
   1571 "Thanked be Fortune, and hir false wheel,\n"
   1572 "That noon estat assureth to be weel.\n"
   1573 "And certes, lord, t'abyden your presence,\n"
   1574 "Here in the temple of the goddesse Clemence\n"
   1575 "We han ben waytinge al this fourtenight;\n"
   1576 "Now help us, lord, sith it is in thy might.\n"
   1577 "I wrecche, which that wepe and waille thus,\n"
   1578 "Was whylom wyf to king Capaneus,\n"
   1579 "That starf at Thebes, cursed be that day!\n"
   1580 "And alle we, that been in this array,\n"
   1581 "And maken al this lamentacioun,\n"
   1582 "We losten alle our housbondes at that toun,\n"
   1583 "Whyl that the sege ther-aboute lay.\n"
   1584 "And yet now th'olde Creon, weylaway!\n"
   1585 "The lord is now of Thebes the citee, \n"
   1586 "Fulfild of ire and of iniquitee,\n"
   1587 "He, for despyt, and for his tirannye,\n"
   1588 "To do the dede bodyes vileinye,\n"
   1589 "Of alle our lordes, whiche that ben slawe,\n"
   1590 "Hath alle the bodyes on an heep y-drawe,\n"
   1591 "And wol nat suffren hem, by noon assent,\n"
   1592 "Neither to been y-buried nor y-brent,\n"
   1593 "But maketh houndes ete hem in despyt. zet'\n";
   1594 
   1595 #define TEST_BOYER_MOORE 1
   1596 const char *cPattern = "maketh houndes ete hem";
   1597 //const char *cPattern = "Whylom";
   1598 //const char *cPattern = "zet";
   1599     const char *testId = "searchTime()";   // for error macros.
   1600     UnicodeString target = longishText;
   1601     UErrorCode status = U_ZERO_ERROR;
   1602 
   1603 
   1604     LocalUCollatorPointer collator(ucol_open("en", &status));
   1605     CollData *data = CollData::open(collator.getAlias(), status);
   1606     if (U_FAILURE(status) || collator.isNull() || data == NULL) {
   1607         errcheckln(status, "Unable to open UCollator or CollData. - %s", u_errorName(status));
   1608         return;
   1609     }
   1610     //ucol_setStrength(collator.getAlias(), collatorStrength);
   1611     //ucol_setAttribute(collator.getAlias(), UCOL_NORMALIZATION_MODE, normalize, &status);
   1612     UnicodeString uPattern = cPattern;
   1613 #ifndef TEST_BOYER_MOORE
   1614     LocalUStringSearchPointer uss(usearch_openFromCollator(uPattern.getBuffer(), uPattern.length(),
   1615                                                            target.getBuffer(), target.length(),
   1616                                                            collator.getAlias(),
   1617                                                            NULL,     // the break iterator
   1618                                                            &status));
   1619     TEST_ASSERT_SUCCESS(status);
   1620 #else
   1621     BoyerMooreSearch bms(data, uPattern, &target, status);
   1622     TEST_ASSERT_SUCCESS(status);
   1623 #endif
   1624 
   1625 //  int32_t foundStart;
   1626 //  int32_t foundEnd;
   1627     UBool   found;
   1628 
   1629     // Find the match position usgin strstr
   1630     const char *pm = strstr(longishText, cPattern);
   1631     TEST_ASSERT_M(pm!=NULL, "No pattern match with strstr");
   1632     int32_t  refMatchPos = (int32_t)(pm - longishText);
   1633     int32_t  icuMatchPos;
   1634     int32_t  icuMatchEnd;
   1635 #ifndef TEST_BOYER_MOORE
   1636     usearch_search(uss.getAlias(), 0, &icuMatchPos, &icuMatchEnd, &status);
   1637     TEST_ASSERT_SUCCESS(status);
   1638 #else
   1639     found = bms.search(0, icuMatchPos, icuMatchEnd);
   1640 #endif
   1641     TEST_ASSERT_M(refMatchPos == icuMatchPos, "strstr and icu give different match positions.");
   1642 
   1643     int32_t i;
   1644     int32_t j=0;
   1645 
   1646     // Try loopcounts around 100000 to some millions, depending on the operation,
   1647     //   to get runtimes of at least several seconds.
   1648     for (i=0; i<10000; i++) {
   1649 #ifndef TEST_BOYER_MOORE
   1650         found = usearch_search(uss.getAlias(), 0, &icuMatchPos, &icuMatchEnd, &status);
   1651 #else
   1652         found = bms.search(0, icuMatchPos, icuMatchEnd);
   1653 #endif
   1654         //TEST_ASSERT_SUCCESS(status);
   1655         //TEST_ASSERT(found);
   1656 
   1657         // usearch_setOffset(uss.getAlias(), 0, &status);
   1658         // icuMatchPos = usearch_next(uss.getAlias(), &status);
   1659 
   1660          // The i+j stuff is to confuse the optimizer and get it to actually leave the
   1661          //   call to strstr in place.
   1662          //pm = strstr(longishText+j, cPattern);
   1663          //j = (j + i)%5;
   1664     }
   1665 
   1666     printf("%ld, %d\n", pm-longishText, j);
   1667 #ifdef TEST_BOYER_MOORE
   1668     CollData::close(data);
   1669 #endif
   1670 }
   1671 #endif
   1672 
   1673 //----------------------------------------------------------------------------------------
   1674 //
   1675 //   Random Numbers.  Similar to standard lib rand() and srand()
   1676 //                    Not using library to
   1677 //                      1.  Get same results on all platforms.
   1678 //                      2.  Get access to current seed, to more easily reproduce failures.
   1679 //
   1680 //---------------------------------------------------------------------------------------
   1681 static uint32_t m_seed = 1;
   1682 
   1683 static uint32_t m_rand()
   1684 {
   1685     m_seed = m_seed * 1103515245 + 12345;
   1686     return (uint32_t)(m_seed/65536) % 32768;
   1687 }
   1688 
   1689 class Monkey
   1690 {
   1691 public:
   1692     virtual void append(UnicodeString &test, UnicodeString &alternate) = 0;
   1693 
   1694 protected:
   1695     Monkey();
   1696     virtual ~Monkey();
   1697 };
   1698 
   1699 Monkey::Monkey()
   1700 {
   1701     // ook?
   1702 }
   1703 
   1704 Monkey::~Monkey()
   1705 {
   1706     // ook?
   1707 }
   1708 
   1709 class SetMonkey : public Monkey
   1710 {
   1711 public:
   1712     SetMonkey(const USet *theSet);
   1713     ~SetMonkey();
   1714 
   1715     virtual void append(UnicodeString &test, UnicodeString &alternate);
   1716 
   1717 private:
   1718     const USet *set;
   1719 };
   1720 
   1721 SetMonkey::SetMonkey(const USet *theSet)
   1722     : Monkey(), set(theSet)
   1723 {
   1724     // ook?
   1725 }
   1726 
   1727 SetMonkey::~SetMonkey()
   1728 {
   1729     //ook...
   1730 }
   1731 
   1732 void SetMonkey::append(UnicodeString &test, UnicodeString &alternate)
   1733 {
   1734     int32_t size = uset_size(set);
   1735     int32_t index = m_rand() % size;
   1736     UChar32 ch = uset_charAt(set, index);
   1737     UnicodeString str(ch);
   1738 
   1739     test.append(str);
   1740     alternate.append(str); // flip case, or some junk?
   1741 }
   1742 
   1743 class StringSetMonkey : public Monkey
   1744 {
   1745 public:
   1746     StringSetMonkey(const USet *theSet, UCollator *theCollator, CollData *theCollData);
   1747     ~StringSetMonkey();
   1748 
   1749     void append(UnicodeString &testCase, UnicodeString &alternate);
   1750 
   1751 private:
   1752     UnicodeString &generateAlternative(const UnicodeString &testCase, UnicodeString &alternate);
   1753 
   1754     const USet *set;
   1755     UCollator  *coll;
   1756     CollData   *collData;
   1757 };
   1758 
   1759 StringSetMonkey::StringSetMonkey(const USet *theSet, UCollator *theCollator, CollData *theCollData)
   1760 : Monkey(), set(theSet), coll(theCollator), collData(theCollData)
   1761 {
   1762     // ook.
   1763 }
   1764 
   1765 StringSetMonkey::~StringSetMonkey()
   1766 {
   1767     // ook?
   1768 }
   1769 
   1770 void StringSetMonkey::append(UnicodeString &testCase, UnicodeString &alternate)
   1771 {
   1772     int32_t itemCount = uset_getItemCount(set), len = 0;
   1773     int32_t index = m_rand() % itemCount;
   1774     UChar32 rangeStart = 0, rangeEnd = 0;
   1775     UChar buffer[16];
   1776     UErrorCode err = U_ZERO_ERROR;
   1777 
   1778     len = uset_getItem(set, index, &rangeStart, &rangeEnd, buffer, 16, &err);
   1779 
   1780     if (len == 0) {
   1781         int32_t offset = m_rand() % (rangeEnd - rangeStart + 1);
   1782         UChar32 ch = rangeStart + offset;
   1783         UnicodeString str(ch);
   1784 
   1785         testCase.append(str);
   1786         generateAlternative(str, alternate);
   1787     } else if (len > 0) {
   1788         // should check that len < 16...
   1789         UnicodeString str(buffer, len);
   1790 
   1791         testCase.append(str);
   1792         generateAlternative(str, alternate);
   1793     } else {
   1794         // shouldn't happen...
   1795     }
   1796 }
   1797 
   1798 UnicodeString &StringSetMonkey::generateAlternative(const UnicodeString &testCase, UnicodeString &alternate)
   1799 {
   1800     // find out shortest string for the longest sequence of ces.
   1801     // needs to be refined to use dynamic programming, but will be roughly right
   1802     UErrorCode status = U_ZERO_ERROR;
   1803     CEList ceList(coll, testCase, status);
   1804     UnicodeString alt;
   1805     int32_t offset = 0;
   1806 
   1807     if (ceList.size() == 0) {
   1808         return alternate.append(testCase);
   1809     }
   1810 
   1811     while (offset < ceList.size()) {
   1812         int32_t ce = ceList.get(offset);
   1813         const StringList *strings = collData->getStringList(ce);
   1814 
   1815         if (strings == NULL) {
   1816             return alternate.append(testCase);
   1817         }
   1818 
   1819         int32_t stringCount = strings->size();
   1820         int32_t tries = 0;
   1821 
   1822         // find random string that generates the same CEList
   1823         const CEList *ceList2 = NULL;
   1824         const UnicodeString *string = NULL;
   1825               UBool matches = FALSE;
   1826 
   1827         do {
   1828             int32_t s = m_rand() % stringCount;
   1829 
   1830             if (tries++ > stringCount) {
   1831                 alternate.append(testCase);
   1832                 return alternate;
   1833             }
   1834 
   1835             string = strings->get(s);
   1836             ceList2 = collData->getCEList(string);
   1837             matches = ceList.matchesAt(offset, ceList2);
   1838 
   1839             if (! matches) {
   1840                 collData->freeCEList((CEList *) ceList2);
   1841             }
   1842         } while (! matches);
   1843 
   1844         alt.append(*string);
   1845         offset += ceList2->size();
   1846         collData->freeCEList(ceList2);
   1847     }
   1848 
   1849     const CEList altCEs(coll, alt, status);
   1850 
   1851     if (ceList.matchesAt(0, &altCEs)) {
   1852         return alternate.append(alt);
   1853     }
   1854 
   1855     return alternate.append(testCase);
   1856 }
   1857 
   1858 static void generateTestCase(UCollator *coll, Monkey *monkeys[], int32_t monkeyCount, UnicodeString &testCase, UnicodeString &alternate)
   1859 {
   1860     int32_t pieces = (m_rand() % 4) + 1;
   1861     UErrorCode status = U_ZERO_ERROR;
   1862     UBool matches;
   1863 
   1864     do {
   1865         testCase.remove();
   1866         alternate.remove();
   1867         monkeys[0]->append(testCase, alternate);
   1868 
   1869         for(int32_t piece = 0; piece < pieces; piece += 1) {
   1870             int32_t monkey = m_rand() % monkeyCount;
   1871 
   1872             monkeys[monkey]->append(testCase, alternate);
   1873         }
   1874 
   1875         const CEList ceTest(coll, testCase, status);
   1876         const CEList ceAlt(coll, alternate, status);
   1877 
   1878         matches = ceTest.matchesAt(0, &ceAlt);
   1879     } while (! matches);
   1880 }
   1881 
   1882 //
   1883 //  Find the next acceptable boundary following the specified starting index
   1884 //     in the target text being searched.
   1885 //      TODO:  refine what is an acceptable boundary.  For the moment,
   1886 //             choose the next position not within a combining sequence.
   1887 //
   1888 #if 0
   1889 static int32_t nextBoundaryAfter(const UnicodeString &string, int32_t startIndex) {
   1890     const UChar *text = string.getBuffer();
   1891     int32_t textLen   = string.length();
   1892 
   1893     if (startIndex >= textLen) {
   1894         return startIndex;
   1895     }
   1896 
   1897     UChar32  c;
   1898     int32_t  i = startIndex;
   1899 
   1900     U16_NEXT(text, i, textLen, c);
   1901 
   1902     // If we are on a control character, stop without looking for combining marks.
   1903     //    Control characters do not combine.
   1904     int32_t gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
   1905     if (gcProperty==U_GCB_CONTROL || gcProperty==U_GCB_LF || gcProperty==U_GCB_CR) {
   1906         return i;
   1907     }
   1908 
   1909     // The initial character was not a control, and can thus accept trailing
   1910     //   combining characters.  Advance over however many of them there are.
   1911     int32_t  indexOfLastCharChecked;
   1912 
   1913     for (;;) {
   1914         indexOfLastCharChecked = i;
   1915 
   1916         if (i>=textLen) {
   1917             break;
   1918         }
   1919 
   1920         U16_NEXT(text, i, textLen, c);
   1921         gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
   1922 
   1923         if (gcProperty != U_GCB_EXTEND && gcProperty != U_GCB_SPACING_MARK) {
   1924             break;
   1925         }
   1926     }
   1927 
   1928     return indexOfLastCharChecked;
   1929 }
   1930 #endif
   1931 
   1932 #if 0
   1933 static UBool isInCombiningSequence(const UnicodeString &string, int32_t index) {
   1934     const UChar *text = string.getBuffer();
   1935     int32_t textLen   = string.length();
   1936 
   1937     if (index>=textLen || index<=0) {
   1938         return FALSE;
   1939     }
   1940 
   1941     // If the character at the current index is not a GRAPHEME_EXTEND
   1942     //    then we can not be within a combining sequence.
   1943     UChar32  c;
   1944     U16_GET(text, 0, index, textLen, c);
   1945     int32_t gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
   1946     if (gcProperty != U_GCB_EXTEND && gcProperty != U_GCB_SPACING_MARK) {
   1947         return FALSE;
   1948     }
   1949 
   1950     // We are at a combining mark.  If the preceding character is anything
   1951     //   except a CONTROL, CR or LF, we are in a combining sequence.
   1952     U16_PREV(text, 0, index, c);
   1953     gcProperty = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);
   1954 
   1955     return !(gcProperty==U_GCB_CONTROL || gcProperty==U_GCB_LF || gcProperty==U_GCB_CR);
   1956 }
   1957 #endif
   1958 
   1959 static UBool simpleSearch(UCollator *coll, const UnicodeString &target, int32_t offset, const UnicodeString &pattern, int32_t &matchStart, int32_t &matchEnd)
   1960 {
   1961     UErrorCode      status = U_ZERO_ERROR;
   1962     OrderList       targetOrders(coll, target, offset);
   1963     OrderList       patternOrders(coll, pattern);
   1964     int32_t         targetSize  = targetOrders.size() - 1;
   1965     int32_t         patternSize = patternOrders.size() - 1;
   1966     UBreakIterator *charBreakIterator = ubrk_open(UBRK_CHARACTER, ucol_getLocaleByType(coll, ULOC_VALID_LOCALE, &status),
   1967                                                   target.getBuffer(), target.length(), &status);
   1968 
   1969     if (patternSize == 0) {
   1970         // Searching for an empty pattern always fails
   1971         matchStart = matchEnd = -1;
   1972         ubrk_close(charBreakIterator);
   1973         return FALSE;
   1974     }
   1975 
   1976     matchStart = matchEnd = -1;
   1977 
   1978     for(int32_t i = 0; i < targetSize; i += 1) {
   1979         if (targetOrders.matchesAt(i, patternOrders)) {
   1980             int32_t start    = targetOrders.getLowOffset(i);
   1981             int32_t maxLimit = targetOrders.getLowOffset(i + patternSize);
   1982             int32_t minLimit = targetOrders.getLowOffset(i + patternSize - 1);
   1983 
   1984             // if the low and high offsets of the first CE in
   1985             // the match are the same, it means that the match
   1986             // starts in the middle of an expansion - all but
   1987             // the first CE of the expansion will have the offset
   1988             // of the following character.
   1989             if (start == targetOrders.getHighOffset(i)) {
   1990                 continue;
   1991             }
   1992 
   1993             // Make sure match starts on a grapheme boundary
   1994             if (! ubrk_isBoundary(charBreakIterator, start)) {
   1995                 continue;
   1996             }
   1997 
   1998             // If the low and high offsets of the CE after the match
   1999             // are the same, it means that the match ends in the middle
   2000             // of an expansion sequence.
   2001             if (maxLimit == targetOrders.getHighOffset(i + patternSize) &&
   2002                 targetOrders.getOrder(i + patternSize) != UCOL_NULLORDER) {
   2003                 continue;
   2004             }
   2005 
   2006             int32_t mend = maxLimit;
   2007 
   2008             // Find the first grapheme break after the character index
   2009             // of the last CE in the match. If it's after character index
   2010             // that's after the last CE in the match, use that index
   2011             // as the end of the match.
   2012             if (minLimit < maxLimit) {
   2013                 int32_t nba = ubrk_following(charBreakIterator, minLimit);
   2014 
   2015                 if (nba >= targetOrders.getHighOffset(i + patternSize - 1)) {
   2016                     mend = nba;
   2017                 }
   2018             }
   2019 
   2020             if (mend > maxLimit) {
   2021                 continue;
   2022             }
   2023 
   2024             if (! ubrk_isBoundary(charBreakIterator, mend)) {
   2025                 continue;
   2026             }
   2027 
   2028             matchStart = start;
   2029             matchEnd   = mend;
   2030 
   2031             ubrk_close(charBreakIterator);
   2032             return TRUE;
   2033         }
   2034     }
   2035 
   2036     ubrk_close(charBreakIterator);
   2037     return FALSE;
   2038 }
   2039 
   2040 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
   2041 static int32_t  getIntParam(UnicodeString name, UnicodeString &params, int32_t defaultVal) {
   2042     int32_t val = defaultVal;
   2043 
   2044     name.append(" *= *(-?\\d+)");
   2045 
   2046     UErrorCode status = U_ZERO_ERROR;
   2047     RegexMatcher m(name, params, 0, status);
   2048 
   2049     if (m.find()) {
   2050         // The param exists.  Convert the string to an int.
   2051         char valString[100];
   2052         int32_t paramLength = m.end(1, status) - m.start(1, status);
   2053 
   2054         if (paramLength >= (int32_t)(sizeof(valString)-1)) {
   2055             paramLength = (int32_t)(sizeof(valString)-2);
   2056         }
   2057 
   2058         params.extract(m.start(1, status), paramLength, valString, sizeof(valString));
   2059         val = strtol(valString,  NULL, 10);
   2060 
   2061         // Delete this parameter from the params string.
   2062         m.reset();
   2063         params = m.replaceFirst("", status);
   2064     }
   2065 
   2066   //U_ASSERT(U_SUCCESS(status));
   2067     if (! U_SUCCESS(status)) {
   2068         val = defaultVal;
   2069     }
   2070 
   2071     return val;
   2072 }
   2073 #endif
   2074 
   2075 #if !UCONFIG_NO_COLLATION
   2076 int32_t SSearchTest::monkeyTestCase(UCollator *coll, const UnicodeString &testCase, const UnicodeString &pattern, const UnicodeString &altPattern,
   2077                                     const char *name, const char *strength, uint32_t seed)
   2078 {
   2079     UErrorCode status = U_ZERO_ERROR;
   2080     int32_t actualStart = -1, actualEnd = -1;
   2081   //int32_t expectedStart = prefix.length(), expectedEnd = prefix.length() + altPattern.length();
   2082     int32_t expectedStart = -1, expectedEnd = -1;
   2083     int32_t notFoundCount = 0;
   2084     LocalUStringSearchPointer uss(usearch_openFromCollator(pattern.getBuffer(), pattern.length(),
   2085                                                            testCase.getBuffer(), testCase.length(),
   2086                                                            coll,
   2087                                                            NULL,     // the break iterator
   2088                                                            &status));
   2089 
   2090     // **** TODO: find *all* matches, not just first one ****
   2091     simpleSearch(coll, testCase, 0, pattern, expectedStart, expectedEnd);
   2092 
   2093     usearch_search(uss.getAlias(), 0, &actualStart, &actualEnd, &status);
   2094 
   2095     if (expectedStart >= 0 && (actualStart != expectedStart || actualEnd != expectedEnd)) {
   2096         errln("Search for <pattern> in <%s> failed: expected [%d, %d], got [%d, %d]\n"
   2097               "    strength=%s seed=%d",
   2098               name, expectedStart, expectedEnd, actualStart, actualEnd, strength, seed);
   2099     }
   2100 
   2101     if (expectedStart == -1 && actualStart == -1) {
   2102         notFoundCount += 1;
   2103     }
   2104 
   2105     // **** TODO: find *all* matches, not just first one ****
   2106     simpleSearch(coll, testCase, 0, altPattern, expectedStart, expectedEnd);
   2107 
   2108     usearch_setPattern(uss.getAlias(), altPattern.getBuffer(), altPattern.length(), &status);
   2109 
   2110     usearch_search(uss.getAlias(), 0, &actualStart, &actualEnd, &status);
   2111 
   2112     if (expectedStart >= 0 && (actualStart != expectedStart || actualEnd != expectedEnd)) {
   2113         errln("Search for <alt_pattern> in <%s> failed: expected [%d, %d], got [%d, %d]\n"
   2114               "    strength=%s seed=%d",
   2115               name, expectedStart, expectedEnd, actualStart, actualEnd, strength, seed);
   2116     }
   2117 
   2118     if (expectedStart == -1 && actualStart == -1) {
   2119         notFoundCount += 1;
   2120     }
   2121 
   2122     return notFoundCount;
   2123 }
   2124 
   2125 static void hexForUnicodeString(const UnicodeString &ustr, char * cbuf, int32_t cbuflen)
   2126 {
   2127     int32_t ustri, ustrlen = ustr.length();
   2128 
   2129     for (ustri = 0; ustri < ustrlen; ++ustri) {
   2130         if (cbuflen >= 9 /* format width for single code unit(5) + terminating ellipsis(3) + null(1) */) {
   2131             int len = sprintf(cbuf, " %04X", ustr.charAt(ustri));
   2132             cbuflen -= len;
   2133             cbuf += len;
   2134         } else {
   2135             if (cbuflen >= 4 /* terminating ellipsis(3) + null(1) */) {
   2136                 sprintf(cbuf, "...");
   2137             } else if (cbuflen >= 1) {
   2138                 cbuf = 0;
   2139             }
   2140             break;
   2141         }
   2142     }
   2143 }
   2144 
   2145 int32_t SSearchTest::bmMonkeyTestCase(UCollator *coll, const UnicodeString &testCase, const UnicodeString &pattern, const UnicodeString &altPattern,
   2146                                     BoyerMooreSearch *bms, BoyerMooreSearch *abms,
   2147                                     const char *name, const char *strength, uint32_t seed)
   2148 {
   2149     UErrorCode status = U_ZERO_ERROR;
   2150     int32_t actualStart = -1, actualEnd = -1;
   2151   //int32_t expectedStart = prefix.length(), expectedEnd = prefix.length() + altPattern.length();
   2152     int32_t expectedStart = -1, expectedEnd = -1;
   2153     int32_t notFoundCount = 0;
   2154     char    hexbuf[128];
   2155 
   2156     // **** TODO: find *all* matches, not just first one ****
   2157     simpleSearch(coll, testCase, 0, pattern, expectedStart, expectedEnd);
   2158 
   2159     bms->setTargetString(&testCase, status);
   2160     bms->search(0, actualStart, actualEnd);
   2161 
   2162     if (expectedStart >= 0 && (actualStart != expectedStart || actualEnd != expectedEnd)) {
   2163         hexForUnicodeString(pattern, hexbuf, sizeof(hexbuf));
   2164         errln("Boyer-Moore Search for <pattern> in <%s> failed: expected [%d, %d], got [%d, %d]\n"
   2165               "    strength=%s seed=%d <pattern>: %s",
   2166               name, expectedStart, expectedEnd, actualStart, actualEnd, strength, seed, hexbuf);
   2167     }
   2168 
   2169     if (expectedStart == -1 && actualStart == -1) {
   2170         notFoundCount += 1;
   2171     }
   2172 
   2173     // **** TODO: find *all* matches, not just first one ****
   2174     simpleSearch(coll, testCase, 0, altPattern, expectedStart, expectedEnd);
   2175 
   2176     abms->setTargetString(&testCase, status);
   2177     abms->search(0, actualStart, actualEnd);
   2178 
   2179     if (expectedStart >= 0 && (actualStart != expectedStart || actualEnd != expectedEnd)) {
   2180         hexForUnicodeString(altPattern, hexbuf, sizeof(hexbuf));
   2181         errln("Boyer-Moore Search for <alt_pattern> in <%s> failed: expected [%d, %d], got [%d, %d]\n"
   2182               "    strength=%s seed=%d <pattern>: %s",
   2183               name, expectedStart, expectedEnd, actualStart, actualEnd, strength, seed, hexbuf);
   2184     }
   2185 
   2186     if (expectedStart == -1 && actualStart == -1) {
   2187         notFoundCount += 1;
   2188     }
   2189 
   2190 
   2191     return notFoundCount;
   2192 }
   2193 #endif
   2194 
   2195 void SSearchTest::monkeyTest(char *params)
   2196 {
   2197     // ook!
   2198     UErrorCode status = U_ZERO_ERROR;
   2199   //UCollator *coll = ucol_open(NULL, &status);
   2200     UCollator *coll = ucol_openFromShortString("S1", FALSE, NULL, &status);
   2201 
   2202     if (U_FAILURE(status)) {
   2203         errcheckln(status, "Failed to create collator in MonkeyTest! - %s", u_errorName(status));
   2204         return;
   2205     }
   2206 
   2207     CollData  *monkeyData = CollData::open(coll, status);
   2208 
   2209     USet *expansions   = uset_openEmpty();
   2210     USet *contractions = uset_openEmpty();
   2211 
   2212     ucol_getContractionsAndExpansions(coll, contractions, expansions, FALSE, &status);
   2213 
   2214     U_STRING_DECL(letter_pattern, "[[:letter:]-[:ideographic:]-[:hangul:]]", 39);
   2215     U_STRING_INIT(letter_pattern, "[[:letter:]-[:ideographic:]-[:hangul:]]", 39);
   2216     USet *letters = uset_openPattern(letter_pattern, 39, &status);
   2217     SetMonkey letterMonkey(letters);
   2218     StringSetMonkey contractionMonkey(contractions, coll, monkeyData);
   2219     StringSetMonkey expansionMonkey(expansions, coll, monkeyData);
   2220     UnicodeString testCase;
   2221     UnicodeString alternate;
   2222     UnicodeString pattern, altPattern;
   2223     UnicodeString prefix, altPrefix;
   2224     UnicodeString suffix, altSuffix;
   2225 
   2226     Monkey *monkeys[] = {
   2227         &letterMonkey,
   2228         &contractionMonkey,
   2229         &expansionMonkey,
   2230         &contractionMonkey,
   2231         &expansionMonkey,
   2232         &contractionMonkey,
   2233         &expansionMonkey,
   2234         &contractionMonkey,
   2235         &expansionMonkey};
   2236     int32_t monkeyCount = sizeof(monkeys) / sizeof(monkeys[0]);
   2237     // int32_t nonMatchCount = 0;
   2238 
   2239     UCollationStrength strengths[] = {UCOL_PRIMARY, UCOL_SECONDARY, UCOL_TERTIARY};
   2240     const char *strengthNames[] = {"primary", "secondary", "tertiary"};
   2241     int32_t strengthCount = sizeof(strengths) / sizeof(strengths[0]);
   2242     int32_t loopCount = quick? 1000 : 10000;
   2243     int32_t firstStrength = 0;
   2244     int32_t lastStrength  = strengthCount - 1; //*/ 0;
   2245 
   2246     if (params != NULL) {
   2247 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
   2248         UnicodeString p(params);
   2249 
   2250         loopCount = getIntParam("loop", p, loopCount);
   2251         m_seed    = getIntParam("seed", p, m_seed);
   2252 
   2253         RegexMatcher m(" *strength *= *(primary|secondary|tertiary) *", p, 0, status);
   2254         if (m.find()) {
   2255             UnicodeString breakType = m.group(1, status);
   2256 
   2257             for (int32_t s = 0; s < strengthCount; s += 1) {
   2258                 if (breakType == strengthNames[s]) {
   2259                     firstStrength = lastStrength = s;
   2260                     break;
   2261                 }
   2262             }
   2263 
   2264             m.reset();
   2265             p = m.replaceFirst("", status);
   2266         }
   2267 
   2268         if (RegexMatcher("\\S", p, 0, status).find()) {
   2269             // Each option is stripped out of the option string as it is processed.
   2270             // All options have been checked.  The option string should have been completely emptied..
   2271             char buf[100];
   2272             p.extract(buf, sizeof(buf), NULL, status);
   2273             buf[sizeof(buf)-1] = 0;
   2274             errln("Unrecognized or extra parameter:  %s\n", buf);
   2275             return;
   2276         }
   2277 #else
   2278         infoln("SSearchTest built with UCONFIG_NO_REGULAR_EXPRESSIONS: ignoring parameters.");
   2279 #endif
   2280     }
   2281 
   2282     for(int32_t s = firstStrength; s <= lastStrength; s += 1) {
   2283         int32_t notFoundCount = 0;
   2284 
   2285         logln("Setting strength to %s.", strengthNames[s]);
   2286         ucol_setStrength(coll, strengths[s]);
   2287 
   2288         // TODO: try alternate prefix and suffix too?
   2289         // TODO: alterntaes are only equal at primary strength. Is this OK?
   2290         for(int32_t t = 0; t < loopCount; t += 1) {
   2291             uint32_t seed = m_seed;
   2292             // int32_t  nmc = 0;
   2293 
   2294             generateTestCase(coll, monkeys, monkeyCount, pattern, altPattern);
   2295             generateTestCase(coll, monkeys, monkeyCount, prefix,  altPrefix);
   2296             generateTestCase(coll, monkeys, monkeyCount, suffix,  altSuffix);
   2297 
   2298             // pattern
   2299             notFoundCount += monkeyTestCase(coll, pattern, pattern, altPattern, "pattern", strengthNames[s], seed);
   2300 
   2301             testCase.remove();
   2302             testCase.append(prefix);
   2303             testCase.append(/*alt*/pattern);
   2304 
   2305             // prefix + pattern
   2306             notFoundCount += monkeyTestCase(coll, testCase, pattern, altPattern, "prefix + pattern", strengthNames[s], seed);
   2307 
   2308             testCase.append(suffix);
   2309 
   2310             // prefix + pattern + suffix
   2311             notFoundCount += monkeyTestCase(coll, testCase, pattern, altPattern, "prefix + pattern + suffix", strengthNames[s], seed);
   2312 
   2313             testCase.remove();
   2314             testCase.append(pattern);
   2315             testCase.append(suffix);
   2316 
   2317             // pattern + suffix
   2318             notFoundCount += monkeyTestCase(coll, testCase, pattern, altPattern, "pattern + suffix", strengthNames[s], seed);
   2319         }
   2320 
   2321        logln("For strength %s the not found count is %d.", strengthNames[s], notFoundCount);
   2322     }
   2323 
   2324     uset_close(contractions);
   2325     uset_close(expansions);
   2326     uset_close(letters);
   2327 
   2328     CollData::close(monkeyData);
   2329 
   2330     ucol_close(coll);
   2331 }
   2332 
   2333 void SSearchTest::bmMonkeyTest(char *params)
   2334 {
   2335     static const UVersionInfo icu47 = { 4, 7, 0, 0 }; // for timebomb
   2336     static const UChar skipChars[] = { 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0xAAB5, 0xAAB6, 0xAAB9, 0xAABB, 0xAABC, 0 }; // for timebomb
   2337     // ook!
   2338     UErrorCode status = U_ZERO_ERROR;
   2339     UCollator *coll = ucol_openFromShortString("LEN_S1", FALSE, NULL, &status);
   2340 
   2341     if (U_FAILURE(status)) {
   2342         errcheckln(status, "Failed to create collator in MonkeyTest! - %s", u_errorName(status));
   2343         return;
   2344     }
   2345 
   2346     CollData  *monkeyData = CollData::open(coll, status);
   2347 
   2348     USet *expansions   = uset_openEmpty();
   2349     USet *contractions = uset_openEmpty();
   2350 
   2351     ucol_getContractionsAndExpansions(coll, contractions, expansions, FALSE, &status);
   2352 
   2353     U_STRING_DECL(letter_pattern, "[[:letter:]-[:ideographic:]-[:hangul:]]", 39);
   2354     U_STRING_INIT(letter_pattern, "[[:letter:]-[:ideographic:]-[:hangul:]]", 39);
   2355     USet *letters = uset_openPattern(letter_pattern, 39, &status);
   2356     SetMonkey letterMonkey(letters);
   2357     StringSetMonkey contractionMonkey(contractions, coll, monkeyData);
   2358     StringSetMonkey expansionMonkey(expansions, coll, monkeyData);
   2359     UnicodeString testCase;
   2360     UnicodeString alternate;
   2361     UnicodeString pattern, altPattern;
   2362     UnicodeString prefix, altPrefix;
   2363     UnicodeString suffix, altSuffix;
   2364 
   2365     Monkey *monkeys[] = {
   2366         &letterMonkey,
   2367         &contractionMonkey,
   2368         &expansionMonkey,
   2369         &contractionMonkey,
   2370         &expansionMonkey,
   2371         &contractionMonkey,
   2372         &expansionMonkey,
   2373         &contractionMonkey,
   2374         &expansionMonkey};
   2375     int32_t monkeyCount = sizeof(monkeys) / sizeof(monkeys[0]);
   2376     // int32_t nonMatchCount = 0;
   2377 
   2378     UCollationStrength strengths[] = {UCOL_PRIMARY, UCOL_SECONDARY, UCOL_TERTIARY};
   2379     const char *strengthNames[] = {"primary", "secondary", "tertiary"};
   2380     int32_t strengthCount = sizeof(strengths) / sizeof(strengths[0]);
   2381     int32_t loopCount = quick? 1000 : 10000;
   2382     int32_t firstStrength = 0;
   2383     int32_t lastStrength  = strengthCount - 1; //*/ 0;
   2384 
   2385     if (params != NULL) {
   2386 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
   2387         UnicodeString p(params);
   2388 
   2389         loopCount = getIntParam("loop", p, loopCount);
   2390         m_seed    = getIntParam("seed", p, m_seed);
   2391 
   2392         RegexMatcher m(" *strength *= *(primary|secondary|tertiary) *", p, 0, status);
   2393         if (m.find()) {
   2394             UnicodeString breakType = m.group(1, status);
   2395 
   2396             for (int32_t s = 0; s < strengthCount; s += 1) {
   2397                 if (breakType == strengthNames[s]) {
   2398                     firstStrength = lastStrength = s;
   2399                     break;
   2400                 }
   2401             }
   2402 
   2403             m.reset();
   2404             p = m.replaceFirst("", status);
   2405         }
   2406 
   2407         if (RegexMatcher("\\S", p, 0, status).find()) {
   2408             // Each option is stripped out of the option string as it is processed.
   2409             // All options have been checked.  The option string should have been completely emptied..
   2410             char buf[100];
   2411             p.extract(buf, sizeof(buf), NULL, status);
   2412             buf[sizeof(buf)-1] = 0;
   2413             errln("Unrecognized or extra parameter:  %s\n", buf);
   2414             return;
   2415         }
   2416 #else
   2417         infoln("SSearchTest built with UCONFIG_NO_REGULAR_EXPRESSIONS: ignoring parameters.");
   2418 #endif
   2419     }
   2420 
   2421     for(int32_t s = firstStrength; s <= lastStrength; s += 1) {
   2422         int32_t notFoundCount = 0;
   2423 
   2424         logln("Setting strength to %s.", strengthNames[s]);
   2425         ucol_setStrength(coll, strengths[s]);
   2426 
   2427         CollData *data = CollData::open(coll, status);
   2428 
   2429         UnicodeString skipString(skipChars); // for timebomb
   2430         UnicodeSet* skipSet = UnicodeSet::createFromAll(skipString); // for timebomb
   2431         // TODO: try alternate prefix and suffix too?
   2432         // TODO: alterntaes are only equal at primary strength. Is this OK?
   2433         for(int32_t t = 0; t < loopCount; t += 1) {
   2434             uint32_t seed = m_seed;
   2435             // int32_t  nmc = 0;
   2436 
   2437             generateTestCase(coll, monkeys, monkeyCount, pattern, altPattern);
   2438             generateTestCase(coll, monkeys, monkeyCount, prefix,  altPrefix);
   2439             generateTestCase(coll, monkeys, monkeyCount, suffix,  altSuffix);
   2440 
   2441             if (!isICUVersionAtLeast(icu47) && skipSet->containsSome(pattern)) {
   2442                 continue; // timebomb until ticket #8080 is resolved
   2443             }
   2444 
   2445             BoyerMooreSearch pat(data, pattern, NULL, status);
   2446             BoyerMooreSearch alt(data, altPattern, NULL, status);
   2447 
   2448             // **** need a better way to deal with this ****
   2449 #if 0
   2450             if (pat.empty() ||
   2451                 alt.empty()) {
   2452                     continue;
   2453             }
   2454 #endif
   2455 
   2456             // pattern
   2457             notFoundCount += bmMonkeyTestCase(coll, pattern, pattern, altPattern, &pat, &alt, "pattern", strengthNames[s], seed);
   2458 
   2459             testCase.remove();
   2460             testCase.append(prefix);
   2461             testCase.append(/*alt*/pattern);
   2462 
   2463             // prefix + pattern
   2464             notFoundCount += bmMonkeyTestCase(coll, testCase, pattern, altPattern, &pat, &alt, "prefix + pattern", strengthNames[s], seed);
   2465 
   2466             testCase.append(suffix);
   2467 
   2468             // prefix + pattern + suffix
   2469             notFoundCount += bmMonkeyTestCase(coll, testCase, pattern, altPattern, &pat, &alt, "prefix + pattern + suffix", strengthNames[s], seed);
   2470 
   2471             testCase.remove();
   2472             testCase.append(pattern);
   2473             testCase.append(suffix);
   2474 
   2475             // pattern + suffix
   2476             notFoundCount += bmMonkeyTestCase(coll, testCase, pattern, altPattern, &pat, &alt, "pattern + suffix", strengthNames[s], seed);
   2477         }
   2478         delete skipSet; // for timebomb
   2479 
   2480         CollData::close(data);
   2481 
   2482         logln("For strength %s the not found count is %d.", strengthNames[s], notFoundCount);
   2483     }
   2484 
   2485     uset_close(contractions);
   2486     uset_close(expansions);
   2487     uset_close(letters);
   2488 
   2489     CollData::close(monkeyData);
   2490 
   2491     ucol_close(coll);
   2492 }
   2493 
   2494 void SSearchTest::stringListTest(){
   2495     UErrorCode status = U_ZERO_ERROR;
   2496     StringList *sl = new StringList(status);
   2497     if(U_FAILURE(status)){
   2498         errln("ERROR: stringListTest: Could not start StringList");
   2499     }
   2500 
   2501     const UChar chars[] = {
   2502             0x0000
   2503     };
   2504     sl->add(chars, (int32_t) 0, status);
   2505     if(U_FAILURE(status)){
   2506         errln("ERROR: stringListTest: StringList::add");
   2507     }
   2508 
   2509     if(sl->getDynamicClassID() != StringList::getStaticClassID()){
   2510         errln("ERROR: stringListTest: getDynamicClassID and getStaticClassID does not match");
   2511     }
   2512     delete sl;
   2513 }
   2514 
   2515 #endif
   2516 
   2517 #endif
   2518