1 /********************************************************************
3 * Copyright (c) 1997-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6 /********************************************************************************
10 * Modification History:
12 * Madhu Katragadda Creation
13 *********************************************************************************
16 /*The main root for C API tests*/
21 #include "unicode/utypes.h"
22 #include "unicode/putil.h"
27 #include "unicode/uchar.h"
28 #include "unicode/ustring.h"
29 #include "unicode/ucnv.h"
30 #include "unicode/ures.h"
31 #include "unicode/uclean.h"
32 #include "unicode/ucal.h"
34 #include "putilimp.h" /* for uprv_getRawUTCtime() */
36 #include "uresimp.h" /* for ures_dumpCacheContents() */
43 #define CTST_MAX_ALLOC 8192
44 /* Array used as a queue */
45 static void * ctst_allocated_stuff
[CTST_MAX_ALLOC
] = {0};
46 static int ctst_allocated
= 0;
47 static UBool ctst_free
= FALSE
;
48 static int ctst_allocated_total
= 0;
50 #define CTST_LEAK_CHECK 1
52 #ifdef CTST_LEAK_CHECK
53 static void ctst_freeAll(void);
56 static char* _testDataPath
=NULL
;
59 * Forward Declarations
61 void ctest_setICU_DATA(void);
65 #if UCONFIG_NO_LEGACY_CONVERSION
66 # define TRY_CNV_1 "iso-8859-1"
67 # define TRY_CNV_2 "ibm-1208"
69 # define TRY_CNV_1 "iso-8859-7"
70 # define TRY_CNV_2 "sjis"
74 static const char* const * gOrigArgv
;
76 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
77 U_CAPI
void unistr_printLengths();
80 int main(int argc
, const char* const argv
[])
83 UBool defaultDataFound
;
85 const char *warnOrErr
= "Failure";
86 UDate startTime
, endTime
;
89 /* initial check for the default converter */
90 UErrorCode errorCode
= U_ZERO_ERROR
;
94 U_MAIN_INIT_ARGS(argc
, argv
);
96 startTime
= uprv_getRawUTCtime();
100 if (!initArgs(argc
, argv
, NULL
, NULL
)) {
101 /* Error already displayed. */
105 /* Check whether ICU will initialize without forcing the build data directory into
106 * the ICU_DATA path. Success here means either the data dll contains data, or that
107 * this test program was run with ICU_DATA set externally. Failure of this check
108 * is normal when ICU data is not packaged into a shared library.
110 * Whether or not this test succeeds, we want to cleanup and reinitialize
111 * with a data path so that data loading from individual files can be tested.
113 defaultDataFound
= TRUE
;
115 if (U_FAILURE(errorCode
)) {
117 "#### Note: ICU Init without build-specific setDataDirectory() failed. %s\n", u_errorName(errorCode
));
118 defaultDataFound
= FALSE
;
122 fprintf(stderr
, "After initial u_cleanup: RB cache %s empty.\n", ures_dumpCacheContents()?"WAS NOT":"was");
125 while (getTestOption(REPEAT_TESTS_OPTION
) > 0) { /* Loop runs once per complete execution of the tests
126 * used for -r (repeat) test option. */
127 if (!initArgs(argc
, argv
, NULL
, NULL
)) {
128 /* Error already displayed. */
131 errorCode
= U_ZERO_ERROR
;
134 if (!defaultDataFound
) {
135 ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init() */
138 if (U_FAILURE(errorCode
)) {
140 "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
141 "*** Check the ICU_DATA environment variable and \n"
142 "*** check that the data files are present.\n", argv
[0], u_errorName(errorCode
));
143 if(!getTestOption(WARN_ON_MISSING_DATA_OPTION
)) {
144 fprintf(stderr
, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
153 cnv
= ucnv_open(TRY_CNV_2
, &errorCode
);
159 "*** %s! The converter for " TRY_CNV_2
" cannot be opened.\n"
160 "*** Check the ICU_DATA environment variable and \n"
161 "*** check that the data files are present.\n", warnOrErr
);
162 if(!getTestOption(WARN_ON_MISSING_DATA_OPTION
)) {
163 fprintf(stderr
, "*** Exitting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
169 rb
= ures_open(NULL
, "en", &errorCode
);
170 if(U_SUCCESS(errorCode
)) {
175 "*** %s! The \"en\" locale resource bundle cannot be opened.\n"
176 "*** Check the ICU_DATA environment variable and \n"
177 "*** check that the data files are present.\n", warnOrErr
);
178 if(!getTestOption(WARN_ON_MISSING_DATA_OPTION
)) {
179 fprintf(stderr
, "*** Exitting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
185 errorCode
= U_ZERO_ERROR
;
186 rb
= ures_open(NULL
, NULL
, &errorCode
);
187 if(U_SUCCESS(errorCode
)) {
189 if (errorCode
== U_USING_DEFAULT_WARNING
|| errorCode
== U_USING_FALLBACK_WARNING
) {
191 "#### Note: The default locale %s is not available\n", uloc_getDefault());
196 "*** %s! Can not open a resource bundle for the default locale %s\n", warnOrErr
, uloc_getDefault());
197 if(!getTestOption(WARN_ON_MISSING_DATA_OPTION
)) {
198 fprintf(stderr
, "*** Exitting. Use the '-w' option if data files were\n"
199 "*** purposely removed, to continue test anyway.\n");
204 fprintf(stdout
, "Default locale for this run is %s\n", uloc_getDefault());
206 /* Build a tree of all tests.
207 * Subsequently will be used to find / iterate the tests to run */
211 /* Tests acutally run HERE. TODO: separate command line option parsing & setting from test execution!! */
212 nerrors
= runTestRequest(root
, argc
, argv
);
214 setTestOption(REPEAT_TESTS_OPTION
, DECREMENT_OPTION_VALUE
);
215 if (getTestOption(REPEAT_TESTS_OPTION
) > 0) {
216 printf("Repeating tests %d more time(s)\n", getTestOption(REPEAT_TESTS_OPTION
));
218 cleanUpTestTree(root
);
220 #ifdef CTST_LEAK_CHECK
222 /* To check for leaks */
223 u_cleanup(); /* nuke the hashtable.. so that any still-open cnvs are leaked */
225 if(getTestOption(VERBOSITY_OPTION
) && ctst_allocated_total
>0) {
226 fprintf(stderr
,"ctst_freeAll(): cleaned up after %d allocations (queue of %d)\n", ctst_allocated_total
, CTST_MAX_ALLOC
);
229 if(ures_dumpCacheContents()) {
230 fprintf(stderr
, "Error: After final u_cleanup, RB cache was not empty.\n");
233 fprintf(stderr
,"OK: After final u_cleanup, RB cache was empty.\n");
238 } /* End of loop that repeats the entire test, if requested. (Normally doesn't loop) */
240 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
241 unistr_printLengths();
244 endTime
= uprv_getRawUTCtime();
245 diffTime
= (int32_t)(endTime
- startTime
);
246 printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
247 (int)((diffTime%U_MILLIS_PER_DAY
)/U_MILLIS_PER_HOUR
),
248 (int)((diffTime%U_MILLIS_PER_HOUR
)/U_MILLIS_PER_MINUTE
),
249 (int)((diffTime%U_MILLIS_PER_MINUTE
)/U_MILLIS_PER_SECOND
),
250 (int)(diffTime%U_MILLIS_PER_SECOND
));
252 return nerrors
? 1 : 0;
256 static void ctest_appendToDataDirectory(const char *toAppend)
258 const char *oldPath ="";
260 char *newPath = newBuf;
264 if((toAppend == NULL) || (*toAppend == 0)) {
268 oldPath = u_getDataDirectory();
269 if( (oldPath==NULL) || (*oldPath == 0)) {
270 u_setDataDirectory(toAppend);
272 oldLen = strlen(oldPath);
273 newLen = strlen(toAppend)+1+oldLen;
277 newPath = (char *)ctst_malloc(newLen);
280 strcpy(newPath, oldPath);
281 strcpy(newPath+oldLen, U_PATH_SEP_STRING);
282 strcpy(newPath+oldLen+1, toAppend);
284 u_setDataDirectory(newPath);
286 if(newPath != newBuf)
294 /* returns the path to icu/source/data */
295 const char * ctest_dataSrcDir()
297 static const char *dataSrcDir
= NULL
;
303 /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
304 // to point to the top of the build hierarchy, which may or
305 // may not be the same as the source directory, depending on
306 // the configure options used. At any rate,
307 // set the data path to the built data from this directory.
308 // The value is complete with quotes, so it can be used
309 // as-is as a string constant.
311 #if defined (U_TOPSRCDIR)
313 dataSrcDir
= U_TOPSRCDIR U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
;
317 /* On Windows, the file name obtained from __FILE__ includes a full path.
318 * This file is "wherever\icu\source\test\cintltst\cintltst.c"
319 * Change to "wherever\icu\source\data"
322 static char p
[sizeof(__FILE__
) + 20];
327 /* We want to back over three '\' chars. */
328 /* Only Windows should end up here, so looking for '\' is safe. */
329 for (i
=1; i
<=3; i
++) {
330 pBackSlash
= strrchr(p
, U_FILE_SEP_CHAR
);
331 if (pBackSlash
!= NULL
) {
332 *pBackSlash
= 0; /* Truncate the string at the '\' */
336 if (pBackSlash
!= NULL
) {
337 /* We found and truncated three names from the path.
338 * Now append "source\data" and set the environment
340 strcpy(pBackSlash
, U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
);
344 /* __FILE__ on MSVC7 does not contain the directory */
345 FILE *file
= fopen(".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"Makefile.in", "r");
348 dataSrcDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
;
351 dataSrcDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
;
361 /* returns the path to icu/source/data/out */
362 const char *ctest_dataOutDir()
364 static const char *dataOutDir
= NULL
;
370 /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
371 // to point to the top of the build hierarchy, which may or
372 // may not be the same as the source directory, depending on
373 // the configure options used. At any rate,
374 // set the data path to the built data from this directory.
375 // The value is complete with quotes, so it can be used
376 // as-is as a string constant.
378 #if defined (U_TOPBUILDDIR)
380 dataOutDir
= U_TOPBUILDDIR
"data"U_FILE_SEP_STRING
"out"U_FILE_SEP_STRING
;
384 /* On Windows, the file name obtained from __FILE__ includes a full path.
385 * This file is "wherever\icu\source\test\cintltst\cintltst.c"
386 * Change to "wherever\icu\source\data"
389 static char p
[sizeof(__FILE__
) + 20];
394 /* We want to back over three '\' chars. */
395 /* Only Windows should end up here, so looking for '\' is safe. */
396 for (i
=1; i
<=3; i
++) {
397 pBackSlash
= strrchr(p
, U_FILE_SEP_CHAR
);
398 if (pBackSlash
!= NULL
) {
399 *pBackSlash
= 0; /* Truncate the string at the '\' */
403 if (pBackSlash
!= NULL
) {
404 /* We found and truncated three names from the path.
405 * Now append "source\data" and set the environment
407 strcpy(pBackSlash
, U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
);
411 /* __FILE__ on MSVC7 does not contain the directory */
412 FILE *file
= fopen(".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"Makefile.in", "r");
415 dataOutDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
;
418 dataOutDir
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"data" U_FILE_SEP_STRING
"out" U_FILE_SEP_STRING
;
427 /* ctest_setICU_DATA - if the ICU_DATA environment variable is not already
428 * set, try to deduce the directory in which ICU was built,
429 * and set ICU_DATA to "icu/source/data" in that location.
430 * The intent is to allow the tests to have a good chance
431 * of running without requiring that the user manually set
432 * ICU_DATA. Common data isn't a problem, since it is
433 * picked up via a static (build time) reference, but the
434 * tests dynamically load some data.
436 void ctest_setICU_DATA() {
438 /* No location for the data dir was identifiable.
439 * Add other fallbacks for the test data location here if the need arises
441 if (getenv("ICU_DATA") == NULL
) {
442 /* If ICU_DATA isn't set, set it to the usual location */
443 u_setDataDirectory(ctest_dataOutDir());
447 /* These tests do cleanup and reinitialize ICU in the course of their operation.
448 * The ICU data directory must be preserved across these operations.
449 * Here is a helper function to assist with that.
451 static char *safeGetICUDataDirectory() {
452 const char *dataDir
= u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
454 if (dataDir
!= NULL
) {
455 retStr
= (char *)malloc(strlen(dataDir
)+1);
456 strcpy(retStr
, dataDir
);
461 UBool
ctest_resetICU() {
462 UErrorCode status
= U_ZERO_ERROR
;
463 char *dataDir
= safeGetICUDataDirectory();
466 if (!initArgs(gOrigArgc
, gOrigArgv
, NULL
, NULL
)) {
467 /* Error already displayed. */
470 u_setDataDirectory(dataDir
);
473 if (U_FAILURE(status
)) {
474 log_err_status(status
, "u_init failed with %s\n", u_errorName(status
));
480 UChar
* CharsToUChars(const char* str
) {
481 /* Might be faster to just use uprv_strlen() as the preflight len - liu */
482 int32_t len
= u_unescape(str
, 0, 0); /* preflight */
483 /* Do NOT use malloc() - we are supposed to be acting like user code! */
484 UChar
*buf
= (UChar
*) malloc(sizeof(UChar
) * (len
+ 1));
485 u_unescape(str
, buf
, len
+ 1);
489 char *austrdup(const UChar
* unichars
)
494 length
= u_strlen ( unichars
);
495 /*newString = (char*)malloc ( sizeof( char ) * 4 * ( length + 1 ) );*/ /* this leaks for now */
496 newString
= (char*)ctst_malloc ( sizeof( char ) * 4 * ( length
+ 1 ) ); /* this shouldn't */
498 if ( newString
== NULL
)
501 u_austrcpy ( newString
, unichars
);
506 char *aescstrdup(const UChar
* unichars
,int32_t length
){
507 char *newString
,*targetLimit
,*target
;
508 UConverterFromUCallback cb
;
510 UErrorCode errorCode
= U_ZERO_ERROR
;
511 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
512 # if U_PLATFORM == U_PF_OS390
513 static const char convName
[] = "ibm-1047";
515 static const char convName
[] = "ibm-37";
518 static const char convName
[] = "US-ASCII";
520 UConverter
* conv
= ucnv_open(convName
, &errorCode
);
522 length
= u_strlen( unichars
);
524 newString
= (char*)ctst_malloc ( sizeof(char) * 8 * (length
+1));
526 targetLimit
= newString
+sizeof(char) * 8 * (length
+1);
527 ucnv_setFromUCallBack(conv
, UCNV_FROM_U_CALLBACK_ESCAPE
, UCNV_ESCAPE_C
, &cb
, &p
, &errorCode
);
528 ucnv_fromUnicode(conv
,&target
,targetLimit
, &unichars
, (UChar
*)(unichars
+length
),NULL
,TRUE
,&errorCode
);
534 const char* loadTestData(UErrorCode
* err
){
535 if( _testDataPath
== NULL
){
536 const char* directory
=NULL
;
537 UResourceBundle
* test
=NULL
;
539 const char* tdrelativepath
;
540 #if defined (U_TOPBUILDDIR)
541 tdrelativepath
= "test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
"out"U_FILE_SEP_STRING
;
542 directory
= U_TOPBUILDDIR
;
544 tdrelativepath
= ".."U_FILE_SEP_STRING
".."U_FILE_SEP_STRING
"test"U_FILE_SEP_STRING
"testdata"U_FILE_SEP_STRING
"out"U_FILE_SEP_STRING
;
545 directory
= ctest_dataOutDir();
548 tdpath
= (char*) ctst_malloc(sizeof(char) *(( strlen(directory
) * strlen(tdrelativepath
)) + 10));
551 /* u_getDataDirectory shoul return \source\data ... set the
552 * directory to ..\source\data\..\test\testdata\out\testdata
554 * Fallback: When Memory mapped file is built
555 * ..\source\data\out\..\..\test\testdata\out\testdata
557 strcpy(tdpath
, directory
);
558 strcat(tdpath
, tdrelativepath
);
559 strcat(tdpath
,"testdata");
562 test
=ures_open(tdpath
, "testtypes", err
);
564 /* Fall back did not succeed either so return */
566 *err
= U_FILE_ACCESS_ERROR
;
567 log_data_err("Could not load testtypes.res in testdata bundle with path %s - %s\n", tdpath
, u_errorName(*err
));
571 _testDataPath
= tdpath
;
572 return _testDataPath
;
574 return _testDataPath
;
577 #define CTEST_MAX_TIMEZONE_SIZE 256
578 static UChar gOriginalTimeZone
[CTEST_MAX_TIMEZONE_SIZE
] = {0};
581 * Call this once to get a consistent timezone. Use ctest_resetTimeZone to set it back to the original value.
582 * @param optionalTimeZone Set this to a requested timezone.
583 * Set to NULL to use the standard test timezone (Pacific Time)
585 U_CFUNC
void ctest_setTimeZone(const char *optionalTimeZone
, UErrorCode
*status
) {
586 #if !UCONFIG_NO_FORMATTING
587 UChar zoneID
[CTEST_MAX_TIMEZONE_SIZE
];
589 if (optionalTimeZone
== NULL
) {
590 optionalTimeZone
= "America/Los_Angeles";
592 if (gOriginalTimeZone
[0]) {
593 log_data_err("*** Error: time zone saved twice. New value will be %s (Are you missing data?)\n",
596 ucal_getDefaultTimeZone(gOriginalTimeZone
, CTEST_MAX_TIMEZONE_SIZE
, status
);
597 if (U_FAILURE(*status
)) {
598 log_err("*** Error: Failed to save default time zone: %s\n",
599 u_errorName(*status
));
600 *status
= U_ZERO_ERROR
;
603 u_uastrncpy(zoneID
, optionalTimeZone
, CTEST_MAX_TIMEZONE_SIZE
-1);
604 zoneID
[CTEST_MAX_TIMEZONE_SIZE
-1] = 0;
605 ucal_setDefaultTimeZone(zoneID
, status
);
606 if (U_FAILURE(*status
)) {
607 log_err("*** Error: Failed to set default time zone to \"%s\": %s\n",
608 optionalTimeZone
, u_errorName(*status
));
614 * Call this once get back the original timezone
616 U_CFUNC
void ctest_resetTimeZone(void) {
617 #if !UCONFIG_NO_FORMATTING
618 UErrorCode status
= U_ZERO_ERROR
;
620 ucal_setDefaultTimeZone(gOriginalTimeZone
, &status
);
621 if (U_FAILURE(status
)) {
622 log_err("*** Error: Failed to reset default time zone: %s\n",
623 u_errorName(status
));
625 /* Set to an empty state */
626 gOriginalTimeZone
[0] = 0;
631 void *ctst_malloc(size_t size
) {
632 ctst_allocated_total
++;
633 if(ctst_allocated
>= CTST_MAX_ALLOC
- 1) {
637 if(ctst_allocated_stuff
[ctst_allocated
]) {
638 free(ctst_allocated_stuff
[ctst_allocated
]);
640 return ctst_allocated_stuff
[ctst_allocated
++] = malloc(size
);
643 #ifdef CTST_LEAK_CHECK
644 static void ctst_freeAll() {
646 if(ctst_free
== FALSE
) { /* only free up to the allocated mark */
647 for(i
=0; i
<ctst_allocated
; i
++) {
648 free(ctst_allocated_stuff
[i
]);
649 ctst_allocated_stuff
[i
] = NULL
;
651 } else { /* free all */
652 for(i
=0; i
<CTST_MAX_ALLOC
; i
++) {
653 free(ctst_allocated_stuff
[i
]);
654 ctst_allocated_stuff
[i
] = NULL
;
661 #define VERBOSE_ASSERTIONS
663 U_CFUNC UBool
assertSuccessCheck(const char* msg
, UErrorCode
* ec
, UBool possibleDataError
) {
665 if (U_FAILURE(*ec
)) {
666 if (possibleDataError
) {
667 log_data_err("FAIL: %s (%s)\n", msg
, u_errorName(*ec
));
669 log_err_status(*ec
, "FAIL: %s (%s)\n", msg
, u_errorName(*ec
));
676 U_CFUNC UBool
assertSuccess(const char* msg
, UErrorCode
* ec
) {
678 return assertSuccessCheck(msg
, ec
, FALSE
);
681 /* if 'condition' is a UBool, the compiler complains bitterly about
682 expressions like 'a > 0' which it evaluates as int */
683 U_CFUNC UBool
assertTrue(const char* msg
, int /*not UBool*/ condition
) {
685 log_err("FAIL: assertTrue() failed: %s\n", msg
);
687 #ifdef VERBOSE_ASSERTIONS
689 log_verbose("Ok: %s\n", msg
);
692 return (UBool
)condition
;
695 U_CFUNC UBool
assertEquals(const char* message
, const char* expected
,
696 const char* actual
) {
697 if (uprv_strcmp(expected
, actual
) != 0) {
698 log_err("FAIL: %s; got \"%s\"; expected \"%s\"\n",
699 message
, actual
, expected
);
702 #ifdef VERBOSE_ASSERTIONS
704 log_verbose("Ok: %s; got \"%s\"\n", message
, actual
);