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
31void addComplexTest(TestNode** root);
32
33static void testCharFromDirProp(void);
34
35static void testBidi(void);
36
37static void doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst);
38
39static void doMisc(void);
40
41static void doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test,
42                   int32_t lineStart, UBool countRunsFirst);
43
44static void _testReordering(UBiDi *pBiDi, int testNumber);
45
46static void testInverse(void);
47
48static void _testManyInverseBidi(UBiDi *pBiDi, UBiDiLevel direction);
49
50static void _testInverseBidi(UBiDi *pBiDi, const UChar *src, int32_t srcLength,
51                             UBiDiLevel direction, UErrorCode *pErrorCode);
52
53static void _testWriteReverse(void);
54
55static void _testManyAddedPoints(void);
56
57static void _testMisc(void);
58
59static void doArabicShapingTest(void);
60
61static void doLamAlefSpecialVLTRArabicShapingTest(void);
62
63static void doTashkeelSpecialVLTRArabicShapingTest(void);
64
65static void doLOGICALArabicDeShapingTest(void);
66
67static void doArabicShapingTestForBug5421(void);
68
69static void testReorder(void);
70
71static void testFailureRecovery(void);
72
73static void testMultipleParagraphs(void);
74
75static void testGetBaseDirection(void);
76
77static void testContext(void);
78
79static void doTailTest(void);
80
81/* new BIDI API */
82static void testReorderingMode(void);
83static void testReorderRunsOnly(void);
84static void testStreaming(void);
85static void testClassOverride(void);
86static const char* inverseBasic(UBiDi *pBiDi, const char *src, int32_t srcLen,
87                                uint32_t option, UBiDiLevel level, char *result);
88static 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);
92static UBool checkResultLength(UBiDi *pBiDi, const char *srcChars,
93                               const char *destChars,
94                               int32_t destLen, const char *mode,
95                               const char *option, UBiDiLevel level);
96static 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
102static const char *levelString="...............................................................";
103
104static void initCharFromDirProps(void);
105
106static UChar *
107getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer);
108
109static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels);
110
111/* regression tests ---------------------------------------------------------*/
112
113void
114addComplexTest(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
136static void
137testCharFromDirProp(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
153static void
154testBidi(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
184static void
185doTests(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
221static const char columns[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
222
223#define TABLE_SIZE  256
224static UBool   tablesInitialized = FALSE;
225static UChar   pseudoToUChar[TABLE_SIZE];
226static uint8_t UCharToPseudo[TABLE_SIZE];    /* used for Unicode chars < 0x0100 */
227static uint8_t UCharToPseud2[TABLE_SIZE];    /* used for Unicode chars >=0x0100 */
228
229static 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
338static 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
355static 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
375static 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}
397static 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
406static 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
420static 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
476static 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
503static 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
625static void
626testReorder(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
888static void
889doTest(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
996static 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
1147static 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
1265static 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
1551static void
1552testFailureRecovery(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
1650static void
1651testMultipleParagraphs(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
2019static int countRoundtrips=0, countNonRoundtrips=0;
2020
2021#define STRING_TEST_CASE(s) { (s), LENGTHOF(s) }
2022
2023static void
2024testInverse(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
2086static 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
2095static 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
2121static 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
2199static 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
2237static 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
2266static 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
2289static void
2290doArabicShapingTest(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
2486static void
2487doLamAlefSpecialVLTRArabicShapingTest(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
2637static void
2638doTashkeelSpecialVLTRArabicShapingTest(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
2689static void
2690doLOGICALArabicDeShapingTest(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
2768static void
2769doTailTest(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
2813static void
2814doArabicShapingTestForBug5421(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
2890static 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 */
2907static UChar *
2908getStringFromDirProps(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
2921static 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
2939static const UBiDiLevel paraLevels[] = { UBIDI_LTR, UBIDI_RTL };
2940
2941static UBool
2942assertSuccessful(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
2950static UBool
2951assertStringsEqual(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
2969static UBiDi*
2970getBiDiObject(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
2980static const struct {
2981    UBiDiReorderingMode value;
2982    const char* description;
2983}
2984modes[] = {
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};
2991static const struct {
2992    uint32_t value;
2993    const char* description;
2994}
2995options[] = {
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
3005static 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
3034static 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
3086static 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
3135static 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
3184static 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
3266static UBool
3267assertRoundTrip(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
3443static UBool
3444checkResultLength(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
3464static void
3465testReorderRunsOnly(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
3586static void
3587testReorderingMode(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
3700static 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
3727static void
3728testStreaming(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
3831U_CDECL_BEGIN
3832
3833static UCharDirection U_CALLCONV
3834overrideBidiClass(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
3864U_CDECL_END
3865
3866static 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
3882static void
3883testClassOverride(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
3945static 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
3963static UBool
3964checkMaps(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
4100static UBool
4101assertIllegalArgument(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
4109typedef struct {
4110    const char* prologue;
4111    const char* source;
4112    const char* epilogue;
4113    const char* expected;
4114    UBiDiLevel paraLevel;
4115} contextCase;
4116
4117static 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
4147static void
4148testContext(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