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