]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/letest/letest.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / test / letest / letest.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4 *******************************************************************************
5 *
57a6839d 6 * Copyright (C) 1999-2014, International Business Machines
b75a7d8f
A
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
73c04bcf
A
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"
b75a7d8f 27
46f4442e
A
28#include "layout/ParagraphLayout.h"
29#include "layout/RunArrays.h"
30
b75a7d8f 31#include "PortableFontInstance.h"
73c04bcf 32#include "SimpleFontInstance.h"
b75a7d8f 33
73c04bcf 34#include "letsutil.h"
b75a7d8f
A
35#include "letest.h"
36
73c04bcf
A
37#include "xmlparser.h"
38#include "putilimp.h" // for uprv_getUTCtime()
39
40#include <stdlib.h>
41#include <string.h>
42
b75a7d8f
A
43U_NAMESPACE_USE
44
73c04bcf
A
45#define CH_COMMA 0x002C
46
47U_CDECL_BEGIN
46f4442e
A
48
49static 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
73c04bcf
A
56static 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
212bail:
213 delete engine;
214 delete font;
215}
216U_CDECL_END
217
218U_CDECL_BEGIN
219static 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}
238U_CDECL_END
239
240U_CDECL_BEGIN
241static 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;
340931cb 247 LEGlyphID glyphs[6], extraBitGlyphs[6];
73c04bcf
A
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
324bail:
325 delete engine;
326 delete font;
327}
328U_CDECL_END
329
330le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
b75a7d8f
A
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) {
73c04bcf
A
334 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
335 testID, expected->glyphCount, actual->glyphCount);
374ca955 336 return FALSE;
b75a7d8f
A
337 }
338
339 le_int32 i;
340
341 for (i = 0; i < actual->glyphCount; i += 1) {
342 if (actual->glyphs[i] != expected->glyphs[i]) {
73c04bcf
A
343 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
344 testID, i, expected->glyphs[i], actual->glyphs[i]);
374ca955 345 return FALSE;
b75a7d8f
A
346 }
347 }
348
349 for (i = 0; i < actual->glyphCount; i += 1) {
350 if (actual->indices[i] != expected->indices[i]) {
73c04bcf
A
351 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
352 testID, i, expected->indices[i], actual->indices[i]);
374ca955 353 return FALSE;
b75a7d8f
A
354 }
355 }
356
357 for (i = 0; i <= actual->glyphCount; i += 1) {
73c04bcf 358 double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]);
b75a7d8f
A
359
360 if (xError > 0.0001) {
73c04bcf
A
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]);
374ca955 363 return FALSE;
b75a7d8f
A
364 }
365
73c04bcf 366 double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]);
b75a7d8f
A
367
368 if (yError < 0) {
369 yError = -yError;
370 }
371
372 if (yError > 0.0001) {
73c04bcf
A
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]);
374ca955 375 return FALSE;
b75a7d8f
A
376 }
377 }
378
374ca955 379 return TRUE;
b75a7d8f
A
380}
381
73c04bcf
A
382static void checkFontVersion(PortableFontInstance *fontInstance, const char *testVersionString,
383 le_uint32 testChecksum, const char *testID)
b75a7d8f 384{
73c04bcf
A
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);
46f4442e
A
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 }
b75a7d8f 398
73c04bcf 399 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
46f4442e
A
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
73c04bcf
A
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");
73c04bcf
A
411 }
412}
413
414/* Returns the path to icu/source/test/testdata/ */
415const char *getSourceTestData() {
416 const char *srcDataDir = NULL;
417#ifdef U_TOPSRCDIR
57a6839d 418 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING;
73c04bcf 419#else
b331163b
A
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");
73c04bcf
A
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) */
b331163b
A
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;
73c04bcf
A
430 }
431#endif
432
433 return srcDataDir;
434}
b75a7d8f 435
73c04bcf
A
436const char *getPath(char buffer[2048], const char *filename) {
437 const char *testDataDirectory = getSourceTestData();
b75a7d8f 438
73c04bcf
A
439 strcpy(buffer, testDataDirectory);
440 strcat(buffer, filename);
441
442 return buffer;
443}
444
445le_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;
b75a7d8f 475 }
73c04bcf
A
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
491float *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 }
b75a7d8f 510
73c04bcf
A
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;
b75a7d8f 515
73c04bcf
A
516 sscanf(number, "%f", &array[count++]);
517
518 // trim whiteapce following the comma
519 while(u_isUWhiteSpace(numbers[start])) {
520 start += 1;
b75a7d8f 521 }
73c04bcf
A
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
541LEFontInstance *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
565U_CDECL_BEGIN
566static 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);
b75a7d8f 629
73c04bcf
A
630 if (languageCode < 0) {
631 log_err("invalid language name: %s.\n", lang);
632 goto free_c_strings;
633 }
634 }
b75a7d8f 635
73c04bcf
A
636 while((element = testCase->nextChildElement(ec)) != NULL) {
637 UnicodeString tag = element->getTagName();
b75a7d8f 638
73c04bcf
A
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));
b75a7d8f 644
73c04bcf
A
645 font = openFont(fontName, fontCksum, fontVer, id);
646 freeCString(fontCksum);
647 freeCString(fontVer);
648 freeCString(fontName);
b75a7d8f 649
73c04bcf
A
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) {
46f4442e 688 log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
73c04bcf
A
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
57a6839d 718 log_verbose("OK - %4d glyphs: %s\n", actual.glyphCount, id);
73c04bcf
A
719free_expected:
720 DELETE_ARRAY(expected.positions);
721 DELETE_ARRAY(expected.indices);
722 DELETE_ARRAY(expected.glyphs);
723
724 delete font;
725
726free_c_strings:
727 freeCString(lang);
728 freeCString(script);
729 freeCString(id);
b75a7d8f 730 }
73c04bcf
A
731 }
732
733 delete root;
734 delete parser;
735#endif
736}
737U_CDECL_END
738
46f4442e
A
739U_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 */
752static void U_CALLCONV GlyphToCharTest(void)
753{
57a6839d 754#if !UCONFIG_NO_BREAK_ITERATION
46f4442e
A
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 }
957close_paragraph:
958 delete paragraphLayout;
959
960close_font:
961 delete font;
962
963finish:
964 return;
57a6839d 965#endif
46f4442e
A
966}
967U_CDECL_END
968
969static void addAllTests(TestNode **root)
73c04bcf 970{
46f4442e
A
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
b331163b 978#ifndef USING_ICULEHB
46f4442e 979 addCTests(root);
b331163b 980#endif
73c04bcf
A
981}
982
983/* returns the path to icu/source/data/out */
984static const char *ctest_dataOutDir()
985{
986 static const char *dataOutDir = NULL;
b75a7d8f 987
73c04bcf
A
988 if(dataOutDir) {
989 return dataOutDir;
b75a7d8f
A
990 }
991
73c04bcf
A
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 {
51004dcb 1002 dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
73c04bcf
A
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 */
b331163b 1034 FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
73c04bcf
A
1035 if (file) {
1036 fclose(file);
b331163b 1037 dataOutDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
73c04bcf
A
1038 }
1039 else {
b331163b 1040 dataOutDir = ".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
73c04bcf
A
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 */
1058static 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 }
b75a7d8f 1067}
73c04bcf
A
1068
1069int 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
46f4442e
A
1079 if (!initArgs(argc, argv, NULL, NULL)) {
1080 /* Error already displayed. */
1081 return -1;
1082 }
1083
73c04bcf
A
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
46f4442e
A
1102 if (!initArgs(argc, argv, NULL, NULL)) {
1103 /* Error already displayed. */
1104 return -1;
1105 }
1106/* Initialize ICU */
73c04bcf
A
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);
46f4442e 1119 nerrors = runTestRequest(root, argc, argv);
73c04bcf
A
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