Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / letest / letest.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  *
6  *   Copyright (C) 1999-2014, International Business Machines
7  *   Corporation and others.  All Rights Reserved.
8  *
9  *******************************************************************************
10  *   file name:  letest.cpp
11  *
12  *   created on: 11/06/2000
13  *   created by: Eric R. Mader
14  */
15
16 #include "unicode/utypes.h"
17 #include "unicode/uclean.h"
18 #include "unicode/uchar.h"
19 #include "unicode/unistr.h"
20 #include "unicode/uscript.h"
21 #include "unicode/putil.h"
22 #include "unicode/ctest.h"
23
24 #include "layout/LETypes.h"
25 #include "layout/LEScripts.h"
26 #include "layout/LayoutEngine.h"
27
28 #include "layout/ParagraphLayout.h"
29 #include "layout/RunArrays.h"
30
31 #include "PortableFontInstance.h"
32 #include "SimpleFontInstance.h"
33
34 #include "letsutil.h"
35 #include "letest.h"
36
37 #include "xmlparser.h"
38 #include "putilimp.h" // for uprv_getUTCtime()
39
40 #include <stdlib.h>
41 #include <string.h>
42
43 U_NAMESPACE_USE
44
45 #define CH_COMMA 0x002C
46
47 U_CDECL_BEGIN
48
49 static void U_CALLCONV ScriptTest(void)
50 {
51     if ((int)scriptCodeCount != (int)USCRIPT_CODE_LIMIT) {
52         log_err("ScriptCodes::scriptCodeCount = %d, but UScriptCode::USCRIPT_CODE_LIMIT = %d\n", scriptCodeCount, USCRIPT_CODE_LIMIT);
53     }
54 }
55
56 static void U_CALLCONV ParamTest(void)
57 {
58     LEErrorCode status = LE_NO_ERROR;
59     SimpleFontInstance *font = new SimpleFontInstance(12, status);
60     LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
61     LEGlyphID *glyphs    = NULL;
62     le_int32  *indices   = NULL;
63     float     *positions = NULL;
64     le_int32   glyphCount = 0;
65
66     glyphCount = engine->getGlyphCount();
67     if (glyphCount != 0) {
68         log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount);
69     }
70
71     glyphs    = NEW_ARRAY(LEGlyphID, glyphCount + 10);
72     indices   = NEW_ARRAY(le_int32, glyphCount + 10);
73     positions = NEW_ARRAY(float, glyphCount + 10);
74
75     engine->getGlyphs(NULL, status);
76
77     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
78         log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
79     }
80
81     status = LE_NO_ERROR;
82     engine->getGlyphs(glyphs, status);
83
84     if (status != LE_NO_LAYOUT_ERROR) {
85         log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
86     }
87
88     status = LE_NO_ERROR;
89     engine->getGlyphs(NULL, 0xFF000000L, status);
90
91     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
92         log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
93     }
94
95     status = LE_NO_ERROR;
96     engine->getGlyphs(glyphs, 0xFF000000L, status);
97
98     if (status != LE_NO_LAYOUT_ERROR) {
99         log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
100     }
101
102     status = LE_NO_ERROR;
103     engine->getCharIndices(NULL, status);
104
105     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
106         log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
107     }
108
109     status = LE_NO_ERROR;
110     engine->getCharIndices(indices, status);
111
112     if (status != LE_NO_LAYOUT_ERROR) {
113         log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
114     }
115
116     status = LE_NO_ERROR;
117     engine->getCharIndices(NULL, 1024, status);
118
119     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
120         log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
121     }
122
123     status = LE_NO_ERROR;
124     engine->getCharIndices(indices, 1024, status);
125
126     if (status != LE_NO_LAYOUT_ERROR) {
127         log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
128     }
129
130     status = LE_NO_ERROR;
131     engine->getGlyphPositions(NULL, status);
132
133     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
134         log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
135     }
136
137     status = LE_NO_ERROR;
138     engine->getGlyphPositions(positions, status);
139
140     if (status != LE_NO_LAYOUT_ERROR) {
141         log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
142     }
143
144     DELETE_ARRAY(positions);
145     DELETE_ARRAY(indices);
146     DELETE_ARRAY(glyphs);
147
148     status = LE_NO_ERROR;
149     glyphCount = engine->layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status);
150
151     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
152         log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
153     }
154
155     LEUnicode chars[] = {
156         0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
157         0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634,                 // MEM ALIF KAF NOON TEH WAW SHEEN
158         0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E                   // " text."
159     };
160
161     status = LE_NO_ERROR;
162     glyphCount = engine->layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status);
163
164     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
165         log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
166     }
167
168     status = LE_NO_ERROR;
169     glyphCount = engine->layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status);
170
171     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
172         log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
173     }
174
175     status = LE_NO_ERROR;
176     glyphCount = engine->layoutChars(chars, 8, 6, -1, TRUE, 0.0, 0.0, status);
177
178     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
179         log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
180     }
181
182     status = LE_NO_ERROR;
183     glyphCount = engine->layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status);
184
185     if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
186         log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
187     }
188
189     float x = 0.0, y = 0.0;
190
191     status = LE_NO_ERROR;
192     glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
193
194     if (LE_FAILURE(status)) {
195         log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
196         goto bail;
197     }
198
199     engine->getGlyphPosition(-1, x, y, status);
200
201     if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
202         log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
203     }
204
205     status = LE_NO_ERROR;
206     engine->getGlyphPosition(glyphCount + 1, x, y, status);
207
208     if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
209         log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
210     }
211
212 bail:
213     delete engine;
214     delete font;
215 }
216 U_CDECL_END
217
218 U_CDECL_BEGIN
219 static void U_CALLCONV FactoryTest(void)
220 {
221     LEErrorCode status = LE_NO_ERROR;
222     SimpleFontInstance *font = new SimpleFontInstance(12, status);
223     LayoutEngine *engine = NULL;
224
225     for(le_int32 scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) {
226         status = LE_NO_ERROR;
227         engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, status);
228
229         if (LE_FAILURE(status)) {
230             log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode));
231         }
232
233         delete engine;
234     }
235
236     delete font;
237 }
238 U_CDECL_END
239
240 U_CDECL_BEGIN
241 static void U_CALLCONV AccessTest(void)
242 {
243     LEErrorCode status = LE_NO_ERROR;
244     SimpleFontInstance *font = new SimpleFontInstance(12, status);
245     LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
246     le_int32 glyphCount;
247     LEGlyphID glyphs[6], extraBitGlyphs[6];;
248     le_int32 biasedIndices[6], indices[6], glyph;
249     float positions[6 * 2 + 2];
250     LEUnicode chars[] = {
251         0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
252         0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634,                 // MEM ALIF KAF NOON TEH WAW SHEEN
253         0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E                   // " text."
254     };
255
256     if (LE_FAILURE(status)) {
257         log_err("Could not create LayoutEngine.\n");
258         goto bail;
259     }
260
261     glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
262
263     if (LE_FAILURE(status) || glyphCount != 6) {
264         log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
265         goto bail;
266     }
267
268     engine->getGlyphs(glyphs, status);
269     engine->getCharIndices(indices, status);
270     engine->getGlyphPositions(positions, status);
271
272     if (LE_FAILURE(status)) {
273         log_err("Could not get glyph, indices and position arrays.\n");
274         goto bail;
275     }
276
277     engine->getGlyphs(extraBitGlyphs, 0xFF000000L, status);
278
279     if (LE_FAILURE(status)) {
280         log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n");
281     } else {
282         for(glyph = 0; glyph < glyphCount; glyph += 1) {
283             if (extraBitGlyphs[glyph] != (glyphs[glyph] | 0xFF000000L)) {
284                 log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8X\n",
285                     glyph, glyph, extraBitGlyphs[glyph], glyphs[glyph]);
286                 break;
287             }
288         }
289     }
290
291     status = LE_NO_ERROR;
292     engine->getCharIndices(biasedIndices, 1024, status);
293
294     if (LE_FAILURE(status)) {
295         log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
296     } else {
297         for (glyph = 0; glyph < glyphCount; glyph += 1) {
298             if (biasedIndices[glyph] != (indices[glyph] + 1024)) {
299                 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
300                     glyph, glyph, biasedIndices[glyph], indices[glyph]);
301                 break;
302             }
303         }
304     }
305
306     status = LE_NO_ERROR;
307     for (glyph = 0; glyph <= glyphCount; glyph += 1) {
308         float x = 0.0, y = 0.0;
309
310         engine->getGlyphPosition(glyph, x, y, status);
311
312         if (LE_FAILURE(status)) {
313             log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph);
314             break;
315         }
316
317         if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) {
318             log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
319                 glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]);
320             break;
321         }
322     }
323
324 bail:
325     delete engine;
326     delete font;
327 }
328 U_CDECL_END
329
330 le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
331 {
332     /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
333     if (actual->glyphCount != expected->glyphCount) {
334         log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
335             testID, expected->glyphCount, actual->glyphCount);
336         return FALSE;
337     }
338
339     le_int32 i;
340
341     for (i = 0; i < actual->glyphCount; i += 1) {
342         if (actual->glyphs[i] != expected->glyphs[i]) {
343             log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
344                 testID, i, expected->glyphs[i], actual->glyphs[i]);
345             return FALSE;
346         }
347     }
348
349     for (i = 0; i < actual->glyphCount; i += 1) {
350         if (actual->indices[i] != expected->indices[i]) {
351             log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
352                 testID, i, expected->indices[i], actual->indices[i]);
353             return FALSE;
354         }
355     }
356
357     for (i = 0; i <= actual->glyphCount; i += 1) {
358         double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]);
359
360         if (xError > 0.0001) {
361             log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
362                 testID, i, expected->positions[i * 2], actual->positions[i * 2]);
363             return FALSE;
364         }
365
366         double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]);
367
368         if (yError < 0) {
369             yError = -yError;
370         }
371
372         if (yError > 0.0001) {
373             log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
374                 testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
375             return FALSE;
376         }
377     }
378
379     return TRUE;
380 }
381
382 static void checkFontVersion(PortableFontInstance *fontInstance, const char *testVersionString,
383                              le_uint32 testChecksum, const char *testID)
384 {
385     le_uint32 fontChecksum = fontInstance->getFontChecksum();
386
387     if (fontChecksum != testChecksum) {
388         const char *fontVersionString = fontInstance->getNameString(NAME_VERSION_STRING,
389             PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
390         const LEUnicode *uFontVersionString = NULL;
391
392             // The standard recommends that the Macintosh Roman/English name string be present, but
393             // if it's not, try the Microsoft Unicode/English string.
394             if (fontVersionString == NULL) {
395                 uFontVersionString = fontInstance->getUnicodeNameString(NAME_VERSION_STRING,
396                     PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLISH);
397             }
398
399         log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
400
401         if (uFontVersionString != NULL) {
402             log_info("Your font's version string is \"%S\"\n", uFontVersionString);
403             fontInstance->deleteNameString(uFontVersionString);
404         } else {
405             log_info("Your font's version string is \"%s\"\n", fontVersionString);
406             fontInstance->deleteNameString(fontVersionString);
407         }
408
409         log_info("The expected version string is \"%s\"\n", testVersionString);
410         log_info("If you see errors, they may be due to the version of the font you're using.\n");
411     }
412 }
413
414 /* Returns the path to icu/source/test/testdata/ */
415 const char *getSourceTestData() {
416     const char *srcDataDir = NULL;
417 #ifdef U_TOPSRCDIR
418     srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
419 #else
420     srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
421     FILE *f = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "rbbitst.txt", "r");
422
423     if (f != NULL) {
424         /* We're in icu/source/test/letest/ */
425         fclose(f);
426     } else {
427         /* We're in icu/source/test/letest/(Debug|Release) */
428         srcDataDir =  ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" 
429                       U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
430     }
431 #endif
432
433     return srcDataDir;
434 }
435
436 const char *getPath(char buffer[2048], const char *filename) {
437     const char *testDataDirectory = getSourceTestData();
438
439     strcpy(buffer, testDataDirectory);
440     strcat(buffer, filename);
441
442     return buffer;
443 }
444
445 le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
446 {
447     int32_t offset = -1;
448
449     arraySize = 1;
450     while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
451         arraySize += 1;
452     }
453
454     le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
455     char number[16];
456     le_int32 count = 0;
457     le_int32 start = 0, end = 0;
458     le_int32 len = 0;
459
460     // trim leading whitespace
461     while(u_isUWhiteSpace(numbers[start])) {
462         start += 1;
463     }
464
465     while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
466         len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
467         number[len] = '\0';
468         start = end + 1;
469
470         sscanf(number, "%x", &array[count++]);
471
472         // trim whitespace following the comma
473         while(u_isUWhiteSpace(numbers[start])) {
474             start += 1;
475         }
476     }
477
478     // trim trailing whitespace
479     end = numbers.length();
480     while(u_isUWhiteSpace(numbers[end - 1])) {
481         end -= 1;
482     }
483
484     len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
485     number[len] = '\0';
486     sscanf(number, "%x", &array[count]);
487
488     return array;
489 }
490
491 float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
492 {
493     int32_t offset = -1;
494
495     arraySize = 1;
496     while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
497         arraySize += 1;
498     }
499
500     float *array = NEW_ARRAY(float, arraySize);
501     char number[32];
502     le_int32 count = 0;
503     le_int32 start = 0, end = 0;
504     le_int32 len = 0;
505
506     // trim leading whitespace
507     while(u_isUWhiteSpace(numbers[start])) {
508         start += 1;
509     }
510
511     while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
512         len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
513         number[len] = '\0';
514         start = end + 1;
515
516         sscanf(number, "%f", &array[count++]);
517
518         // trim whiteapce following the comma
519         while(u_isUWhiteSpace(numbers[start])) {
520             start += 1;
521         }
522     }
523
524     while(u_isUWhiteSpace(numbers[start])) {
525         start += 1;
526     }
527
528     // trim trailing whitespace
529     end = numbers.length();
530     while(u_isUWhiteSpace(numbers[end - 1])) {
531         end -= 1;
532     }
533
534     len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
535     number[len] = '\0';
536     sscanf(number, "%f", &array[count]);
537
538     return array;
539 }
540
541 LEFontInstance *openFont(const char *fontName, const char *checksum, const char *version, const char *testID)
542 {
543     char path[2048];
544     PortableFontInstance *font;
545     LEErrorCode fontStatus = LE_NO_ERROR;
546
547
548     font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus);
549
550     if (LE_FAILURE(fontStatus)) {
551         log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName);
552         delete font;
553         return NULL;
554     } else {
555         le_uint32 cksum = 0;
556
557         sscanf(checksum, "%x", &cksum);
558
559         checkFontVersion(font, version, cksum, testID);
560     }
561
562     return font;
563 }
564
565 U_CDECL_BEGIN
566 static void U_CALLCONV DataDrivenTest(void)
567 {
568 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
569     UErrorCode status = U_ZERO_ERROR;
570     char path[2048];
571     const char *testFilePath = getPath(path, "letest.xml");
572
573     UXMLParser  *parser = UXMLParser::createParser(status);
574     UXMLElement *root   = parser->parseFile(testFilePath, status);
575
576     if (root == NULL) {
577         log_err("Could not open the test data file: %s\n", testFilePath);
578         delete parser;
579         return;
580     }
581
582     UnicodeString test_case        = UNICODE_STRING_SIMPLE("test-case");
583     UnicodeString test_text        = UNICODE_STRING_SIMPLE("test-text");
584     UnicodeString test_font        = UNICODE_STRING_SIMPLE("test-font");
585     UnicodeString result_glyphs    = UNICODE_STRING_SIMPLE("result-glyphs");
586     UnicodeString result_indices   = UNICODE_STRING_SIMPLE("result-indices");
587     UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
588
589     // test-case attributes
590     UnicodeString id_attr     = UNICODE_STRING_SIMPLE("id");
591     UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
592     UnicodeString lang_attr   = UNICODE_STRING_SIMPLE("lang");
593
594     // test-font attributes
595     UnicodeString name_attr   = UNICODE_STRING_SIMPLE("name");
596     UnicodeString ver_attr    = UNICODE_STRING_SIMPLE("version");
597     UnicodeString cksum_attr  = UNICODE_STRING_SIMPLE("checksum");
598
599     const UXMLElement *testCase;
600     int32_t tc = 0;
601
602     while((testCase = root->nextChildElement(tc)) != NULL) {
603         if (testCase->getTagName().compare(test_case) == 0) {
604             char *id = getCString(testCase->getAttribute(id_attr));
605             char *script = getCString(testCase->getAttribute(script_attr));
606             char *lang   = getCString(testCase->getAttribute(lang_attr));
607             LEFontInstance *font = NULL;
608             const UXMLElement *element;
609             int32_t ec = 0;
610             int32_t charCount = 0;
611             int32_t typoFlags = 3; // kerning + ligatures...
612             UScriptCode scriptCode;
613             le_int32 languageCode = -1;
614             UnicodeString text, glyphs, indices, positions;
615             int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
616             TestResult expected = {0, NULL, NULL, NULL};
617             TestResult actual   = {0, NULL, NULL, NULL};
618             LEErrorCode success = LE_NO_ERROR;
619             LayoutEngine *engine = NULL;
620
621             uscript_getCode(script, &scriptCode, 1, &status);
622             if (LE_FAILURE(status)) {
623                 log_err("invalid script name: %s.\n", script);
624                 goto free_c_strings;
625             }
626
627             if (lang != NULL) {
628                 languageCode = getLanguageCode(lang);
629
630                 if (languageCode < 0) {
631                     log_err("invalid language name: %s.\n", lang);
632                     goto free_c_strings;
633                 }
634             }
635
636             while((element = testCase->nextChildElement(ec)) != NULL) {
637                 UnicodeString tag = element->getTagName();
638
639                 // TODO: make sure that each element is only used once.
640                 if (tag.compare(test_font) == 0) {
641                     char *fontName  = getCString(element->getAttribute(name_attr));
642                     char *fontVer   = getCString(element->getAttribute(ver_attr));
643                     char *fontCksum = getCString(element->getAttribute(cksum_attr));
644
645                     font = openFont(fontName, fontCksum, fontVer, id);
646                     freeCString(fontCksum);
647                     freeCString(fontVer);
648                     freeCString(fontName);
649
650                     if (font == NULL) {
651                         // warning message already displayed...
652                         goto free_c_strings;
653                     }
654                 } else if (tag.compare(test_text) == 0) {
655                     text = element->getText(TRUE);
656                     charCount = text.length();
657                 } else if (tag.compare(result_glyphs) == 0) {
658                     glyphs = element->getText(TRUE);
659                 } else if (tag.compare(result_indices) == 0) {
660                     indices = element->getText(TRUE);
661                 } else if (tag.compare(result_positions) == 0) {
662                     positions = element->getText(TRUE);
663                 } else {
664                     // an unknown tag...
665                     char *cTag = getCString(&tag);
666
667                     log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
668                     freeCString(cTag);
669                 }
670             }
671
672             // TODO: make sure that the font, test-text, result-glyphs, result-indices and result-positions
673             // have all been provided
674             if (font == NULL) {
675                 LEErrorCode fontStatus = LE_NO_ERROR;
676
677                 font = new SimpleFontInstance(12, fontStatus);
678                 typoFlags |= 0x80000000L;  // use CharSubstitutionFilter...
679             }
680
681             expected.glyphs    = (LEGlyphID *) getHexArray(glyphs, glyphCount);
682             expected.indices   = (le_int32 *)  getHexArray(indices, indexCount);
683             expected.positions = getFloatArray(positions, positionCount);
684
685             expected.glyphCount = glyphCount;
686
687             if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
688                 log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
689                     id, charCount, glyphCount, indexCount, positionCount);
690                 goto free_expected;
691             };
692
693             engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languageCode, typoFlags, success);
694
695             if (LE_FAILURE(success)) {
696                 log_err("Test %s: could not create a LayoutEngine.\n", id);
697                 goto free_expected;
698             }
699
700             actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, charCount, getRTL(text), 0, 0, success);
701
702             actual.glyphs    = NEW_ARRAY(LEGlyphID, actual.glyphCount);
703             actual.indices   = NEW_ARRAY(le_int32, actual.glyphCount);
704             actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2);
705
706             engine->getGlyphs(actual.glyphs, success);
707             engine->getCharIndices(actual.indices, success);
708             engine->getGlyphPositions(actual.positions, success);
709
710             compareResults(id, &expected, &actual);
711
712             DELETE_ARRAY(actual.positions);
713             DELETE_ARRAY(actual.indices);
714             DELETE_ARRAY(actual.glyphs);
715
716             delete engine;
717
718             log_verbose("OK - %4d glyphs: %s\n", actual.glyphCount, id);
719 free_expected:
720             DELETE_ARRAY(expected.positions);
721             DELETE_ARRAY(expected.indices);
722             DELETE_ARRAY(expected.glyphs);
723
724             delete font;
725
726 free_c_strings:
727             freeCString(lang);
728             freeCString(script);
729             freeCString(id);
730         }
731     }
732
733     delete root;
734     delete parser;
735 #endif
736 }
737 U_CDECL_END
738
739 U_CDECL_BEGIN
740 /*
741  * From ticket:5923:
742  *
743  * Build a paragraph that contains a mixture of left to right and right to left text.
744  * Break it into multiple lines and make sure that the glyphToCharMap for run in each
745  * line is correct.
746  *
747  * Note: it might be a good idea to also check the glyphs and positions for each run,
748  * that we get the expected number of runs per line and that the line breaks are where
749  * we expect them to be. Really, it would be a good idea to make a whole test suite
750  * for ParagraphLayout.
751  */
752 static void U_CALLCONV GlyphToCharTest(void)
753 {
754 #if !UCONFIG_NO_BREAK_ITERATION
755     LEErrorCode status = LE_NO_ERROR;
756     LEFontInstance *font;
757     FontRuns fontRuns(0);
758     ParagraphLayout *paragraphLayout;
759     const ParagraphLayout::Line *line;
760     /*
761      * This is the same text that's in <icu>/source/samples/layout/Sample.txt
762      */
763     LEUnicode chars[] = {
764         /*BOM*/ 0x0054, 0x0068, 0x0065, 0x0020, 0x004c, 0x0061, 0x0079, 
765         0x006f, 0x0075, 0x0074, 0x0045, 0x006e, 0x0067, 0x0069, 0x006e, 
766         0x0065, 0x0020, 0x0064, 0x006f, 0x0065, 0x0073, 0x0020, 0x0061, 
767         0x006c, 0x006c, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0077, 
768         0x006f, 0x0072, 0x006b, 0x0020, 0x006e, 0x0065, 0x0063, 0x0065, 
769         0x0073, 0x0073, 0x0061, 0x0072, 0x0079, 0x0020, 0x0074, 0x006f, 
770         0x0020, 0x0064, 0x0069, 0x0073, 0x0070, 0x006c, 0x0061, 0x0079, 
771         0x0020, 0x0055, 0x006e, 0x0069, 0x0063, 0x006f, 0x0064, 0x0065, 
772         0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 
773         0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 
774         0x0020, 0x006c, 0x0061, 0x006e, 0x0067, 0x0075, 0x0061, 0x0067, 
775         0x0065, 0x0073, 0x0020, 0x0077, 0x0069, 0x0074, 0x0068, 0x0020, 
776         0x0063, 0x006f, 0x006d, 0x0070, 0x006c, 0x0065, 0x0078, 0x0020, 
777         0x0077, 0x0072, 0x0069, 0x0074, 0x0069, 0x006e, 0x0067, 0x0020, 
778         0x0073, 0x0079, 0x0073, 0x0074, 0x0065, 0x006d, 0x0073, 0x0020, 
779         0x0073, 0x0075, 0x0063, 0x0068, 0x0020, 0x0061, 0x0073, 0x0020, 
780         0x0048, 0x0069, 0x006e, 0x0064, 0x0069, 0x0020, 0x0028, 0x0939, 
781         0x093f, 0x0928, 0x094d, 0x0926, 0x0940, 0x0029, 0x0020, 0x0054, 
782         0x0068, 0x0061, 0x0069, 0x0020, 0x0028, 0x0e44, 0x0e17, 0x0e22, 
783         0x0029, 0x0020, 0x0061, 0x006e, 0x0064, 0x0020, 0x0041, 0x0072, 
784         0x0061, 0x0062, 0x0069, 0x0063, 0x0020, 0x0028, 0x0627, 0x0644, 
785         0x0639, 0x0631, 0x0628, 0x064a, 0x0629, 0x0029, 0x002e, 0x0020, 
786         0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 0x0073, 0x0020, 0x0061, 
787         0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 0x006c, 0x0065, 0x0020, 
788         0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 0x006d, 0x0065, 0x0020, 
789         0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 0x0077, 0x0072, 0x0069, 
790         0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 0x0069, 0x006e, 0x0020, 
791         0x0053, 0x0061, 0x006e, 0x0073, 0x006b, 0x0072, 0x0069, 0x0074, 
792         0x003a, 0x0020, 0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926, 
793         0x094d, 0x0020, 0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917, 
794         0x0940, 0x0924, 0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f, 
795         0x093e, 0x092f, 0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941, 
796         0x0928, 0x0020, 0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020, 
797         0x092f, 0x094b, 0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930, 
798         0x093e, 0x0937, 0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909, 
799         0x0935, 0x093e, 0x091a, 0x0964, 0x0020, 0x0927, 0x0930, 0x094d, 
800         0x092e, 0x0915, 0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 
801         0x0947, 0x0020, 0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d, 
802         0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938, 
803         0x092e, 0x0935, 0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941, 
804         0x092f, 0x0941, 0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020, 
805         0x092e, 0x093e, 0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a, 
806         0x093e, 0x0923, 0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d, 
807         0x091a, 0x0948, 0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915, 
808         0x0941, 0x0930, 0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902, 
809         0x091c, 0x092f, 0x0020, 0x0048, 0x0065, 0x0072, 0x0065, 0x0027, 
810         0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 0x0070, 
811         0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 0x006f, 
812         0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x0020, 
813         0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 0x0020, 
814         0x0069, 0x006e, 0x0020, 0x0041, 0x0072, 0x0061, 0x0062, 0x0069, 
815         0x0063, 0x003a, 0x0020, 0x0623, 0x0633, 0x0627, 0x0633, 0x064b, 
816         0x0627, 0x060c, 0x0020, 0x062a, 0x062a, 0x0639, 0x0627, 0x0645, 
817         0x0644, 0x0020, 0x0627, 0x0644, 0x062d, 0x0648, 0x0627, 0x0633, 
818         0x064a, 0x0628, 0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645, 
819         0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627, 
820         0x0645, 0x060c, 0x0020, 0x0648, 0x062a, 0x0642, 0x0648, 0x0645, 
821         0x0020, 0x0628, 0x062a, 0x062e, 0x0632, 0x064a, 0x0646, 0x0020, 
822         0x0627, 0x0644, 0x0623, 0x062d, 0x0631, 0x0641, 0x0020, 0x0648, 
823         0x0627, 0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 
824         0x0627, 0x0644, 0x0623, 0x062e, 0x0631, 0x0649, 0x0020, 0x0628, 
825         0x0639, 0x062f, 0x0020, 0x0623, 0x0646, 0x0020, 0x062a, 0x064f, 
826         0x0639, 0x0637, 0x064a, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627, 
827         0x0020, 0x0645, 0x0639, 0x064a, 0x0646, 0x0627, 0x0020, 0x0644, 
828         0x0643, 0x0644, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, 
829         0x0645, 0x0646, 0x0647, 0x0627, 0x002e, 0x0020, 0x0648, 0x0642, 
830         0x0628, 0x0644, 0x0020, 0x0627, 0x062e, 0x062a, 0x0631, 0x0627, 
831         0x0639, 0x0020, 0x0022, 0x064a, 0x0648, 0x0646, 0x0650, 0x0643, 
832         0x0648, 0x062f, 0x0022, 0x060c, 0x0020, 0x0643, 0x0627, 0x0646, 
833         0x0020, 0x0647, 0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626, 
834         0x0627, 0x062a, 0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638, 
835         0x0645, 0x0629, 0x0020, 0x0644, 0x0644, 0x062a, 0x0634, 0x0641, 
836         0x064a, 0x0631, 0x0020, 0x0648, 0x062a, 0x062e, 0x0635, 0x064a, 
837         0x0635, 0x0020, 0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644, 
838         0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644, 
839         0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x060c, 0x0020, 0x0648, 
840         0x0644, 0x0645, 0x0020, 0x064a, 0x0648, 0x062c, 0x062f, 0x0020, 
841         0x0646, 0x0638, 0x0627, 0x0645, 0x0020, 0x062a, 0x0634, 0x0641, 
842         0x064a, 0x0631, 0x0020, 0x0648, 0x0627, 0x062d, 0x062f, 0x0020, 
843         0x064a, 0x062d, 0x062a, 0x0648, 0x064a, 0x0020, 0x0639, 0x0644, 
844         0x0649, 0x0020, 0x062c, 0x0645, 0x064a, 0x0639, 0x0020, 0x0627, 
845         0x0644, 0x0645, 0x062d, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, 
846         0x0644, 0x0636, 0x0631, 0x0648, 0x0631, 0x064a, 0x0629, 0x0020, 
847         0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x0065, 0x0072, 0x0065, 
848         0x0027, 0x0073, 0x0020, 0x0061, 0x0020, 0x0073, 0x0061, 0x006d, 
849         0x0070, 0x006c, 0x0065, 0x0020, 0x006f, 0x0066, 0x0020, 0x0073, 
850         0x006f, 0x006d, 0x0065, 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 
851         0x0020, 0x0077, 0x0072, 0x0069, 0x0074, 0x0074, 0x0065, 0x006e, 
852         0x0020, 0x0069, 0x006e, 0x0020, 0x0054, 0x0068, 0x0061, 0x0069, 
853         0x003a, 0x0020, 0x0e1a, 0x0e17, 0x0e17, 0x0e35, 0x0e48, 0x0e51, 
854         0x0e1e, 0x0e32, 0x0e22, 0x0e38, 0x0e44, 0x0e0b, 0x0e42, 0x0e04, 
855         0x0e25, 0x0e19, 0x0e42, 0x0e14, 0x0e42, 0x0e23, 0x0e18, 0x0e35, 
856         0x0e2d, 0x0e32, 0x0e28, 0x0e31, 0x0e22, 0x0e2d, 0x0e22, 0x0e39, 
857         0x0e48, 0x0e17, 0x0e48, 0x0e32, 0x0e21, 0x0e01, 0x0e25, 0x0e32, 
858         0x0e07, 0x0e17, 0x0e38, 0x0e48, 0x0e07, 0x0e43, 0x0e2b, 0x0e0d, 
859         0x0e48, 0x0e43, 0x0e19, 0x0e41, 0x0e04, 0x0e19, 0x0e0b, 0x0e31, 
860         0x0e2a, 0x0e01, 0x0e31, 0x0e1a, 0x0e25, 0x0e38, 0x0e07, 0x0e40, 
861         0x0e2e, 0x0e19, 0x0e23, 0x0e35, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 
862         0x0e23, 0x0e48, 0x0e41, 0x0e25, 0x0e30, 0x0e1b, 0x0e49, 0x0e32, 
863         0x0e40, 0x0e2d, 0x0e47, 0x0e21, 0x0e20, 0x0e23, 0x0e23, 0x0e22, 
864         0x0e32, 0x0e0a, 0x0e32, 0x0e27, 0x0e44, 0x0e23, 0x0e48, 0x0e1a, 
865         0x0e49, 0x0e32, 0x0e19, 0x0e02, 0x0e2d, 0x0e07, 0x0e1e, 0x0e27, 
866         0x0e01, 0x0e40, 0x0e02, 0x0e32, 0x0e2b, 0x0e25, 0x0e31, 0x0e07, 
867         0x0e40, 0x0e25, 0x0e47, 0x0e01, 0x0e40, 0x0e1e, 0x0e23, 0x0e32, 
868         0x0e30, 0x0e44, 0x0e21, 0x0e49, 0x0e2a, 0x0e23, 0x0e49, 0x0e32, 
869         0x0e07, 0x0e1a, 0x0e49, 0x0e32, 0x0e19, 0x0e15, 0x0e49, 0x0e2d, 
870         0x0e07, 0x0e02, 0x0e19, 0x0e21, 0x0e32, 0x0e14, 0x0e49, 0x0e27, 
871         0x0e22, 0x0e40, 0x0e01, 0x0e27, 0x0e35, 0x0e22, 0x0e19, 0x0e40, 
872         0x0e1b, 0x0e47, 0x0e19, 0x0e23, 0x0e30, 0x0e22, 0x0e30, 0x0e17, 
873         0x0e32, 0x0e07, 0x0e2b, 0x0e25, 0x0e32, 0x0e22, 0x0e44, 0x0e21, 
874         0x0e25, 0x0e4c
875     };
876     le_int32 charCount = LE_ARRAY_SIZE(chars);
877     le_int32 charIndex = 0, lineNumber = 1;
878     const float lineWidth = 600;
879
880     font = new SimpleFontInstance(12, status);
881
882     if (LE_FAILURE(status)) {
883         goto finish;
884     }
885
886     fontRuns.add(font, charCount);
887
888     paragraphLayout = new ParagraphLayout(chars, charCount, &fontRuns, NULL, NULL, NULL, 0, FALSE, status);
889
890     if (LE_FAILURE(status)) {
891         goto close_font;
892     }
893
894     paragraphLayout->reflow();
895     while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) {
896         le_int32 runCount = line->countRuns();
897
898         for(le_int32 run = 0; run < runCount; run += 1) {
899             const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run);
900             le_int32 glyphCount = visualRun->getGlyphCount();
901             const le_int32 *glyphToCharMap = visualRun->getGlyphToCharMap();
902
903             if (visualRun->getDirection() == UBIDI_RTL) {
904                 /*
905                  * For a right to left run, make sure that the character indices
906                  * increase from the right most glyph to the left most glyph. If
907                  * there are any one to many glyph substitutions, we might get several
908                  * glyphs in a row with the same character index.
909                  */
910                 for(le_int32 i = glyphCount - 1; i >= 0; i -= 1) {
911                     le_int32 ix = glyphToCharMap[i];
912
913                     if (ix != charIndex) {
914                         if (ix != charIndex - 1) {
915                             log_err("Bad glyph to char index for glyph %d on line %d: expected %d, got %d\n",
916                                 i, lineNumber, charIndex, ix);
917                             goto close_paragraph; // once there's one error, we can't count on anything else...
918                         }
919                     } else {
920                         charIndex += 1;
921                     }
922                 }
923             } else {
924                 /*
925                  * We can't just check the order of the character indices
926                  * for left to right runs because Indic text might have been
927                  * reordered. What we can do is find the minimum and maximum
928                  * character indices in the run and make sure that the minimum
929                  * is equal to charIndex and then advance charIndex to the maximum.
930                  */
931                 le_int32 minIndex = 0x7FFFFFFF, maxIndex = -1;
932
933                 for(le_int32 i = 0; i < glyphCount; i += 1) {
934                     le_int32 ix = glyphToCharMap[i];
935
936                     if (ix > maxIndex) {
937                         maxIndex = ix;
938                     }
939
940                     if (ix < minIndex) {
941                         minIndex = ix;
942                     }
943                 }
944
945                 if (minIndex != charIndex) {
946                     log_err("Bad minIndex for run %d on line %d: expected %d, got %d\n",
947                         run, lineNumber, charIndex, minIndex);
948                     goto close_paragraph; // once there's one error, we can't count on anything else...
949                 }
950
951                 charIndex = maxIndex + 1;
952             }
953         }
954
955         lineNumber += 1;
956     }
957 close_paragraph:
958     delete paragraphLayout;
959
960 close_font:
961     delete font;
962
963 finish:
964     return;
965 #endif
966 }
967 U_CDECL_END
968
969 static void addAllTests(TestNode **root)
970 {
971     addTest(root, &ScriptTest,      "api/ScriptTest");
972     addTest(root, &ParamTest,       "api/ParameterTest");
973     addTest(root, &FactoryTest,     "api/FactoryTest");
974     addTest(root, &AccessTest,      "layout/AccessTest");
975     addTest(root, &DataDrivenTest,  "layout/DataDrivenTest");
976     addTest(root, &GlyphToCharTest, "paragraph/GlyphToCharTest");
977
978 #ifndef USING_ICULEHB
979     addCTests(root);
980 #endif
981 }
982
983 /* returns the path to icu/source/data/out */
984 static const char *ctest_dataOutDir()
985 {
986     static const char *dataOutDir = NULL;
987
988     if(dataOutDir) {
989         return dataOutDir;
990     }
991
992     /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
993     //              to point to the top of the build hierarchy, which may or
994     //              may not be the same as the source directory, depending on
995     //              the configure options used.  At any rate,
996     //              set the data path to the built data from this directory.
997     //              The value is complete with quotes, so it can be used
998     //              as-is as a string constant.
999     */
1000 #if defined (U_TOPBUILDDIR)
1001     {
1002         dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1003     }
1004 #else
1005
1006     /* On Windows, the file name obtained from __FILE__ includes a full path.
1007      *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
1008      *             Change to    "wherever\icu\source\data"
1009      */
1010     {
1011         static char p[sizeof(__FILE__) + 20];
1012         char *pBackSlash;
1013         int i;
1014
1015         strcpy(p, __FILE__);
1016         /* We want to back over three '\' chars.                            */
1017         /*   Only Windows should end up here, so looking for '\' is safe.   */
1018         for (i=1; i<=3; i++) {
1019             pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
1020             if (pBackSlash != NULL) {
1021                 *pBackSlash = 0;        /* Truncate the string at the '\'   */
1022             }
1023         }
1024
1025         if (pBackSlash != NULL) {
1026             /* We found and truncated three names from the path.
1027              *  Now append "source\data" and set the environment
1028              */
1029             strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
1030             dataOutDir = p;
1031         }
1032         else {
1033             /* __FILE__ on MSVC7 does not contain the directory */
1034             FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
1035             if (file) {
1036                 fclose(file);
1037                 dataOutDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1038             }
1039             else {
1040                 dataOutDir = ".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
1041             }
1042         }
1043     }
1044 #endif
1045
1046     return dataOutDir;
1047 }
1048
1049 /*  ctest_setICU_DATA  - if the ICU_DATA environment variable is not already
1050  *                       set, try to deduce the directory in which ICU was built,
1051  *                       and set ICU_DATA to "icu/source/data" in that location.
1052  *                       The intent is to allow the tests to have a good chance
1053  *                       of running without requiring that the user manually set
1054  *                       ICU_DATA.  Common data isn't a problem, since it is
1055  *                       picked up via a static (build time) reference, but the
1056  *                       tests dynamically load some data.
1057  */
1058 static void ctest_setICU_DATA() {
1059
1060     /* No location for the data dir was identifiable.
1061      *   Add other fallbacks for the test data location here if the need arises
1062      */
1063     if (getenv("ICU_DATA") == NULL) {
1064         /* If ICU_DATA isn't set, set it to the usual location */
1065         u_setDataDirectory(ctest_dataOutDir());
1066     }
1067 }
1068
1069 int main(int argc, char* argv[])
1070 {
1071     int32_t nerrors = 0;
1072     TestNode *root = NULL;
1073     UErrorCode errorCode = U_ZERO_ERROR;
1074     UDate startTime, endTime;
1075     int32_t diffTime;
1076
1077     startTime = uprv_getUTCtime();
1078
1079     if (!initArgs(argc, argv, NULL, NULL)) {
1080         /* Error already displayed. */
1081         return -1;
1082     }
1083
1084     /* Check whether ICU will initialize without forcing the build data directory into
1085     *  the ICU_DATA path.  Success here means either the data dll contains data, or that
1086     *  this test program was run with ICU_DATA set externally.  Failure of this check
1087     *  is normal when ICU data is not packaged into a shared library.
1088     *
1089     *  Whether or not this test succeeds, we want to cleanup and reinitialize
1090     *  with a data path so that data loading from individual files can be tested.
1091     */
1092     u_init(&errorCode);
1093
1094     if (U_FAILURE(errorCode)) {
1095         fprintf(stderr,
1096             "#### Note:  ICU Init without build-specific setDataDirectory() failed.\n");
1097     }
1098
1099     u_cleanup();
1100     errorCode = U_ZERO_ERROR;
1101
1102     if (!initArgs(argc, argv, NULL, NULL)) {
1103         /* Error already displayed. */
1104         return -1;
1105     }
1106 /* Initialize ICU */
1107     ctest_setICU_DATA();    /* u_setDataDirectory() must happen Before u_init() */
1108     u_init(&errorCode);
1109
1110     if (U_FAILURE(errorCode)) {
1111         fprintf(stderr,
1112             "#### ERROR! %s: u_init() failed with status = \"%s\".\n" 
1113             "*** Check the ICU_DATA environment variable and \n"
1114             "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
1115         return 1;
1116     }
1117
1118     addAllTests(&root);
1119     nerrors = runTestRequest(root, argc, argv);
1120
1121     cleanUpTestTree(root);
1122     u_cleanup();
1123
1124     endTime = uprv_getUTCtime();
1125     diffTime = (int32_t)(endTime - startTime);
1126     printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
1127         (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
1128         (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
1129         (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
1130         (int)(diffTime%U_MILLIS_PER_SECOND));
1131
1132     return nerrors;
1133 }
1134