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