1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4**********************************************************************
5*   Copyright (C) 2002-2016, International Business Machines
6*   Corporation and others.  All Rights Reserved.
7**********************************************************************
8*   file name:  iotest.cpp
9*   encoding:   UTF-8
10*   tab size:   8 (not used)
11*   indentation:4
12*
13*   created on: 2002feb21
14*   created by: George Rhoten
15*/
16
17
18#include "unicode/ustdio.h"
19#include "unicode/uclean.h"
20
21#include "unicode/ucnv.h"
22#include "unicode/uchar.h"
23#include "unicode/unistr.h"
24#include "unicode/ustring.h"
25#include "cmemory.h"
26#include "ustr_cnv.h"
27#include "iotest.h"
28#include "unicode/tstdtmod.h"
29#include "putilimp.h"
30
31#include <string.h>
32#include <stdlib.h>
33
34class DataDrivenLogger : public TestLog {
35    static const char* fgDataDir;
36    static char *fgTestDataPath;
37
38public:
39    static void cleanUp() {
40        if (fgTestDataPath) {
41            free(fgTestDataPath);
42            fgTestDataPath = NULL;
43        }
44    }
45    virtual void errln( const UnicodeString &message ) {
46        char buffer[4000];
47        message.extract(0, message.length(), buffer, sizeof(buffer));
48        buffer[3999] = 0; /* NULL terminate */
49        log_err(buffer);
50    }
51
52    virtual void logln( const UnicodeString &message ) {
53        char buffer[4000];
54        message.extract(0, message.length(), buffer, sizeof(buffer));
55        buffer[3999] = 0; /* NULL terminate */
56        log_info(buffer);
57    }
58
59    virtual void dataerrln( const UnicodeString &message ) {
60        char buffer[4000];
61        message.extract(0, message.length(), buffer, sizeof(buffer));
62        buffer[3999] = 0; /* NULL terminate */
63        log_data_err(buffer);
64    }
65
66    static const char * pathToDataDirectory(void)
67    {
68
69        if(fgDataDir != NULL) {
70            return fgDataDir;
71        }
72
73        /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
74        //              to point to the top of the build hierarchy, which may or
75        //              may not be the same as the source directory, depending on
76        //              the configure options used.  At any rate,
77        //              set the data path to the built data from this directory.
78        //              The value is complete with quotes, so it can be used
79        //              as-is as a string constant.
80        */
81    #if defined (U_TOPSRCDIR)
82        {
83            fgDataDir = U_TOPSRCDIR  U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
84        }
85    #else
86
87        /* On Windows, the file name obtained from __FILE__ includes a full path.
88        *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
89        *             Change to    "wherever\icu\source\data"
90        */
91        {
92            static char p[sizeof(__FILE__) + 10];
93            char *pBackSlash;
94            int i;
95
96            strcpy(p, __FILE__);
97            /* We want to back over three '\' chars.                            */
98            /*   Only Windows should end up here, so looking for '\' is safe.   */
99            for (i=1; i<=3; i++) {
100                pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
101                if (pBackSlash != NULL) {
102                    *pBackSlash = 0;        /* Truncate the string at the '\'   */
103                }
104            }
105
106            if (pBackSlash != NULL) {
107                /* We found and truncated three names from the path.
108                *  Now append "source\data" and set the environment
109                */
110                strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
111                fgDataDir = p;
112            }
113            else {
114                /* __FILE__ on MSVC7 does not contain the directory */
115                FILE *file = fopen(".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
116                if (file) {
117                    fclose(file);
118                    fgDataDir = ".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
119                }
120                else {
121                    fgDataDir = ".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
122                }
123            }
124        }
125    #endif
126
127        return fgDataDir;
128
129    }
130
131    static const char* loadTestData(UErrorCode& err){
132        if( fgTestDataPath == NULL){
133            const char*      directory=NULL;
134            UResourceBundle* test =NULL;
135            char* tdpath=NULL;
136            const char* tdrelativepath;
137
138#if defined (U_TOPBUILDDIR)
139            tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
140            directory = U_TOPBUILDDIR;
141#else
142            tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
143            directory = pathToDataDirectory();
144#endif
145
146            tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100));
147
148
149            /* u_getDataDirectory shoul return \source\data ... set the
150            * directory to ..\source\data\..\test\testdata\out\testdata
151            */
152            strcpy(tdpath, directory);
153            strcat(tdpath, tdrelativepath);
154            strcat(tdpath,"testdata");
155
156            test=ures_open(tdpath, "testtypes", &err);
157
158            if(U_FAILURE(err)){
159                err = U_FILE_ACCESS_ERROR;
160                log_data_err("Could not load testtypes.res in testdata bundle with path %s - %s\n", tdpath, u_errorName(err));
161                return "";
162            }
163            ures_close(test);
164            fgTestDataPath = tdpath;
165        }
166        return fgTestDataPath;
167    }
168
169    virtual const char* getTestDataPath(UErrorCode& err) {
170        return loadTestData(err);
171    }
172};
173
174const char* DataDrivenLogger::fgDataDir = NULL;
175char* DataDrivenLogger::fgTestDataPath = NULL;
176
177#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO
178static int64_t
179uto64(const UChar     *buffer)
180{
181    int64_t result = 0;
182    /* iterate through buffer */
183    while(*buffer) {
184        /* read the next digit */
185        result *= 16;
186        if (!u_isxdigit(*buffer)) {
187            log_err("\\u%04X is not a valid hex digit for this test\n", (UChar)*buffer);
188        }
189        result += *buffer - 0x0030 - (*buffer >= 0x0041 ? (*buffer >= 0x0061 ? 39 : 7) : 0);
190        buffer++;
191    }
192    return result;
193}
194#endif
195
196U_CDECL_BEGIN
197static void U_CALLCONV DataDrivenPrintf(void)
198{
199#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO
200    UErrorCode errorCode;
201    TestDataModule *dataModule;
202    TestData *testData;
203    const DataMap *testCase;
204    DataDrivenLogger logger;
205    UChar uBuffer[512];
206    char cBuffer[512];
207    char cFormat[sizeof(cBuffer)];
208    char cExpected[sizeof(cBuffer)];
209    UnicodeString tempStr;
210    UChar format[512];
211    UChar expectedResult[512];
212    UChar argument[512];
213    int32_t i;
214    int8_t i8;
215    int16_t i16;
216    int32_t i32;
217    int64_t i64;
218    double dbl;
219    int32_t uBufferLenReturned;
220
221    const char *fileLocale = "en_US_POSIX";
222    int32_t uFileBufferLenReturned;
223    LocalUFILEPointer testFile;
224
225    errorCode=U_ZERO_ERROR;
226    dataModule=TestDataModule::getTestDataModule("icuio", logger, errorCode);
227    if(U_SUCCESS(errorCode)) {
228        testData=dataModule->createTestData("printf", errorCode);
229        if(U_SUCCESS(errorCode)) {
230            for(i=0; testData->nextCase(testCase, errorCode); ++i) {
231                if(U_FAILURE(errorCode)) {
232                    log_err("error retrieving icuio/printf test case %d - %s\n",
233                            i, u_errorName(errorCode));
234                    errorCode=U_ZERO_ERROR;
235                    continue;
236                }
237                testFile.adoptInstead(u_fopen(STANDARD_TEST_FILE, "w", fileLocale, "UTF-8"));
238                if (testFile.isNull()) {
239                    log_err("Can't open test file - %s\n",
240                            STANDARD_TEST_FILE);
241                    continue;
242                }
243                u_memset(uBuffer, 0x2A, UPRV_LENGTHOF(uBuffer));
244                uBuffer[UPRV_LENGTHOF(uBuffer)-1] = 0;
245                tempStr=testCase->getString("format", errorCode);
246                tempStr.extract(format, UPRV_LENGTHOF(format), errorCode);
247                tempStr=testCase->getString("result", errorCode);
248                tempStr.extract(expectedResult, UPRV_LENGTHOF(expectedResult), errorCode);
249                tempStr=testCase->getString("argument", errorCode);
250                tempStr.extract(argument, UPRV_LENGTHOF(argument), errorCode);
251                u_austrncpy(cBuffer, format, sizeof(cBuffer));
252                if(U_FAILURE(errorCode)) {
253                    log_err("error retrieving icuio/printf test case %d - %s\n",
254                            i, u_errorName(errorCode));
255                    errorCode=U_ZERO_ERROR;
256                    continue;
257                }
258                log_verbose("Test %d: format=\"%s\"\n", i, cBuffer);
259                switch (testCase->getString("argumentType", errorCode)[0]) {
260                case 0x64:  // 'd' double
261                    dbl = atof(u_austrcpy(cBuffer, argument));
262                    uBufferLenReturned = u_sprintf_u(uBuffer, format, dbl);
263                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, dbl);
264                    break;
265                case 0x31:  // '1' int8_t
266                    i8 = (int8_t)uto64(argument);
267                    uBufferLenReturned = u_sprintf_u(uBuffer, format, i8);
268                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, i8);
269                    break;
270                case 0x32:  // '2' int16_t
271                    i16 = (int16_t)uto64(argument);
272                    uBufferLenReturned = u_sprintf_u(uBuffer, format, i16);
273                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, i16);
274                    break;
275                case 0x34:  // '4' int32_t
276                    i32 = (int32_t)uto64(argument);
277                    uBufferLenReturned = u_sprintf_u(uBuffer, format, i32);
278                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, i32);
279                    break;
280                case 0x38:  // '8' int64_t
281                    i64 = uto64(argument);
282                    uBufferLenReturned = u_sprintf_u(uBuffer, format, i64);
283                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, i64);
284                    break;
285                case 0x73:  // 's' char *
286                    u_austrncpy(cBuffer, argument, sizeof(cBuffer));
287                    uBufferLenReturned = u_sprintf_u(uBuffer, format, cBuffer);
288                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, cBuffer);
289                    break;
290                case 0x53:  // 'S' UChar *
291                    uBufferLenReturned = u_sprintf_u(uBuffer, format, argument);
292                    uFileBufferLenReturned = u_fprintf_u(testFile.getAlias(), format, argument);
293                    break;
294                default:
295                    uBufferLenReturned = 0;
296                    uFileBufferLenReturned = 0;
297                    log_err("Unknown type %c for test %d\n", testCase->getString("argumentType", errorCode)[0], i);
298                }
299                if (u_strcmp(uBuffer, expectedResult) != 0) {
300                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
301                    u_austrncpy(cFormat, format, sizeof(cFormat));
302                    u_austrncpy(cExpected, expectedResult, sizeof(cExpected));
303                    cBuffer[sizeof(cBuffer)-1] = 0;
304                    log_err("FAILURE string test case %d \"%s\" - Got: \"%s\" Expected: \"%s\"\n",
305                            i, cFormat, cBuffer, cExpected);
306                }
307                if (uBufferLenReturned <= 0) {
308                    log_err("FAILURE test case %d - \"%s\" is an empty string.\n",
309                            i, cBuffer);
310                }
311                else if (uBuffer[uBufferLenReturned-1] == 0
312                    || uBuffer[uBufferLenReturned] != 0
313                    || uBuffer[uBufferLenReturned+1] != 0x2A
314                    || uBuffer[uBufferLenReturned+2] != 0x2A)
315                {
316                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
317                    cBuffer[sizeof(cBuffer)-1] = 0;
318                    log_err("FAILURE test case %d - \"%s\" wrong amount of characters was written. Got %d.\n",
319                            i, cBuffer, uBufferLenReturned);
320                }
321                testFile.adoptInstead(u_fopen(STANDARD_TEST_FILE, "r", fileLocale, "UTF-8"));
322                if (testFile.isNull()) {
323                    log_err("Can't open test file - %s\n",
324                            STANDARD_TEST_FILE);
325                }
326                uBuffer[0]=0;
327                u_fgets(uBuffer, UPRV_LENGTHOF(uBuffer), testFile.getAlias());
328                if (u_strcmp(uBuffer, expectedResult) != 0) {
329                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
330                    u_austrncpy(cFormat, format, sizeof(cFormat));
331                    u_austrncpy(cExpected, expectedResult, sizeof(cExpected));
332                    cBuffer[sizeof(cBuffer)-1] = 0;
333                    log_err("FAILURE file test case %d \"%s\" - Got: \"%s\" Expected: \"%s\"\n",
334                            i, cFormat, cBuffer, cExpected);
335                }
336                if (uFileBufferLenReturned != uBufferLenReturned)
337                {
338                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
339                    cBuffer[sizeof(cBuffer)-1] = 0;
340                    log_err("FAILURE uFileBufferLenReturned(%d) != uBufferLenReturned(%d)\n",
341                            uFileBufferLenReturned, uBufferLenReturned);
342                }
343
344                if(U_FAILURE(errorCode)) {
345                    log_err("error running icuio/printf test case %d - %s\n",
346                            i, u_errorName(errorCode));
347                    errorCode=U_ZERO_ERROR;
348                    continue;
349                }
350            }
351            delete testData;
352        }
353        delete dataModule;
354    }
355    else {
356        log_data_err("Failed: could not load test icuio data\n");
357    }
358#endif
359}
360U_CDECL_END
361
362U_CDECL_BEGIN
363static void U_CALLCONV DataDrivenScanf(void)
364{
365#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO
366    UErrorCode errorCode;
367    TestDataModule *dataModule;
368    TestData *testData;
369    const DataMap *testCase;
370    DataDrivenLogger logger;
371    UChar uBuffer[512];
372    char cBuffer[512];
373    char cExpected[sizeof(cBuffer)];
374    UnicodeString tempStr;
375    UChar format[512];
376    UChar expectedResult[512];
377    UChar argument[512];
378    int32_t i;
379    int8_t i8, expected8;
380    int16_t i16, expected16;
381    int32_t i32, expected32;
382    int64_t i64, expected64;
383    double dbl, expectedDbl;
384    volatile float flt, expectedFlt; // Use volatile in order to get around an Intel compiler issue.
385    int32_t uBufferLenReturned;
386
387    //const char *fileLocale = "en_US_POSIX";
388    //int32_t uFileBufferLenReturned;
389    //UFILE *testFile;
390
391    errorCode=U_ZERO_ERROR;
392    dataModule=TestDataModule::getTestDataModule("icuio", logger, errorCode);
393    if(U_SUCCESS(errorCode)) {
394        testData=dataModule->createTestData("scanf", errorCode);
395        if(U_SUCCESS(errorCode)) {
396            for(i=0; testData->nextCase(testCase, errorCode); ++i) {
397                if(U_FAILURE(errorCode)) {
398                    log_err("error retrieving icuio/printf test case %d - %s\n",
399                            i, u_errorName(errorCode));
400                    errorCode=U_ZERO_ERROR;
401                    continue;
402                }
403/*                testFile = u_fopen(STANDARD_TEST_FILE, "w", fileLocale, "UTF-8");
404                if (!testFile) {
405                    log_err("Can't open test file - %s\n",
406                            STANDARD_TEST_FILE);
407                }*/
408                u_memset(uBuffer, 0x2A, UPRV_LENGTHOF(uBuffer));
409                uBuffer[UPRV_LENGTHOF(uBuffer)-1] = 0;
410                tempStr=testCase->getString("format", errorCode);
411                tempStr.extract(format, UPRV_LENGTHOF(format), errorCode);
412                tempStr=testCase->getString("result", errorCode);
413                tempStr.extract(expectedResult, UPRV_LENGTHOF(expectedResult), errorCode);
414                tempStr=testCase->getString("argument", errorCode);
415                tempStr.extract(argument, UPRV_LENGTHOF(argument), errorCode);
416                u_austrncpy(cBuffer, format, sizeof(cBuffer));
417                if(U_FAILURE(errorCode)) {
418                    log_err("error retrieving icuio/printf test case %d - %s\n",
419                            i, u_errorName(errorCode));
420                    errorCode=U_ZERO_ERROR;
421                    continue;
422                }
423                log_verbose("Test %d: format=\"%s\"\n", i, cBuffer);
424                switch (testCase->getString("argumentType", errorCode)[0]) {
425                case 0x64:  // 'd' double
426                    expectedDbl = atof(u_austrcpy(cBuffer, expectedResult));
427                    uBufferLenReturned = u_sscanf_u(argument, format, &dbl);
428                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, dbl);
429                    if (dbl != expectedDbl) {
430                        log_err("error in scanf test case[%d] Got: %f Exp: %f\n",
431                                i, dbl, expectedDbl);
432                    }
433                    break;
434                case 0x66:  // 'f' float
435                    expectedFlt = (float)atof(u_austrcpy(cBuffer, expectedResult));
436                    uBufferLenReturned = u_sscanf_u(argument, format, &flt);
437                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, flt);
438                    if (flt != expectedFlt) {
439                        log_err("error in scanf test case[%d] Got: %f Exp: %f\n",
440                                i, flt, expectedFlt);
441                    }
442                    break;
443                case 0x31:  // '1' int8_t
444                    expected8 = (int8_t)uto64(expectedResult);
445                    uBufferLenReturned = u_sscanf_u(argument, format, &i8);
446                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, i8);
447                    if (i8 != expected8) {
448                        log_err("error in scanf test case[%d] Got: %02X Exp: %02X\n",
449                                i, i8, expected8);
450                    }
451                    break;
452                case 0x32:  // '2' int16_t
453                    expected16 = (int16_t)uto64(expectedResult);
454                    uBufferLenReturned = u_sscanf_u(argument, format, &i16);
455                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, i16);
456                    if (i16 != expected16) {
457                        log_err("error in scanf test case[%d] Got: %04X Exp: %04X\n",
458                                i, i16, expected16);
459                    }
460                    break;
461                case 0x34:  // '4' int32_t
462                    expected32 = (int32_t)uto64(expectedResult);
463                    uBufferLenReturned = u_sscanf_u(argument, format, &i32);
464                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, i32);
465                    if (i32 != expected32) {
466                        log_err("error in scanf test case[%d] Got: %08X Exp: %08X\n",
467                                i, i32, expected32);
468                    }
469                    break;
470                case 0x38:  // '8' int64_t
471                    expected64 = uto64(expectedResult);
472                    uBufferLenReturned = u_sscanf_u(argument, format, &i64);
473                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, i64);
474                    if (i64 != expected64) {
475                        log_err("error in scanf 64-bit. Test case = %d\n", i);
476                    }
477                    break;
478                case 0x73:  // 's' char *
479                    u_austrcpy(cExpected, expectedResult);
480                    uBufferLenReturned = u_sscanf_u(argument, format, cBuffer);
481                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, cBuffer);
482                    if (strcmp(cBuffer, cExpected) != 0) {
483                        log_err("error in scanf char * string. Got \"%s\" Expected \"%s\". Test case = %d\n", cBuffer, cExpected, i);
484                    }
485                    break;
486                case 0x53:  // 'S' UChar *
487                    uBufferLenReturned = u_sscanf_u(argument, format, uBuffer);
488                    //uFileBufferLenReturned = u_fscanf_u(testFile, format, argument);
489                    if (u_strcmp(uBuffer, expectedResult) != 0) {
490                        u_austrcpy(cExpected, format);
491                        u_austrcpy(cBuffer, uBuffer);
492                        log_err("error in scanf UChar * string %s Got: \"%s\". Test case = %d\n", cExpected, cBuffer, i);
493                    }
494                    break;
495                default:
496                    uBufferLenReturned = 0;
497                    //uFileBufferLenReturned = 0;
498                    log_err("Unknown type %c for test %d\n", testCase->getString("argumentType", errorCode)[0], i);
499                }
500                if (uBufferLenReturned != 1) {
501                    log_err("error scanf converted %d arguments. Test case = %d\n", uBufferLenReturned, i);
502                }
503/*                if (u_strcmp(uBuffer, expectedResult) != 0) {
504                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
505                    u_austrncpy(cFormat, format, sizeof(cFormat));
506                    u_austrncpy(cExpected, expectedResult, sizeof(cExpected));
507                    cBuffer[sizeof(cBuffer)-1] = 0;
508                    log_err("FAILURE string test case %d \"%s\" - Got: \"%s\" Expected: \"%s\"\n",
509                            i, cFormat, cBuffer, cExpected);
510                }
511                if (uBuffer[uBufferLenReturned-1] == 0
512                    || uBuffer[uBufferLenReturned] != 0
513                    || uBuffer[uBufferLenReturned+1] != 0x2A
514                    || uBuffer[uBufferLenReturned+2] != 0x2A)
515                {
516                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
517                    cBuffer[sizeof(cBuffer)-1] = 0;
518                    log_err("FAILURE test case %d - \"%s\" wrong amount of characters was written. Got %d.\n",
519                            i, cBuffer, uBufferLenReturned);
520                }*/
521/*                u_fclose(testFile);
522                testFile = u_fopen(STANDARD_TEST_FILE, "r", fileLocale, "UTF-8");
523                if (!testFile) {
524                    log_err("Can't open test file - %s\n",
525                            STANDARD_TEST_FILE);
526                }
527                uBuffer[0];
528                u_fgets(uBuffer, UPRV_LENGTHOF(uBuffer), testFile);
529                if (u_strcmp(uBuffer, expectedResult) != 0) {
530                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
531                    u_austrncpy(cFormat, format, sizeof(cFormat));
532                    u_austrncpy(cExpected, expectedResult, sizeof(cExpected));
533                    cBuffer[sizeof(cBuffer)-1] = 0;
534                    log_err("FAILURE file test case %d \"%s\" - Got: \"%s\" Expected: \"%s\"\n",
535                            i, cFormat, cBuffer, cExpected);
536                }
537                if (uFileBufferLenReturned != uBufferLenReturned)
538                {
539                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
540                    cBuffer[sizeof(cBuffer)-1] = 0;
541                    log_err("FAILURE uFileBufferLenReturned(%d) != uBufferLenReturned(%d)\n",
542                            uFileBufferLenReturned, uBufferLenReturned);
543                }
544*/
545                if(U_FAILURE(errorCode)) {
546                    log_err("error running icuio/printf test case %d - %s\n",
547                            i, u_errorName(errorCode));
548                    errorCode=U_ZERO_ERROR;
549                    continue;
550                }
551//                u_fclose(testFile);
552            }
553            delete testData;
554        }
555        delete dataModule;
556    }
557    else {
558        log_data_err("Failed: could not load test icuio data\n");
559    }
560#endif
561}
562U_CDECL_END
563
564U_CDECL_BEGIN
565static void U_CALLCONV DataDrivenPrintfPrecision(void)
566{
567#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO
568    UErrorCode errorCode;
569    TestDataModule *dataModule;
570    TestData *testData;
571    const DataMap *testCase;
572    DataDrivenLogger logger;
573    UChar uBuffer[512];
574    char cBuffer[512];
575    char cFormat[sizeof(cBuffer)];
576    char cExpected[sizeof(cBuffer)];
577    UnicodeString tempStr;
578    UChar format[512];
579    UChar expectedResult[512];
580    UChar argument[512];
581    int32_t precision;
582    int32_t i;
583    int8_t i8;
584    int16_t i16;
585    int32_t i32;
586    int64_t i64;
587    double dbl;
588    int32_t uBufferLenReturned;
589
590    errorCode=U_ZERO_ERROR;
591    dataModule=TestDataModule::getTestDataModule("icuio", logger, errorCode);
592    if(U_SUCCESS(errorCode)) {
593        testData=dataModule->createTestData("printfPrecision", errorCode);
594        if(U_SUCCESS(errorCode)) {
595            for(i=0; testData->nextCase(testCase, errorCode); ++i) {
596                if(U_FAILURE(errorCode)) {
597                    log_err("error retrieving icuio/printf test case %d - %s\n",
598                            i, u_errorName(errorCode));
599                    errorCode=U_ZERO_ERROR;
600                    continue;
601                }
602                u_memset(uBuffer, 0x2A, UPRV_LENGTHOF(uBuffer));
603                uBuffer[UPRV_LENGTHOF(uBuffer)-1] = 0;
604                tempStr=testCase->getString("format", errorCode);
605                tempStr.extract(format, UPRV_LENGTHOF(format), errorCode);
606                tempStr=testCase->getString("result", errorCode);
607                tempStr.extract(expectedResult, UPRV_LENGTHOF(expectedResult), errorCode);
608                tempStr=testCase->getString("argument", errorCode);
609                tempStr.extract(argument, UPRV_LENGTHOF(argument), errorCode);
610                precision=testCase->getInt28("precision", errorCode);
611                u_austrncpy(cBuffer, format, sizeof(cBuffer));
612                if(U_FAILURE(errorCode)) {
613                    log_err("error retrieving icuio/printf test case %d - %s\n",
614                            i, u_errorName(errorCode));
615                    errorCode=U_ZERO_ERROR;
616                    continue;
617                }
618                log_verbose("Test %d: format=\"%s\"\n", i, cBuffer);
619                switch (testCase->getString("argumentType", errorCode)[0]) {
620                case 0x64:  // 'd' double
621                    dbl = atof(u_austrcpy(cBuffer, argument));
622                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, dbl);
623                    break;
624                case 0x31:  // '1' int8_t
625                    i8 = (int8_t)uto64(argument);
626                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, i8);
627                    break;
628                case 0x32:  // '2' int16_t
629                    i16 = (int16_t)uto64(argument);
630                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, i16);
631                    break;
632                case 0x34:  // '4' int32_t
633                    i32 = (int32_t)uto64(argument);
634                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, i32);
635                    break;
636                case 0x38:  // '8' int64_t
637                    i64 = uto64(argument);
638                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, i64);
639                    break;
640                case 0x73:  // 's' char *
641                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
642                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, cBuffer);
643                    break;
644                case 0x53:  // 'S' UChar *
645                    uBufferLenReturned = u_sprintf_u(uBuffer, format, precision, argument);
646                    break;
647                default:
648                    uBufferLenReturned = 0;
649                    log_err("Unknown type %c for test %d\n", testCase->getString("argumentType", errorCode)[0], i);
650                }
651                if (u_strcmp(uBuffer, expectedResult) != 0) {
652                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
653                    u_austrncpy(cFormat, format, sizeof(cFormat));
654                    u_austrncpy(cExpected, expectedResult, sizeof(cExpected));
655                    cBuffer[sizeof(cBuffer)-1] = 0;
656                    log_err("FAILURE test case %d \"%s\" - Got: \"%s\" Expected: \"%s\"\n",
657                            i, cFormat, cBuffer, cExpected);
658                }
659                if (uBufferLenReturned <= 0) {
660                    log_err("FAILURE test case %d - \"%s\" is an empty string.\n",
661                            i, cBuffer);
662                }
663                else if (uBuffer[uBufferLenReturned-1] == 0
664                    || uBuffer[uBufferLenReturned] != 0
665                    || uBuffer[uBufferLenReturned+1] != 0x2A
666                    || uBuffer[uBufferLenReturned+2] != 0x2A)
667                {
668                    u_austrncpy(cBuffer, uBuffer, sizeof(cBuffer));
669                    cBuffer[sizeof(cBuffer)-1] = 0;
670                    log_err("FAILURE test case %d - \"%s\" wrong amount of characters was written. Got %d.\n",
671                            i, cBuffer, uBufferLenReturned);
672                }
673                if(U_FAILURE(errorCode)) {
674                    log_err("error running icuio/printf test case %d - %s\n",
675                            i, u_errorName(errorCode));
676                    errorCode=U_ZERO_ERROR;
677                    continue;
678                }
679            }
680            delete testData;
681        }
682        delete dataModule;
683    }
684    else {
685        log_data_err("Failed: could not load test icuio data\n");
686    }
687#endif
688}
689U_CDECL_END
690
691static void addAllTests(TestNode** root) {
692    addFileTest(root);
693    addStringTest(root);
694    addTranslitTest(root);
695
696#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_LEGACY_CONVERSION
697    addTest(root, &DataDrivenPrintf, "datadriv/DataDrivenPrintf");
698    addTest(root, &DataDrivenPrintfPrecision, "datadriv/DataDrivenPrintfPrecision");
699    addTest(root, &DataDrivenScanf, "datadriv/DataDrivenScanf");
700#endif
701    addStreamTests(root);
702}
703
704/* returns the path to icu/source/data/out */
705static const char *ctest_dataOutDir()
706{
707    static const char *dataOutDir = NULL;
708
709    if(dataOutDir) {
710        return dataOutDir;
711    }
712
713    /* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
714    //              to point to the top of the build hierarchy, which may or
715    //              may not be the same as the source directory, depending on
716    //              the configure options used.  At any rate,
717    //              set the data path to the built data from this directory.
718    //              The value is complete with quotes, so it can be used
719    //              as-is as a string constant.
720    */
721#if defined (U_TOPBUILDDIR)
722    {
723        dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
724    }
725#else
726
727    /* On Windows, the file name obtained from __FILE__ includes a full path.
728     *             This file is "wherever\icu\source\test\cintltst\cintltst.c"
729     *             Change to    "wherever\icu\source\data"
730     */
731    {
732        static char p[sizeof(__FILE__) + 20];
733        char *pBackSlash;
734        int i;
735
736        strcpy(p, __FILE__);
737        /* We want to back over three '\' chars.                            */
738        /*   Only Windows should end up here, so looking for '\' is safe.   */
739        for (i=1; i<=3; i++) {
740            pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
741            if (pBackSlash != NULL) {
742                *pBackSlash = 0;        /* Truncate the string at the '\'   */
743            }
744        }
745
746        if (pBackSlash != NULL) {
747            /* We found and truncated three names from the path.
748             *  Now append "source\data" and set the environment
749             */
750            strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
751            dataOutDir = p;
752        }
753        else {
754            /* __FILE__ on MSVC7 does not contain the directory */
755            FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
756            if (file) {
757                fclose(file);
758                dataOutDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
759            }
760            else {
761                dataOutDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
762            }
763        }
764    }
765#endif
766
767    return dataOutDir;
768}
769
770/*  ctest_setICU_DATA  - if the ICU_DATA environment variable is not already
771 *                       set, try to deduce the directory in which ICU was built,
772 *                       and set ICU_DATA to "icu/source/data" in that location.
773 *                       The intent is to allow the tests to have a good chance
774 *                       of running without requiring that the user manually set
775 *                       ICU_DATA.  Common data isn't a problem, since it is
776 *                       picked up via a static (build time) reference, but the
777 *                       tests dynamically load some data.
778 */
779static void ctest_setICU_DATA() {
780
781    /* No location for the data dir was identifiable.
782     *   Add other fallbacks for the test data location here if the need arises
783     */
784    if (getenv("ICU_DATA") == NULL) {
785        /* If ICU_DATA isn't set, set it to the usual location */
786        u_setDataDirectory(ctest_dataOutDir());
787    }
788}
789
790U_CDECL_BEGIN
791/*
792 * Note: this assumes that context is a pointer to STANDARD_TEST_FILE. It would be
793 * cleaner to define an acutal context with a string pointer in it and set STANDARD_TEST_FILE
794 * after the call to initArgs()...
795 */
796static int U_CALLCONV argHandler(int arg, int /*argc*/, const char * const argv[], void *context)
797{
798    const char **str = (const char **) context;
799
800    if (argv[arg][0] != '/' && argv[arg][0] != '-') {
801        *str = argv[arg];
802        return 1;
803    }
804
805    return 0;
806}
807U_CDECL_END
808
809int main(int argc, char* argv[])
810{
811    int32_t nerrors = 0;
812    TestNode *root = NULL;
813    UErrorCode errorCode = U_ZERO_ERROR;
814    UDate startTime, endTime;
815    int32_t diffTime;
816
817    startTime = uprv_getRawUTCtime();
818
819    /* Check whether ICU will initialize without forcing the build data directory into
820    *  the ICU_DATA path.  Success here means either the data dll contains data, or that
821    *  this test program was run with ICU_DATA set externally.  Failure of this check
822    *  is normal when ICU data is not packaged into a shared library.
823    *
824    *  Whether or not this test succeeds, we want to cleanup and reinitialize
825    *  with a data path so that data loading from individual files can be tested.
826    */
827    u_init(&errorCode);
828    if (U_FAILURE(errorCode)) {
829        fprintf(stderr,
830            "#### Note:  ICU Init without build-specific setDataDirectory() failed.\n");
831    }
832    u_cleanup();
833    errorCode = U_ZERO_ERROR;
834    if (!initArgs(argc, argv, argHandler, (void *) &STANDARD_TEST_FILE)) {
835        /* Error already displayed. */
836        return -1;
837    }
838
839    /* Initialize ICU */
840    ctest_setICU_DATA();    /* u_setDataDirectory() must happen Before u_init() */
841    u_init(&errorCode);
842    if (U_FAILURE(errorCode)) {
843        fprintf(stderr,
844            "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
845            "*** Check the ICU_DATA environment variable and \n"
846            "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
847        return 1;
848    }
849
850    fprintf(stdout, "Default charset for this run is %s\n", ucnv_getDefaultName());
851
852    addAllTests(&root);
853    nerrors = runTestRequest(root, argc, argv);
854
855#if 1
856    {
857        FILE* fileToRemove = fopen(STANDARD_TEST_FILE, "r");
858        /* This should delete any temporary files. */
859        if (fileToRemove) {
860            fclose(fileToRemove);
861            log_verbose("Deleting: %s\n", STANDARD_TEST_FILE);
862            if (remove(STANDARD_TEST_FILE) != 0) {
863                /* Maybe someone didn't close the file correctly. */
864                fprintf(stderr, "FAIL: Could not delete %s\n", STANDARD_TEST_FILE);
865                nerrors += 1;
866            }
867        }
868    }
869#endif
870
871    cleanUpTestTree(root);
872    DataDrivenLogger::cleanUp();
873    u_cleanup();
874
875    endTime = uprv_getRawUTCtime();
876    diffTime = (int32_t)(endTime - startTime);
877    printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
878        (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
879        (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
880        (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
881        (int)(diffTime%U_MILLIS_PER_SECOND));
882
883    return nerrors;
884}
885