2 *******************************************************************************
4 * Copyright (C) 1999-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: letest.cpp
10 * created on: 11/06/2000
11 * created by: Eric R. Mader
14 #include "unicode/utypes.h"
15 #include "unicode/uclean.h"
16 #include "unicode/uchar.h"
17 #include "unicode/unistr.h"
18 #include "unicode/uscript.h"
19 #include "unicode/putil.h"
20 #include "unicode/ctest.h"
22 #include "layout/LETypes.h"
23 #include "layout/LEScripts.h"
24 #include "layout/LayoutEngine.h"
26 #include "PortableFontInstance.h"
27 #include "SimpleFontInstance.h"
32 #include "xmlparser.h"
33 #include "putilimp.h" // for uprv_getUTCtime()
40 #define CH_COMMA 0x002C
43 static void U_CALLCONV
ParamTest(void)
45 LEErrorCode status
= LE_NO_ERROR
;
46 SimpleFontInstance
*font
= new SimpleFontInstance(12, status
);
47 LayoutEngine
*engine
= LayoutEngine::layoutEngineFactory(font
, arabScriptCode
, -1, status
);
48 LEGlyphID
*glyphs
= NULL
;
49 le_int32
*indices
= NULL
;
50 float *positions
= NULL
;
51 le_int32 glyphCount
= 0;
53 glyphCount
= engine
->getGlyphCount();
54 if (glyphCount
!= 0) {
55 log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount
);
58 glyphs
= NEW_ARRAY(LEGlyphID
, glyphCount
+ 10);
59 indices
= NEW_ARRAY(le_int32
, glyphCount
+ 10);
60 positions
= NEW_ARRAY(float, glyphCount
+ 10);
62 engine
->getGlyphs(NULL
, status
);
64 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
65 log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
69 engine
->getGlyphs(glyphs
, status
);
71 if (status
!= LE_NO_LAYOUT_ERROR
) {
72 log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
76 engine
->getGlyphs(NULL
, 0xFF000000L
, status
);
78 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
79 log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
83 engine
->getGlyphs(glyphs
, 0xFF000000L
, status
);
85 if (status
!= LE_NO_LAYOUT_ERROR
) {
86 log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
90 engine
->getCharIndices(NULL
, status
);
92 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
93 log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
97 engine
->getCharIndices(indices
, status
);
99 if (status
!= LE_NO_LAYOUT_ERROR
) {
100 log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
103 status
= LE_NO_ERROR
;
104 engine
->getCharIndices(NULL
, 1024, status
);
106 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
107 log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
110 status
= LE_NO_ERROR
;
111 engine
->getCharIndices(indices
, 1024, status
);
113 if (status
!= LE_NO_LAYOUT_ERROR
) {
114 log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
117 status
= LE_NO_ERROR
;
118 engine
->getGlyphPositions(NULL
, status
);
120 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
121 log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
124 status
= LE_NO_ERROR
;
125 engine
->getGlyphPositions(positions
, status
);
127 if (status
!= LE_NO_LAYOUT_ERROR
) {
128 log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
131 DELETE_ARRAY(positions
);
132 DELETE_ARRAY(indices
);
133 DELETE_ARRAY(glyphs
);
135 status
= LE_NO_ERROR
;
136 glyphCount
= engine
->layoutChars(NULL
, 0, 0, 0, FALSE
, 0.0, 0.0, status
);
138 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
139 log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
142 LEUnicode chars
[] = {
143 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
144 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN
145 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text."
148 status
= LE_NO_ERROR
;
149 glyphCount
= engine
->layoutChars(chars
, -1, 6, 20, TRUE
, 0.0, 0.0, status
);
151 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
152 log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
155 status
= LE_NO_ERROR
;
156 glyphCount
= engine
->layoutChars(chars
, 8, -1, 20, TRUE
, 0.0, 0.0, status
);
158 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
159 log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
162 status
= LE_NO_ERROR
;
163 glyphCount
= engine
->layoutChars(chars
, 8, 6, -1, TRUE
, 0.0, 0.0, status
);
165 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
166 log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
169 status
= LE_NO_ERROR
;
170 glyphCount
= engine
->layoutChars(chars
, 8, 6, 10, TRUE
, 0.0, 0.0, status
);
172 if (status
!= LE_ILLEGAL_ARGUMENT_ERROR
) {
173 log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
176 float x
= 0.0, y
= 0.0;
178 status
= LE_NO_ERROR
;
179 glyphCount
= engine
->layoutChars(chars
, 8, 6, 20, TRUE
, 0.0, 0.0, status
);
181 if (LE_FAILURE(status
)) {
182 log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
186 engine
->getGlyphPosition(-1, x
, y
, status
);
188 if (status
!= LE_INDEX_OUT_OF_BOUNDS_ERROR
) {
189 log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
192 status
= LE_NO_ERROR
;
193 engine
->getGlyphPosition(glyphCount
+ 1, x
, y
, status
);
195 if (status
!= LE_INDEX_OUT_OF_BOUNDS_ERROR
) {
196 log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
206 static void U_CALLCONV
FactoryTest(void)
208 LEErrorCode status
= LE_NO_ERROR
;
209 SimpleFontInstance
*font
= new SimpleFontInstance(12, status
);
210 LayoutEngine
*engine
= NULL
;
212 for(le_int32 scriptCode
= 0; scriptCode
< scriptCodeCount
; scriptCode
+= 1) {
213 status
= LE_NO_ERROR
;
214 engine
= LayoutEngine::layoutEngineFactory(font
, scriptCode
, -1, status
);
216 if (LE_FAILURE(status
)) {
217 log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode
)scriptCode
));
228 static void U_CALLCONV
AccessTest(void)
230 LEErrorCode status
= LE_NO_ERROR
;
231 SimpleFontInstance
*font
= new SimpleFontInstance(12, status
);
232 LayoutEngine
*engine
= LayoutEngine::layoutEngineFactory(font
, arabScriptCode
, -1, status
);
234 LEGlyphID glyphs
[6], extraBitGlyphs
[6];;
235 le_int32 biasedIndices
[6], indices
[6], glyph
;
236 float positions
[6 * 2 + 2];
237 LEUnicode chars
[] = {
238 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
239 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN
240 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text."
243 if (LE_FAILURE(status
)) {
244 log_err("Could not create LayoutEngine.\n");
248 glyphCount
= engine
->layoutChars(chars
, 8, 6, 20, TRUE
, 0.0, 0.0, status
);
250 if (LE_FAILURE(status
) || glyphCount
!= 6) {
251 log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
255 engine
->getGlyphs(glyphs
, status
);
256 engine
->getCharIndices(indices
, status
);
257 engine
->getGlyphPositions(positions
, status
);
259 if (LE_FAILURE(status
)) {
260 log_err("Could not get glyph, indices and position arrays.\n");
264 engine
->getGlyphs(extraBitGlyphs
, 0xFF000000L
, status
);
266 if (LE_FAILURE(status
)) {
267 log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n");
269 for(glyph
= 0; glyph
< glyphCount
; glyph
+= 1) {
270 if (extraBitGlyphs
[glyph
] != (glyphs
[glyph
] | 0xFF000000L
)) {
271 log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8X\n",
272 glyph
, glyph
, extraBitGlyphs
[glyph
], glyphs
[glyph
]);
278 status
= LE_NO_ERROR
;
279 engine
->getCharIndices(biasedIndices
, 1024, status
);
281 if (LE_FAILURE(status
)) {
282 log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
284 for (glyph
= 0; glyph
< glyphCount
; glyph
+= 1) {
285 if (biasedIndices
[glyph
] != (indices
[glyph
] + 1024)) {
286 log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
287 glyph
, glyph
, biasedIndices
[glyph
], indices
[glyph
]);
293 status
= LE_NO_ERROR
;
294 for (glyph
= 0; glyph
<= glyphCount
; glyph
+= 1) {
295 float x
= 0.0, y
= 0.0;
297 engine
->getGlyphPosition(glyph
, x
, y
, status
);
299 if (LE_FAILURE(status
)) {
300 log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph
);
304 if (x
!= positions
[glyph
*2] || y
!= positions
[glyph
*2 + 1]) {
305 log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
306 glyph
, x
, y
, positions
[glyph
*2], positions
[glyph
*2 + 1]);
317 le_bool
compareResults(const char *testID
, TestResult
*expected
, TestResult
*actual
)
319 /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
320 if (actual
->glyphCount
!= expected
->glyphCount
) {
321 log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
322 testID
, expected
->glyphCount
, actual
->glyphCount
);
328 for (i
= 0; i
< actual
->glyphCount
; i
+= 1) {
329 if (actual
->glyphs
[i
] != expected
->glyphs
[i
]) {
330 log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
331 testID
, i
, expected
->glyphs
[i
], actual
->glyphs
[i
]);
336 for (i
= 0; i
< actual
->glyphCount
; i
+= 1) {
337 if (actual
->indices
[i
] != expected
->indices
[i
]) {
338 log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
339 testID
, i
, expected
->indices
[i
], actual
->indices
[i
]);
344 for (i
= 0; i
<= actual
->glyphCount
; i
+= 1) {
345 double xError
= uprv_fabs(actual
->positions
[i
* 2] - expected
->positions
[i
* 2]);
347 if (xError
> 0.0001) {
348 log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
349 testID
, i
, expected
->positions
[i
* 2], actual
->positions
[i
* 2]);
353 double yError
= uprv_fabs(actual
->positions
[i
* 2 + 1] - expected
->positions
[i
* 2 + 1]);
359 if (yError
> 0.0001) {
360 log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
361 testID
, i
, expected
->positions
[i
* 2 + 1], actual
->positions
[i
* 2 + 1]);
369 static void checkFontVersion(PortableFontInstance
*fontInstance
, const char *testVersionString
,
370 le_uint32 testChecksum
, const char *testID
)
372 le_uint32 fontChecksum
= fontInstance
->getFontChecksum();
374 if (fontChecksum
!= testChecksum
) {
375 const char *fontVersionString
= fontInstance
->getNameString(NAME_VERSION_STRING
,
376 PLATFORM_MACINTOSH
, MACINTOSH_ROMAN
, MACINTOSH_ENGLISH
);
378 log_info("Test %s: this may not be the same font used to generate the test data.\n", testID
);
379 log_info("Your font's version string is \"%s\"\n", fontVersionString
);
380 log_info("The expected version string is \"%s\"\n", testVersionString
);
381 log_info("If you see errors, they may be due to the version of the font you're using.\n");
383 fontInstance
->deleteNameString(fontVersionString
);
387 /* Returns the path to icu/source/test/testdata/ */
388 const char *getSourceTestData() {
389 const char *srcDataDir
= NULL
;
391 srcDataDir
= U_TOPSRCDIR U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
393 srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
394 FILE *f
= fopen(".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
"rbbitst.txt", "r");
397 /* We're in icu/source/test/letest/ */
400 /* We're in icu/source/test/letest/(Debug|Release) */
401 srcDataDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
;
408 const char *getPath(char buffer
[2048], const char *filename
) {
409 const char *testDataDirectory
= getSourceTestData();
411 strcpy(buffer
, testDataDirectory
);
412 strcat(buffer
, filename
);
417 le_uint32
*getHexArray(const UnicodeString
&numbers
, int32_t &arraySize
)
422 while((offset
= numbers
.indexOf(CH_COMMA
, offset
+ 1)) >= 0) {
426 le_uint32
*array
= NEW_ARRAY(le_uint32
, arraySize
);
429 le_int32 start
= 0, end
= 0;
432 // trim leading whitespace
433 while(u_isUWhiteSpace(numbers
[start
])) {
437 while((end
= numbers
.indexOf(CH_COMMA
, start
)) >= 0) {
438 len
= numbers
.extract(start
, end
- start
, number
, ARRAY_SIZE(number
), US_INV
);
442 sscanf(number
, "%x", &array
[count
++]);
444 // trim whitespace following the comma
445 while(u_isUWhiteSpace(numbers
[start
])) {
450 // trim trailing whitespace
451 end
= numbers
.length();
452 while(u_isUWhiteSpace(numbers
[end
- 1])) {
456 len
= numbers
.extract(start
, end
- start
, number
, ARRAY_SIZE(number
), US_INV
);
458 sscanf(number
, "%x", &array
[count
]);
463 float *getFloatArray(const UnicodeString
&numbers
, int32_t &arraySize
)
468 while((offset
= numbers
.indexOf(CH_COMMA
, offset
+ 1)) >= 0) {
472 float *array
= NEW_ARRAY(float, arraySize
);
475 le_int32 start
= 0, end
= 0;
478 // trim leading whitespace
479 while(u_isUWhiteSpace(numbers
[start
])) {
483 while((end
= numbers
.indexOf(CH_COMMA
, start
)) >= 0) {
484 len
= numbers
.extract(start
, end
- start
, number
, ARRAY_SIZE(number
), US_INV
);
488 sscanf(number
, "%f", &array
[count
++]);
490 // trim whiteapce following the comma
491 while(u_isUWhiteSpace(numbers
[start
])) {
496 while(u_isUWhiteSpace(numbers
[start
])) {
500 // trim trailing whitespace
501 end
= numbers
.length();
502 while(u_isUWhiteSpace(numbers
[end
- 1])) {
506 len
= numbers
.extract(start
, end
- start
, number
, ARRAY_SIZE(number
), US_INV
);
508 sscanf(number
, "%f", &array
[count
]);
513 LEFontInstance
*openFont(const char *fontName
, const char *checksum
, const char *version
, const char *testID
)
516 PortableFontInstance
*font
;
517 LEErrorCode fontStatus
= LE_NO_ERROR
;
520 font
= new PortableFontInstance(getPath(path
, fontName
), 12, fontStatus
);
522 if (LE_FAILURE(fontStatus
)) {
523 log_info("Test %s: can't open font %s - test skipped.\n", testID
, fontName
);
529 sscanf(checksum
, "%x", &cksum
);
531 checkFontVersion(font
, version
, cksum
, testID
);
538 static void U_CALLCONV
DataDrivenTest(void)
540 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
541 UErrorCode status
= U_ZERO_ERROR
;
543 const char *testFilePath
= getPath(path
, "letest.xml");
545 UXMLParser
*parser
= UXMLParser::createParser(status
);
546 UXMLElement
*root
= parser
->parseFile(testFilePath
, status
);
549 log_err("Could not open the test data file: %s\n", testFilePath
);
554 UnicodeString test_case
= UNICODE_STRING_SIMPLE("test-case");
555 UnicodeString test_text
= UNICODE_STRING_SIMPLE("test-text");
556 UnicodeString test_font
= UNICODE_STRING_SIMPLE("test-font");
557 UnicodeString result_glyphs
= UNICODE_STRING_SIMPLE("result-glyphs");
558 UnicodeString result_indices
= UNICODE_STRING_SIMPLE("result-indices");
559 UnicodeString result_positions
= UNICODE_STRING_SIMPLE("result-positions");
561 // test-case attributes
562 UnicodeString id_attr
= UNICODE_STRING_SIMPLE("id");
563 UnicodeString script_attr
= UNICODE_STRING_SIMPLE("script");
564 UnicodeString lang_attr
= UNICODE_STRING_SIMPLE("lang");
566 // test-font attributes
567 UnicodeString name_attr
= UNICODE_STRING_SIMPLE("name");
568 UnicodeString ver_attr
= UNICODE_STRING_SIMPLE("version");
569 UnicodeString cksum_attr
= UNICODE_STRING_SIMPLE("checksum");
571 const UXMLElement
*testCase
;
574 while((testCase
= root
->nextChildElement(tc
)) != NULL
) {
575 if (testCase
->getTagName().compare(test_case
) == 0) {
576 char *id
= getCString(testCase
->getAttribute(id_attr
));
577 char *script
= getCString(testCase
->getAttribute(script_attr
));
578 char *lang
= getCString(testCase
->getAttribute(lang_attr
));
579 LEFontInstance
*font
= NULL
;
580 const UXMLElement
*element
;
582 int32_t charCount
= 0;
583 int32_t typoFlags
= 3; // kerning + ligatures...
584 UScriptCode scriptCode
;
585 le_int32 languageCode
= -1;
586 UnicodeString text
, glyphs
, indices
, positions
;
587 int32_t glyphCount
= 0, indexCount
= 0, positionCount
= 0;
588 TestResult expected
= {0, NULL
, NULL
, NULL
};
589 TestResult actual
= {0, NULL
, NULL
, NULL
};
590 LEErrorCode success
= LE_NO_ERROR
;
591 LayoutEngine
*engine
= NULL
;
593 uscript_getCode(script
, &scriptCode
, 1, &status
);
594 if (LE_FAILURE(status
)) {
595 log_err("invalid script name: %s.\n", script
);
600 languageCode
= getLanguageCode(lang
);
602 if (languageCode
< 0) {
603 log_err("invalid language name: %s.\n", lang
);
608 while((element
= testCase
->nextChildElement(ec
)) != NULL
) {
609 UnicodeString tag
= element
->getTagName();
611 // TODO: make sure that each element is only used once.
612 if (tag
.compare(test_font
) == 0) {
613 char *fontName
= getCString(element
->getAttribute(name_attr
));
614 char *fontVer
= getCString(element
->getAttribute(ver_attr
));
615 char *fontCksum
= getCString(element
->getAttribute(cksum_attr
));
617 font
= openFont(fontName
, fontCksum
, fontVer
, id
);
618 freeCString(fontCksum
);
619 freeCString(fontVer
);
620 freeCString(fontName
);
623 // warning message already displayed...
626 } else if (tag
.compare(test_text
) == 0) {
627 text
= element
->getText(TRUE
);
628 charCount
= text
.length();
629 } else if (tag
.compare(result_glyphs
) == 0) {
630 glyphs
= element
->getText(TRUE
);
631 } else if (tag
.compare(result_indices
) == 0) {
632 indices
= element
->getText(TRUE
);
633 } else if (tag
.compare(result_positions
) == 0) {
634 positions
= element
->getText(TRUE
);
637 char *cTag
= getCString(&tag
);
639 log_info("Test %s: unknown element with tag \"%s\"\n", id
, cTag
);
644 // TODO: make sure that the font, test-text, result-glyphs, result-indices and result-positions
645 // have all been provided
647 LEErrorCode fontStatus
= LE_NO_ERROR
;
649 font
= new SimpleFontInstance(12, fontStatus
);
650 typoFlags
|= 0x80000000L
; // use CharSubstitutionFilter...
653 expected
.glyphs
= (LEGlyphID
*) getHexArray(glyphs
, glyphCount
);
654 expected
.indices
= (le_int32
*) getHexArray(indices
, indexCount
);
655 expected
.positions
= getFloatArray(positions
, positionCount
);
657 expected
.glyphCount
= glyphCount
;
659 if (glyphCount
< charCount
|| indexCount
!= glyphCount
|| positionCount
< glyphCount
* 2 + 2) {
660 log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
661 id
, charCount
, glyphCount
, indexCount
, positionCount
);
665 engine
= LayoutEngine::layoutEngineFactory(font
, scriptCode
, languageCode
, typoFlags
, success
);
667 if (LE_FAILURE(success
)) {
668 log_err("Test %s: could not create a LayoutEngine.\n", id
);
672 actual
.glyphCount
= engine
->layoutChars(text
.getBuffer(), 0, charCount
, charCount
, getRTL(text
), 0, 0, success
);
674 actual
.glyphs
= NEW_ARRAY(LEGlyphID
, actual
.glyphCount
);
675 actual
.indices
= NEW_ARRAY(le_int32
, actual
.glyphCount
);
676 actual
.positions
= NEW_ARRAY(float, actual
.glyphCount
* 2 + 2);
678 engine
->getGlyphs(actual
.glyphs
, success
);
679 engine
->getCharIndices(actual
.indices
, success
);
680 engine
->getGlyphPositions(actual
.positions
, success
);
682 compareResults(id
, &expected
, &actual
);
684 DELETE_ARRAY(actual
.positions
);
685 DELETE_ARRAY(actual
.indices
);
686 DELETE_ARRAY(actual
.glyphs
);
691 DELETE_ARRAY(expected
.positions
);
692 DELETE_ARRAY(expected
.indices
);
693 DELETE_ARRAY(expected
.glyphs
);
710 static void addAllTests(TestNode
** root
)
712 addTest(root
, &ParamTest
, "api/ParameterTest");
713 addTest(root
, &FactoryTest
, "api/FactoryTest");
714 addTest(root
, &AccessTest
, "layout/AccessTest");
715 addTest(root
, &DataDrivenTest
, "layout/DataDrivenTest");
718 /* returns the path to icu/source/data/out */
719 static const char *ctest_dataOutDir()
721 static const char *dataOutDir
= NULL
;
727 /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
728 // to point to the top of the build hierarchy, which may or
729 // may not be the same as the source directory, depending on
730 // the configure options used. At any rate,
731 // set the data path to the built data from this directory.
732 // The value is complete with quotes, so it can be used
733 // as-is as a string constant.
735 #if defined (U_TOPBUILDDIR)
737 dataOutDir
= U_TOPBUILDDIR
"data"U_FILE_SEP_STRING
"out"U_FILE_SEP_STRING
;
741 /* On Windows, the file name obtained from __FILE__ includes a full path.
742 * This file is "wherever\icu\source\test\cintltst\cintltst.c"
743 * Change to "wherever\icu\source\data"
746 static char p
[sizeof(__FILE__
) + 20];
751 /* We want to back over three '\' chars. */
752 /* Only Windows should end up here, so looking for '\' is safe. */
753 for (i
=1; i
<=3; i
++) {
754 pBackSlash
= strrchr(p
, U_FILE_SEP_CHAR
);
755 if (pBackSlash
!= NULL
) {
756 *pBackSlash
= 0; /* Truncate the string at the '\' */
760 if (pBackSlash
!= NULL
) {
761 /* We found and truncated three names from the path.
762 * Now append "source\data" and set the environment
764 strcpy(pBackSlash
, U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
);
768 /* __FILE__ on MSVC7 does not contain the directory */
769 FILE *file
= fopen(".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"Makefile.in", "r");
772 dataOutDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
;
775 dataOutDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
;
784 /* ctest_setICU_DATA - if the ICU_DATA environment variable is not already
785 * set, try to deduce the directory in which ICU was built,
786 * and set ICU_DATA to "icu/source/data" in that location.
787 * The intent is to allow the tests to have a good chance
788 * of running without requiring that the user manually set
789 * ICU_DATA. Common data isn't a problem, since it is
790 * picked up via a static (build time) reference, but the
791 * tests dynamically load some data.
793 static void ctest_setICU_DATA() {
795 /* No location for the data dir was identifiable.
796 * Add other fallbacks for the test data location here if the need arises
798 if (getenv("ICU_DATA") == NULL
) {
799 /* If ICU_DATA isn't set, set it to the usual location */
800 u_setDataDirectory(ctest_dataOutDir());
804 int main(int argc
, char* argv
[])
807 TestNode
*root
= NULL
;
808 UErrorCode errorCode
= U_ZERO_ERROR
;
809 UDate startTime
, endTime
;
812 startTime
= uprv_getUTCtime();
814 /* Check whether ICU will initialize without forcing the build data directory into
815 * the ICU_DATA path. Success here means either the data dll contains data, or that
816 * this test program was run with ICU_DATA set externally. Failure of this check
817 * is normal when ICU data is not packaged into a shared library.
819 * Whether or not this test succeeds, we want to cleanup and reinitialize
820 * with a data path so that data loading from individual files can be tested.
824 if (U_FAILURE(errorCode
)) {
826 "#### Note: ICU Init without build-specific setDataDirectory() failed.\n");
830 errorCode
= U_ZERO_ERROR
;
833 ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init() */
836 if (U_FAILURE(errorCode
)) {
838 "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
839 "*** Check the ICU_DATA environment variable and \n"
840 "*** check that the data files are present.\n", argv
[0], u_errorName(errorCode
));
845 nerrors
= processArgs(root
, argc
, argv
);
847 cleanUpTestTree(root
);
850 endTime
= uprv_getUTCtime();
851 diffTime
= (int32_t)(endTime
- startTime
);
852 printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
853 (int)((diffTime%U_MILLIS_PER_DAY
)/U_MILLIS_PER_HOUR
),
854 (int)((diffTime%U_MILLIS_PER_HOUR
)/U_MILLIS_PER_MINUTE
),
855 (int)((diffTime%U_MILLIS_PER_MINUTE
)/U_MILLIS_PER_SECOND
),
856 (int)(diffTime%U_MILLIS_PER_SECOND
));