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