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