Home | History | Annotate | Download | only in cintltst
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1997-2011, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 /*   file name:  cbiditst.cpp
      7 *   encoding:   US-ASCII
      8 *   tab size:   8 (not used)
      9 *   indentation:4
     10 *
     11 *   created on: 1999sep27
     12 *   created by: Markus W. Scherer, updated by Matitiahu Allouche
     13 */
     14 
     15 #include "cintltst.h"
     16 #include "unicode/utypes.h"
     17 #include "unicode/uchar.h"
     18 #include "unicode/ustring.h"
     19 #include "unicode/ubidi.h"
     20 #include "unicode/ushape.h"
     21 #include "cbiditst.h"
     22 #include "cstring.h"
     23 /* the following include is needed for sprintf */
     24 #include <stdio.h>
     25 
     26 #define MAXLEN      MAX_STRING_LENGTH
     27 #define LENGTHOF(array) (sizeof(array)/sizeof((array)[0]))
     28 
     29 /* prototypes ---------------------------------------------------------------*/
     30 
     31 void addComplexTest(TestNode** root);
     32 
     33 static void testCharFromDirProp(void);
     34 
     35 static void testBidi(void);
     36 
     37 static void doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst);
     38 
     39 static void doMisc(void);
     40 
     41 static void doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test,
     42                    int32_t lineStart, UBool countRunsFirst);
     43 
     44 static void _testReordering(UBiDi *pBiDi, int testNumber);
     45 
     46 static void testInverse(void);
     47 
     48 static void _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction);
     49 
     50 static void _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
     51                              UBiDiLevel direction, UErrorCode *pErrorCode);
     52 
     53 static void _testWriteReverse(void);
     54 
     55 static void _testManyAddedPoints(void);
     56 
     57 static void _testMisc(void);
     58 
     59 static void doArabicShapingTest(void);
     60 
     61 static void doLamAlefSpecialVLTRArabicShapingTest(void);
     62 
     63 static void doTashkeelSpecialVLTRArabicShapingTest(void);
     64 
     65 static void doLOGICALArabicDeShapingTest(void);
     66 
     67 static void doArabicShapingTestForBug5421(void);
     68 
     69 static void testReorder(void);
     70 
     71 static void testFailureRecovery(void);
     72 
     73 static void testMultipleParagraphs(void);
     74 
     75 static void testGetBaseDirection(void);
     76 
     77 static void testContext(void);
     78 
     79 static void doTailTest(void);
     80 
     81 /* new BIDI API */
     82 static void testReorderingMode(void);
     83 static void testReorderRunsOnly(void);
     84 static void testStreaming(void);
     85 static void testClassOverride(void);
     86 static const char* inverseBasic(UBiDi *pBiDi, const char *src, int32_t srcLen,
     87                                 uint32_t option, UBiDiLevel level, char *result);
     88 static UBool assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex,
     89                              const char *srcChars, const char *destChars,
     90                              const UChar *dest, int32_t destLen, int mode,
     91                              int option, UBiDiLevel level);
     92 static UBool checkResultLength(UBiDi *pBiDi, const char *srcChars,
     93                                const char *destChars,
     94                                int32_t destLen, const char *mode,
     95                                const char *option, UBiDiLevel level);
     96 static UBool checkMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src,
     97                        const char *dest, const char *mode, const char* option,
     98                        UBiDiLevel level, UBool forward);
     99 
    100 /* helpers ------------------------------------------------------------------ */
    101 
    102 static const char *levelString="...............................................................";
    103 
    104 static void initCharFromDirProps(void);
    105 
    106 static UChar *
    107 getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer);
    108 
    109 static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels);
    110 
    111 /* regression tests ---------------------------------------------------------*/
    112 
    113 void
    114 addComplexTest(TestNode** root) {
    115     addTest(root, testCharFromDirProp, "complex/bidi/TestCharFromDirProp");
    116     addTest(root, testBidi, "complex/bidi/TestBidi");
    117     addTest(root, testInverse, "complex/bidi/TestInverse");
    118     addTest(root, testReorder,"complex/bidi/TestReorder");
    119     addTest(root, testFailureRecovery,"complex/bidi/TestFailureRecovery");
    120     addTest(root, testMultipleParagraphs,"complex/bidi/TestMultipleParagraphs");
    121     addTest(root, testReorderingMode, "complex/bidi/TestReorderingMode");
    122     addTest(root, testReorderRunsOnly, "complex/bidi/TestReorderRunsOnly");
    123     addTest(root, testStreaming, "complex/bidi/TestStreaming");
    124     addTest(root, testClassOverride, "complex/bidi/TestClassOverride");
    125     addTest(root, testGetBaseDirection, "complex/bidi/testGetBaseDirection");
    126     addTest(root, testContext, "complex/bidi/testContext");
    127 
    128     addTest(root, doArabicShapingTest, "complex/arabic-shaping/ArabicShapingTest");
    129     addTest(root, doLamAlefSpecialVLTRArabicShapingTest, "complex/arabic-shaping/lamalef");
    130     addTest(root, doTashkeelSpecialVLTRArabicShapingTest, "complex/arabic-shaping/tashkeel");
    131     addTest(root, doLOGICALArabicDeShapingTest, "complex/arabic-shaping/unshaping");
    132     addTest(root, doArabicShapingTestForBug5421, "complex/arabic-shaping/bug-5421");
    133     addTest(root, doTailTest, "complex/arabic-shaping/tailtest");
    134 }
    135 
    136 static void
    137 testCharFromDirProp(void) {
    138     /* verify that the exemplar characters have the expected bidi classes */
    139     int32_t i;
    140 
    141     log_verbose("\nEntering TestCharFromDirProp\n\n");
    142     initCharFromDirProps();
    143 
    144     for(i=0; i<U_CHAR_DIRECTION_COUNT; ++i) {
    145         if(u_charDirection(charFromDirProp[i])!=(UCharDirection)i) {
    146             log_err("\nu_charDirection(charFromDirProp[%d]=U+%04x)==%d!=%d\n",
    147                     i, charFromDirProp[i], u_charDirection(charFromDirProp[i]), i);
    148         }
    149     }
    150     log_verbose("\nExiting TestCharFromDirProp\n\n");
    151 }
    152 
    153 static void
    154 testBidi(void) {
    155     UBiDi *pBiDi, *pLine=NULL;
    156     UErrorCode errorCode=U_ZERO_ERROR;
    157 
    158     log_verbose("\nEntering TestBidi\n\n");
    159 
    160     pBiDi=ubidi_openSized(MAXLEN, 0, &errorCode);
    161     if(pBiDi!=NULL) {
    162         pLine=ubidi_open();
    163         if(pLine!=NULL) {
    164             doTests(pBiDi, pLine, FALSE);
    165             doTests(pBiDi, pLine, TRUE);
    166         } else {
    167             log_err("ubidi_open() returned NULL, out of memory\n");
    168         }
    169     } else {
    170         log_err("ubidi_openSized() returned NULL, errorCode %s\n", myErrorName(errorCode));
    171     }
    172     doMisc();
    173 
    174     if(pLine!=NULL) {
    175         ubidi_close(pLine);
    176     }
    177     if(pBiDi!=NULL) {
    178         ubidi_close(pBiDi);
    179     }
    180 
    181     log_verbose("\nExiting TestBidi\n\n");
    182 }
    183 
    184 static void
    185 doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst) {
    186     int testNumber;
    187     UChar string[MAXLEN];
    188     UErrorCode errorCode;
    189     int32_t lineStart;
    190     UBiDiLevel paraLevel;
    191 
    192     for(testNumber=0; testNumber<bidiTestCount; ++testNumber) {
    193         errorCode=U_ZERO_ERROR;
    194         getStringFromDirProps(tests[testNumber].text, tests[testNumber].length, string);
    195         paraLevel=tests[testNumber].paraLevel;
    196         ubidi_setPara(pBiDi, string, -1, paraLevel, NULL, &errorCode);
    197         if(U_SUCCESS(errorCode)) {
    198             log_verbose("ubidi_setPara(tests[%d], paraLevel %d) ok, direction %d paraLevel=%d\n",
    199                     testNumber, paraLevel, ubidi_getDirection(pBiDi), paraLevel);
    200             lineStart=tests[testNumber].lineStart;
    201             if(lineStart==-1) {
    202                 doTest(pBiDi, testNumber, tests+testNumber, 0, countRunsFirst);
    203             } else {
    204                 ubidi_setLine(pBiDi, lineStart, tests[testNumber].lineLimit, pLine, &errorCode);
    205                 if(U_SUCCESS(errorCode)) {
    206                     log_verbose("ubidi_setLine(%d, %d) ok, direction %d paraLevel=%d\n",
    207                             lineStart, tests[testNumber].lineLimit, ubidi_getDirection(pLine), ubidi_getParaLevel(pLine));
    208                     doTest(pLine, testNumber, tests+testNumber, lineStart, countRunsFirst);
    209                 } else {
    210                     log_err("ubidi_setLine(tests[%d], %d, %d) failed with errorCode %s\n",
    211                             testNumber, lineStart, tests[testNumber].lineLimit, myErrorName(errorCode));
    212                 }
    213             }
    214         } else {
    215             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    216                     testNumber, paraLevel, myErrorName(errorCode));
    217         }
    218     }
    219 }
    220 
    221 static const char columns[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    222 
    223 #define TABLE_SIZE  256
    224 static UBool   tablesInitialized = FALSE;
    225 static UChar   pseudoToUChar[TABLE_SIZE];
    226 static uint8_t UCharToPseudo[TABLE_SIZE];    /* used for Unicode chars < 0x0100 */
    227 static uint8_t UCharToPseud2[TABLE_SIZE];    /* used for Unicode chars >=0x0100 */
    228 
    229 static void buildPseudoTables(void)
    230 /*
    231     The rules for pseudo-Bidi are as follows:
    232     - [ == LRE
    233     - ] == RLE
    234     - { == LRO
    235     - } == RLO
    236     - ^ == PDF
    237     - @ == LRM
    238     - & == RLM
    239     - A-F == Arabic Letters 0631-0636
    240     - G-V == Hebrew letters 05d7-05e6
    241     - W-Z == Unassigned RTL 08d0-08d3
    242     - 0-5 == western digits 0030-0035
    243     - 6-9 == Arabic-Indic digits 0666-0669
    244     - ` == Combining Grave Accent 0300 (NSM)
    245     - ~ == Delete 007f (BN)
    246     - | == Paragraph Separator 2029 (B)
    247     - _ == Info Separator 1 001f (S)
    248     All other characters represent themselves as Latin-1, with the corresponding
    249     Bidi properties.
    250 */
    251 {
    252     int             i;
    253     UChar           uchar;
    254     uint8_t         c;
    255     /* initialize all tables to unknown */
    256     for (i=0; i < TABLE_SIZE; i++) {
    257         pseudoToUChar[i] = 0xFFFD;
    258         UCharToPseudo[i] = '?';
    259         UCharToPseud2[i] = '?';
    260     }
    261     /* initialize non letters or digits */
    262     pseudoToUChar[(uint8_t) 0 ] = 0x0000;    UCharToPseudo[0x00] = (uint8_t) 0 ;
    263     pseudoToUChar[(uint8_t)' '] = 0x0020;    UCharToPseudo[0x20] = (uint8_t)' ';
    264     pseudoToUChar[(uint8_t)'!'] = 0x0021;    UCharToPseudo[0x21] = (uint8_t)'!';
    265     pseudoToUChar[(uint8_t)'"'] = 0x0022;    UCharToPseudo[0x22] = (uint8_t)'"';
    266     pseudoToUChar[(uint8_t)'#'] = 0x0023;    UCharToPseudo[0x23] = (uint8_t)'#';
    267     pseudoToUChar[(uint8_t)'$'] = 0x0024;    UCharToPseudo[0x24] = (uint8_t)'$';
    268     pseudoToUChar[(uint8_t)'%'] = 0x0025;    UCharToPseudo[0x25] = (uint8_t)'%';
    269     pseudoToUChar[(uint8_t)'\'']= 0x0027;    UCharToPseudo[0x27] = (uint8_t)'\'';
    270     pseudoToUChar[(uint8_t)'('] = 0x0028;    UCharToPseudo[0x28] = (uint8_t)'(';
    271     pseudoToUChar[(uint8_t)')'] = 0x0029;    UCharToPseudo[0x29] = (uint8_t)')';
    272     pseudoToUChar[(uint8_t)'*'] = 0x002A;    UCharToPseudo[0x2A] = (uint8_t)'*';
    273     pseudoToUChar[(uint8_t)'+'] = 0x002B;    UCharToPseudo[0x2B] = (uint8_t)'+';
    274     pseudoToUChar[(uint8_t)','] = 0x002C;    UCharToPseudo[0x2C] = (uint8_t)',';
    275     pseudoToUChar[(uint8_t)'-'] = 0x002D;    UCharToPseudo[0x2D] = (uint8_t)'-';
    276     pseudoToUChar[(uint8_t)'.'] = 0x002E;    UCharToPseudo[0x2E] = (uint8_t)'.';
    277     pseudoToUChar[(uint8_t)'/'] = 0x002F;    UCharToPseudo[0x2F] = (uint8_t)'/';
    278     pseudoToUChar[(uint8_t)':'] = 0x003A;    UCharToPseudo[0x3A] = (uint8_t)':';
    279     pseudoToUChar[(uint8_t)';'] = 0x003B;    UCharToPseudo[0x3B] = (uint8_t)';';
    280     pseudoToUChar[(uint8_t)'<'] = 0x003C;    UCharToPseudo[0x3C] = (uint8_t)'<';
    281     pseudoToUChar[(uint8_t)'='] = 0x003D;    UCharToPseudo[0x3D] = (uint8_t)'=';
    282     pseudoToUChar[(uint8_t)'>'] = 0x003E;    UCharToPseudo[0x3E] = (uint8_t)'>';
    283     pseudoToUChar[(uint8_t)'?'] = 0x003F;    UCharToPseudo[0x3F] = (uint8_t)'?';
    284     pseudoToUChar[(uint8_t)'\\']= 0x005C;    UCharToPseudo[0x5C] = (uint8_t)'\\';
    285     /* initialize specially used characters */
    286     pseudoToUChar[(uint8_t)'`'] = 0x0300;    UCharToPseud2[0x00] = (uint8_t)'`';  /* NSM */
    287     pseudoToUChar[(uint8_t)'@'] = 0x200E;    UCharToPseud2[0x0E] = (uint8_t)'@';  /* LRM */
    288     pseudoToUChar[(uint8_t)'&'] = 0x200F;    UCharToPseud2[0x0F] = (uint8_t)'&';  /* RLM */
    289     pseudoToUChar[(uint8_t)'_'] = 0x001F;    UCharToPseudo[0x1F] = (uint8_t)'_';  /* S   */
    290     pseudoToUChar[(uint8_t)'|'] = 0x2029;    UCharToPseud2[0x29] = (uint8_t)'|';  /* B   */
    291     pseudoToUChar[(uint8_t)'['] = 0x202A;    UCharToPseud2[0x2A] = (uint8_t)'[';  /* LRE */
    292     pseudoToUChar[(uint8_t)']'] = 0x202B;    UCharToPseud2[0x2B] = (uint8_t)']';  /* RLE */
    293     pseudoToUChar[(uint8_t)'^'] = 0x202C;    UCharToPseud2[0x2C] = (uint8_t)'^';  /* PDF */
    294     pseudoToUChar[(uint8_t)'{'] = 0x202D;    UCharToPseud2[0x2D] = (uint8_t)'{';  /* LRO */
    295     pseudoToUChar[(uint8_t)'}'] = 0x202E;    UCharToPseud2[0x2E] = (uint8_t)'}';  /* RLO */
    296     pseudoToUChar[(uint8_t)'~'] = 0x007F;    UCharToPseudo[0x7F] = (uint8_t)'~';  /* BN  */
    297     /* initialize western digits */
    298     for (i = 0, uchar = 0x0030; i < 6; i++, uchar++) {
    299         c = (uint8_t)columns[i];
    300         pseudoToUChar[c] = uchar;
    301         UCharToPseudo[uchar & 0x00ff] = c;
    302     }
    303     /* initialize Hindi digits */
    304     for (i = 6, uchar = 0x0666; i < 10; i++, uchar++) {
    305         c = (uint8_t)columns[i];
    306         pseudoToUChar[c] = uchar;
    307         UCharToPseud2[uchar & 0x00ff] = c;
    308     }
    309     /* initialize Arabic letters */
    310     for (i = 10, uchar = 0x0631; i < 16; i++, uchar++) {
    311         c = (uint8_t)columns[i];
    312         pseudoToUChar[c] = uchar;
    313         UCharToPseud2[uchar & 0x00ff] = c;
    314     }
    315     /* initialize Hebrew letters */
    316     for (i = 16, uchar = 0x05D7; i < 32; i++, uchar++) {
    317         c = (uint8_t)columns[i];
    318         pseudoToUChar[c] = uchar;
    319         UCharToPseud2[uchar & 0x00ff] = c;
    320     }
    321     /* initialize Unassigned code points */
    322     for (i = 32, uchar=0x08D0; i < 36; i++, uchar++) {
    323         c = (uint8_t)columns[i];
    324         pseudoToUChar[c] = uchar;
    325         UCharToPseud2[uchar & 0x00ff] = c;
    326     }
    327     /* initialize Latin lower case letters */
    328     for (i = 36, uchar = 0x0061; i < 62; i++, uchar++) {
    329         c = (uint8_t)columns[i];
    330         pseudoToUChar[c] = uchar;
    331         UCharToPseudo[uchar & 0x00ff] = c;
    332     }
    333     tablesInitialized = TRUE;
    334 }
    335 
    336 /*----------------------------------------------------------------------*/
    337 
    338 static int pseudoToU16(const int length, const char * input, UChar * output)
    339 /*  This function converts a pseudo-Bidi string into a UChar string.
    340     It returns the length of the UChar string.
    341 */
    342 {
    343     int             i;
    344     if (!tablesInitialized) {
    345         buildPseudoTables();
    346     }
    347     for (i = 0; i < length; i++)
    348         output[i] = pseudoToUChar[(uint8_t)input[i]];
    349     output[length] = 0;
    350     return length;
    351 }
    352 
    353 /*----------------------------------------------------------------------*/
    354 
    355 static int u16ToPseudo(const int length, const UChar * input, char * output)
    356 /*  This function converts a UChar string into a pseudo-Bidi string.
    357     It returns the length of the pseudo-Bidi string.
    358 */
    359 {
    360     int             i;
    361     UChar           uchar;
    362     if (!tablesInitialized) {
    363         buildPseudoTables();
    364     }
    365     for (i = 0; i < length; i++)
    366     {
    367         uchar = input[i];
    368         output[i] = uchar < 0x0100 ? UCharToPseudo[uchar] :
    369                                         UCharToPseud2[uchar & 0x00ff];
    370     }
    371     output[length] = '\0';
    372     return length;
    373 }
    374 
    375 static char * formatLevels(UBiDi *bidi, char *buffer) {
    376     UErrorCode ec = U_ZERO_ERROR;
    377     const UBiDiLevel* gotLevels = ubidi_getLevels(bidi, &ec);
    378     int len = ubidi_getLength(bidi);
    379     char c;
    380     int i, k;
    381 
    382     if(U_FAILURE(ec)) {
    383         strcpy(buffer, "BAD LEVELS");
    384         return buffer;
    385     }
    386     for (i=0; i<len; i++) {
    387         k = gotLevels[i];
    388         if (k >= sizeof(columns))
    389             c = '+';
    390         else
    391             c = columns[k];
    392         buffer[i] = c;
    393     }
    394     buffer[len] = '\0';
    395     return buffer;
    396 }
    397 static const char *reorderingModeNames[] = {
    398     "UBIDI_REORDER_DEFAULT",
    399     "UBIDI_REORDER_NUMBERS_SPECIAL",
    400     "UBIDI_REORDER_GROUP_NUMBERS_WITH_R",
    401     "UBIDI_REORDER_RUNS_ONLY",
    402     "UBIDI_REORDER_INVERSE_NUMBERS_AS_L",
    403     "UBIDI_REORDER_INVERSE_LIKE_DIRECT",
    404     "UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL"};
    405 
    406 static char *reorderingOptionNames(char *buffer, int options) {
    407     buffer[0] = 0;
    408     if (options & UBIDI_OPTION_INSERT_MARKS) {
    409         strcat(buffer, " UBIDI_OPTION_INSERT_MARKS");
    410     }
    411     if (options & UBIDI_OPTION_REMOVE_CONTROLS) {
    412         strcat(buffer, " UBIDI_OPTION_REMOVE_CONTROLS");
    413     }
    414     if (options & UBIDI_OPTION_STREAMING) {
    415         strcat(buffer, " UBIDI_OPTION_STREAMING");
    416     }
    417     return buffer;
    418 }
    419 
    420 static void printCaseInfo(UBiDi *bidi, const char *src, const char *dst)
    421 /* src and dst are char arrays encoded as pseudo Bidi */
    422 {
    423     /* Since calls to log_err with a \n within the pattern increment the
    424      * error count, new lines are issued via fputs, except when we want the
    425      * increment to happen.
    426      */
    427     UErrorCode errorCode=U_ZERO_ERROR;
    428     int32_t i, length = ubidi_getProcessedLength(bidi);
    429     const UBiDiLevel *levels;
    430     char levelChars[MAXLEN];
    431     UBiDiLevel lev;
    432     int32_t runCount;
    433     char buffer[100];
    434     log_err("========================================"); fputs("\n", stderr);
    435     levels = ubidi_getLevels(bidi, &errorCode);
    436     if (U_FAILURE(errorCode)) {
    437         strcpy(levelChars, "BAD LEVELS");
    438     } else {
    439         log_err("Processed length: %d", length); fputs("\n", stderr);
    440         for (i = 0; i < length; i++) {
    441             lev = levels[i];
    442             if (lev < sizeof(columns)) {
    443                 levelChars[i] = columns[lev];
    444             } else {
    445                 levelChars[i] = '+';
    446             }
    447         }
    448         levelChars[length] = 0;
    449     }
    450     log_err("Levels: %s", levelChars); fputs("\n", stderr);
    451     log_err("Source: %s", src); fputs("\n", stderr);
    452     log_err("Result: %s", dst); fputs("\n", stderr);
    453     log_err("Direction: %d", ubidi_getDirection(bidi)); fputs("\n", stderr);
    454     log_err("paraLevel: %d", ubidi_getParaLevel(bidi)); fputs("\n", stderr);
    455     i = ubidi_getReorderingMode(bidi);
    456     log_err("reorderingMode: %d = %s", i, reorderingModeNames[i]);
    457     fputs("\n", stderr);
    458     i = ubidi_getReorderingOptions(bidi);
    459     log_err("reorderingOptions: %d = %s", i, reorderingOptionNames(buffer, i));
    460     fputs("\n", stderr);
    461     runCount = ubidi_countRuns(bidi, &errorCode);
    462     if (U_FAILURE(errorCode)) {
    463         log_err( "BAD RUNS");
    464     } else {
    465         log_err("Runs: %d => logicalStart.length/level: ", runCount);
    466         for (i = 0; i < runCount; i++) {
    467             UBiDiDirection dir;
    468             int32_t start, len;
    469             dir = ubidi_getVisualRun(bidi, i, &start, &len);
    470             log_err(" %d.%d/%d", start, len, dir);
    471         }
    472     }
    473     fputs("\n", stderr);
    474 }
    475 
    476 static UBool matchingPair(UBiDi *bidi, int32_t i, char c1, char c2)
    477 {
    478     /* No test for []{} since they have special meaning for pseudo Bidi */
    479     static char mates1Chars[] = "<>()";
    480     static char mates2Chars[] = "><)(";
    481     UBiDiLevel level;
    482     int k, len;
    483 
    484     if (c1 == c2) {
    485         return TRUE;
    486     }
    487     /* For UBIDI_REORDER_RUNS_ONLY, it would not be correct to check levels[i],
    488        so we use the appropriate run's level, which is good for all cases.
    489      */
    490     ubidi_getLogicalRun(bidi, i, NULL, &level);
    491     if ((level & 1) == 0) {
    492         return FALSE;
    493     }
    494     len = strlen(mates1Chars);
    495     for (k = 0; k < len; k++) {
    496         if ((c1 == mates1Chars[k]) && (c2 == mates2Chars[k])) {
    497             return TRUE;
    498         }
    499     }
    500     return FALSE;
    501 }
    502 
    503 static UBool checkWhatYouCan(UBiDi *bidi, const char *srcChars, const char *dstChars)
    504 /* srcChars and dstChars are char arrays encoded as pseudo Bidi */
    505 {
    506     int32_t i, idx, logLimit, visLimit;
    507     UBool testOK, errMap, errDst;
    508     UErrorCode errorCode=U_ZERO_ERROR;
    509     int32_t visMap[MAXLEN];
    510     int32_t logMap[MAXLEN];
    511     char accumSrc[MAXLEN];
    512     char accumDst[MAXLEN];
    513     ubidi_getVisualMap(bidi, visMap, &errorCode);
    514     ubidi_getLogicalMap(bidi, logMap, &errorCode);
    515     if (U_FAILURE(errorCode)) {
    516         log_err("Error #1 invoking ICU within checkWhatYouCan\n");
    517         return FALSE;
    518     }
    519 
    520     testOK = TRUE;
    521     errMap = errDst = FALSE;
    522     logLimit = ubidi_getProcessedLength(bidi);
    523     visLimit = ubidi_getResultLength(bidi);
    524     memset(accumSrc, '?', logLimit);
    525     memset(accumDst, '?', visLimit);
    526 
    527     for (i = 0; i < logLimit; i++) {
    528         idx = ubidi_getVisualIndex(bidi, i, &errorCode);
    529         if (idx != logMap[i]) {
    530             errMap = TRUE;
    531         }
    532         if (idx == UBIDI_MAP_NOWHERE) {
    533             continue;
    534         }
    535         if (idx >= visLimit) {
    536             continue;
    537         }
    538         accumDst[idx] = srcChars[i];
    539         if (!matchingPair(bidi, i, srcChars[i], dstChars[idx])) {
    540             errDst = TRUE;
    541         }
    542     }
    543     accumDst[visLimit] = 0;
    544     if (U_FAILURE(errorCode)) {
    545         log_err("Error #2 invoking ICU within checkWhatYouCan\n");
    546         return FALSE;
    547     }
    548     if (errMap) {
    549         if (testOK) {
    550             printCaseInfo(bidi, srcChars, dstChars);
    551             testOK = FALSE;
    552         }
    553         log_err("Mismatch between getLogicalMap() and getVisualIndex()\n");
    554         log_err("Map    :");
    555         for (i = 0; i < logLimit; i++) {
    556             log_err(" %d", logMap[i]);
    557         }
    558         fputs("\n", stderr);
    559         log_err("Indexes:");
    560         for (i = 0; i < logLimit; i++) {
    561             log_err(" %d", ubidi_getVisualIndex(bidi, i, &errorCode));
    562         }
    563         fputs("\n", stderr);
    564     }
    565     if (errDst) {
    566         if (testOK) {
    567             printCaseInfo(bidi, srcChars, dstChars);
    568             testOK = FALSE;
    569         }
    570         log_err("Source does not map to Result\n");
    571         log_err("We got: %s", accumDst); fputs("\n", stderr);
    572     }
    573 
    574     errMap = errDst = FALSE;
    575     for (i = 0; i < visLimit; i++) {
    576         idx = ubidi_getLogicalIndex(bidi, i, &errorCode);
    577         if (idx != visMap[i]) {
    578             errMap = TRUE;
    579         }
    580         if (idx == UBIDI_MAP_NOWHERE) {
    581             continue;
    582         }
    583         if (idx >= logLimit) {
    584             continue;
    585         }
    586         accumSrc[idx] = dstChars[i];
    587         if (!matchingPair(bidi, idx, srcChars[idx], dstChars[i])) {
    588             errDst = TRUE;
    589         }
    590     }
    591     accumSrc[logLimit] = 0;
    592     if (U_FAILURE(errorCode)) {
    593         log_err("Error #3 invoking ICU within checkWhatYouCan\n");
    594         return FALSE;
    595     }
    596     if (errMap) {
    597         if (testOK) {
    598             printCaseInfo(bidi, srcChars, dstChars);
    599             testOK = FALSE;
    600         }
    601         log_err("Mismatch between getVisualMap() and getLogicalIndex()\n");
    602         log_err("Map    :");
    603         for (i = 0; i < visLimit; i++) {
    604             log_err(" %d", visMap[i]);
    605         }
    606         fputs("\n", stderr);
    607         log_err("Indexes:");
    608         for (i = 0; i < visLimit; i++) {
    609             log_err(" %d", ubidi_getLogicalIndex(bidi, i, &errorCode));
    610         }
    611         fputs("\n", stderr);
    612     }
    613     if (errDst) {
    614         if (testOK) {
    615             printCaseInfo(bidi, srcChars, dstChars);
    616             testOK = FALSE;
    617         }
    618         log_err("Result does not map to Source\n");
    619         log_err("We got: %s", accumSrc);
    620         fputs("\n", stderr);
    621     }
    622     return testOK;
    623 }
    624 
    625 static void
    626 testReorder(void) {
    627     static const char* const logicalOrder[] ={
    628             "del(KC)add(K.C.&)",
    629             "del(QDVT) add(BVDL)",
    630             "del(PQ)add(R.S.)T)U.&",
    631             "del(LV)add(L.V.) L.V.&",
    632             "day  0  R  DPDHRVR dayabbr",
    633             "day  1  H  DPHPDHDA dayabbr",
    634             "day  2   L  DPBLENDA dayabbr",
    635             "day  3  J  DPJQVM  dayabbr",
    636             "day  4   I  DPIQNF    dayabbr",
    637             "day  5  M  DPMEG  dayabbr",
    638             "helloDPMEG",
    639             "hello WXYZ"
    640     };
    641     static const char* const visualOrder[]={
    642             "del(CK)add(&.C.K)",
    643             "del(TVDQ) add(LDVB)",
    644             "del(QP)add(&.U(T(.S.R",
    645             "del(VL)add(&.V.L (.V.L",
    646             "day  0  RVRHDPD  R dayabbr",
    647             "day  1  ADHDPHPD  H dayabbr",
    648             "day  2   ADNELBPD  L dayabbr",
    649             "day  3  MVQJPD  J  dayabbr",
    650             "day  4   FNQIPD  I    dayabbr",
    651             "day  5  GEMPD  M  dayabbr",
    652             "helloGEMPD",
    653             "hello ZYXW"
    654     };
    655     static const char* const visualOrder1[]={
    656             ")K.C.&(dda)KC(led",
    657             ")BVDL(dda )QDVT(led",
    658             "R.S.(T(U.&(dda)PQ(led",
    659             "L.V.( L.V.&(dda)LV(led",
    660             "rbbayad R  DPDHRVR  0  yad",
    661             "rbbayad H  DPHPDHDA  1  yad",
    662             "rbbayad L  DPBLENDA   2  yad",
    663             "rbbayad  J  DPJQVM  3  yad",
    664             "rbbayad    I  DPIQNF   4  yad",
    665             "rbbayad  M  DPMEG  5  yad",
    666             "DPMEGolleh",
    667             "WXYZ olleh"
    668     };
    669 
    670     static const char* const visualOrder2[]={
    671             "@)@K.C.&@(dda)@KC@(led",
    672             "@)@BVDL@(dda )@QDVT@(led",
    673             "R.S.)T)U.&@(dda)@PQ@(led",
    674             "L.V.) L.V.&@(dda)@LV@(led",
    675             "rbbayad @R  DPDHRVR@  0  yad",
    676             "rbbayad @H  DPHPDHDA@  1  yad",
    677             "rbbayad @L  DPBLENDA@   2  yad",
    678             "rbbayad  @J  DPJQVM@  3  yad",
    679             "rbbayad    @I  DPIQNF@   4  yad",
    680             "rbbayad  @M  DPMEG@  5  yad",
    681             "DPMEGolleh",
    682             "WXYZ@ olleh"
    683     };
    684     static const char* const visualOrder3[]={
    685             ")K.C.&(KC)dda(led",
    686             ")BVDL(ddaQDVT) (led",
    687             "R.S.)T)U.&(PQ)dda(led",
    688             "L.V.) L.V.&(LV)dda(led",
    689             "rbbayad DPDHRVR   R  0 yad",
    690             "rbbayad DPHPDHDA   H  1 yad",
    691             "rbbayad DPBLENDA     L 2 yad",
    692             "rbbayad  DPJQVM   J  3 yad",
    693             "rbbayad    DPIQNF     I 4 yad",
    694             "rbbayad  DPMEG   M  5 yad",
    695             "DPMEGolleh",
    696             "WXYZ olleh"
    697     };
    698     static const char* const visualOrder4[]={
    699             "del(add(CK(.C.K)",
    700             "del( (TVDQadd(LDVB)",
    701             "del(add(QP(.U(T(.S.R",
    702             "del(add(VL(.V.L (.V.L",
    703             "day 0  R   RVRHDPD dayabbr",
    704             "day 1  H   ADHDPHPD dayabbr",
    705             "day 2 L     ADNELBPD dayabbr",
    706             "day 3  J   MVQJPD  dayabbr",
    707             "day 4 I     FNQIPD    dayabbr",
    708             "day 5  M   GEMPD  dayabbr",
    709             "helloGEMPD",
    710             "hello ZYXW"
    711     };
    712     char formatChars[MAXLEN];
    713     UErrorCode ec = U_ZERO_ERROR;
    714     UBiDi* bidi = ubidi_open();
    715     int i;
    716 
    717     log_verbose("\nEntering TestReorder\n\n");
    718 
    719     for(i=0;i<LENGTHOF(logicalOrder);i++){
    720         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
    721         int32_t destSize = srcSize*2;
    722         UChar src[MAXLEN];
    723         UChar dest[MAXLEN];
    724         char chars[MAXLEN];
    725         log_verbose("Testing L2V #1 for case %d\n", i);
    726         pseudoToU16(srcSize,logicalOrder[i],src);
    727         ec = U_ZERO_ERROR;
    728         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
    729         if(U_FAILURE(ec)){
    730             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    731                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
    732         }
    733         /* try pre-flighting */
    734         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING,&ec);
    735         if(ec!=U_BUFFER_OVERFLOW_ERROR){
    736             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
    737         }else if(destSize!=srcSize){
    738             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
    739         }else{
    740             ec= U_ZERO_ERROR;
    741         }
    742         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING,&ec);
    743         u16ToPseudo(destSize,dest,chars);
    744         if(destSize!=srcSize){
    745             log_err("ubidi_writeReordered() destSize and srcSize do not match\n");
    746         }else if(strcmp(visualOrder[i],chars)!=0){
    747             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING.\n"
    748                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
    749                     logicalOrder[i],visualOrder[i],chars,formatLevels(bidi, formatChars),i);
    750         }
    751         checkWhatYouCan(bidi, logicalOrder[i], chars);
    752     }
    753 
    754     for(i=0;i<LENGTHOF(logicalOrder);i++){
    755         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
    756         int32_t destSize = srcSize*2;
    757         UChar src[MAXLEN];
    758         UChar dest[MAXLEN];
    759         char chars[MAXLEN];
    760         log_verbose("Testing L2V #2 for case %d\n", i);
    761         pseudoToU16(srcSize,logicalOrder[i],src);
    762         ec = U_ZERO_ERROR;
    763         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
    764         if(U_FAILURE(ec)){
    765             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    766                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
    767         }
    768         /* try pre-flighting */
    769         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec);
    770         if(ec!=U_BUFFER_OVERFLOW_ERROR){
    771             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
    772         }else if(destSize!=srcSize){
    773             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
    774         }else{
    775             ec= U_ZERO_ERROR;
    776         }
    777         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec);
    778         u16ToPseudo(destSize,dest,chars);
    779         if(destSize!=srcSize){
    780             log_err("ubidi_writeReordered() destSize and srcSize do not match\n");
    781         }else if(strcmp(visualOrder1[i],chars)!=0){
    782             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE.\n"
    783                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
    784                     logicalOrder[i],visualOrder1[i],chars,formatLevels(bidi, formatChars),i);
    785         }
    786     }
    787 
    788     for(i=0;i<LENGTHOF(logicalOrder);i++){
    789         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
    790         int32_t destSize = srcSize*2;
    791         UChar src[MAXLEN];
    792         UChar dest[MAXLEN];
    793         char chars[MAXLEN];
    794         log_verbose("Testing V2L #3 for case %d\n", i);
    795         pseudoToU16(srcSize,logicalOrder[i],src);
    796         ec = U_ZERO_ERROR;
    797         ubidi_setInverse(bidi,TRUE);
    798         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec);
    799         if(U_FAILURE(ec)){
    800             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    801                     i, UBIDI_DEFAULT_LTR, u_errorName(ec));
    802         }
    803                 /* try pre-flighting */
    804         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec);
    805         if(ec!=U_BUFFER_OVERFLOW_ERROR){
    806             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
    807         }else{
    808             ec= U_ZERO_ERROR;
    809         }
    810         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec);
    811         u16ToPseudo(destSize,dest,chars);
    812         if(strcmp(visualOrder2[i],chars)!=0){
    813             log_err("ubidi_writeReordered() did not give expected results for UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE.\n"
    814                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
    815                     logicalOrder[i],visualOrder2[i],chars,formatLevels(bidi, formatChars),i);
    816         }
    817     }
    818         /* Max Explicit level */
    819     for(i=0;i<LENGTHOF(logicalOrder);i++){
    820         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
    821         int32_t destSize = srcSize*2;
    822         UChar src[MAXLEN];
    823         UChar dest[MAXLEN];
    824         char chars[MAXLEN];
    825         UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10};
    826         log_verbose("Testing V2L #4 for case %d\n", i);
    827         pseudoToU16(srcSize,logicalOrder[i],src);
    828         ec = U_ZERO_ERROR;
    829         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec);
    830         if(U_FAILURE(ec)){
    831             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    832                     i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec));
    833         }
    834                 /* try pre-flighting */
    835         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_OUTPUT_REVERSE,&ec);
    836         if(ec!=U_BUFFER_OVERFLOW_ERROR){
    837             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
    838         }else if(destSize!=srcSize){
    839             log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize);
    840         }else{
    841             ec = U_ZERO_ERROR;
    842         }
    843         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_OUTPUT_REVERSE,&ec);
    844         u16ToPseudo(destSize,dest,chars);
    845         if(destSize!=srcSize){
    846             log_err("ubidi_writeReordered() destSize and srcSize do not match. Dest Size = %d Source Size = %d\n",destSize,srcSize );
    847         }else if(strcmp(visualOrder3[i],chars)!=0){
    848             log_err("ubidi_writeReordered() did not give expected results for UBIDI_OUTPUT_REVERSE.\n"
    849                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
    850                     logicalOrder[i],visualOrder3[i],chars,formatLevels(bidi, formatChars),i);
    851         }
    852     }
    853     for(i=0;i<LENGTHOF(logicalOrder);i++){
    854         int32_t srcSize = (int32_t)strlen(logicalOrder[i]);
    855         int32_t destSize = srcSize*2;
    856         UChar src[MAXLEN];
    857         UChar dest[MAXLEN];
    858         char chars[MAXLEN];
    859         UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10};
    860         log_verbose("Testing V2L #5 for case %d\n", i);
    861         pseudoToU16(srcSize,logicalOrder[i],src);
    862         ec = U_ZERO_ERROR;
    863         ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec);
    864         if(U_FAILURE(ec)){
    865             log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n",
    866                     i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec));
    867         }
    868         /* try pre-flighting */
    869         destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec);
    870         if(ec!=U_BUFFER_OVERFLOW_ERROR){
    871             log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec));
    872         }else{
    873             ec= U_ZERO_ERROR;
    874         }
    875         destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec);
    876         u16ToPseudo(destSize,dest,chars);
    877         if(strcmp(visualOrder4[i],chars)!=0){
    878             log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS.\n"
    879                     "Input   : %s\nExpected: %s\nGot     : %s\nLevels  : %s\nAt Index: %d\n",
    880                     logicalOrder[i],visualOrder4[i],chars,formatLevels(bidi, formatChars),i);
    881         }
    882     }
    883     ubidi_close(bidi);
    884 
    885     log_verbose("\nExiting TestReorder\n\n");
    886 }
    887 
    888 static void
    889 doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test, int32_t lineStart, UBool countRunsFirst) {
    890     const uint8_t *dirProps=test->text+lineStart;
    891     const UBiDiLevel *levels=test->levels;
    892     const uint8_t *visualMap=test->visualMap;
    893     int32_t i, len=ubidi_getLength(pBiDi), logicalIndex, runCount = 0;
    894     UErrorCode errorCode=U_ZERO_ERROR;
    895     UBiDiLevel level, level2;
    896 
    897     if (countRunsFirst) {
    898         log_verbose("Calling ubidi_countRuns() first.\n");
    899 
    900         runCount = ubidi_countRuns(pBiDi, &errorCode);
    901 
    902         if(U_FAILURE(errorCode)) {
    903             log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
    904             return;
    905         }
    906     } else {
    907         log_verbose("Calling ubidi_getLogicalMap() first.\n");
    908     }
    909 
    910     _testReordering(pBiDi, testNumber);
    911 
    912     for(i=0; i<len; ++i) {
    913         log_verbose("%3d %3d %.*s%-3s @%d\n",
    914                 i, ubidi_getLevelAt(pBiDi, i), ubidi_getLevelAt(pBiDi, i), levelString,
    915                 dirPropNames[dirProps[i]],
    916                 ubidi_getVisualIndex(pBiDi, i, &errorCode));
    917     }
    918 
    919     log_verbose("\n-----levels:");
    920     for(i=0; i<len; ++i) {
    921         if(i>0) {
    922             log_verbose(",");
    923         }
    924         log_verbose(" %d", ubidi_getLevelAt(pBiDi, i));
    925     }
    926 
    927     log_verbose("\n--reordered:");
    928     for(i=0; i<len; ++i) {
    929         if(i>0) {
    930             log_verbose(",");
    931         }
    932         log_verbose(" %d", ubidi_getVisualIndex(pBiDi, i, &errorCode));
    933     }
    934     log_verbose("\n");
    935 
    936     if(test->direction!=ubidi_getDirection(pBiDi)) {
    937         log_err("ubidi_getDirection(tests[%d]): wrong direction %d\n", testNumber, ubidi_getDirection(pBiDi));
    938     }
    939 
    940     if(test->resultLevel!=ubidi_getParaLevel(pBiDi)) {
    941         log_err("ubidi_getParaLevel(tests[%d]): wrong paragraph level %d\n", testNumber, ubidi_getParaLevel(pBiDi));
    942     }
    943 
    944     for(i=0; i<len; ++i) {
    945         if(levels[i]!=ubidi_getLevelAt(pBiDi, i)) {
    946             log_err("ubidi_getLevelAt(tests[%d], %d): wrong level %d, expected %d\n", testNumber, i, ubidi_getLevelAt(pBiDi, i), levels[i]);
    947             return;
    948         }
    949     }
    950 
    951     for(i=0; i<len; ++i) {
    952         logicalIndex=ubidi_getVisualIndex(pBiDi, i, &errorCode);
    953         if(U_FAILURE(errorCode)) {
    954             log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
    955             return;
    956         }
    957         if(visualMap[i]!=logicalIndex) {
    958             log_err("ubidi_getVisualIndex(tests[%d], %d): wrong index %d\n", testNumber, i, logicalIndex);
    959             return;
    960         }
    961     }
    962 
    963     if (! countRunsFirst) {
    964         runCount=ubidi_countRuns(pBiDi, &errorCode);
    965         if(U_FAILURE(errorCode)) {
    966             log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
    967             return;
    968         }
    969     }
    970 
    971     for(logicalIndex=0; logicalIndex<len;) {
    972         level=ubidi_getLevelAt(pBiDi, logicalIndex);
    973         ubidi_getLogicalRun(pBiDi, logicalIndex, &logicalIndex, &level2);
    974         if(level!=level2) {
    975             log_err("ubidi_getLogicalRun(tests[%d], run ending at index %d): "
    976                     "wrong level %d instead of %d\n",
    977                     testNumber, logicalIndex, level, level2);
    978         }
    979         if(--runCount<0) {
    980             log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs "
    981                     "compared to %d=ubidi_countRuns()\n",
    982                     testNumber, ubidi_countRuns(pBiDi, &errorCode));
    983             return;
    984         }
    985     }
    986     if(runCount!=0) {
    987         log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs "
    988                 "compared to %d=ubidi_getRunCount()\n",
    989                 testNumber, ubidi_countRuns(pBiDi, &errorCode));
    990         return;
    991     }
    992 
    993     log_verbose("\n\n");
    994 }
    995 
    996 static void
    997 _testReordering(UBiDi *pBiDi, int testNumber) {
    998     int32_t
    999         logicalMap1[MAXLEN], logicalMap2[MAXLEN], logicalMap3[MAXLEN],
   1000         visualMap1[MAXLEN], visualMap2[MAXLEN], visualMap3[MAXLEN], visualMap4[MAXLEN];
   1001     UErrorCode errorCode=U_ZERO_ERROR;
   1002     const UBiDiLevel *levels;
   1003     int32_t i, length=ubidi_getLength(pBiDi),
   1004                destLength=ubidi_getResultLength(pBiDi);
   1005     int32_t runCount, visualIndex, logicalStart, runLength;
   1006     UBool odd;
   1007 
   1008     if(length<=0) {
   1009         return;
   1010     }
   1011 
   1012     /* get the logical and visual maps from the object */
   1013     ubidi_getLogicalMap(pBiDi, logicalMap1, &errorCode);
   1014     if(U_FAILURE(errorCode)) {
   1015         log_err("ubidi_getLogicalMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
   1016         return;
   1017     }
   1018 
   1019     ubidi_getVisualMap(pBiDi, visualMap1, &errorCode);
   1020     if(U_FAILURE(errorCode)) {
   1021         log_err("ubidi_getVisualMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
   1022         return;
   1023     }
   1024 
   1025     /* invert them both */
   1026     ubidi_invertMap(logicalMap1, visualMap2, length);
   1027     ubidi_invertMap(visualMap1, logicalMap2, destLength);
   1028 
   1029     /* get them from the levels array, too */
   1030     levels=ubidi_getLevels(pBiDi, &errorCode);
   1031 
   1032     if(U_FAILURE(errorCode)) {
   1033         log_err("ubidi_getLevels(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
   1034         return;
   1035     }
   1036 
   1037     ubidi_reorderLogical(levels, length, logicalMap3);
   1038     ubidi_reorderVisual(levels, length, visualMap3);
   1039 
   1040     /* get the visual map from the runs, too */
   1041     runCount=ubidi_countRuns(pBiDi, &errorCode);
   1042     if(U_FAILURE(errorCode)) {
   1043         log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode));
   1044         return;
   1045     }
   1046     log_verbose("\n----%2d runs:", runCount);
   1047     visualIndex=0;
   1048     for(i=0; i<runCount; ++i) {
   1049         odd=(UBool)ubidi_getVisualRun(pBiDi, i, &logicalStart, &runLength);
   1050         log_verbose(" (%c @%d[%d])", odd ? 'R' : 'L', logicalStart, runLength);
   1051         if(UBIDI_LTR==odd) {
   1052             do { /* LTR */
   1053                 visualMap4[visualIndex++]=logicalStart++;
   1054             } while(--runLength>0);
   1055         } else {
   1056             logicalStart+=runLength;   /* logicalLimit */
   1057             do { /* RTL */
   1058                 visualMap4[visualIndex++]=--logicalStart;
   1059             } while(--runLength>0);
   1060         }
   1061     }
   1062     log_verbose("\n");
   1063 
   1064     /* print all the maps */
   1065     log_verbose("logical maps:\n");
   1066     for(i=0; i<length; ++i) {
   1067         log_verbose("%4d", logicalMap1[i]);
   1068     }
   1069     log_verbose("\n");
   1070     for(i=0; i<length; ++i) {
   1071         log_verbose("%4d", logicalMap2[i]);
   1072     }
   1073     log_verbose("\n");
   1074     for(i=0; i<length; ++i) {
   1075         log_verbose("%4d", logicalMap3[i]);
   1076     }
   1077 
   1078     log_verbose("\nvisual maps:\n");
   1079     for(i=0; i<destLength; ++i) {
   1080         log_verbose("%4d", visualMap1[i]);
   1081     }
   1082     log_verbose("\n");
   1083     for(i=0; i<destLength; ++i) {
   1084         log_verbose("%4d", visualMap2[i]);
   1085     }
   1086     log_verbose("\n");
   1087     for(i=0; i<length; ++i) {
   1088         log_verbose("%4d", visualMap3[i]);
   1089     }
   1090     log_verbose("\n");
   1091     for(i=0; i<length; ++i) {
   1092         log_verbose("%4d", visualMap4[i]);
   1093     }
   1094     log_verbose("\n");
   1095 
   1096     /* check that the indexes are the same between these and ubidi_getLogical/VisualIndex() */
   1097     for(i=0; i<length; ++i) {
   1098         if(logicalMap1[i]!=logicalMap2[i]) {
   1099             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap2[i] at i=%d\n", testNumber, i);
   1100             break;
   1101         }
   1102         if(logicalMap1[i]!=logicalMap3[i]) {
   1103             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap3[i] at i=%d\n", testNumber, i);
   1104             break;
   1105         }
   1106 
   1107         if(visualMap1[i]!=visualMap2[i]) {
   1108             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap2[i] at i=%d\n", testNumber, i);
   1109             break;
   1110         }
   1111         if(visualMap1[i]!=visualMap3[i]) {
   1112             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap3[i] at i=%d\n", testNumber, i);
   1113             break;
   1114         }
   1115         if(visualMap1[i]!=visualMap4[i]) {
   1116             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap4[i] at i=%d\n", testNumber, i);
   1117             break;
   1118         }
   1119 
   1120         if(logicalMap1[i]!=ubidi_getVisualIndex(pBiDi, i, &errorCode)) {
   1121             log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=ubidi_getVisualIndex(i) at i=%d\n", testNumber, i);
   1122             break;
   1123         }
   1124         if(U_FAILURE(errorCode)) {
   1125             log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
   1126             break;
   1127         }
   1128         if(visualMap1[i]!=ubidi_getLogicalIndex(pBiDi, i, &errorCode)) {
   1129             log_err("bidi reordering error in tests[%d]: visualMap1[i]!=ubidi_getLogicalIndex(i) at i=%d\n", testNumber, i);
   1130             break;
   1131         }
   1132         if(U_FAILURE(errorCode)) {
   1133             log_err("ubidi_getLogicalIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode));
   1134             break;
   1135         }
   1136     }
   1137 }
   1138 
   1139 #define RETURN_IF_BAD_ERRCODE(x)    \
   1140     if (U_FAILURE(errorCode)) {      \
   1141         log_err("\nbad errorCode %d at %s\n", errorCode, (x));  \
   1142         return;     \
   1143     }               \
   1144 
   1145 #define STRING_TEST_CASE(s) { (s), LENGTHOF(s) }
   1146 
   1147 static void testGetBaseDirection(void) {
   1148     UBiDiDirection dir;
   1149     int i;
   1150 
   1151 /* Test Data */
   1152     static const UChar
   1153 /*Mixed Start with L*/
   1154     stringMixedEnglishFirst[]={ 0x61, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0 },
   1155 /*Mixed Start with AL*/
   1156     stringMixedArabicFirst[]={ 0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
   1157 /*Mixed Start with R*/
   1158     stringMixedHebrewFirst[]={ 0x05EA, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 },
   1159 /*All AL (Arabic. Persian)*/
   1160     stringPersian[]={0x0698, 0x067E, 0x0686, 0x06AF, 0},
   1161 /*All R (Hebrew etc.)*/
   1162     stringHebrew[]={0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
   1163 /*All L (English)*/
   1164     stringEnglish[]={0x71, 0x61, 0x66, 0},
   1165 /*Mixed Start with weak AL an then L*/
   1166     stringStartWeakAL[]={ 0x0663, 0x71, 0x61, 0x66, 0},
   1167 /*Mixed Start with weak L and then AL*/
   1168     stringStartWeakL[]={0x31, 0x0698, 0x067E, 0x0686, 0x06AF, 0},
   1169 /*Empty*/
   1170     stringEmpty[]={0},
   1171 /*Surrogate Char.*/
   1172     stringSurrogateChar[]={0xD800, 0xDC00, 0},
   1173 /*Invalid UChar*/
   1174     stringInvalidUchar[]={-1},
   1175 /*All weak L (English Digits)*/
   1176     stringAllEnglishDigits[]={0x31, 0x32, 0x33, 0},
   1177 /*All weak AL (Arabic Digits)*/
   1178     stringAllArabicDigits[]={0x0663, 0x0664, 0x0665, 0},
   1179 /*First L (English) others are R (Hebrew etc.) */
   1180     stringFirstL[] = {0x71, 0x0590, 0x05D5, 0x05EA, 0x05F1, 0},
   1181 /*Last R (Hebrew etc.) others are weak L (English Digits)*/
   1182     stringLastR[] = {0x31, 0x32, 0x33, 0x05F1, 0};
   1183 
   1184     static const struct {
   1185         const UChar *s;
   1186         int32_t length;
   1187     } testCases[]={
   1188         STRING_TEST_CASE(stringMixedEnglishFirst),
   1189         STRING_TEST_CASE(stringMixedArabicFirst),
   1190         STRING_TEST_CASE(stringMixedHebrewFirst),
   1191         STRING_TEST_CASE(stringPersian),
   1192         STRING_TEST_CASE(stringHebrew),
   1193         STRING_TEST_CASE(stringEnglish),
   1194         STRING_TEST_CASE(stringStartWeakAL),
   1195         STRING_TEST_CASE(stringStartWeakL),
   1196         STRING_TEST_CASE(stringEmpty),
   1197         STRING_TEST_CASE(stringSurrogateChar),
   1198         STRING_TEST_CASE(stringInvalidUchar),
   1199         STRING_TEST_CASE(stringAllEnglishDigits),
   1200         STRING_TEST_CASE(stringAllArabicDigits),
   1201         STRING_TEST_CASE(stringFirstL),
   1202         STRING_TEST_CASE(stringLastR),
   1203     };
   1204 
   1205 /* Expected results */
   1206     static const UBiDiDirection expectedDir[] ={
   1207         UBIDI_LTR, UBIDI_RTL, UBIDI_RTL,
   1208         UBIDI_RTL, UBIDI_RTL, UBIDI_LTR,
   1209         UBIDI_LTR, UBIDI_RTL, UBIDI_NEUTRAL,
   1210         UBIDI_LTR, UBIDI_NEUTRAL, UBIDI_NEUTRAL,
   1211         UBIDI_NEUTRAL, UBIDI_LTR, UBIDI_RTL
   1212     };
   1213 
   1214     log_verbose("testGetBaseDirection() with %u test cases ---\n",
   1215     LENGTHOF(testCases));
   1216 /* Run Tests */
   1217      for(i=0; i<LENGTHOF(testCases); ++i) {
   1218         dir = ubidi_getBaseDirection(testCases[i].s, testCases[i].length );
   1219         log_verbose("Testing case %d\tReceived dir %d\n", i, dir);
   1220         if (dir != expectedDir[i])
   1221             log_err("\nFailed getBaseDirection case %d Expected  %d \tReceived %d\n",
   1222             i, expectedDir[i], dir);
   1223     }
   1224 
   1225 /* Misc. tests */
   1226 /* NULL string */
   1227     dir = ubidi_getBaseDirection(NULL, 3);
   1228     if (dir != UBIDI_NEUTRAL )
   1229         log_err("\nFailed getBaseDirection for NULL string " ,
   1230         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
   1231 /*All L- English string and length=-3 */
   1232     dir = ubidi_getBaseDirection( stringEnglish, -3);
   1233     if (dir != UBIDI_NEUTRAL )
   1234         log_err("\nFailed getBaseDirection for string w length= -3 ",
   1235         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
   1236 /*All L- English string and length=-1 */
   1237     dir = ubidi_getBaseDirection( stringEnglish, -1);
   1238     if (dir != UBIDI_LTR )
   1239         log_err("\nFailed getBaseDirection for English string w length= -1 ",
   1240         "\nExpected  %d \nReceived %d", UBIDI_LTR, dir);
   1241 /*All AL- Persian string and length=-1 */
   1242     dir = ubidi_getBaseDirection( stringPersian, -1);
   1243     if (dir != UBIDI_RTL )
   1244         log_err("\nFailed getBaseDirection for Persian string w length= -1 ",
   1245         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
   1246 /*All R- Hebrew string and length=-1 */
   1247     dir = ubidi_getBaseDirection( stringHebrew, -1);
   1248     if (dir != UBIDI_RTL )
   1249         log_err("\nFailed getBaseDirection for Hebrew string w length= -1 ",
   1250         "\nExpected  %d \nReceived %d", UBIDI_RTL, dir);
   1251 /*All weak L- English digits string and length=-1 */
   1252     dir = ubidi_getBaseDirection(stringAllEnglishDigits, -1);
   1253     if (dir != UBIDI_NEUTRAL )
   1254         log_err("\nFailed getBaseDirection for English digits string w length= -1 ",
   1255         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
   1256 /*All weak AL- Arabic digits string and length=-1 */
   1257     dir = ubidi_getBaseDirection(stringAllArabicDigits, -1);
   1258     if (dir != UBIDI_NEUTRAL )
   1259         log_err("\nFailed getBaseDirection for Arabic string w length= -1 ",
   1260         "\nExpected  %d \nReceived %d", UBIDI_NEUTRAL, dir);
   1261 
   1262 }
   1263 
   1264 
   1265 static void doMisc(void) {
   1266 /* Miscellaneous tests to exercize less popular code paths */
   1267     UBiDi *bidi, *bidiLine;
   1268     UChar src[MAXLEN], dest[MAXLEN];
   1269     int32_t srcLen, destLen, runCount, i;
   1270     UBiDiLevel level;
   1271     UBiDiDirection dir;
   1272     int32_t map[MAXLEN];
   1273     UErrorCode errorCode=U_ZERO_ERROR;
   1274     static const int32_t srcMap[6] = {0,1,-1,5,4};
   1275     static const int32_t dstMap[6] = {0,1,-1,-1,4,3};
   1276 
   1277     bidi = ubidi_openSized(120, 66, &errorCode);
   1278     if (bidi == NULL) {
   1279         log_err("Error with openSized(120, 66)\n");
   1280         return;
   1281     }
   1282     bidiLine = ubidi_open();
   1283     if (bidi == NULL) {
   1284         log_err("Error with open()\n");
   1285         return;
   1286     }
   1287 
   1288     destLen = ubidi_writeReverse(src, 0, dest, MAXLEN, 0, &errorCode);
   1289     if (destLen != 0) {
   1290         log_err("\nwriteReverse should return zero length, ",
   1291                 "returned %d instead\n", destLen);
   1292     }
   1293     RETURN_IF_BAD_ERRCODE("#1#");
   1294 
   1295     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
   1296     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1297     if (destLen != 0) {
   1298         log_err("\nwriteReordered should return zero length, ",
   1299                 "returned %d instead\n", destLen);
   1300     }
   1301     RETURN_IF_BAD_ERRCODE("#2#");
   1302 
   1303     srcLen = u_unescape("abc       ", src, MAXLEN);
   1304     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1305     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1306     for (i = 3; i < 6; i++) {
   1307         level = ubidi_getLevelAt(bidiLine, i);
   1308         if (level != UBIDI_RTL) {
   1309             log_err("\nTrailing space at index %d should get paragraph level"
   1310                     "%d, got %d instead\n", i, UBIDI_RTL, level);
   1311         }
   1312     }
   1313     RETURN_IF_BAD_ERRCODE("#3#");
   1314 
   1315     srcLen = u_unescape("abc       def", src, MAXLEN);
   1316     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1317     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1318     for (i = 3; i < 6; i++) {
   1319         level = ubidi_getLevelAt(bidiLine, i);
   1320         if (level != UBIDI_RTL) {
   1321             log_err("\nTrailing space at index %d should get paragraph level"
   1322                     "%d, got %d instead\n", i, UBIDI_RTL, level);
   1323         }
   1324     }
   1325     RETURN_IF_BAD_ERRCODE("#4#");
   1326 
   1327     srcLen = u_unescape("abcdefghi    ", src, MAXLEN);
   1328     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1329     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1330     for (i = 3; i < 6; i++) {
   1331         level = ubidi_getLevelAt(bidiLine, i);
   1332         if (level != 2) {
   1333             log_err("\nTrailing char at index %d should get level 2, "
   1334                     "got %d instead\n", i, level);
   1335         }
   1336     }
   1337     RETURN_IF_BAD_ERRCODE("#5#");
   1338 
   1339     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_REMOVE_CONTROLS);
   1340     srcLen = u_unescape("\\u200eabc       def", src, MAXLEN);
   1341     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1342     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1343     destLen = ubidi_getResultLength(bidiLine);
   1344     if (destLen != 5) {
   1345         log_err("\nWrong result length, should be 5, got %d\n", destLen);
   1346     }
   1347     RETURN_IF_BAD_ERRCODE("#6#");
   1348 
   1349     srcLen = u_unescape("abcdefghi", src, MAXLEN);
   1350     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1351     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1352     dir = ubidi_getDirection(bidiLine);
   1353     if (dir != UBIDI_LTR) {
   1354         log_err("\nWrong direction #1, should be %d, got %d\n",
   1355                 UBIDI_LTR, dir);
   1356     }
   1357     RETURN_IF_BAD_ERRCODE("#7#");
   1358 
   1359     ubidi_setPara(bidi, src, 0, UBIDI_LTR, NULL, &errorCode);
   1360     runCount = ubidi_countRuns(bidi, &errorCode);
   1361     if (runCount != 0) {
   1362         log_err("\nWrong number of runs #1, should be 0, got %d\n", runCount);
   1363     }
   1364     RETURN_IF_BAD_ERRCODE("#8#");
   1365 
   1366     srcLen = u_unescape("          ", src, MAXLEN);
   1367     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1368     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1369     runCount = ubidi_countRuns(bidiLine, &errorCode);
   1370     if (runCount != 1) {
   1371         log_err("\nWrong number of runs #2, should be 1, got %d\n", runCount);
   1372     }
   1373     RETURN_IF_BAD_ERRCODE("#9#");
   1374 
   1375     srcLen = u_unescape("a\\u05d0        bc", src, MAXLEN);
   1376     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1377     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1378     dir = ubidi_getDirection(bidi);
   1379     if (dir != UBIDI_MIXED) {
   1380         log_err("\nWrong direction #2, should be %d, got %d\n",
   1381                 UBIDI_MIXED, dir);
   1382     }
   1383     dir = ubidi_getDirection(bidiLine);
   1384     if (dir != UBIDI_MIXED) {
   1385         log_err("\nWrong direction #3, should be %d, got %d\n",
   1386                 UBIDI_MIXED, dir);
   1387     }
   1388     runCount = ubidi_countRuns(bidiLine, &errorCode);
   1389     if (runCount != 2) {
   1390         log_err("\nWrong number of runs #3, should be 2, got %d\n", runCount);
   1391     }
   1392     RETURN_IF_BAD_ERRCODE("#10#");
   1393 
   1394     ubidi_invertMap(srcMap, map, 5);
   1395     if (memcmp(dstMap, map, sizeof(dstMap))) {
   1396         log_err("\nUnexpected inverted Map, got ");
   1397         for (i = 0; i < 6; i++) {
   1398             log_err("%d ", map[i]);
   1399         }
   1400         log_err("\n");
   1401     }
   1402 
   1403     /* test REMOVE_BIDI_CONTROLS together with DO_MIRRORING */
   1404     srcLen = u_unescape("abc\\u200e", src, MAXLEN);
   1405     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1406     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
   1407               UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_DO_MIRRORING, &errorCode);
   1408     if (destLen != 3 || memcmp(dest, src, 3 * sizeof(UChar))) {
   1409         log_err("\nWrong result #1, should be 'abc', got '%s'\n",
   1410                 aescstrdup(dest, destLen));
   1411     }
   1412     RETURN_IF_BAD_ERRCODE("#11#");
   1413 
   1414     /* test inverse Bidi with marks and contextual orientation */
   1415     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
   1416     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
   1417     ubidi_setPara(bidi, src, 0, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1418     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1419     if (destLen != 0) {
   1420         log_err("\nWrong result #2, length should be 0, got %d\n", destLen);
   1421     }
   1422     RETURN_IF_BAD_ERRCODE("#12#");
   1423     srcLen = u_unescape("   ", src, MAXLEN);
   1424     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1425     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1426     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1427         log_err("\nWrong result #3, should be '   ', got '%s'\n",
   1428                 aescstrdup(dest, destLen));
   1429     }
   1430     RETURN_IF_BAD_ERRCODE("#13#");
   1431     srcLen = u_unescape("abc", src, MAXLEN);
   1432     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1433     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1434     if (destLen != 3 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1435         log_err("\nWrong result #4, should be 'abc', got '%s'\n",
   1436                 aescstrdup(dest, destLen));
   1437     }
   1438     RETURN_IF_BAD_ERRCODE("#14#");
   1439     srcLen = u_unescape("\\u05d0\\u05d1", src, MAXLEN);
   1440     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1441     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1442     srcLen = u_unescape("\\u05d1\\u05d0", src, MAXLEN);
   1443     if (destLen != 2 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1444         log_err("\nWrong result #5, should be '%s', got '%s'\n",
   1445                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1446     }
   1447     RETURN_IF_BAD_ERRCODE("#15#");
   1448     srcLen = u_unescape("abc \\u05d0\\u05d1", src, MAXLEN);
   1449     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1450     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1451     srcLen = u_unescape("\\u05d1\\u05d0 abc", src, MAXLEN);
   1452     if (destLen != 6 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1453         log_err("\nWrong result #6, should be '%s', got '%s'\n",
   1454                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1455     }
   1456     RETURN_IF_BAD_ERRCODE("#16#");
   1457     srcLen = u_unescape("\\u05d0\\u05d1 abc", src, MAXLEN);
   1458     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1459     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1460     srcLen = u_unescape("\\u200fabc \\u05d1\\u05d0", src, MAXLEN);
   1461     if (destLen != 7 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1462         log_err("\nWrong result #7, should be '%s', got '%s'\n",
   1463                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1464     }
   1465     RETURN_IF_BAD_ERRCODE("#17#");
   1466     srcLen = u_unescape("\\u05d0\\u05d1 abc .-=", src, MAXLEN);
   1467     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1468     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1469     srcLen = u_unescape("\\u200f=-. abc \\u05d1\\u05d0", src, MAXLEN);
   1470     if (destLen != 11 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1471         log_err("\nWrong result #8, should be '%s', got '%s'\n",
   1472                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1473     }
   1474     RETURN_IF_BAD_ERRCODE("#18#");
   1475     ubidi_orderParagraphsLTR(bidi, TRUE);
   1476     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d0\\u05d1\rabc \\u05d2\\u05d3\n\r"
   1477                         "\\u05d4\\u05d5 abc\n\\u05d6\\u05d7 abc .-=\r\n"
   1478                         "-* \\u05d8\\u05d9 abc .-=", src, MAXLEN);
   1479     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1480     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1481     srcLen = u_unescape("\n\r   \n\rabc\n\\u05d1\\u05d0\r\\u05d3\\u05d2 abc\n\r"
   1482                         "\\u200fabc \\u05d5\\u05d4\n\\u200f=-. abc \\u05d7\\u05d6\r\n"
   1483                         "\\u200f=-. abc \\u05d9\\u05d8 *-", src, MAXLEN);
   1484     if (destLen != 57 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1485         log_err("\nWrong result #9, should be '%s', got '%s'\n",
   1486                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1487     }
   1488     RETURN_IF_BAD_ERRCODE("#19#");
   1489     srcLen = u_unescape("\\u05d0 \t", src, MAXLEN);
   1490     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1491     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1492     srcLen = u_unescape("\\u05D0\\u200e \t", src, MAXLEN);
   1493     if (destLen != 4 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1494         log_err("\nWrong result #10, should be '%s', got '%s'\n",
   1495                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1496     }
   1497     RETURN_IF_BAD_ERRCODE("#20#");
   1498     srcLen = u_unescape("\\u05d0 123 \t\\u05d1 123 \\u05d2", src, MAXLEN);
   1499     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1500     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1501     srcLen = u_unescape("\\u05d0 \\u200e123\\u200e \t\\u05d2 123 \\u05d1", src, MAXLEN);
   1502     if (destLen != 16 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1503         log_err("\nWrong result #11, should be '%s', got '%s'\n",
   1504                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1505     }
   1506     RETURN_IF_BAD_ERRCODE("#21#");
   1507     srcLen = u_unescape("\\u05d0 123 \\u0660\\u0661 ab", src, MAXLEN);
   1508     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1509     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1510     srcLen = u_unescape("\\u05d0 \\u200e123 \\u200e\\u0660\\u0661 ab", src, MAXLEN);
   1511     if (destLen != 13 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1512         log_err("\nWrong result #12, should be '%s', got '%s'\n",
   1513                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1514     }
   1515     RETURN_IF_BAD_ERRCODE("#22#");
   1516     srcLen = u_unescape("ab \t", src, MAXLEN);
   1517     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1518     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   1519     srcLen = u_unescape("\\u200f\t ab", src, MAXLEN);
   1520     if (destLen != 5 || memcmp(dest, src, destLen * sizeof(UChar))) {
   1521         log_err("\nWrong result #13, should be '%s', got '%s'\n",
   1522                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1523     }
   1524     RETURN_IF_BAD_ERRCODE("#23#");
   1525 
   1526     /* check exceeding para level */
   1527     ubidi_close(bidi);
   1528     bidi = ubidi_open();
   1529     srcLen = u_unescape("A\\u202a\\u05d0\\u202aC\\u202c\\u05d1\\u202cE", src, MAXLEN);
   1530     ubidi_setPara(bidi, src, srcLen, UBIDI_MAX_EXPLICIT_LEVEL - 1, NULL, &errorCode);
   1531     level = ubidi_getLevelAt(bidi, 2);
   1532     if (level != 61) {
   1533         log_err("\nWrong level at index 2\n, should be 61, got %d\n", level);
   1534     }
   1535     RETURN_IF_BAD_ERRCODE("#24#");
   1536 
   1537     /* check 1-char runs with RUNS_ONLY */
   1538     ubidi_setReorderingMode(bidi, UBIDI_REORDER_RUNS_ONLY);
   1539     srcLen = u_unescape("a \\u05d0 b \\u05d1 c \\u05d2 d ", src, MAXLEN);
   1540     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1541     runCount = ubidi_countRuns(bidi, &errorCode);
   1542     if (runCount != 14) {
   1543         log_err("\nWrong number of runs #3, should be 14, got %d\n", runCount);
   1544     }
   1545     RETURN_IF_BAD_ERRCODE("#25#");
   1546 
   1547     ubidi_close(bidi);
   1548     ubidi_close(bidiLine);
   1549 }
   1550 
   1551 static void
   1552 testFailureRecovery(void) {
   1553     UErrorCode errorCode;
   1554     UBiDi *bidi, *bidiLine;
   1555     UChar src[MAXLEN];
   1556     int32_t srcLen;
   1557     UBiDiLevel level;
   1558     UBiDiReorderingMode rm;
   1559     static UBiDiLevel myLevels[3] = {6,5,4};
   1560 
   1561     log_verbose("\nEntering TestFailureRecovery\n\n");
   1562     errorCode = U_FILE_ACCESS_ERROR;
   1563     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0) {
   1564         log_err("ubidi_writeReordered did not return 0 when passed a failing UErrorCode\n");
   1565     }
   1566     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0) {
   1567         log_err("ubidi_writeReverse did not return 0 when passed a failing UErrorCode\n");
   1568     }
   1569     errorCode = U_ZERO_ERROR;
   1570     if (ubidi_writeReordered(NULL, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
   1571         log_err("ubidi_writeReordered did not fail as expected\n");
   1572     }
   1573 
   1574     bidi = ubidi_open();
   1575     srcLen = u_unescape("abc", src, MAXLEN);
   1576     errorCode = U_ZERO_ERROR;
   1577     ubidi_setPara(bidi, src, srcLen, UBIDI_DEFAULT_LTR - 1, NULL, &errorCode);
   1578     if (U_SUCCESS(errorCode)) {
   1579         log_err("\nubidi_setPara did not fail when passed too big para level\n");
   1580     }
   1581     errorCode = U_ZERO_ERROR;
   1582     if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &errorCode) != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) {
   1583         log_err("ubidi_writeReverse did not fail as expected\n");
   1584     }
   1585     bidiLine = ubidi_open();
   1586     errorCode = U_ZERO_ERROR;
   1587     ubidi_setLine(bidi, 0, 6, bidiLine, &errorCode);
   1588     if (U_SUCCESS(errorCode)) {
   1589         log_err("\nubidi_setLine did not fail when called before valid setPara()\n");
   1590     }
   1591     errorCode = U_ZERO_ERROR;
   1592     srcLen = u_unescape("abc", src, MAXLEN);
   1593     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR + 4, NULL, &errorCode);
   1594     level = ubidi_getLevelAt(bidi, 3);
   1595     if (level != 0) {
   1596         log_err("\nubidi_getLevelAt did not fail when called with bad argument\n");
   1597     }
   1598     errorCode = U_ZERO_ERROR;
   1599     ubidi_close(bidi);
   1600     bidi = ubidi_openSized(-1, 0, &errorCode);
   1601     if (U_SUCCESS(errorCode)) {
   1602         log_err("\nubidi_openSized did not fail when called with bad argument\n");
   1603     }
   1604     ubidi_close(bidi);
   1605     bidi = ubidi_openSized(2, 1, &errorCode);
   1606     errorCode = U_ZERO_ERROR;
   1607     srcLen = u_unescape("abc", src, MAXLEN);
   1608     ubidi_setPara(bidi, src, srcLen, UBIDI_LTR, NULL, &errorCode);
   1609     if (U_SUCCESS(errorCode)) {
   1610         log_err("\nsetPara did not fail when called with text too long\n");
   1611     }
   1612     errorCode = U_ZERO_ERROR;
   1613     srcLen = u_unescape("=2", src, MAXLEN);
   1614     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1615     ubidi_countRuns(bidi, &errorCode);
   1616     if (U_SUCCESS(errorCode)) {
   1617         log_err("\nsetPara did not fail when called for too many runs\n");
   1618     }
   1619     ubidi_close(bidi);
   1620     bidi = ubidi_open();
   1621     rm = ubidi_getReorderingMode(bidi);
   1622     ubidi_setReorderingMode(bidi, UBIDI_REORDER_DEFAULT - 1);
   1623     if (rm != ubidi_getReorderingMode(bidi)) {
   1624         log_err("\nsetReorderingMode with bad argument #1 should have no effect\n");
   1625     }
   1626     ubidi_setReorderingMode(bidi, 9999);
   1627     if (rm != ubidi_getReorderingMode(bidi)) {
   1628         log_err("\nsetReorderingMode with bad argument #2 should have no effect\n");
   1629     }
   1630 
   1631     /* Try a surrogate char */
   1632     errorCode = U_ZERO_ERROR;
   1633     srcLen = u_unescape("\\uD800\\uDC00", src, MAXLEN);
   1634     ubidi_setPara(bidi, src, srcLen, UBIDI_RTL, NULL, &errorCode);
   1635     if (ubidi_getDirection(bidi) != UBIDI_MIXED) {
   1636         log_err("\ngetDirection for 1st surrogate char should be MIXED\n");
   1637     }
   1638     errorCode = U_ZERO_ERROR;
   1639     srcLen = u_unescape("abc", src, MAXLEN);
   1640     ubidi_setPara(bidi, src, srcLen, 5, myLevels, &errorCode);
   1641     if (U_SUCCESS(errorCode)) {
   1642         log_err("\nsetPara did not fail when called with bad levels\n");
   1643     }
   1644     ubidi_close(bidi);
   1645     ubidi_close(bidiLine);
   1646 
   1647     log_verbose("\nExiting TestFailureRecovery\n\n");
   1648 }
   1649 
   1650 static void
   1651 testMultipleParagraphs(void) {
   1652     static const char* const text = "__ABC\\u001c"          /* Para #0 offset 0 */
   1653                                     "__\\u05d0DE\\u001c"    /*       1        6 */
   1654                                     "__123\\u001c"          /*       2       12 */
   1655                                     "\\u000d\\u000a"        /*       3       18 */
   1656                                     "FG\\u000d"             /*       4       20 */
   1657                                     "\\u000d"               /*       5       23 */
   1658                                     "HI\\u000d\\u000a"      /*       6       24 */
   1659                                     "\\u000d\\u000a"        /*       7       28 */
   1660                                     "\\u000a"               /*       8       30 */
   1661                                     "\\u000a"               /*       9       31 */
   1662                                     "JK\\u001c";            /*      10       32 */
   1663     static const int32_t paraCount=11;
   1664     static const int32_t paraBounds[]={0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35};
   1665     static const UBiDiLevel paraLevels[]={UBIDI_LTR, UBIDI_RTL, UBIDI_DEFAULT_LTR, UBIDI_DEFAULT_RTL, 22, 23};
   1666     static const UBiDiLevel multiLevels[6][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   1667                                                   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
   1668                                                   {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   1669                                                   {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0},
   1670                                                   {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},
   1671                                                   {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}};
   1672     static const char* const text2 = "\\u05d0 1-2\\u001c\\u0630 1-2\\u001c1-2";
   1673     static const UBiDiLevel levels2[] = {1,1,2,2,2,0, 1,1,2,1,2,0, 2,2,2};
   1674     static UBiDiLevel myLevels[10] = {0,0,0,0,0,0,0,0,0,0};
   1675     static const UChar multiparaTestString[] = {
   1676         0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da,
   1677         0x20,  0xa,   0xa,   0x41,  0x72,  0x74,  0x69,  0x73,
   1678         0x74,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1, 0x5d4, 0x20,
   1679         0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,   0x41,  0x6c,
   1680         0x62,  0x75,  0x6d,  0x3a,  0x20,  0x5de, 0x5e0, 0x5e1,
   1681         0x5d4, 0x20,  0x5e1, 0x5e4, 0x5da, 0x20,  0xa,   0xa,
   1682         0x54,  0x69,  0x6d,  0x65,  0x3a,  0x20,  0x32,  0x3a,
   1683         0x32,  0x37,  0xa,  0xa
   1684     };
   1685     static const UBiDiLevel multiparaTestLevels[] = {
   1686         1, 1, 1, 1, 1, 1, 1, 1,
   1687         1, 1, 0, 0, 0, 0, 0, 0,
   1688         0, 0, 0, 1, 1, 1, 1, 1,
   1689         1, 1, 1, 0, 0, 0, 0, 0,
   1690         0, 0, 0, 0, 0, 1, 1, 1,
   1691         1, 1, 1, 1, 1, 0, 0, 0,
   1692         0, 0, 0, 0, 0, 0, 0, 0,
   1693         0, 0, 0, 0
   1694     };
   1695     UBiDiLevel gotLevel;
   1696     const UBiDiLevel* gotLevels;
   1697     UBool orderParagraphsLTR;
   1698     UChar src[MAXLEN], dest[MAXLEN];
   1699     UErrorCode errorCode=U_ZERO_ERROR;
   1700     UBiDi* pBidi=ubidi_open();
   1701     UBiDi* pLine;
   1702     int32_t srcSize, count, paraStart, paraLimit, paraIndex, length;
   1703     int32_t srcLen, destLen;
   1704     int i, j, k;
   1705 
   1706     log_verbose("\nEntering TestMultipleParagraphs\n\n");
   1707     u_unescape(text, src, MAXLEN);
   1708     srcSize=u_strlen(src);
   1709     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
   1710     if(U_FAILURE(errorCode)){
   1711         log_err("ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
   1712                 UBIDI_LTR, u_errorName(errorCode));
   1713         ubidi_close(pBidi);
   1714         return;
   1715     }
   1716     /* check paragraph count and boundaries */
   1717     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
   1718         log_err("ubidi_countParagraphs returned %d, should be %d\n",
   1719                 count, paraCount);
   1720     }
   1721     for (i=0; i<paraCount; i++) {
   1722         ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
   1723         if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
   1724             log_err("Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
   1725                     i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
   1726         }
   1727     }
   1728     errorCode=U_ZERO_ERROR;
   1729     /* check with last paragraph not terminated by B */
   1730     src[srcSize-1]='L';
   1731     ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode);
   1732     if(U_FAILURE(errorCode)){
   1733         log_err("2nd ubidi_setPara failed, paraLevel=%d, errorCode %s\n",
   1734                 UBIDI_LTR, u_errorName(errorCode));
   1735         ubidi_close(pBidi);
   1736         return;
   1737     }
   1738     if (paraCount!=(count=ubidi_countParagraphs(pBidi))) {
   1739         log_err("2nd ubidi_countParagraphs returned %d, should be %d\n",
   1740                 count, paraCount);
   1741     }
   1742     i=paraCount-1;
   1743     ubidi_getParagraphByIndex(pBidi, i, &paraStart, &paraLimit, NULL, &errorCode);
   1744     if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) {
   1745         log_err("2nd Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n",
   1746                 i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]);
   1747     }
   1748     errorCode=U_ZERO_ERROR;
   1749     /* check paraLevel for all paragraphs under various paraLevel specs */
   1750     for (k=0; k<6; k++) {
   1751         ubidi_setPara(pBidi, src, srcSize, paraLevels[k], NULL, &errorCode);
   1752         for (i=0; i<paraCount; i++) {
   1753             paraIndex=ubidi_getParagraph(pBidi, paraBounds[i], NULL, NULL, &gotLevel, &errorCode);
   1754             if (paraIndex!=i) {
   1755                 log_err("For paraLevel=%d paragraph=%d, found paragraph index=%d expected=%d\n",
   1756                         paraLevels[k], i, paraIndex, i);
   1757             }
   1758             if (gotLevel!=multiLevels[k][i]) {
   1759                 log_err("For paraLevel=%d paragraph=%d, found level=%d expected %d\n",
   1760                         paraLevels[k], i, gotLevel, multiLevels[k][i]);
   1761             }
   1762         }
   1763         gotLevel=ubidi_getParaLevel(pBidi);
   1764         if (gotLevel!=multiLevels[k][0]) {
   1765             log_err("For paraLevel=%d getParaLevel=%d, expected %d\n",
   1766                     paraLevels[k], gotLevel, multiLevels[k][0]);
   1767         }
   1768     }
   1769     errorCode=U_ZERO_ERROR;
   1770     /* check that the result of ubidi_getParaLevel changes if the first
   1771      * paragraph has a different level
   1772      */
   1773     src[0]=0x05d2;                      /* Hebrew letter Gimel */
   1774     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_LTR, NULL, &errorCode);
   1775     gotLevel=ubidi_getParaLevel(pBidi);
   1776     if (gotLevel!=UBIDI_RTL) {
   1777         log_err("For paraLevel=UBIDI_DEFAULT_LTR getParaLevel=%d, expected=%d\n",
   1778                         gotLevel, UBIDI_RTL);
   1779     }
   1780     errorCode=U_ZERO_ERROR;
   1781     /* check that line cannot overlap paragraph boundaries */
   1782     pLine=ubidi_open();
   1783     i=paraBounds[1];
   1784     k=paraBounds[2]+1;
   1785     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
   1786     if (U_SUCCESS(errorCode)) {
   1787         log_err("For line limits %d-%d got success %s\n",
   1788                 i, k, u_errorName(errorCode));
   1789     }
   1790     errorCode=U_ZERO_ERROR;
   1791     i=paraBounds[1];
   1792     k=paraBounds[2];
   1793     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
   1794     if (U_FAILURE(errorCode)) {
   1795         log_err("For line limits %d-%d got error %s\n",
   1796                 i, k, u_errorName(errorCode));
   1797         errorCode=U_ZERO_ERROR;
   1798     }
   1799     /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */
   1800     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
   1801     /* get levels through para Bidi block */
   1802     gotLevels=ubidi_getLevels(pBidi, &errorCode);
   1803     if (U_FAILURE(errorCode)) {
   1804         log_err("Error on Para getLevels %s\n", u_errorName(errorCode));
   1805         ubidi_close(pLine);
   1806         ubidi_close(pBidi);
   1807         return;
   1808     }
   1809     for (i=26; i<32; i++) {
   1810         if (gotLevels[i]!=UBIDI_RTL) {
   1811             log_err("For char %d(%04x), level=%d, expected=%d\n",
   1812                     i, src[i], gotLevels[i], UBIDI_RTL);
   1813         }
   1814     }
   1815     /* get levels through para Line block */
   1816     i=paraBounds[1];
   1817     k=paraBounds[2];
   1818     ubidi_setLine(pBidi, i, k, pLine, &errorCode);
   1819     if (U_FAILURE(errorCode)) {
   1820         log_err("For line limits %d-%d got error %s\n",
   1821                 i, k, u_errorName(errorCode));
   1822         ubidi_close(pLine);
   1823         ubidi_close(pBidi);
   1824         return;
   1825     }
   1826     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
   1827     gotLevels=ubidi_getLevels(pLine, &errorCode);
   1828     if (U_FAILURE(errorCode)) {
   1829         log_err("Error on Line getLevels %s\n", u_errorName(errorCode));
   1830         ubidi_close(pLine);
   1831         ubidi_close(pBidi);
   1832         return;
   1833     }
   1834     length=ubidi_getLength(pLine);
   1835     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=UBIDI_RTL)) {
   1836         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
   1837                 "level of separator=%d expected=%d\n",
   1838                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], UBIDI_RTL);
   1839     }
   1840     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
   1841     if (orderParagraphsLTR) {
   1842         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, FALSE);
   1843     }
   1844     ubidi_orderParagraphsLTR(pBidi, TRUE);
   1845     orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi);
   1846     if (!orderParagraphsLTR) {
   1847         log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, TRUE);
   1848     }
   1849     /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */
   1850     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
   1851     /* get levels through para Bidi block */
   1852     gotLevels=ubidi_getLevels(pBidi, &errorCode);
   1853     for (i=26; i<32; i++) {
   1854         if (gotLevels[i]!=0) {
   1855             log_err("For char %d(%04x), level=%d, expected=%d\n",
   1856                     i, src[i], gotLevels[i], 0);
   1857         }
   1858     }
   1859     errorCode=U_ZERO_ERROR;
   1860     /* get levels through para Line block */
   1861     i=paraBounds[1];
   1862     k=paraBounds[2];
   1863     ubidi_setLine(pBidi, paraStart, paraLimit, pLine, &errorCode);
   1864     paraIndex=ubidi_getParagraph(pLine, i, &paraStart, &paraLimit, &gotLevel, &errorCode);
   1865     gotLevels=ubidi_getLevels(pLine, &errorCode);
   1866     length=ubidi_getLength(pLine);
   1867     if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=0)) {
   1868         log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, "
   1869                 "level of separator=%d expected=%d\n",
   1870                 paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], 0);
   1871         log_verbose("levels=");
   1872         for (count=0; count<length; count++) {
   1873             log_verbose(" %d", gotLevels[count]);
   1874         }
   1875         log_verbose("\n");
   1876     }
   1877 
   1878     /* test that the concatenation of separate invocations of the bidi code
   1879      * on each individual paragraph in order matches the levels array that
   1880      * results from invoking bidi once over the entire multiparagraph tests
   1881      * (with orderParagraphsLTR false, of course)
   1882      */
   1883     u_unescape(text, src, MAXLEN);      /* restore original content */
   1884     srcSize=u_strlen(src);
   1885     ubidi_orderParagraphsLTR(pBidi, FALSE);
   1886     ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1887     gotLevels=ubidi_getLevels(pBidi, &errorCode);
   1888     for (i=0; i<paraCount; i++) {
   1889         /* use pLine for individual paragraphs */
   1890         paraStart = paraBounds[i];
   1891         length = paraBounds[i+1] - paraStart;
   1892         ubidi_setPara(pLine, src+paraStart, length, UBIDI_DEFAULT_RTL, NULL, &errorCode);
   1893         for (j=0; j<length; j++) {
   1894             if ((k=ubidi_getLevelAt(pLine, j)) != (gotLevel=gotLevels[paraStart+j])) {
   1895                 log_err("Checking paragraph concatenation: for paragraph=%d, "
   1896                         "char=%d(%04x), level=%d, expected=%d\n",
   1897                         i, j, src[paraStart+j], k, gotLevel);
   1898             }
   1899         }
   1900     }
   1901 
   1902     /* ensure that leading numerics in a paragraph are not treated as arabic
   1903        numerals because of arabic text in a preceding paragraph
   1904      */
   1905     u_unescape(text2, src, MAXLEN);
   1906     srcSize=u_strlen(src);
   1907     ubidi_orderParagraphsLTR(pBidi, TRUE);
   1908     ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode);
   1909     gotLevels=ubidi_getLevels(pBidi, &errorCode);
   1910     if (U_FAILURE(errorCode)) {
   1911         log_err("Can't get levels. %s\n", u_errorName(errorCode));
   1912         return;
   1913     }
   1914     for (i=0; i<srcSize; i++) {
   1915         if (gotLevels[i]!=levels2[i]) {
   1916             log_err("Checking leading numerics: for char %d(%04x), level=%d, expected=%d\n",
   1917                     i, src[i], gotLevels[i], levels2[i]);
   1918         }
   1919     }
   1920 
   1921     /* check handling of whitespace before end of paragraph separator when
   1922      * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B
   1923      */
   1924     u_memset(src, 0x0020, MAXLEN);
   1925     srcSize = 5;
   1926     ubidi_orderParagraphsLTR(pBidi, TRUE);
   1927     for (i=0x001c; i<=0x0020; i+=(0x0020-0x001c)) {
   1928         src[4]=(UChar)i;                /* with and without terminating B */
   1929         for (j=0x0041; j<=0x05d0; j+=(0x05d0-0x0041)) {
   1930             src[0]=(UChar)j;            /* leading 'A' or Alef */
   1931             for (gotLevel=4; gotLevel<=5; gotLevel++) {
   1932                 /* test even and odd paraLevel */
   1933                 ubidi_setPara(pBidi, src, srcSize, gotLevel, NULL, &errorCode);
   1934                 gotLevels=ubidi_getLevels(pBidi, &errorCode);
   1935                 for (k=1; k<=3; k++) {
   1936                     if (gotLevels[k]!=gotLevel) {
   1937                         log_err("Checking trailing spaces: for leading_char=%04x, "
   1938                                 "last_char=%04x, index=%d, level=%d, expected=%d\n",
   1939                                 src[0], src[4], k, gotLevels[k], gotLevel);
   1940                     }
   1941                 }
   1942             }
   1943         }
   1944     }
   1945 
   1946     /* check default orientation when inverse bidi and paragraph starts
   1947      * with LTR strong char and ends with RTL strong char, with and without
   1948      * a terminating B
   1949      */
   1950     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
   1951     srcLen = u_unescape("abc \\u05d2\\u05d1\n", src, MAXLEN);
   1952     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
   1953     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
   1954     srcLen = u_unescape("\\u05d1\\u05d2 abc\n", src, MAXLEN);
   1955     if (memcmp(src, dest, destLen * sizeof(UChar))) {
   1956         log_err("\nInvalid output #0, should be '%s', got '%s'\n",
   1957                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1958     }
   1959     srcLen = u_unescape("abc \\u05d2\\u05d1", src, MAXLEN);
   1960     ubidi_setPara(pBidi, src, srcLen, UBIDI_DEFAULT_LTR, NULL, &errorCode);
   1961     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
   1962     srcLen = u_unescape("\\u05d1\\u05d2 abc", src, MAXLEN);
   1963     if (memcmp(src, dest, destLen * sizeof(UChar))) {
   1964         log_err("\nInvalid output #1, should be '%s', got '%s'\n",
   1965                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1966     }
   1967 
   1968     /* check multiple paragraphs together with explicit levels
   1969      */
   1970     ubidi_setReorderingMode(pBidi, UBIDI_REORDER_DEFAULT);
   1971     srcLen = u_unescape("ab\\u05d1\\u05d2\n\\u05d3\\u05d4123", src, MAXLEN);
   1972     ubidi_setPara(pBidi, src, srcLen, UBIDI_LTR, myLevels, &errorCode);
   1973     destLen = ubidi_writeReordered(pBidi, dest, MAXLEN, 0, &errorCode);
   1974     srcLen = u_unescape("ab\\u05d2\\u05d1\\n123\\u05d4\\u05d3", src, MAXLEN);
   1975     if (memcmp(src, dest, destLen * sizeof(UChar))) {
   1976         log_err("\nInvalid output #2, should be '%s', got '%s'\n",
   1977                 aescstrdup(src, srcLen), aescstrdup(dest, destLen));
   1978     }
   1979     count = ubidi_countParagraphs(pBidi);
   1980     if (count != 2) {
   1981         log_err("\nInvalid number of paras, should be 2, got %d\n", count);
   1982     }
   1983 
   1984     ubidi_close(pLine);
   1985     ubidi_close(pBidi);
   1986     log_verbose("\nExiting TestMultipleParagraphs\n\n");
   1987 
   1988     /* check levels in multiple paragraphs with default para level
   1989      */
   1990     pBidi = ubidi_open();
   1991     errorCode = U_ZERO_ERROR;
   1992     ubidi_setPara(pBidi, multiparaTestString, LENGTHOF(multiparaTestString),
   1993                   UBIDI_DEFAULT_LTR, NULL, &errorCode);
   1994     if (U_FAILURE(errorCode)) {
   1995         log_err("ubidi_setPara failed for multiparaTestString\n");
   1996         ubidi_close(pBidi);
   1997         return;
   1998     }
   1999     gotLevels = ubidi_getLevels(pBidi, &errorCode);
   2000     if (U_FAILURE(errorCode)) {
   2001         log_err("ubidi_getLevels failed for multiparaTestString\n");
   2002         ubidi_close(pBidi);
   2003         return;
   2004     }
   2005     for (i = 0; i < LENGTHOF(multiparaTestString); i++) {
   2006         if (gotLevels[i] != multiparaTestLevels[i]) {
   2007             log_err("Error on level for multiparaTestString at index %d, "
   2008                     "expected=%d, actual=%d\n",
   2009                     i, multiparaTestLevels[i], gotLevels[i]);
   2010         }
   2011     }
   2012     ubidi_close(pBidi);
   2013 
   2014 }
   2015 
   2016 
   2017 /* inverse BiDi ------------------------------------------------------------- */
   2018 
   2019 static int countRoundtrips=0, countNonRoundtrips=0;
   2020 
   2021 #define STRING_TEST_CASE(s) { (s), LENGTHOF(s) }
   2022 
   2023 static void
   2024 testInverse(void) {
   2025     static const UChar
   2026         string0[]={ 0x6c, 0x61, 0x28, 0x74, 0x69, 0x6e, 0x20, 0x5d0, 0x5d1, 0x29, 0x5d2, 0x5d3 },
   2027         string1[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x31, 0x32, 0x33 },
   2028         string2[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x28, 0x5d1, 0x5d2, 0x20, 0x31, 0x29, 0x32, 0x33 },
   2029         string3[]={ 0x31, 0x32, 0x33, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x34, 0x35, 0x36 },
   2030         string4[]={ 0x61, 0x62, 0x20, 0x61, 0x62, 0x20, 0x661, 0x662 };
   2031 
   2032     static const struct {
   2033         const UChar *s;
   2034         int32_t length;
   2035     } testCases[]={
   2036         STRING_TEST_CASE(string0),
   2037         STRING_TEST_CASE(string1),
   2038         STRING_TEST_CASE(string2),
   2039         STRING_TEST_CASE(string3),
   2040         STRING_TEST_CASE(string4)
   2041     };
   2042 
   2043     UBiDi *pBiDi;
   2044     UErrorCode errorCode;
   2045     int i;
   2046 
   2047     log_verbose("\nEntering TestInverse\n\n");
   2048     pBiDi=ubidi_open();
   2049     if(pBiDi==NULL) {
   2050         log_err("unable to open a UBiDi object (out of memory)\n");
   2051         return;
   2052     }
   2053 
   2054     log_verbose("inverse Bidi: testInverse(L) with %u test cases ---\n", LENGTHOF(testCases));
   2055      for(i=0; i<LENGTHOF(testCases); ++i) {
   2056         log_verbose("Testing case %d\n", i);
   2057         errorCode=U_ZERO_ERROR;
   2058         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 0, &errorCode);
   2059     }
   2060 
   2061     log_verbose("inverse Bidi: testInverse(R) with %u test cases ---\n", LENGTHOF(testCases));
   2062     for(i=0; i<LENGTHOF(testCases); ++i) {
   2063         log_verbose("Testing case %d\n", i);
   2064         errorCode=U_ZERO_ERROR;
   2065         _testInverseBidi(pBiDi, testCases[i].s, testCases[i].length, 1, &errorCode);
   2066     }
   2067 
   2068     _testManyInverseBidi(pBiDi, 0);
   2069     _testManyInverseBidi(pBiDi, 1);
   2070 
   2071     ubidi_close(pBiDi);
   2072 
   2073     log_verbose("inverse Bidi: rountrips: %5u\nnon-roundtrips: %5u\n", countRoundtrips, countNonRoundtrips);
   2074 
   2075     _testWriteReverse();
   2076 
   2077     _testManyAddedPoints();
   2078 
   2079     _testMisc();
   2080 
   2081     log_verbose("\nExiting TestInverse\n\n");
   2082 }
   2083 
   2084 #define COUNT_REPEAT_SEGMENTS 6
   2085 
   2086 static const UChar repeatSegments[COUNT_REPEAT_SEGMENTS][2]={
   2087     { 0x61, 0x62 },     /* L */
   2088     { 0x5d0, 0x5d1 },   /* R */
   2089     { 0x627, 0x628 },   /* AL */
   2090     { 0x31, 0x32 },     /* EN */
   2091     { 0x661, 0x662 },   /* AN */
   2092     { 0x20, 0x20 }      /* WS (N) */
   2093 };
   2094 
   2095 static void
   2096 _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction) {
   2097     UChar text[8]={ 0, 0, 0x20, 0, 0, 0x20, 0, 0 };
   2098     int i, j, k;
   2099     UErrorCode errorCode;
   2100 
   2101     log_verbose("inverse Bidi: testManyInverseBidi(%c) - test permutations of text snippets ---\n",
   2102                  direction==0 ? 'L' : 'R');
   2103     for(i=0; i<COUNT_REPEAT_SEGMENTS; ++i) {
   2104         text[0]=repeatSegments[i][0];
   2105         text[1]=repeatSegments[i][1];
   2106         for(j=0; j<COUNT_REPEAT_SEGMENTS; ++j) {
   2107             text[3]=repeatSegments[j][0];
   2108             text[4]=repeatSegments[j][1];
   2109             for(k=0; k<COUNT_REPEAT_SEGMENTS; ++k) {
   2110                 text[6]=repeatSegments[k][0];
   2111                 text[7]=repeatSegments[k][1];
   2112 
   2113                 errorCode=U_ZERO_ERROR;
   2114                 log_verbose("inverse Bidi: testManyInverseBidi()[%u %u %u]\n", i, j, k);
   2115                 _testInverseBidi(pBiDi, text, 8, direction, &errorCode);
   2116             }
   2117         }
   2118     }
   2119 }
   2120 
   2121 static void
   2122 _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
   2123                 UBiDiLevel direction, UErrorCode *pErrorCode) {
   2124     UChar visualLTR[MAXLEN], logicalDest[MAXLEN], visualDest[MAXLEN];
   2125     int32_t ltrLength, logicalLength, visualLength;
   2126 
   2127     if(direction==0) {
   2128         log_verbose("inverse Bidi: testInverse(L)\n");
   2129 
   2130         /* convert visual to logical */
   2131         ubidi_setInverse(pBiDi, TRUE);
   2132         if (!ubidi_isInverse(pBiDi)) {
   2133             log_err("Error while doing ubidi_setInverse(TRUE)\n");
   2134         }
   2135         ubidi_setPara(pBiDi, src, srcLength, 0, NULL, pErrorCode);
   2136         if (src != ubidi_getText(pBiDi)) {
   2137             log_err("Wrong value returned by ubidi_getText\n");
   2138         }
   2139         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, LENGTHOF(logicalDest),
   2140                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
   2141         log_verbose("  v ");
   2142         printUnicode(src, srcLength, ubidi_getLevels(pBiDi, pErrorCode));
   2143         log_verbose("\n");
   2144 
   2145         /* convert back to visual LTR */
   2146         ubidi_setInverse(pBiDi, FALSE);
   2147         if (ubidi_isInverse(pBiDi)) {
   2148             log_err("Error while doing ubidi_setInverse(FALSE)\n");
   2149         }
   2150         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
   2151         visualLength=ubidi_writeReordered(pBiDi, visualDest, LENGTHOF(visualDest),
   2152                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS, pErrorCode);
   2153     } else {
   2154         log_verbose("inverse Bidi: testInverse(R)\n");
   2155 
   2156         /* reverse visual from RTL to LTR */
   2157         ltrLength=ubidi_writeReverse(src, srcLength, visualLTR, LENGTHOF(visualLTR), 0, pErrorCode);
   2158         log_verbose("  vr");
   2159         printUnicode(src, srcLength, NULL);
   2160         log_verbose("\n");
   2161 
   2162         /* convert visual RTL to logical */
   2163         ubidi_setInverse(pBiDi, TRUE);
   2164         ubidi_setPara(pBiDi, visualLTR, ltrLength, 0, NULL, pErrorCode);
   2165         logicalLength=ubidi_writeReordered(pBiDi, logicalDest, LENGTHOF(logicalDest),
   2166                                            UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode);
   2167         log_verbose("  vl");
   2168         printUnicode(visualLTR, ltrLength, ubidi_getLevels(pBiDi, pErrorCode));
   2169         log_verbose("\n");
   2170 
   2171         /* convert back to visual RTL */
   2172         ubidi_setInverse(pBiDi, FALSE);
   2173         ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode);
   2174         visualLength=ubidi_writeReordered(pBiDi, visualDest, LENGTHOF(visualDest),
   2175                                           UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_OUTPUT_REVERSE, pErrorCode);
   2176     }
   2177     log_verbose("  l ");
   2178     printUnicode(logicalDest, logicalLength, ubidi_getLevels(pBiDi, pErrorCode));
   2179     log_verbose("\n");
   2180     log_verbose("  v ");
   2181     printUnicode(visualDest, visualLength, NULL);
   2182     log_verbose("\n");
   2183 
   2184     /* check and print results */
   2185     if(U_FAILURE(*pErrorCode)) {
   2186         log_err("inverse BiDi: *** error %s\n"
   2187                 "                 turn on verbose mode to see details\n", u_errorName(*pErrorCode));
   2188     } else if(srcLength==visualLength && memcmp(src, visualDest, srcLength*U_SIZEOF_UCHAR)==0) {
   2189         ++countRoundtrips;
   2190         log_verbose(" + roundtripped\n");
   2191     } else {
   2192         ++countNonRoundtrips;
   2193         log_verbose(" * did not roundtrip\n");
   2194         log_err("inverse BiDi: transformation visual->logical->visual did not roundtrip the text;\n"
   2195                 "                 turn on verbose mode to see details\n");
   2196     }
   2197 }
   2198 
   2199 static void
   2200 _testWriteReverse(void) {
   2201     /* U+064e and U+0650 are combining marks (Mn) */
   2202     static const UChar forward[]={
   2203         0x200f, 0x627, 0x64e, 0x650, 0x20, 0x28, 0x31, 0x29
   2204     }, reverseKeepCombining[]={
   2205         0x29, 0x31, 0x28, 0x20, 0x627, 0x64e, 0x650, 0x200f
   2206     }, reverseRemoveControlsKeepCombiningDoMirror[]={
   2207         0x28, 0x31, 0x29, 0x20, 0x627, 0x64e, 0x650
   2208     };
   2209     UChar reverse[10];
   2210     UErrorCode errorCode;
   2211     int32_t length;
   2212 
   2213     /* test ubidi_writeReverse() with "interesting" options */
   2214     errorCode=U_ZERO_ERROR;
   2215     length=ubidi_writeReverse(forward, LENGTHOF(forward),
   2216                               reverse, LENGTHOF(reverse),
   2217                               UBIDI_KEEP_BASE_COMBINING,
   2218                               &errorCode);
   2219     if(U_FAILURE(errorCode) || length!=LENGTHOF(reverseKeepCombining) || memcmp(reverse, reverseKeepCombining, length*U_SIZEOF_UCHAR)!=0) {
   2220         log_err("failure in ubidi_writeReverse(UBIDI_KEEP_BASE_COMBINING): length=%d (should be %d), error code %s\n",
   2221                 length, LENGTHOF(reverseKeepCombining), u_errorName(errorCode));
   2222     }
   2223 
   2224     memset(reverse, 0xa5, LENGTHOF(reverse)*U_SIZEOF_UCHAR);
   2225     errorCode=U_ZERO_ERROR;
   2226     length=ubidi_writeReverse(forward, LENGTHOF(forward),
   2227                               reverse, LENGTHOF(reverse),
   2228                               UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING,
   2229                               &errorCode);
   2230     if(U_FAILURE(errorCode) || length!=LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror) || memcmp(reverse, reverseRemoveControlsKeepCombiningDoMirror, length*U_SIZEOF_UCHAR)!=0) {
   2231         log_err("failure in ubidi_writeReverse(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING):\n"
   2232                 "    length=%d (should be %d), error code %s\n",
   2233                 length, LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror), u_errorName(errorCode));
   2234     }
   2235 }
   2236 
   2237 static void _testManyAddedPoints(void) {
   2238     UErrorCode errorCode = U_ZERO_ERROR;
   2239     UBiDi *bidi = ubidi_open();
   2240     UChar text[90], dest[MAXLEN], expected[120];
   2241     int destLen, i;
   2242     for (i = 0; i < LENGTHOF(text); i+=3) {
   2243         text[i] = 0x0061; /* 'a' */
   2244         text[i+1] = 0x05d0;
   2245         text[i+2] = 0x0033; /* '3' */
   2246     }
   2247     ubidi_setReorderingMode(bidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
   2248     ubidi_setReorderingOptions(bidi, UBIDI_OPTION_INSERT_MARKS);
   2249     ubidi_setPara(bidi, text, LENGTHOF(text), UBIDI_LTR, NULL, &errorCode);
   2250     destLen = ubidi_writeReordered(bidi, dest, MAXLEN, 0, &errorCode);
   2251     for (i = 0; i < LENGTHOF(expected); i+=4) {
   2252         expected[i] = 0x0061; /* 'a' */
   2253         expected[i+1] = 0x05d0;
   2254         expected[i+2] = 0x200e;
   2255         expected[i+3] = 0x0033; /* '3' */
   2256     }
   2257     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
   2258         log_err("\nInvalid output with many added points, "
   2259                 "expected '%s', got '%s'\n",
   2260                 aescstrdup(expected, LENGTHOF(expected)),
   2261                 aescstrdup(dest, destLen));
   2262     }
   2263     ubidi_close(bidi);
   2264 }
   2265 
   2266 static void _testMisc(void) {
   2267     UErrorCode errorCode = U_ZERO_ERROR;
   2268     UBiDi *bidi = ubidi_open();
   2269     UChar src[3], dest[MAXLEN], expected[5];
   2270     int destLen;
   2271     ubidi_setInverse(bidi, TRUE);
   2272     src[0] = src[1] = src[2] = 0x0020;
   2273     ubidi_setPara(bidi, src, LENGTHOF(src), UBIDI_RTL, NULL, &errorCode);
   2274     destLen = ubidi_writeReordered(bidi, dest, MAXLEN,
   2275               UBIDI_OUTPUT_REVERSE | UBIDI_INSERT_LRM_FOR_NUMERIC,
   2276               &errorCode);
   2277     u_unescape("\\u200f   \\u200f", expected, 5);
   2278     if (memcmp(dest, expected, destLen * sizeof(UChar))) {
   2279         log_err("\nInvalid output with RLM at both sides, "
   2280                 "expected '%s', got '%s'\n",
   2281                 aescstrdup(expected, LENGTHOF(expected)),
   2282                 aescstrdup(dest, destLen));
   2283     }
   2284     ubidi_close(bidi);
   2285 }
   2286 
   2287 /* arabic shaping ----------------------------------------------------------- */
   2288 
   2289 static void
   2290 doArabicShapingTest(void) {
   2291     static const UChar
   2292     source[]={
   2293         0x31,   /* en:1 */
   2294         0x627,  /* arabic:alef */
   2295         0x32,   /* en:2 */
   2296         0x6f3,  /* an:3 */
   2297         0x61,   /* latin:a */
   2298         0x34,   /* en:4 */
   2299         0
   2300     }, en2an[]={
   2301         0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0
   2302     }, an2en[]={
   2303         0x31, 0x627, 0x32, 0x33, 0x61, 0x34, 0
   2304     }, logical_alen2an_init_lr[]={
   2305         0x31, 0x627, 0x662, 0x6f3, 0x61, 0x34, 0
   2306     }, logical_alen2an_init_al[]={
   2307         0x6f1, 0x627, 0x6f2, 0x6f3, 0x61, 0x34, 0
   2308     }, reverse_alen2an_init_lr[]={
   2309         0x661, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0
   2310     }, reverse_alen2an_init_al[]={
   2311         0x6f1, 0x627, 0x32, 0x6f3, 0x61, 0x6f4, 0
   2312     }, lamalef[]={
   2313         0xfefb, 0
   2314     };
   2315     UChar dest[8];
   2316     UErrorCode errorCode;
   2317     int32_t length;
   2318 
   2319     /* test number shaping */
   2320 
   2321     /* european->arabic */
   2322     errorCode=U_ZERO_ERROR;
   2323     length=u_shapeArabic(source, LENGTHOF(source),
   2324                          dest, LENGTHOF(dest),
   2325                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2326                          &errorCode);
   2327     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, en2an, length*U_SIZEOF_UCHAR)!=0) {
   2328         log_err("failure in u_shapeArabic(en2an)\n");
   2329     }
   2330 
   2331     /* arabic->european */
   2332     errorCode=U_ZERO_ERROR;
   2333     length=u_shapeArabic(source, -1,
   2334                          dest, LENGTHOF(dest),
   2335                          U_SHAPE_DIGITS_AN2EN|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
   2336                          &errorCode);
   2337     if(U_FAILURE(errorCode) || length!=u_strlen(source) || memcmp(dest, an2en, length*U_SIZEOF_UCHAR)!=0) {
   2338         log_err("failure in u_shapeArabic(an2en)\n");
   2339     }
   2340 
   2341     /* european->arabic with context, logical order, initial state not AL */
   2342     errorCode=U_ZERO_ERROR;
   2343     length=u_shapeArabic(source, LENGTHOF(source),
   2344                          dest, LENGTHOF(dest),
   2345                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN,
   2346                          &errorCode);
   2347     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, logical_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
   2348         log_err("failure in u_shapeArabic(logical_alen2an_init_lr)\n");
   2349     }
   2350 
   2351     /* european->arabic with context, logical order, initial state AL */
   2352     errorCode=U_ZERO_ERROR;
   2353     length=u_shapeArabic(source, LENGTHOF(source),
   2354                          dest, LENGTHOF(dest),
   2355                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED,
   2356                          &errorCode);
   2357     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, logical_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
   2358         log_err("failure in u_shapeArabic(logical_alen2an_init_al)\n");
   2359     }
   2360 
   2361     /* european->arabic with context, reverse order, initial state not AL */
   2362     errorCode=U_ZERO_ERROR;
   2363     length=u_shapeArabic(source, LENGTHOF(source),
   2364                          dest, LENGTHOF(dest),
   2365                          U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2366                          &errorCode);
   2367     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) {
   2368         log_err("failure in u_shapeArabic(reverse_alen2an_init_lr)\n");
   2369     }
   2370 
   2371     /* european->arabic with context, reverse order, initial state AL */
   2372     errorCode=U_ZERO_ERROR;
   2373     length=u_shapeArabic(source, LENGTHOF(source),
   2374                          dest, LENGTHOF(dest),
   2375                          U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2376                          &errorCode);
   2377     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, reverse_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) {
   2378         log_err("failure in u_shapeArabic(reverse_alen2an_init_al)\n");
   2379     }
   2380 
   2381     /* test noop */
   2382     errorCode=U_ZERO_ERROR;
   2383     length=u_shapeArabic(source, LENGTHOF(source),
   2384                          dest, LENGTHOF(dest),
   2385                          0,
   2386                          &errorCode);
   2387     if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || memcmp(dest, source, length*U_SIZEOF_UCHAR)!=0) {
   2388         log_err("failure in u_shapeArabic(noop)\n");
   2389     }
   2390 
   2391     errorCode=U_ZERO_ERROR;
   2392     length=u_shapeArabic(source, 0,
   2393                          dest, LENGTHOF(dest),
   2394                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2395                          &errorCode);
   2396     if(U_FAILURE(errorCode) || length!=0) {
   2397         log_err("failure in u_shapeArabic(en2an, sourceLength=0), returned %d/%s\n", u_errorName(errorCode), LENGTHOF(source));
   2398     }
   2399 
   2400     /* preflight digit shaping */
   2401     errorCode=U_ZERO_ERROR;
   2402     length=u_shapeArabic(source, LENGTHOF(source),
   2403                          NULL, 0,
   2404                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2405                          &errorCode);
   2406     if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=LENGTHOF(source)) {
   2407         log_err("failure in u_shapeArabic(en2an preflighting), returned %d/%s instead of %d/U_BUFFER_OVERFLOW_ERROR\n",
   2408                 length, u_errorName(errorCode), LENGTHOF(source));
   2409     }
   2410 
   2411     /* test illegal arguments */
   2412     errorCode=U_ZERO_ERROR;
   2413     length=u_shapeArabic(NULL, LENGTHOF(source),
   2414                          dest, LENGTHOF(dest),
   2415                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2416                          &errorCode);
   2417     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2418         log_err("failure in u_shapeArabic(source=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2419     }
   2420 
   2421     errorCode=U_ZERO_ERROR;
   2422     length=u_shapeArabic(source, -2,
   2423                          dest, LENGTHOF(dest),
   2424                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2425                          &errorCode);
   2426     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2427         log_err("failure in u_shapeArabic(sourceLength=-2), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2428     }
   2429 
   2430     errorCode=U_ZERO_ERROR;
   2431     length=u_shapeArabic(source, LENGTHOF(source),
   2432                          NULL, LENGTHOF(dest),
   2433                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2434                          &errorCode);
   2435     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2436         log_err("failure in u_shapeArabic(dest=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2437     }
   2438 
   2439     errorCode=U_ZERO_ERROR;
   2440     length=u_shapeArabic(source, LENGTHOF(source),
   2441                          dest, -1,
   2442                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2443                          &errorCode);
   2444     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2445         log_err("failure in u_shapeArabic(destSize=-1), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2446     }
   2447 
   2448     errorCode=U_ZERO_ERROR;
   2449     length=u_shapeArabic(source, LENGTHOF(source),
   2450                          dest, LENGTHOF(dest),
   2451                          U_SHAPE_DIGITS_RESERVED|U_SHAPE_DIGIT_TYPE_AN,
   2452                          &errorCode);
   2453     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2454         log_err("failure in u_shapeArabic(U_SHAPE_DIGITS_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2455     }
   2456 
   2457     errorCode=U_ZERO_ERROR;
   2458     length=u_shapeArabic(source, LENGTHOF(source),
   2459                          dest, LENGTHOF(dest),
   2460                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_RESERVED,
   2461                          &errorCode);
   2462     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2463         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2464     }
   2465 
   2466     errorCode=U_ZERO_ERROR;
   2467     length=u_shapeArabic(source, LENGTHOF(source),
   2468                          (UChar *)(source+2), LENGTHOF(dest), /* overlap source and destination */
   2469                          U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN,
   2470                          &errorCode);
   2471     if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
   2472         log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode));
   2473     }
   2474 
   2475     errorCode=U_ZERO_ERROR;
   2476     length=u_shapeArabic(lamalef, LENGTHOF(lamalef),
   2477                          dest, LENGTHOF(dest),
   2478                          U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2479                          &errorCode);
   2480     if(U_FAILURE(errorCode) || length == LENGTHOF(lamalef)) {
   2481         log_err("failure in u_shapeArabic(U_SHAPE_LETTERS_UNSHAPE | U_SHAPE_LENGTH_GROW_SHRINK | U_SHAPE_TEXT_DIRECTION_VISUAL_LTR)\n");
   2482         log_err("returned %s instead of U_ZERO_ERROR or returned length %d instead of 3\n", u_errorName(errorCode), length);
   2483     }
   2484 }
   2485 
   2486 static void
   2487 doLamAlefSpecialVLTRArabicShapingTest(void) {
   2488     static const UChar
   2489     source[]={
   2490 /*a*/   0x20 ,0x646,0x622,0x644,0x627,0x20,
   2491 /*b*/   0x646,0x623,0x64E,0x644,0x627,0x20,
   2492 /*c*/   0x646,0x627,0x670,0x644,0x627,0x20,
   2493 /*d*/   0x646,0x622,0x653,0x644,0x627,0x20,
   2494 /*e*/   0x646,0x625,0x655,0x644,0x627,0x20,
   2495 /*f*/   0x646,0x622,0x654,0x644,0x627,0x20,
   2496 /*g*/   0xFEFC,0x639
   2497     }, shape_near[]={
   2498         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
   2499         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
   2500         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
   2501         0xfefc,0xfecb
   2502     }, shape_at_end[]={
   2503         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
   2504         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
   2505         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,0x20,0x20,0x20
   2506     }, shape_at_begin[]={
   2507         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
   2508         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
   2509         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
   2510     }, shape_grow_shrink[]={
   2511         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
   2512         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
   2513         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
   2514     }, shape_excepttashkeel_near[]={
   2515         0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20,
   2516         0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20,
   2517         0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20,
   2518         0xfefc,0xfecb
   2519     }, shape_excepttashkeel_at_end[]={
   2520         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,
   2521         0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,
   2522         0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,
   2523         0x20,0x20,0x20
   2524     }, shape_excepttashkeel_at_begin[]={
   2525         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,
   2526         0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,
   2527         0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
   2528     }, shape_excepttashkeel_grow_shrink[]={
   2529         0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670,
   2530         0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d,
   2531         0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb
   2532     };
   2533 
   2534     UChar dest[38];
   2535     UErrorCode errorCode;
   2536     int32_t length;
   2537 
   2538     errorCode=U_ZERO_ERROR;
   2539 
   2540     length=u_shapeArabic(source, LENGTHOF(source),
   2541                          dest, LENGTHOF(dest),
   2542                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
   2543                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2544                          &errorCode);
   2545 
   2546     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
   2547         log_err("failure in u_shapeArabic(LAMALEF shape_near)\n");
   2548     }
   2549 
   2550     errorCode=U_ZERO_ERROR;
   2551 
   2552     length=u_shapeArabic(source, LENGTHOF(source),
   2553                          dest, LENGTHOF(dest),
   2554                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
   2555                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2556                          &errorCode);
   2557 
   2558     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_at_end) || memcmp(dest, shape_at_end, length*U_SIZEOF_UCHAR)!=0) {
   2559         log_err("failure in u_shapeArabic(LAMALEF shape_at_end)\n");
   2560     }
   2561 
   2562     errorCode=U_ZERO_ERROR;
   2563 
   2564     length=u_shapeArabic(source, LENGTHOF(source),
   2565                          dest, LENGTHOF(dest),
   2566                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
   2567                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2568                          &errorCode);
   2569 
   2570     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_at_begin) || memcmp(dest, shape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
   2571         log_err("failure in u_shapeArabic(LAMALEF shape_at_begin)\n");
   2572     }
   2573 
   2574     errorCode=U_ZERO_ERROR;
   2575 
   2576     length=u_shapeArabic(source, LENGTHOF(source),
   2577                          dest, LENGTHOF(dest),
   2578                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
   2579                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2580                          &errorCode);
   2581 
   2582     if(U_FAILURE(errorCode) || memcmp(dest, shape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
   2583         log_err("failure in u_shapeArabic(LAMALEF shape_grow_shrink)\n");
   2584     }
   2585 
   2586     /* ==================== U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED ==================== */
   2587 
   2588     errorCode=U_ZERO_ERROR;
   2589 
   2590     length=u_shapeArabic(source, LENGTHOF(source),
   2591                          dest, LENGTHOF(dest),
   2592                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
   2593                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2594                          &errorCode);
   2595 
   2596     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
   2597         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_near)\n");
   2598     }
   2599 
   2600     errorCode=U_ZERO_ERROR;
   2601 
   2602     length=u_shapeArabic(source, LENGTHOF(source),
   2603                          dest, LENGTHOF(dest),
   2604                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
   2605                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2606                          &errorCode);
   2607 
   2608     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_at_end) || memcmp(dest,shape_excepttashkeel_at_end , length*U_SIZEOF_UCHAR)!=0) {
   2609         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_end)\n");
   2610     }
   2611 
   2612     errorCode=U_ZERO_ERROR;
   2613 
   2614     length=u_shapeArabic(source, LENGTHOF(source),
   2615                          dest, LENGTHOF(dest),
   2616                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
   2617                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2618                          &errorCode);
   2619 
   2620     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_at_begin) || memcmp(dest, shape_excepttashkeel_at_begin, length*U_SIZEOF_UCHAR)!=0) {
   2621         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_begin)\n");
   2622     }
   2623 
   2624     errorCode=U_ZERO_ERROR;
   2625 
   2626     length=u_shapeArabic(source, LENGTHOF(source),
   2627                          dest, LENGTHOF(dest),
   2628                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_GROW_SHRINK|
   2629                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2630                          &errorCode);
   2631 
   2632     if(U_FAILURE(errorCode) || memcmp(dest, shape_excepttashkeel_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
   2633         log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_grow_shrink)\n");
   2634     }
   2635 }
   2636 
   2637 static void
   2638 doTashkeelSpecialVLTRArabicShapingTest(void) {
   2639     static const UChar
   2640     source[]={
   2641         0x64A,0x628,0x631,0x639,0x20,
   2642         0x64A,0x628,0x651,0x631,0x64E,0x639,0x20,
   2643         0x64C,0x64A,0x628,0x631,0x64F,0x639,0x20,
   2644         0x628,0x670,0x631,0x670,0x639,0x20,
   2645         0x628,0x653,0x631,0x653,0x639,0x20,
   2646         0x628,0x654,0x631,0x654,0x639,0x20,
   2647         0x628,0x655,0x631,0x655,0x639,0x20,
   2648     }, shape_near[]={
   2649         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe77,0xfecb,
   2650         0x20,0xfe72,0xfef2,0xfe91,0xfeae,0xfe79,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,
   2651         0xfecb,0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,
   2652         0xfecb,0x20,0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
   2653     }, shape_excepttashkeel_near[]={
   2654         0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe76,0xfecb,0x20,
   2655         0xfe72,0xfef2,0xfe91,0xfeae,0xfe78,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,0xfecb,
   2656         0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,0xfecb,0x20,
   2657         0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20
   2658     };
   2659 
   2660     UChar dest[43];
   2661     UErrorCode errorCode;
   2662     int32_t length;
   2663 
   2664     errorCode=U_ZERO_ERROR;
   2665 
   2666     length=u_shapeArabic(source, LENGTHOF(source),
   2667                          dest, LENGTHOF(dest),
   2668                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
   2669                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2670                          &errorCode);
   2671 
   2672     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_near) || memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) {
   2673         log_err("failure in u_shapeArabic(TASHKEEL shape_near)\n");
   2674     }
   2675 
   2676     errorCode=U_ZERO_ERROR;
   2677 
   2678     length=u_shapeArabic(source, LENGTHOF(source),
   2679                          dest, LENGTHOF(dest),
   2680                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
   2681                          U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2682                          &errorCode);
   2683 
   2684     if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_near) || memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) {
   2685         log_err("failure in u_shapeArabic(TASHKEEL shape_excepttashkeel_near)\n");
   2686     }
   2687 }
   2688 
   2689 static void
   2690 doLOGICALArabicDeShapingTest(void) {
   2691     static const UChar
   2692     source[]={
   2693         0x0020,0x0020,0x0020,0xFE8D,0xFEF5,0x0020,0xFEE5,0x0020,0xFE8D,0xFEF7,0x0020,
   2694         0xFED7,0xFEFC,0x0020,0xFEE1,0x0020,0xFE8D,0xFEDF,0xFECC,0xFEAE,0xFE91,0xFEF4,
   2695         0xFE94,0x0020,0xFE8D,0xFEDF,0xFEA4,0xFEAE,0xFE93,0x0020,0x0020,0x0020,0x0020
   2696     }, unshape_near[]={
   2697         0x20,0x20,0x20,0x627,0x644,0x622,0x646,0x20,0x627,0x644,0x623,0x642,0x644,0x627,
   2698         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
   2699         0x629,0x20,0x20,0x20,0x20
   2700     }, unshape_at_end[]={
   2701         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
   2702         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
   2703         0x644,0x62d,0x631,0x629,0x20
   2704     }, unshape_at_begin[]={
   2705         0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,0x644,0x627,0x20,
   2706         0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631,
   2707         0x629,0x20,0x20,0x20,0x20
   2708     }, unshape_grow_shrink[]={
   2709         0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,
   2710         0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,
   2711         0x644,0x62d,0x631,0x629,0x20,0x20,0x20,0x20
   2712     };
   2713 
   2714     UChar dest[36];
   2715     UErrorCode errorCode;
   2716     int32_t length;
   2717 
   2718     errorCode=U_ZERO_ERROR;
   2719 
   2720     length=u_shapeArabic(source, LENGTHOF(source),
   2721                          dest, LENGTHOF(dest),
   2722                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
   2723                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
   2724                          &errorCode);
   2725 
   2726     if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_near) || memcmp(dest, unshape_near, length*U_SIZEOF_UCHAR)!=0) {
   2727         log_err("failure in u_shapeArabic(unshape_near)\n");
   2728     }
   2729 
   2730     errorCode=U_ZERO_ERROR;
   2731 
   2732     length=u_shapeArabic(source, LENGTHOF(source),
   2733                          dest, LENGTHOF(dest),
   2734                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END|
   2735                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
   2736                          &errorCode);
   2737 
   2738     if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_at_end) || memcmp(dest, unshape_at_end, length*U_SIZEOF_UCHAR)!=0) {
   2739         log_err("failure in u_shapeArabic(unshape_at_end)\n");
   2740     }
   2741 
   2742     errorCode=U_ZERO_ERROR;
   2743 
   2744     length=u_shapeArabic(source, LENGTHOF(source),
   2745                          dest, LENGTHOF(dest),
   2746                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING|
   2747                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
   2748                          &errorCode);
   2749 
   2750     if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_at_begin) || memcmp(dest, unshape_at_begin, length*U_SIZEOF_UCHAR)!=0) {
   2751         log_err("failure in u_shapeArabic(unshape_at_begin)\n");
   2752     }
   2753 
   2754     errorCode=U_ZERO_ERROR;
   2755 
   2756     length=u_shapeArabic(source, LENGTHOF(source),
   2757                          dest, LENGTHOF(dest),
   2758                          U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_GROW_SHRINK|
   2759                          U_SHAPE_TEXT_DIRECTION_LOGICAL,
   2760                          &errorCode);
   2761 
   2762     if(U_FAILURE(errorCode) || memcmp(dest, unshape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) {
   2763         log_err("failure in u_shapeArabic(unshape_grow_shrink)\n");
   2764     }
   2765 
   2766 }
   2767 
   2768 static void
   2769 doTailTest(void) {
   2770   static const UChar src[] = { 0x0020, 0x0633, 0 };
   2771   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
   2772   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
   2773   UChar dst[3] = { 0x0000, 0x0000,0 };
   2774   int32_t length;
   2775   UErrorCode status;
   2776 
   2777   log_verbose("SRC: U+%04X U+%04X\n", src[0],src[1]);
   2778 
   2779   log_verbose("Trying old tail\n");
   2780   status = U_ZERO_ERROR;
   2781   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
   2782                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
   2783   if(U_FAILURE(status)) {
   2784     log_err("Fail: status %s\n", u_errorName(status));
   2785   } else if(length!=2) {
   2786     log_err("Fail: len %d expected 3\n", length);
   2787   } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) {
   2788     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
   2789             dst[0],dst[1],dst_old[0],dst_old[1]);
   2790   } else {
   2791     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
   2792             dst[0],dst[1],length,u_errorName(status));
   2793   }
   2794 
   2795 
   2796   log_verbose("Trying new tail\n");
   2797   status = U_ZERO_ERROR;
   2798   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
   2799                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
   2800   if(U_FAILURE(status)) {
   2801     log_err("Fail: status %s\n", u_errorName(status));
   2802   } else if(length!=2) {
   2803     log_err("Fail: len %d expected 3\n", length);
   2804   } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) {
   2805     log_err("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
   2806             dst[0],dst[1],dst_new[0],dst_new[1]);
   2807   } else {
   2808     log_verbose("OK:  U+%04X U+%04X len %d err %s\n",
   2809             dst[0],dst[1],length,u_errorName(status));
   2810   }
   2811 }
   2812 
   2813 static void
   2814 doArabicShapingTestForBug5421(void) {
   2815     static const UChar
   2816     persian_letters_source[]={
   2817         0x0020, 0x0698, 0x067E, 0x0686, 0x06AF, 0x0020
   2818     }, persian_letters[]={
   2819         0x0020, 0xFB8B, 0xFB59, 0xFB7D, 0xFB94, 0x0020
   2820     }, tashkeel_aggregation_source[]={
   2821         0x0020, 0x0628, 0x0651, 0x064E, 0x062A, 0x0631, 0x0645, 0x0020,
   2822         0x0628, 0x064E, 0x0651, 0x062A, 0x0631, 0x0645, 0x0020
   2823     }, tashkeel_aggregation[]={
   2824         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3,
   2825         0x0020, 0xFE90, 0xFC60, 0xFE97, 0xFEAE, 0xFEE3, 0x0020
   2826     }, untouched_presentation_source[]={
   2827         0x0020 ,0x0627, 0xfe90,0x0020
   2828     }, untouched_presentation[]={
   2829         0x0020,0xfe8D, 0xfe90,0x0020
   2830     }, untouched_presentation_r_source[]={
   2831         0x0020 ,0xfe90, 0x0627, 0x0020
   2832     }, untouched_presentation_r[]={
   2833         0x0020, 0xfe90,0xfe8D,0x0020
   2834     };
   2835 
   2836     UChar dest[38];
   2837     UErrorCode errorCode;
   2838     int32_t length;
   2839 
   2840     errorCode=U_ZERO_ERROR;
   2841 
   2842     length=u_shapeArabic(persian_letters_source, LENGTHOF(persian_letters_source),
   2843                          dest, LENGTHOF(dest),
   2844                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2845                          &errorCode);
   2846 
   2847     if(U_FAILURE(errorCode) || length!=LENGTHOF(persian_letters) || memcmp(dest, persian_letters, length*U_SIZEOF_UCHAR)!=0) {
   2848         log_err("failure in u_shapeArabic(persian_letters)\n");
   2849     }
   2850 
   2851     errorCode=U_ZERO_ERROR;
   2852 
   2853     length=u_shapeArabic(tashkeel_aggregation_source, LENGTHOF(tashkeel_aggregation_source),
   2854                          dest, LENGTHOF(dest),
   2855                          U_SHAPE_AGGREGATE_TASHKEEL|U_SHAPE_PRESERVE_PRESENTATION|
   2856                          U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2857                          &errorCode);
   2858 
   2859     if(U_FAILURE(errorCode) || length!=LENGTHOF(tashkeel_aggregation) || memcmp(dest, tashkeel_aggregation, length*U_SIZEOF_UCHAR)!=0) {
   2860         log_err("failure in u_shapeArabic(tashkeel_aggregation)\n");
   2861     }
   2862 
   2863     errorCode=U_ZERO_ERROR;
   2864 
   2865     length=u_shapeArabic(untouched_presentation_source, LENGTHOF(untouched_presentation_source),
   2866                          dest, LENGTHOF(dest),
   2867                          U_SHAPE_PRESERVE_PRESENTATION|
   2868                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR,
   2869                          &errorCode);
   2870 
   2871     if(U_FAILURE(errorCode) || length!=LENGTHOF(untouched_presentation) || memcmp(dest, untouched_presentation, length*U_SIZEOF_UCHAR)!=0) {
   2872         log_err("failure in u_shapeArabic(untouched_presentation)\n");
   2873     }
   2874 
   2875     errorCode=U_ZERO_ERROR;
   2876 
   2877     length=u_shapeArabic(untouched_presentation_r_source, LENGTHOF(untouched_presentation_r_source),
   2878                          dest, LENGTHOF(dest),
   2879                          U_SHAPE_PRESERVE_PRESENTATION|
   2880                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_TEXT_DIRECTION_LOGICAL,
   2881                          &errorCode);
   2882 
   2883     if(U_FAILURE(errorCode) || length!=LENGTHOF(untouched_presentation_r) || memcmp(dest, untouched_presentation_r, length*U_SIZEOF_UCHAR)!=0) {
   2884         log_err("failure in u_shapeArabic(untouched_presentation_r)\n");
   2885     }
   2886 }
   2887 
   2888 /* helpers ------------------------------------------------------------------ */
   2889 
   2890 static void initCharFromDirProps(void) {
   2891     static const UVersionInfo ucd401={ 4, 0, 1, 0 };
   2892     static UVersionInfo ucdVersion={ 0, 0, 0, 0 };
   2893 
   2894     /* lazy initialization */
   2895     if(ucdVersion[0]>0) {
   2896         return;
   2897     }
   2898 
   2899     u_getUnicodeVersion(ucdVersion);
   2900     if(memcmp(ucdVersion, ucd401, sizeof(UVersionInfo))>=0) {
   2901         /* Unicode 4.0.1 changes bidi classes for +-/ */
   2902         charFromDirProp[U_EUROPEAN_NUMBER_SEPARATOR]=0x2b; /* change ES character from / to + */
   2903     }
   2904 }
   2905 
   2906 /* return a string with characters according to the desired directional properties */
   2907 static UChar *
   2908 getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer) {
   2909     int32_t i;
   2910 
   2911     initCharFromDirProps();
   2912 
   2913     /* this part would have to be modified for UTF-x */
   2914     for(i=0; i<length; ++i) {
   2915         buffer[i]=charFromDirProp[dirProps[i]];
   2916     }
   2917     buffer[length]=0;
   2918     return buffer;
   2919 }
   2920 
   2921 static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels) {
   2922     int32_t i;
   2923 
   2924     log_verbose("{ ");
   2925     for(i=0; i<length; ++i) {
   2926         if(levels!=NULL) {
   2927             log_verbose("%4x.%u  ", s[i], levels[i]);
   2928         } else {
   2929             log_verbose("%4x    ", s[i]);
   2930         }
   2931     }
   2932     log_verbose(" }");
   2933 }
   2934 
   2935 /* new BIDI API */
   2936 
   2937 /* Reordering Mode BiDi --------------------------------------------------------- */
   2938 
   2939 static const UBiDiLevel paraLevels[] = { UBIDI_LTR, UBIDI_RTL };
   2940 
   2941 static UBool
   2942 assertSuccessful(const char* message, UErrorCode* rc) {
   2943     if (rc != NULL && U_FAILURE(*rc)) {
   2944         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
   2945         return FALSE;
   2946     }
   2947     return TRUE;
   2948 }
   2949 
   2950 static UBool
   2951 assertStringsEqual(const char* expected, const char* actual, const char* src,
   2952                    const char* mode, const char* option, UBiDi* pBiDi) {
   2953     if (uprv_strcmp(expected, actual)) {
   2954         char formatChars[MAXLEN];
   2955         log_err("\nActual and expected output mismatch.\n"
   2956             "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d %s\n%20s %u\n%20s %d %s\n",
   2957             "Input:", src,
   2958             "Actual output:", actual,
   2959             "Expected output:", expected,
   2960             "Levels:", formatLevels(pBiDi, formatChars),
   2961             "Reordering mode:", ubidi_getReorderingMode(pBiDi), mode,
   2962             "Paragraph level:", ubidi_getParaLevel(pBiDi),
   2963             "Reordering option:", ubidi_getReorderingOptions(pBiDi), option);
   2964         return FALSE;
   2965     }
   2966     return TRUE;
   2967 }
   2968 
   2969 static UBiDi*
   2970 getBiDiObject(void) {
   2971     UBiDi* pBiDi = ubidi_open();
   2972     if (pBiDi == NULL) {
   2973         log_err("Unable to allocate a UBiDi object. Tests are skipped.\n");
   2974     }
   2975     return pBiDi;
   2976 }
   2977 
   2978 #define MAKE_ITEMS(val) val, #val
   2979 
   2980 static const struct {
   2981     UBiDiReorderingMode value;
   2982     const char* description;
   2983 }
   2984 modes[] = {
   2985     { MAKE_ITEMS(UBIDI_REORDER_GROUP_NUMBERS_WITH_R) },
   2986     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_LIKE_DIRECT) },
   2987     { MAKE_ITEMS(UBIDI_REORDER_NUMBERS_SPECIAL) },
   2988     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) },
   2989     { MAKE_ITEMS(UBIDI_REORDER_INVERSE_NUMBERS_AS_L) }
   2990 };
   2991 static const struct {
   2992     uint32_t value;
   2993     const char* description;
   2994 }
   2995 options[] = {
   2996     { MAKE_ITEMS(UBIDI_OPTION_INSERT_MARKS) },
   2997     { MAKE_ITEMS(0) }
   2998 };
   2999 
   3000 #define TC_COUNT                LENGTHOF(textIn)
   3001 #define MODES_COUNT             LENGTHOF(modes)
   3002 #define OPTIONS_COUNT           LENGTHOF(options)
   3003 #define LEVELS_COUNT            LENGTHOF(paraLevels)
   3004 
   3005 static const char* const textIn[] = {
   3006 /* (0) 123 */
   3007     "123",
   3008 /* (1) .123->4.5 */
   3009     ".123->4.5",
   3010 /* (2) 678 */
   3011     "678",
   3012 /* (3) .678->8.9 */
   3013     ".678->8.9",
   3014 /* (4) JIH1.2,3MLK */
   3015     "JIH1.2,3MLK",
   3016 /* (5) FE.>12-> */
   3017     "FE.>12->",
   3018 /* (6) JIH.>12->a */
   3019     "JIH.>12->a",
   3020 /* (7) CBA.>67->89=a */
   3021     "CBA.>67->89=a",
   3022 /* (8) CBA.123->xyz */
   3023     "CBA.123->xyz",
   3024 /* (9) .>12->xyz */
   3025     ".>12->xyz",
   3026 /* (10) a.>67->xyz */
   3027     "a.>67->xyz",
   3028 /* (11) 123JIH */
   3029     "123JIH",
   3030 /* (12) 123 JIH */
   3031     "123 JIH"
   3032 };
   3033 
   3034 static const char* const textOut[] = {
   3035 /* TC 0: 123 */
   3036     "123",                                                              /* (0) */
   3037 /* TC 1: .123->4.5 */
   3038     ".123->4.5",                                                        /* (1) */
   3039     "4.5<-123.",                                                        /* (2) */
   3040 /* TC 2: 678 */
   3041     "678",                                                              /* (3) */
   3042 /* TC 3: .678->8.9 */
   3043     ".8.9<-678",                                                        /* (4) */
   3044     "8.9<-678.",                                                        /* (5) */
   3045     ".678->8.9",                                                        /* (6) */
   3046 /* TC 4: MLK1.2,3JIH */
   3047     "KLM1.2,3HIJ",                                                      /* (7) */
   3048 /* TC 5: FE.>12-> */
   3049     "12<.EF->",                                                         /* (8) */
   3050     "<-12<.EF",                                                         /* (9) */
   3051     "EF.>@12->",                                                        /* (10) */
   3052 /* TC 6: JIH.>12->a */
   3053     "12<.HIJ->a",                                                       /* (11) */
   3054     "a<-12<.HIJ",                                                       /* (12) */
   3055     "HIJ.>@12->a",                                                      /* (13) */
   3056     "a&<-12<.HIJ",                                                      /* (14) */
   3057 /* TC 7: CBA.>67->89=a */
   3058     "ABC.>@67->89=a",                                                   /* (15) */
   3059     "a=89<-67<.ABC",                                                    /* (16) */
   3060     "a&=89<-67<.ABC",                                                   /* (17) */
   3061     "89<-67<.ABC=a",                                                    /* (18) */
   3062 /* TC 8: CBA.123->xyz */
   3063     "123.ABC->xyz",                                                     /* (19) */
   3064     "xyz<-123.ABC",                                                     /* (20) */
   3065     "ABC.@123->xyz",                                                    /* (21) */
   3066     "xyz&<-123.ABC",                                                    /* (22) */
   3067 /* TC 9: .>12->xyz */
   3068     ".>12->xyz",                                                        /* (23) */
   3069     "xyz<-12<.",                                                        /* (24) */
   3070     "xyz&<-12<.",                                                       /* (25) */
   3071 /* TC 10: a.>67->xyz */
   3072     "a.>67->xyz",                                                       /* (26) */
   3073     "a.>@67@->xyz",                                                     /* (27) */
   3074     "xyz<-67<.a",                                                       /* (28) */
   3075 /* TC 11: 123JIH */
   3076     "123HIJ",                                                           /* (29) */
   3077     "HIJ123",                                                           /* (30) */
   3078 /* TC 12: 123 JIH */
   3079     "123 HIJ",                                                          /* (31) */
   3080     "HIJ 123",                                                          /* (32) */
   3081 };
   3082 
   3083 #define NO                  UBIDI_MAP_NOWHERE
   3084 #define MAX_MAP_LENGTH      20
   3085 
   3086 static const int32_t forwardMap[][MAX_MAP_LENGTH] = {
   3087 /* TC 0: 123 */
   3088     { 0, 1, 2 },                                                        /* (0) */
   3089 /* TC 1: .123->4.5 */
   3090     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
   3091     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (2) */
   3092 /* TC 2: 678 */
   3093     { 0, 1, 2 },                                                        /* (3) */
   3094 /* TC 3: .678->8.9 */
   3095     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
   3096     { 8, 5, 6, 7, 4, 3, 0, 1, 2 },                                      /* (5) */
   3097     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
   3098 /* TC 4: MLK1.2,3JIH */
   3099     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
   3100 /* TC 5: FE.>12-> */
   3101     { 5, 4, 3, 2, 0, 1, 6, 7 },                                         /* (8) */
   3102     { 7, 6, 5, 4, 2, 3, 1, 0 },                                         /* (9) */
   3103     { 1, 0, 2, 3, 5, 6, 7, 8 },                                         /* (10) */
   3104 /* TC 6: JIH.>12->a */
   3105     { 6, 5, 4, 3, 2, 0, 1, 7, 8, 9 },                                   /* (11) */
   3106     { 9, 8, 7, 6, 5, 3, 4, 2, 1, 0 },                                   /* (12) */
   3107     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10 },                                  /* (13) */
   3108     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0 },                                  /* (14) */
   3109 /* TC 7: CBA.>67->89=a */
   3110     { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13 },                      /* (15) */
   3111     { 12, 11, 10, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0 },                       /* (16) */
   3112     { 13, 12, 11, 10, 9, 7, 8, 6, 5, 3, 4, 2, 0 },                      /* (17) */
   3113     { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0, 1, 11, 12 },                       /* (18) */
   3114 /* TC 8: CBA.123->xyz */
   3115     { 6, 5, 4, 3, 0, 1, 2, 7, 8, 9, 10, 11 },                           /* (19) */
   3116     { 11, 10, 9, 8, 5, 6, 7, 4, 3, 0, 1, 2 },                           /* (20) */
   3117     { 2, 1, 0, 3, 5, 6, 7, 8, 9, 10, 11, 12 },                          /* (21) */
   3118     { 12, 11, 10, 9, 6, 7, 8, 5, 4, 0, 1, 2 },                          /* (22) */
   3119 /* TC 9: .>12->xyz */
   3120     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
   3121     { 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                      /* (24) */
   3122     { 9, 8, 6, 7, 5, 4, 0, 1, 2 },                                      /* (25) */
   3123 /* TC 10: a.>67->xyz */
   3124     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
   3125     { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11 },                                 /* (27) */
   3126     { 9, 8, 7, 5, 6, 4, 3, 0, 1, 2 },                                   /* (28) */
   3127 /* TC 11: 123JIH */
   3128     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
   3129     { 3, 4, 5, 2, 1, 0 },                                               /* (30) */
   3130 /* TC 12: 123 JIH */
   3131     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
   3132     { 4, 5, 6, 3, 2, 1, 0 },                                            /* (32) */
   3133 };
   3134 
   3135 static const int32_t inverseMap[][MAX_MAP_LENGTH] = {
   3136 /* TC 0: 123 */
   3137     { 0, 1, 2 },                                                        /* (0) */
   3138 /* TC 1: .123->4.5 */
   3139     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (1) */
   3140     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (2) */
   3141 /* TC 2: 678 */
   3142     { 0, 1, 2 },                                                        /* (3) */
   3143 /* TC 3: .678->8.9 */
   3144     { 0, 6, 7, 8, 5, 4, 1, 2, 3 },                                      /* (4) */
   3145     { 6, 7, 8, 5, 4, 1, 2, 3, 0 },                                      /* (5) */
   3146     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (6) */
   3147 /* TC 4: MLK1.2,3JIH */
   3148     { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 },                               /* (7) */
   3149 /* TC 5: FE.>12-> */
   3150     { 4, 5, 3, 2, 1, 0, 6, 7 },                                         /* (8) */
   3151     { 7, 6, 4, 5, 3, 2, 1, 0 },                                         /* (9) */
   3152     { 1, 0, 2, 3, NO, 4, 5, 6, 7 },                                     /* (10) */
   3153 /* TC 6: JIH.>12->a */
   3154     { 5, 6, 4, 3, 2, 1, 0, 7, 8, 9 },                                   /* (11) */
   3155     { 9, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                                   /* (12) */
   3156     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9 },                               /* (13) */
   3157     { 9, NO, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                               /* (14) */
   3158 /* TC 7: CBA.>67->89=a */
   3159     { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9, 10, 11, 12 },                   /* (15) */
   3160     { 12, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                       /* (16) */
   3161     { 12, NO, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 },                   /* (17) */
   3162     { 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0, 11, 12 },                       /* (18) */
   3163 /* TC 8: CBA.123->xyz */
   3164     { 4, 5, 6, 3, 2, 1, 0, 7, 8, 9, 10, 11 },                           /* (19) */
   3165     { 9, 10, 11, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                           /* (20) */
   3166     { 2, 1, 0, 3, NO, 4, 5, 6, 7, 8, 9, 10, 11 },                       /* (21) */
   3167     { 9, 10, 11, NO, 8, 7, 4, 5, 6, 3, 2, 1, 0 },                       /* (22) */
   3168 /* TC 9: .>12->xyz */
   3169     { 0, 1, 2, 3, 4, 5, 6, 7, 8 },                                      /* (23) */
   3170     { 6, 7, 8, 5, 4, 2, 3, 1, 0 },                                      /* (24) */
   3171     { 6, 7, 8, NO, 5, 4, 2, 3, 1, 0 },                                  /* (25) */
   3172 /* TC 10: a.>67->xyz */
   3173     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },                                   /* (26) */
   3174     { 0, 1, 2, NO, 3, 4, NO, 5, 6, 7, 8, 9 },                           /* (27) */
   3175     { 7, 8, 9, 6, 5, 3, 4, 2, 1, 0 },                                   /* (28) */
   3176 /* TC 11: 123JIH */
   3177     { 0, 1, 2, 5, 4, 3 },                                               /* (29) */
   3178     { 5, 4, 3, 0, 1, 2 },                                               /* (30) */
   3179 /* TC 12: 123 JIH */
   3180     { 0, 1, 2, 3, 6, 5, 4 },                                            /* (31) */
   3181     { 6, 5, 4, 3, 0, 1, 2 },                                            /* (32) */
   3182 };
   3183 
   3184 static const char outIndices[TC_COUNT][MODES_COUNT - 1][OPTIONS_COUNT]
   3185             [LEVELS_COUNT] = {
   3186     { /* TC 0: 123 */
   3187         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3188         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3189         {{ 0,  0}, { 0,  0}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3190         {{ 0,  0}, { 0,  0}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3191     },
   3192     { /* TC 1: .123->4.5 */
   3193         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3194         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3195         {{ 1,  2}, { 1,  2}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3196         {{ 1,  2}, { 1,  2}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3197     },
   3198     { /* TC 2: 678 */
   3199         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3200         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3201         {{ 3,  3}, { 3,  3}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3202         {{ 3,  3}, { 3,  3}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3203     },
   3204     { /* TC 3: .678->8.9 */
   3205         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3206         {{ 4,  5}, { 4,  5}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3207         {{ 6,  5}, { 6,  5}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3208         {{ 6,  5}, { 6,  5}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3209     },
   3210     { /* TC 4: MLK1.2,3JIH */
   3211         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3212         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3213         {{ 7,  7}, { 7,  7}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3214         {{ 7,  7}, { 7,  7}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3215     },
   3216     { /* TC 5: FE.>12-> */
   3217         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3218         {{10,  9}, { 8,  9}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3219         {{ 8,  9}, { 8,  9}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3220         {{10,  9}, { 8,  9}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3221     },
   3222     { /* TC 6: JIH.>12->a */
   3223         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3224         {{13, 14}, {11, 12}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3225         {{11, 12}, {11, 12}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3226         {{13, 14}, {11, 12}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3227     },
   3228     { /* TC 7: CBA.>67->89=a */
   3229         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3230         {{18, 17}, {18, 16}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3231         {{18, 16}, {18, 16}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3232         {{15, 17}, {18, 16}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3233     },
   3234     { /* TC 8: CBA.>124->xyz */
   3235         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3236         {{21, 22}, {19, 20}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3237         {{19, 20}, {19, 20}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3238         {{21, 22}, {19, 20}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3239     },
   3240     { /* TC 9: .>12->xyz */
   3241         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3242         {{23, 25}, {23, 24}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3243         {{23, 24}, {23, 24}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3244         {{23, 25}, {23, 24}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3245     },
   3246     { /* TC 10: a.>67->xyz */
   3247         {{26, 26}, {26, 26}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3248         {{26, 27}, {26, 28}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3249         {{26, 28}, {26, 28}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3250         {{26, 27}, {26, 28}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3251     },
   3252     { /* TC 11: 124JIH */
   3253         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3254         {{29, 30}, {29, 30}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3255         {{30, 30}, {30, 30}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3256         {{30, 30}, {30, 30}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3257     },
   3258     { /* TC 12: 124 JIH */
   3259         {{32, 32}, {32, 32}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3260         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3261         {{31, 32}, {31, 32}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3262         {{31, 32}, {31, 32}}  /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3263     }
   3264 };
   3265 
   3266 static UBool
   3267 assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex, const char *srcChars,
   3268                 const char *destChars, const UChar *dest, int32_t destLen,
   3269                 int mode, int option, UBiDiLevel level) {
   3270 
   3271     static const char roundtrip[TC_COUNT][MODES_COUNT][OPTIONS_COUNT]
   3272                 [LEVELS_COUNT] = {
   3273         { /* TC 0: 123 */
   3274             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3275             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3276             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3277             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3278             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3279         },
   3280         { /* TC 1: .123->4.5 */
   3281             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3282             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3283             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3284             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3285             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3286         },
   3287         { /* TC 2: 678 */
   3288             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3289             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3290             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3291             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3292             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3293         },
   3294         { /* TC 3: .678->8.9 */
   3295             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3296             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3297             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3298             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3299             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3300         },
   3301         { /* TC 4: MLK1.2,3JIH */
   3302             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3303             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3304             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3305             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3306             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3307         },
   3308         { /* TC 5: FE.>12-> */
   3309             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3310             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3311             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3312             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3313             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3314         },
   3315         { /* TC 6: JIH.>12->a */
   3316             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3317             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3318             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3319             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3320             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3321         },
   3322         { /* TC 7: CBA.>67->89=a */
   3323             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3324             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3325             {{ 0,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3326             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3327             {{ 0,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3328         },
   3329         { /* TC 8: CBA.>123->xyz */
   3330             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3331             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3332             {{ 0,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3333             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3334             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3335         },
   3336         { /* TC 9: .>12->xyz */
   3337             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3338             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3339             {{ 1,  0}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3340             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3341             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3342         },
   3343         { /* TC 10: a.>67->xyz */
   3344             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3345             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3346             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3347             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3348             {{ 1,  0}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3349         },
   3350         { /* TC 11: 123JIH */
   3351             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3352             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3353             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3354             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3355             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3356         },
   3357         { /* TC 12: 123 JIH */
   3358             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_GROUP_NUMBERS_WITH_R */
   3359             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_LIKE_DIRECT */
   3360             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_NUMBERS_SPECIAL */
   3361             {{ 1,  1}, { 1,  1}}, /* UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL */
   3362             {{ 1,  1}, { 1,  1}}  /* UBIDI_REORDER_INVERSE_NUMBERS_AS_L */
   3363         }
   3364     };
   3365 
   3366     #define SET_ROUND_TRIP_MODE(mode) \
   3367         ubidi_setReorderingMode(pBiDi, mode); \
   3368         desc = #mode; \
   3369         break;
   3370 
   3371     UErrorCode rc = U_ZERO_ERROR;
   3372     UChar dest2[MAXLEN];
   3373     int32_t destLen2;
   3374     const char* desc;
   3375     char destChars2[MAXLEN];
   3376     char destChars3[MAXLEN];
   3377 
   3378     switch (modes[mode].value) {
   3379         case UBIDI_REORDER_NUMBERS_SPECIAL:
   3380             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL)
   3381         case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
   3382             SET_ROUND_TRIP_MODE(UBIDI_REORDER_GROUP_NUMBERS_WITH_R)
   3383         case UBIDI_REORDER_RUNS_ONLY:
   3384             SET_ROUND_TRIP_MODE(UBIDI_REORDER_RUNS_ONLY)
   3385         case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
   3386             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
   3387         case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
   3388             SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT)
   3389         case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
   3390             SET_ROUND_TRIP_MODE(UBIDI_REORDER_NUMBERS_SPECIAL)
   3391         default:
   3392             SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_LIKE_DIRECT)
   3393     }
   3394     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
   3395 
   3396     ubidi_setPara(pBiDi, dest, destLen, level, NULL, &rc);
   3397     assertSuccessful("ubidi_setPara", &rc);
   3398     *dest2 = 0;
   3399     destLen2 = ubidi_writeReordered(pBiDi, dest2, MAXLEN, UBIDI_DO_MIRRORING,
   3400                                     &rc);
   3401     assertSuccessful("ubidi_writeReordered", &rc);
   3402 
   3403     u16ToPseudo(destLen, dest, destChars3);
   3404     u16ToPseudo(destLen2, dest2, destChars2);
   3405     checkWhatYouCan(pBiDi, destChars3, destChars2);
   3406     if (strcmp(srcChars, destChars2)) {
   3407         if (roundtrip[tc][mode][option][level]) {
   3408             log_err("\nRound trip failed for case=%d mode=%d option=%d.\n"
   3409                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
   3410                     "\n%20s %u\n", tc, mode, option,
   3411                     "Original text:", srcChars,
   3412                     "Round-tripped text:", destChars2,
   3413                     "Intermediate  text:", destChars3,
   3414                     "Reordering mode:", modes[mode].description,
   3415                     "Reordering option:", options[option].description,
   3416                     "Paragraph level:", level);
   3417         }
   3418         else {
   3419             log_verbose("\nExpected round trip failure for case=%d mode=%d option=%d.\n"
   3420                     "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s"
   3421                     "\n%20s %u\n", tc, mode, option,
   3422                     "Original text:", srcChars,
   3423                     "Round-tripped text:", destChars2,
   3424                     "Intermediate  text:", destChars3,
   3425                     "Reordering mode:", modes[mode].description,
   3426                     "Reordering option:", options[option].description,
   3427                     "Paragraph level:", level);
   3428         }
   3429         return FALSE;
   3430     }
   3431     if (!checkResultLength(pBiDi, destChars, destChars2, destLen2,
   3432                            desc, "UBIDI_OPTION_REMOVE_CONTROLS", level)) {
   3433         return FALSE;
   3434     }
   3435     if (outIndex > -1 && !checkMaps(pBiDi, outIndex, srcChars, destChars,
   3436                                     desc, "UBIDI_OPTION_REMOVE_CONTROLS",
   3437                                     level, FALSE)) {
   3438         return FALSE;
   3439     }
   3440     return TRUE;
   3441 }
   3442 
   3443 static UBool
   3444 checkResultLength(UBiDi *pBiDi, const char *srcChars, const char *destChars,
   3445                   int32_t destLen, const char* mode,
   3446                   const char* option, UBiDiLevel level) {
   3447     int32_t actualLen;
   3448     if (strcmp(mode, "UBIDI_REORDER_INVERSE_NUMBERS_AS_L") == 0)
   3449         actualLen = strlen(destChars);
   3450     else
   3451         actualLen = ubidi_getResultLength(pBiDi);
   3452     if (actualLen != destLen) {
   3453         log_err("\nubidi_getResultLength failed.\n%20s %7d\n%20s %7d\n"
   3454                 "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %u\n",
   3455                 "Expected:", destLen, "Actual:", actualLen,
   3456                 "Input:", srcChars, "Output:", destChars,
   3457                 "Reordering mode:", mode, "Reordering option:", option,
   3458                 "Paragraph level:", level);
   3459         return FALSE;
   3460     }
   3461     return TRUE;
   3462 }
   3463 
   3464 static void
   3465 testReorderRunsOnly(void) {
   3466     static const struct {
   3467         const char* textIn;
   3468         const char* textOut[2][2];
   3469         const char noroundtrip[2];
   3470     } testCases[] = {
   3471         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*0*/
   3472                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
   3473         {"abcGHI", {{"GHIabc", "GHIabc"}, {"GHIabc", "GHIabc"}}, {0, 0}},        /*1*/
   3474         {"a.>67->", {{"<-67<.a", "<-67<.a"}, {"<-67<.a", "<-67<.a"}}, {0, 0}},   /*2*/
   3475         {"-=%$123/ *", {{"* /%$123=-", "* /%$123=-"},                            /*3*/
   3476                         {"* /%$123=-", "* /%$123=-"}}, {0, 0}},
   3477         {"abc->12..>JKL", {{"JKL<..12<-abc", "JKL<..abc->12"},                   /*4*/
   3478                            {"JKL<..12<-abc", "JKL<..abc->12"}}, {0, 0}},
   3479         {"JKL->12..>abc", {{"abc<..JKL->12", "abc<..12<-JKL"},                   /*5*/
   3480                            {"abc<..JKL->12", "abc<..12<-JKL"}}, {0, 0}},
   3481         {"123->abc", {{"abc<-123", "abc<-123"},                                  /*6*/
   3482                       {"abc&<-123", "abc<-123"}}, {1, 0}},
   3483         {"123->JKL", {{"JKL<-123", "123->JKL"},                                  /*7*/
   3484                       {"JKL<-123", "JKL<-@123"}}, {0, 1}},
   3485         {"*>12.>34->JKL", {{"JKL<-34<.12<*", "12.>34->JKL<*"},                   /*8*/
   3486                            {"JKL<-34<.12<*", "JKL<-@34<.12<*"}}, {0, 1}},
   3487         {"*>67.>89->JKL", {{"67.>89->JKL<*", "67.>89->JKL<*"},                   /*9*/
   3488                            {"67.>89->JKL<*", "67.>89->JKL<*"}}, {0, 0}},
   3489         {"* /abc-=$%123", {{"$%123=-abc/ *", "abc-=$%123/ *"},                   /*10*/
   3490                            {"$%123=-abc/ *", "abc-=$%123/ *"}}, {0, 0}},
   3491         {"* /$%def-=123", {{"123=-def%$/ *", "def-=123%$/ *"},                   /*11*/
   3492                            {"123=-def%$/ *", "def-=123%$/ *"}}, {0, 0}},
   3493         {"-=GHI* /123%$", {{"GHI* /123%$=-", "123%$/ *GHI=-"},                   /*12*/
   3494                            {"GHI* /123%$=-", "123%$/ *GHI=-"}}, {0, 0}},
   3495         {"-=%$JKL* /123", {{"JKL* /%$123=-", "123/ *JKL$%=-"},                   /*13*/
   3496                            {"JKL* /%$123=-", "123/ *JKL$%=-"}}, {0, 0}},
   3497         {"ab =#CD *?450", {{"CD *?450#= ab", "450?* CD#= ab"},                   /*14*/
   3498                            {"CD *?450#= ab", "450?* CD#= ab"}}, {0, 0}},
   3499         {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"},                   /*15*/
   3500                            {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}},
   3501         {"abc-=%$LMN* /123", {{"LMN* /%$123=-abc", "123/ *LMN$%=-abc"},          /*16*/
   3502                               {"LMN* /%$123=-abc", "123/ *LMN$%=-abc"}}, {0, 0}},
   3503         {"123->JKL&MN&P", {{"JKLMNP<-123", "123->JKLMNP"},                       /*17*/
   3504                            {"JKLMNP<-123", "JKLMNP<-@123"}}, {0, 1}},
   3505         {"123", {{"123", "123"},                /* just one run */               /*18*/
   3506                  {"123", "123"}}, {0, 0}}
   3507     };
   3508     UBiDi *pBiDi = getBiDiObject();
   3509     UBiDi *pL2VBiDi = getBiDiObject();
   3510     UChar src[MAXLEN], dest[MAXLEN], visual1[MAXLEN], visual2[MAXLEN];
   3511     char destChars[MAXLEN], vis1Chars[MAXLEN], vis2Chars[MAXLEN];
   3512     int32_t srcLen, destLen, vis1Len, vis2Len, option, i, j, nCases, paras;
   3513     UErrorCode rc = U_ZERO_ERROR;
   3514     UBiDiLevel level;
   3515 
   3516     log_verbose("\nEntering TestReorderRunsOnly\n\n");
   3517 
   3518     if(!pL2VBiDi) {
   3519         ubidi_close(pBiDi);             /* in case this one was allocated */
   3520         return;
   3521     }
   3522     ubidi_setReorderingMode(pBiDi, UBIDI_REORDER_RUNS_ONLY);
   3523     ubidi_setReorderingOptions(pL2VBiDi, UBIDI_OPTION_REMOVE_CONTROLS);
   3524 
   3525     for (option = 0; option < 2; option++) {
   3526         ubidi_setReorderingOptions(pBiDi, option==0 ? UBIDI_OPTION_REMOVE_CONTROLS
   3527                                                     : UBIDI_OPTION_INSERT_MARKS);
   3528         for (i = 0, nCases = LENGTHOF(testCases); i < nCases; i++) {
   3529             srcLen = strlen(testCases[i].textIn);
   3530             pseudoToU16(srcLen, testCases[i].textIn, src);
   3531             for(j = 0; j < 2; j++) {
   3532                 log_verbose("Now doing test for option %d, case %d, level %d\n",
   3533                             i, option, j);
   3534                 level = paraLevels[j];
   3535                 ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
   3536                 assertSuccessful("ubidi_setPara", &rc);
   3537                 *dest = 0;
   3538                 destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
   3539                 assertSuccessful("ubidi_writeReordered", &rc);
   3540                 u16ToPseudo(destLen, dest, destChars);
   3541                 checkWhatYouCan(pBiDi, testCases[i].textIn, destChars);
   3542                 assertStringsEqual(testCases[i].textOut[option][level], destChars,
   3543                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY",
   3544                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
   3545                         pBiDi);
   3546 
   3547                 if((option==0) && testCases[i].noroundtrip[level]) {
   3548                     continue;
   3549                 }
   3550                 ubidi_setPara(pL2VBiDi, src, srcLen, level, NULL, &rc);
   3551                 assertSuccessful("ubidi_setPara1", &rc);
   3552                 *visual1 = 0;
   3553                 vis1Len = ubidi_writeReordered(pL2VBiDi, visual1, MAXLEN, UBIDI_DO_MIRRORING, &rc);
   3554                 assertSuccessful("ubidi_writeReordered1", &rc);
   3555                 u16ToPseudo(vis1Len, visual1, vis1Chars);
   3556                 checkWhatYouCan(pL2VBiDi, testCases[i].textIn, vis1Chars);
   3557                 ubidi_setPara(pL2VBiDi, dest, destLen, level^1, NULL, &rc);
   3558                 assertSuccessful("ubidi_setPara2", &rc);
   3559                 *visual2 = 0;
   3560                 vis2Len = ubidi_writeReordered(pL2VBiDi, visual2, MAXLEN, UBIDI_DO_MIRRORING, &rc);
   3561                 assertSuccessful("ubidi_writeReordered2", &rc);
   3562                 u16ToPseudo(vis2Len, visual2, vis2Chars);
   3563                 checkWhatYouCan(pL2VBiDi, destChars, vis2Chars);
   3564                 assertStringsEqual(vis1Chars, vis2Chars,
   3565                         testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY (2)",
   3566                         option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS",
   3567                         pBiDi);
   3568             }
   3569         }
   3570     }
   3571 
   3572     /* test with null or empty text */
   3573     ubidi_setPara(pBiDi, src, 0, UBIDI_LTR, NULL, &rc);
   3574     assertSuccessful("ubidi_setPara3", &rc);
   3575     paras = ubidi_countParagraphs(pBiDi);
   3576     if (paras != 0) {
   3577         log_err("\nInvalid number of paras (should be 0): %d\n", paras);
   3578     }
   3579 
   3580     ubidi_close(pBiDi);
   3581     ubidi_close(pL2VBiDi);
   3582 
   3583     log_verbose("\nExiting TestReorderRunsOnly\n\n");
   3584 }
   3585 
   3586 static void
   3587 testReorderingMode(void) {
   3588 
   3589     UChar src[MAXLEN], dest[MAXLEN];
   3590     char destChars[MAXLEN];
   3591     UBiDi *pBiDi = NULL, *pBiDi2 = NULL, *pBiDi3 = NULL;
   3592     UErrorCode rc;
   3593     int tc, mode, option, level;
   3594     uint32_t optionValue, optionBack;
   3595     UBiDiReorderingMode modeValue, modeBack;
   3596     int32_t srcLen, destLen, index;
   3597     const char *expectedChars;
   3598     UBool testOK = TRUE;
   3599 
   3600     log_verbose("\nEntering TestReorderingMode\n\n");
   3601 
   3602     pBiDi = getBiDiObject();
   3603     pBiDi2 = getBiDiObject();
   3604     pBiDi3 = getBiDiObject();
   3605     if(!pBiDi3) {
   3606         ubidi_close(pBiDi);             /* in case this one was allocated */
   3607         ubidi_close(pBiDi2);            /* in case this one was allocated */
   3608         return;
   3609     }
   3610 
   3611     ubidi_setInverse(pBiDi2, TRUE);
   3612 
   3613     for (tc = 0; tc < TC_COUNT; tc++) {
   3614         const char *srcChars = textIn[tc];
   3615         srcLen = strlen(srcChars);
   3616         pseudoToU16(srcLen, srcChars, src);
   3617 
   3618         for (mode = 0; mode < MODES_COUNT; mode++) {
   3619             modeValue = modes[mode].value;
   3620             ubidi_setReorderingMode(pBiDi, modeValue);
   3621             modeBack = ubidi_getReorderingMode(pBiDi);
   3622             if (modeValue != modeBack) {
   3623                 log_err("Error while setting reordering mode to %d, returned %d\n",
   3624                         modeValue, modeBack);
   3625             }
   3626 
   3627             for (option = 0; option < OPTIONS_COUNT; option++) {
   3628                 optionValue = options[option].value;
   3629                 ubidi_setReorderingOptions(pBiDi, optionValue);
   3630                 optionBack = ubidi_getReorderingOptions(pBiDi);
   3631                 if (optionValue != optionBack) {
   3632                     log_err("Error while setting reordering option to %d, returned %d\n",
   3633                             optionValue, optionBack);
   3634                 }
   3635 
   3636                 for (level = 0; level < LEVELS_COUNT; level++) {
   3637                     log_verbose("starting test %d mode=%d option=%d level=%d\n",
   3638                                 tc, modes[mode].value, options[option].value, level);
   3639                     rc = U_ZERO_ERROR;
   3640                     ubidi_setPara(pBiDi, src, srcLen, paraLevels[level], NULL, &rc);
   3641                     assertSuccessful("ubidi_setPara", &rc);
   3642 
   3643                     *dest = 0;
   3644                     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
   3645                                                    UBIDI_DO_MIRRORING, &rc);
   3646                     assertSuccessful("ubidi_writeReordered", &rc);
   3647                     u16ToPseudo(destLen, dest, destChars);
   3648                     if (!((modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) &&
   3649                           (options[option].value == UBIDI_OPTION_INSERT_MARKS))) {
   3650                         checkWhatYouCan(pBiDi, srcChars, destChars);
   3651                     }
   3652 
   3653                     if (modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) {
   3654                         index = -1;
   3655                         expectedChars = inverseBasic(pBiDi2, srcChars, srcLen,
   3656                                 options[option].value, paraLevels[level], destChars);
   3657                     }
   3658                     else {
   3659                         index = outIndices[tc][mode][option][level];
   3660                         expectedChars = textOut[index];
   3661                     }
   3662                     if (!assertStringsEqual(expectedChars, destChars, srcChars,
   3663                                 modes[mode].description,
   3664                                 options[option].description,
   3665                                 pBiDi)) {
   3666                         testOK = FALSE;
   3667                     }
   3668                     if (options[option].value == UBIDI_OPTION_INSERT_MARKS &&
   3669                              !assertRoundTrip(pBiDi3, tc, index, srcChars,
   3670                                               destChars, dest, destLen,
   3671                                               mode, option, paraLevels[level])) {
   3672                         testOK = FALSE;
   3673                     }
   3674                     else if (!checkResultLength(pBiDi, srcChars, destChars,
   3675                                 destLen, modes[mode].description,
   3676                                 options[option].description,
   3677                                 paraLevels[level])) {
   3678                         testOK = FALSE;
   3679                     }
   3680                     else if (index > -1 && !checkMaps(pBiDi, index, srcChars,
   3681                             destChars, modes[mode].description,
   3682                             options[option].description, paraLevels[level],
   3683                             TRUE)) {
   3684                         testOK = FALSE;
   3685                     }
   3686                 }
   3687             }
   3688         }
   3689     }
   3690     if (testOK == TRUE) {
   3691         log_verbose("\nReordering mode test OK\n");
   3692     }
   3693     ubidi_close(pBiDi3);
   3694     ubidi_close(pBiDi2);
   3695     ubidi_close(pBiDi);
   3696 
   3697     log_verbose("\nExiting TestReorderingMode\n\n");
   3698 }
   3699 
   3700 static const char* inverseBasic(UBiDi *pBiDi, const char *srcChars, int32_t srcLen,
   3701                                 uint32_t option, UBiDiLevel level, char *result) {
   3702     UErrorCode rc = U_ZERO_ERROR;
   3703     int32_t destLen;
   3704     UChar src[MAXLEN], dest2[MAXLEN];
   3705 
   3706     if (pBiDi == NULL || src == NULL) {
   3707         return NULL;
   3708     }
   3709     ubidi_setReorderingOptions(pBiDi, option);
   3710     pseudoToU16(srcLen, srcChars, src);
   3711     ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc);
   3712     assertSuccessful("ubidi_setPara", &rc);
   3713 
   3714     *dest2 = 0;
   3715     destLen = ubidi_writeReordered(pBiDi, dest2, MAXLEN,
   3716                                    UBIDI_DO_MIRRORING, &rc);
   3717     assertSuccessful("ubidi_writeReordered", &rc);
   3718     u16ToPseudo(destLen, dest2, result);
   3719     if (!(option == UBIDI_OPTION_INSERT_MARKS)) {
   3720         checkWhatYouCan(pBiDi, srcChars, result);
   3721     }
   3722     return result;
   3723 }
   3724 
   3725 #define NULL_CHAR '\0'
   3726 
   3727 static void
   3728 testStreaming(void) {
   3729 #define MAXPORTIONS 10
   3730 
   3731     static const struct {
   3732         const char* textIn;
   3733         short int chunk;
   3734         short int nPortions[2];
   3735         char  portionLens[2][MAXPORTIONS];
   3736         const char* message[2];
   3737     } testData[] = {
   3738         {   "123\\u000A"
   3739             "abc45\\u000D"
   3740             "67890\\u000A"
   3741             "\\u000D"
   3742             "02468\\u000D"
   3743             "ghi",
   3744             6, { 6, 6 }, {{ 6, 4, 6, 1, 6, 3}, { 4, 6, 6, 1, 6, 3 }},
   3745             {"6, 4, 6, 1, 6, 3", "4, 6, 6, 1, 6, 3"}
   3746         },
   3747         {   "abcd\\u000Afgh\\u000D12345\\u000A456",
   3748             6, { 4, 4 }, {{ 6, 3, 6, 3 }, { 5, 4, 6, 3 }},
   3749             {"6, 3, 6, 3", "5, 4, 6, 3"}
   3750         },
   3751         {   "abcd\\u000Afgh\\u000D12345\\u000A45\\u000D",
   3752             6, { 4, 4 }, {{ 6, 3, 6, 3 }, { 5, 4, 6, 3 }},
   3753             {"6, 3, 6, 3", "5, 4, 6, 3"}
   3754         },
   3755         {   "abcde\\u000Afghi",
   3756             10, { 1, 2 }, {{ 10 }, { 6, 4 }},
   3757             {"10", "6, 4"}
   3758         }
   3759     };
   3760     UChar src[MAXLEN];
   3761     UBiDi *pBiDi = NULL;
   3762     UChar *pSrc;
   3763     UErrorCode rc = U_ZERO_ERROR;
   3764     int32_t srcLen, processedLen, chunk, len, nPortions;
   3765     int i, j, levelIndex;
   3766     UBiDiLevel level;
   3767     int nTests = LENGTHOF(testData), nLevels = LENGTHOF(paraLevels);
   3768     UBool mismatch, testOK = TRUE;
   3769     char processedLenStr[MAXPORTIONS * 5];
   3770 
   3771     log_verbose("\nEntering TestStreaming\n\n");
   3772 
   3773     pBiDi = getBiDiObject();
   3774 
   3775     ubidi_orderParagraphsLTR(pBiDi, TRUE);
   3776 
   3777     for (levelIndex = 0; levelIndex < nLevels; levelIndex++) {
   3778         for (i = 0; i < nTests; i++) {
   3779             srcLen = u_unescape(testData[i].textIn, src, MAXLEN);
   3780             chunk = testData[i].chunk;
   3781             nPortions = testData[i].nPortions[levelIndex];
   3782             level = paraLevels[levelIndex];
   3783             *processedLenStr = NULL_CHAR;
   3784             log_verbose("Testing level %d, case %d\n", level, i);
   3785 
   3786             mismatch = FALSE;
   3787 
   3788             ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
   3789             for (j = 0, pSrc = src; j < MAXPORTIONS && srcLen > 0; j++) {
   3790 
   3791                 len = chunk < srcLen ? chunk : srcLen;
   3792                 ubidi_setPara(pBiDi, pSrc, len, level, NULL, &rc);
   3793                 if (!assertSuccessful("ubidi_setPara", &rc)) {
   3794                     break;
   3795                 }
   3796 
   3797                 processedLen = ubidi_getProcessedLength(pBiDi);
   3798                 if (processedLen == 0) {
   3799                     ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_DEFAULT);
   3800                     j--;
   3801                     continue;
   3802                 }
   3803                 ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING);
   3804 
   3805                 mismatch = (UBool)(j >= nPortions ||
   3806                            processedLen != testData[i].portionLens[levelIndex][j]);
   3807 
   3808                 sprintf(processedLenStr + j * 4, "%4d", processedLen);
   3809                 srcLen -= processedLen, pSrc += processedLen;
   3810             }
   3811 
   3812             if (mismatch || j != nPortions) {
   3813                 testOK = FALSE;
   3814                 log_err("\nProcessed lengths mismatch.\n"
   3815                     "\tParagraph level: %u\n"
   3816                     "\tInput string: %s\n"
   3817                     "\tActually processed portion lengths: { %s }\n"
   3818                     "\tExpected portion lengths          : { %s }\n",
   3819                     paraLevels[levelIndex], testData[i].textIn,
   3820                     processedLenStr, testData[i].message[levelIndex]);
   3821             }
   3822         }
   3823     }
   3824     ubidi_close(pBiDi);
   3825     if (testOK == TRUE) {
   3826         log_verbose("\nBiDi streaming test OK\n");
   3827     }
   3828     log_verbose("\nExiting TestStreaming\n\n");
   3829 }
   3830 
   3831 U_CDECL_BEGIN
   3832 
   3833 static UCharDirection U_CALLCONV
   3834 overrideBidiClass(const void *context, UChar32 c) {
   3835 
   3836 #define DEF U_BIDI_CLASS_DEFAULT
   3837 
   3838     static const UCharDirection customClasses[] = {
   3839        /* 0/8    1/9    2/A    3/B    4/C    5/D    6/E    7/F  */
   3840           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 00-07 */
   3841           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 08-0F */
   3842           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 10-17 */
   3843           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 18-1F */
   3844           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,     R,   DEF, /* 20-27 */
   3845           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 28-2F */
   3846            EN,    EN,    EN,    EN,    EN,    EN,    AN,    AN, /* 30-37 */
   3847            AN,    AN,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 38-3F */
   3848             L,    AL,    AL,    AL,    AL,    AL,    AL,     R, /* 40-47 */
   3849             R,     R,     R,     R,     R,     R,     R,     R, /* 48-4F */
   3850             R,     R,     R,     R,     R,     R,     R,     R, /* 50-57 */
   3851             R,     R,     R,   LRE,   DEF,   RLE,   PDF,     S, /* 58-5F */
   3852           NSM,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 60-67 */
   3853           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 68-6F */
   3854           DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF,   DEF, /* 70-77 */
   3855           DEF,   DEF,   DEF,   LRO,     B,   RLO,    BN,   DEF  /* 78-7F */
   3856     };
   3857     static const int nEntries = LENGTHOF(customClasses);
   3858     const char *dummy = context;        /* just to avoid a compiler warning */
   3859     dummy++;
   3860 
   3861     return c >= nEntries ? U_BIDI_CLASS_DEFAULT : customClasses[c];
   3862 }
   3863 
   3864 U_CDECL_END
   3865 
   3866 static void verifyCallbackParams(UBiDiClassCallback* fn, const void* context,
   3867                                  UBiDiClassCallback* expectedFn,
   3868                                  const void* expectedContext,
   3869                                  int32_t sizeOfContext) {
   3870     if (fn != expectedFn) {
   3871         log_err("Class callback pointer is not set properly.\n");
   3872     }
   3873     if (context != expectedContext) {
   3874         log_err("Class callback context is not set properly.\n");
   3875     }
   3876     else if (context != NULL &&
   3877             memcmp(context, expectedContext, sizeOfContext)) {
   3878         log_err("Callback context content doesn't match the expected one.\n");
   3879     }
   3880 }
   3881 
   3882 static void
   3883 testClassOverride(void) {
   3884     static const char* const textSrc  = "JIH.>12->a \\u05D0\\u05D1 6 ABC78";
   3885     static const char* const textResult = "12<.HIJ->a 78CBA 6 \\u05D1\\u05D0";
   3886 
   3887     UChar src[MAXLEN], dest[MAXLEN];
   3888     UErrorCode rc = U_ZERO_ERROR;
   3889     UBiDi *pBiDi = NULL;
   3890     UBiDiClassCallback* oldFn = NULL;
   3891     UBiDiClassCallback* newFn = overrideBidiClass;
   3892     const void* oldContext = NULL;
   3893     int32_t srcLen, destLen, textSrcSize = (int32_t)uprv_strlen(textSrc);
   3894     char* destChars = NULL;
   3895 
   3896     log_verbose("\nEntering TestClassOverride\n\n");
   3897 
   3898     pBiDi = getBiDiObject();
   3899     if(!pBiDi) {
   3900         return;
   3901     }
   3902 
   3903     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
   3904     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
   3905 
   3906     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
   3907     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
   3908         ubidi_close(pBiDi);
   3909         return;
   3910     }
   3911     verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0);
   3912 
   3913     ubidi_getClassCallback(pBiDi, &oldFn, &oldContext);
   3914     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
   3915 
   3916     ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc);
   3917     if (!assertSuccessful("ubidi_setClassCallback", &rc)) {
   3918         ubidi_close(pBiDi);
   3919         return;
   3920     }
   3921     verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize);
   3922 
   3923     srcLen = u_unescape(textSrc, src, MAXLEN);
   3924     ubidi_setPara(pBiDi, src, srcLen, UBIDI_LTR, NULL, &rc);
   3925     assertSuccessful("ubidi_setPara", &rc);
   3926 
   3927     destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN,
   3928                                    UBIDI_DO_MIRRORING, &rc);
   3929     assertSuccessful("ubidi_writeReordered", &rc);
   3930 
   3931     destChars = aescstrdup(dest, destLen);
   3932     if (uprv_strcmp(textResult, destChars)) {
   3933         log_err("\nActual and expected output mismatch.\n"
   3934             "%20s %s\n%20s %s\n%20s %s\n",
   3935             "Input:", textSrc, "Actual output:", destChars,
   3936             "Expected output:", textResult);
   3937     }
   3938     else {
   3939         log_verbose("\nClass override test OK\n");
   3940     }
   3941     ubidi_close(pBiDi);
   3942     log_verbose("\nExiting TestClassOverride\n\n");
   3943 }
   3944 
   3945 static char * formatMap(const int32_t * map, int len, char * buffer)
   3946 {
   3947     int32_t i, k;
   3948     char c;
   3949     for (i = 0; i < len; i++) {
   3950         k = map[i];
   3951         if (k < 0)
   3952             c = '-';
   3953         else if (k >= sizeof(columns))
   3954             c = '+';
   3955         else
   3956             c = columns[k];
   3957         buffer[i] = c;
   3958     }
   3959     buffer[len] = '\0';
   3960     return buffer;
   3961 }
   3962 
   3963 static UBool
   3964 checkMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src, const char *dest,
   3965           const char *mode, const char* option, UBiDiLevel level, UBool forward)
   3966 {
   3967     int32_t actualLogicalMap[MAX_MAP_LENGTH];
   3968     int32_t actualVisualMap[MAX_MAP_LENGTH];
   3969     int32_t getIndexMap[MAX_MAP_LENGTH];
   3970     int32_t i, srcLen, resLen, index;
   3971     const int32_t *expectedLogicalMap, *expectedVisualMap;
   3972     UErrorCode rc = U_ZERO_ERROR;
   3973     UBool testOK = TRUE;
   3974 
   3975     if (forward) {
   3976         expectedLogicalMap = forwardMap[stringIndex];
   3977         expectedVisualMap  = inverseMap[stringIndex];
   3978     }
   3979     else {
   3980         expectedLogicalMap = inverseMap[stringIndex];
   3981         expectedVisualMap  = forwardMap[stringIndex];
   3982     }
   3983     ubidi_getLogicalMap(pBiDi, actualLogicalMap, &rc);
   3984     if (!assertSuccessful("ubidi_getLogicalMap", &rc)) {
   3985         testOK = FALSE;
   3986     }
   3987     srcLen = ubidi_getProcessedLength(pBiDi);
   3988     if (memcmp(expectedLogicalMap, actualLogicalMap, srcLen * sizeof(int32_t))) {
   3989         char expChars[MAX_MAP_LENGTH];
   3990         char actChars[MAX_MAP_LENGTH];
   3991         log_err("\nubidi_getLogicalMap() returns unexpected map for output string "
   3992                 "index %d\n"
   3993                 "source: %s\n"
   3994                 "dest  : %s\n"
   3995                 "Scale : %s\n"
   3996                 "ExpMap: %s\n"
   3997                 "Actual: %s\n"
   3998                 "Paragraph level  : %d == %d\n"
   3999                 "Reordering mode  : %s == %d\n"
   4000                 "Reordering option: %s == %d\n"
   4001                 "Forward flag     : %d\n",
   4002                 stringIndex, src, dest, columns,
   4003                 formatMap(expectedLogicalMap, srcLen, expChars),
   4004                 formatMap(actualLogicalMap, srcLen, actChars),
   4005                 level, ubidi_getParaLevel(pBiDi),
   4006                 mode, ubidi_getReorderingMode(pBiDi),
   4007                 option, ubidi_getReorderingOptions(pBiDi),
   4008                 forward
   4009                 );
   4010         testOK = FALSE;
   4011     }
   4012     resLen = ubidi_getResultLength(pBiDi);
   4013     ubidi_getVisualMap(pBiDi, actualVisualMap, &rc);
   4014     assertSuccessful("ubidi_getVisualMap", &rc);
   4015     if (memcmp(expectedVisualMap, actualVisualMap, resLen * sizeof(int32_t))) {
   4016         char expChars[MAX_MAP_LENGTH];
   4017         char actChars[MAX_MAP_LENGTH];
   4018         log_err("\nubidi_getVisualMap() returns unexpected map for output string "
   4019                 "index %d\n"
   4020                 "source: %s\n"
   4021                 "dest  : %s\n"
   4022                 "Scale : %s\n"
   4023                 "ExpMap: %s\n"
   4024                 "Actual: %s\n"
   4025                 "Paragraph level  : %d == %d\n"
   4026                 "Reordering mode  : %s == %d\n"
   4027                 "Reordering option: %s == %d\n"
   4028                 "Forward flag     : %d\n",
   4029                 stringIndex, src, dest, columns,
   4030                 formatMap(expectedVisualMap, resLen, expChars),
   4031                 formatMap(actualVisualMap, resLen, actChars),
   4032                 level, ubidi_getParaLevel(pBiDi),
   4033                 mode, ubidi_getReorderingMode(pBiDi),
   4034                 option, ubidi_getReorderingOptions(pBiDi),
   4035                 forward
   4036                 );
   4037         testOK = FALSE;
   4038     }
   4039     for (i = 0; i < srcLen; i++) {
   4040         index = ubidi_getVisualIndex(pBiDi, i, &rc);
   4041         assertSuccessful("ubidi_getVisualIndex", &rc);
   4042         getIndexMap[i] = index;
   4043     }
   4044     if (memcmp(actualLogicalMap, getIndexMap, srcLen * sizeof(int32_t))) {
   4045         char actChars[MAX_MAP_LENGTH];
   4046         char gotChars[MAX_MAP_LENGTH];
   4047         log_err("\nMismatch between ubidi_getLogicalMap and ubidi_getVisualIndex for output string "
   4048                 "index %d\n"
   4049                 "source: %s\n"
   4050                 "dest  : %s\n"
   4051                 "Scale : %s\n"
   4052                 "ActMap: %s\n"
   4053                 "IdxMap: %s\n"
   4054                 "Paragraph level  : %d == %d\n"
   4055                 "Reordering mode  : %s == %d\n"
   4056                 "Reordering option: %s == %d\n"
   4057                 "Forward flag     : %d\n",
   4058                 stringIndex, src, dest, columns,
   4059                 formatMap(actualLogicalMap, srcLen, actChars),
   4060                 formatMap(getIndexMap, srcLen, gotChars),
   4061                 level, ubidi_getParaLevel(pBiDi),
   4062                 mode, ubidi_getReorderingMode(pBiDi),
   4063                 option, ubidi_getReorderingOptions(pBiDi),
   4064                 forward
   4065                 );
   4066         testOK = FALSE;
   4067     }
   4068     for (i = 0; i < resLen; i++) {
   4069         index = ubidi_getLogicalIndex(pBiDi, i, &rc);
   4070         assertSuccessful("ubidi_getLogicalIndex", &rc);
   4071         getIndexMap[i] = index;
   4072     }
   4073     if (memcmp(actualVisualMap, getIndexMap, resLen * sizeof(int32_t))) {
   4074         char actChars[MAX_MAP_LENGTH];
   4075         char gotChars[MAX_MAP_LENGTH];
   4076         log_err("\nMismatch between ubidi_getVisualMap and ubidi_getLogicalIndex for output string "
   4077                 "index %d\n"
   4078                 "source: %s\n"
   4079                 "dest  : %s\n"
   4080                 "Scale : %s\n"
   4081                 "ActMap: %s\n"
   4082                 "IdxMap: %s\n"
   4083                 "Paragraph level  : %d == %d\n"
   4084                 "Reordering mode  : %s == %d\n"
   4085                 "Reordering option: %s == %d\n"
   4086                 "Forward flag     : %d\n",
   4087                 stringIndex, src, dest, columns,
   4088                 formatMap(actualVisualMap, resLen, actChars),
   4089                 formatMap(getIndexMap, resLen, gotChars),
   4090                 level, ubidi_getParaLevel(pBiDi),
   4091                 mode, ubidi_getReorderingMode(pBiDi),
   4092                 option, ubidi_getReorderingOptions(pBiDi),
   4093                 forward
   4094                 );
   4095         testOK = FALSE;
   4096     }
   4097     return testOK;
   4098 }
   4099 
   4100 static UBool
   4101 assertIllegalArgument(const char* message, UErrorCode* rc) {
   4102     if (*rc != U_ILLEGAL_ARGUMENT_ERROR) {
   4103         log_err("%s() failed with error %s.\n", message, myErrorName(*rc));
   4104         return FALSE;
   4105     }
   4106     return TRUE;
   4107 }
   4108 
   4109 typedef struct {
   4110     const char* prologue;
   4111     const char* source;
   4112     const char* epilogue;
   4113     const char* expected;
   4114     UBiDiLevel paraLevel;
   4115 } contextCase;
   4116 
   4117 static const contextCase contextData[] = {
   4118     /*00*/  {"", "", "", "", UBIDI_LTR},
   4119     /*01*/  {"", ".-=JKL-+*", "", ".-=LKJ-+*", UBIDI_LTR},
   4120     /*02*/  {" ", ".-=JKL-+*", " ", ".-=LKJ-+*", UBIDI_LTR},
   4121     /*03*/  {"a", ".-=JKL-+*", "b", ".-=LKJ-+*", UBIDI_LTR},
   4122     /*04*/  {"D", ".-=JKL-+*", "", "LKJ=-.-+*", UBIDI_LTR},
   4123     /*05*/  {"", ".-=JKL-+*", " D", ".-=*+-LKJ", UBIDI_LTR},
   4124     /*06*/  {"", ".-=JKL-+*", " 2", ".-=*+-LKJ", UBIDI_LTR},
   4125     /*07*/  {"", ".-=JKL-+*", " 7", ".-=*+-LKJ", UBIDI_LTR},
   4126     /*08*/  {" G 1", ".-=JKL-+*", " H", "*+-LKJ=-.", UBIDI_LTR},
   4127     /*09*/  {"7", ".-=JKL-+*", " H", ".-=*+-LKJ", UBIDI_LTR},
   4128     /*10*/  {"", ".-=abc-+*", "", "*+-abc=-.", UBIDI_RTL},
   4129     /*11*/  {" ", ".-=abc-+*", " ", "*+-abc=-.", UBIDI_RTL},
   4130     /*12*/  {"D", ".-=abc-+*", "G", "*+-abc=-.", UBIDI_RTL},
   4131     /*13*/  {"x", ".-=abc-+*", "", "*+-.-=abc", UBIDI_RTL},
   4132     /*14*/  {"", ".-=abc-+*", " y", "abc-+*=-.", UBIDI_RTL},
   4133     /*15*/  {"", ".-=abc-+*", " 2", "abc-+*=-.", UBIDI_RTL},
   4134     /*16*/  {" x 1", ".-=abc-+*", " 2", ".-=abc-+*", UBIDI_RTL},
   4135     /*17*/  {" x 7", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
   4136     /*18*/  {"x|", ".-=abc-+*", " 8", "*+-abc=-.", UBIDI_RTL},
   4137     /*19*/  {"G|y", ".-=abc-+*", " 8", "*+-.-=abc", UBIDI_RTL},
   4138     /*20*/  {"", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
   4139     /*21*/  {"D", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
   4140     /*22*/  {"G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
   4141     /*23*/  {"xG", ".-=", "", ".-=", UBIDI_DEFAULT_LTR},
   4142     /*24*/  {"x|G", ".-=", "", "=-.", UBIDI_DEFAULT_LTR},
   4143     /*25*/  {"x|G", ".-=|-+*", "", "=-.|-+*", UBIDI_DEFAULT_LTR},
   4144 };
   4145 #define CONTEXT_COUNT       LENGTHOF(contextData)
   4146 
   4147 static void
   4148 testContext(void) {
   4149 
   4150     UChar prologue[MAXLEN], epilogue[MAXLEN], src[MAXLEN], dest[MAXLEN];
   4151     char destChars[MAXLEN];
   4152     UBiDi *pBiDi = NULL;
   4153     UErrorCode rc;
   4154     int32_t proLength, epiLength, srcLen, destLen, tc;
   4155     contextCase cc;
   4156     UBool testOK = TRUE;
   4157 
   4158     log_verbose("\nEntering TestContext \n\n");
   4159 
   4160     /* test null BiDi object */
   4161     rc = U_ZERO_ERROR;
   4162     ubidi_setContext(pBiDi, NULL, 0, NULL, 0, &rc);
   4163     testOK &= assertIllegalArgument("Error when BiDi object is null", &rc);
   4164 
   4165     pBiDi = getBiDiObject();
   4166     ubidi_orderParagraphsLTR(pBiDi, TRUE);
   4167 
   4168     /* test proLength < -1 */
   4169     rc = U_ZERO_ERROR;
   4170     ubidi_setContext(pBiDi, NULL, -2, NULL, 0, &rc);
   4171     testOK &= assertIllegalArgument("Error when proLength < -1", &rc);
   4172     /* test epiLength < -1 */
   4173     rc = U_ZERO_ERROR;
   4174     ubidi_setContext(pBiDi, NULL, 0, NULL, -2, &rc);
   4175     testOK &= assertIllegalArgument("Error when epiLength < -1", &rc);
   4176     /* test prologue == NULL */
   4177     rc = U_ZERO_ERROR;
   4178     ubidi_setContext(pBiDi, NULL, 3, NULL, 0, &rc);
   4179     testOK &= assertIllegalArgument("Prologue is NULL", &rc);
   4180     /* test epilogue == NULL */
   4181     rc = U_ZERO_ERROR;
   4182     ubidi_setContext(pBiDi, NULL, 0, NULL, 4, &rc);
   4183     testOK &= assertIllegalArgument("Epilogue is NULL", &rc);
   4184 
   4185     for (tc = 0; tc < CONTEXT_COUNT; tc++) {
   4186         cc = contextData[tc];
   4187         proLength = strlen(cc.prologue);
   4188         pseudoToU16(proLength, cc.prologue, prologue);
   4189         epiLength = strlen(cc.epilogue);
   4190         pseudoToU16(epiLength, cc.epilogue, epilogue);
   4191         /* in the call below, prologue and epilogue are swapped to show
   4192            that the next call will override this call */
   4193         rc = U_ZERO_ERROR;
   4194         ubidi_setContext(pBiDi, epilogue, epiLength, prologue, proLength, &rc);
   4195         testOK &= assertSuccessful("swapped ubidi_setContext", &rc);
   4196         ubidi_setContext(pBiDi, prologue, -1, epilogue, -1, &rc);
   4197         testOK &= assertSuccessful("regular ubidi_setContext", &rc);
   4198         srcLen = strlen(cc.source);
   4199         pseudoToU16(srcLen, cc.source, src);
   4200         ubidi_setPara(pBiDi, src, srcLen, cc.paraLevel, NULL, &rc);
   4201         testOK &= assertSuccessful("ubidi_setPara", &rc);
   4202         destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc);
   4203         assertSuccessful("ubidi_writeReordered", &rc);
   4204         u16ToPseudo(destLen, dest, destChars);
   4205         if (uprv_strcmp(cc.expected, destChars)) {
   4206             char formatChars[MAXLEN];
   4207             log_err("\nActual and expected output mismatch on case %d.\n"
   4208                 "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d\n%20s %u\n%20s %d\n",
   4209                 tc,
   4210                 "Prologue:", cc.prologue,
   4211                 "Input:", cc.source,
   4212                 "Epilogue:", cc.epilogue,
   4213                 "Expected output:", cc.expected,
   4214                 "Actual output:", destChars,
   4215                 "Levels:", formatLevels(pBiDi, formatChars),
   4216                 "Reordering mode:", ubidi_getReorderingMode(pBiDi),
   4217                 "Paragraph level:", ubidi_getParaLevel(pBiDi),
   4218                 "Reordering option:", ubidi_getReorderingOptions(pBiDi));
   4219             testOK = FALSE;
   4220         }
   4221     }
   4222     if (testOK == TRUE) {
   4223         log_verbose("\nContext test OK\n");
   4224     }
   4225     ubidi_close(pBiDi);
   4226 
   4227     log_verbose("\nExiting TestContext \n\n");
   4228 }
   4229