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