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