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