/* ******************************************************************************* * * Copyright (C) 2009-2013, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: bidiconf.cpp * encoding: US-ASCII * tab size: 8 (not used) * indentation:4 * * created on: 2009oct16 * created by: Markus W. Scherer * * BiDi conformance test, using the Unicode BidiTest.txt and BidiCharacterTest.txt files. */ #include #include #include #include "unicode/utypes.h" #include "unicode/ubidi.h" #include "unicode/errorcode.h" #include "unicode/localpointer.h" #include "unicode/putil.h" #include "unicode/unistr.h" #include "intltest.h" #include "uparse.h" class BiDiConformanceTest : public IntlTest { public: BiDiConformanceTest() : directionBits(0), lineNumber(0), levelsCount(0), orderingCount(0), errorCount(0) {} void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=NULL); void TestBidiTest(); void TestBidiCharacterTest(); private: char *getUnidataPath(char path[]); UBool parseLevels(const char *&start); UBool parseOrdering(const char *start); UBool parseInputStringFromBiDiClasses(const char *&start); UBool checkLevels(const UBiDiLevel actualLevels[], int32_t actualCount); UBool checkOrdering(UBiDi *ubidi); void printErrorLine(); char line[10000]; UBiDiLevel levels[1000]; uint32_t directionBits; int32_t ordering[1000]; int32_t lineNumber; int32_t levelsCount; int32_t orderingCount; int32_t errorCount; UnicodeString inputString; const char *paraLevelName; char levelNameString[12]; }; extern IntlTest *createBiDiConformanceTest() { return new BiDiConformanceTest(); } void BiDiConformanceTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) { if(exec) { logln("TestSuite BiDiConformanceTest: "); } TESTCASE_AUTO_BEGIN; TESTCASE_AUTO(TestBidiTest); TESTCASE_AUTO(TestBidiCharacterTest); TESTCASE_AUTO_END; } // TODO: Move to a common place (IntlTest?) to avoid duplication with UnicodeTest (ucdtest.cpp). char *BiDiConformanceTest::getUnidataPath(char path[]) { IcuTestErrorCode errorCode(*this, "getUnidataPath"); const int kUnicodeDataTxtLength=15; // strlen("UnicodeData.txt") // Look inside ICU_DATA first. strcpy(path, pathToDataDirectory()); strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt"); FILE *f=fopen(path, "r"); if(f!=NULL) { fclose(f); *(strchr(path, 0)-kUnicodeDataTxtLength)=0; // Remove the basename. return path; } // As a fallback, try to guess where the source data was located // at the time ICU was built, and look there. # ifdef U_TOPSRCDIR strcpy(path, U_TOPSRCDIR U_FILE_SEP_STRING "data"); # else strcpy(path, loadTestData(errorCode)); strcat(path, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data"); # endif strcat(path, U_FILE_SEP_STRING); strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt"); f=fopen(path, "r"); if(f!=NULL) { fclose(f); *(strchr(path, 0)-kUnicodeDataTxtLength)=0; // Remove the basename. return path; } return NULL; } U_DEFINE_LOCAL_OPEN_POINTER(LocalStdioFilePointer, FILE, fclose); UBool BiDiConformanceTest::parseLevels(const char *&start) { directionBits=0; levelsCount=0; while(*start!=0 && *(start=u_skipWhitespace(start))!=0 && *start!=';') { if(*start=='x') { levels[levelsCount++]=UBIDI_DEFAULT_LTR; ++start; } else { char *end; uint32_t value=(uint32_t)strtoul(start, &end, 10); if(end<=start || (!U_IS_INV_WHITESPACE(*end) && *end!=0 && *end!=';') || value>(UBIDI_MAX_EXPLICIT_LEVEL+1)) { errln("\nError on line %d: Levels parse error at %s", (int)lineNumber, start); printErrorLine(); return FALSE; } levels[levelsCount++]=(UBiDiLevel)value; directionBits|=(1<<(value&1)); start=end; } } return TRUE; } UBool BiDiConformanceTest::parseOrdering(const char *start) { orderingCount=0; while(*start!=0 && *(start=u_skipWhitespace(start))!=0 && *start!=';') { char *end; uint32_t value=(uint32_t)strtoul(start, &end, 10); if(end<=start || (!U_IS_INV_WHITESPACE(*end) && *end!=0 && *end!=';') || value>=1000) { errln("\nError on line %d: Reorder parse error at %s", (int)lineNumber, start); printErrorLine(); return FALSE; } ordering[orderingCount++]=(int32_t)value; start=end; } return TRUE; } static const UChar charFromBiDiClass[U_CHAR_DIRECTION_COUNT]={ 0x6c, // 'l' for L 0x52, // 'R' for R 0x33, // '3' for EN 0x2d, // '-' for ES 0x25, // '%' for ET 0x39, // '9' for AN 0x2c, // ',' for CS 0x2f, // '/' for B 0x5f, // '_' for S 0x20, // ' ' for WS 0x3d, // '=' for ON 0x65, // 'e' for LRE 0x6f, // 'o' for LRO 0x41, // 'A' for AL 0x45, // 'E' for RLE 0x4f, // 'O' for RLO 0x2a, // '*' for PDF 0x60, // '`' for NSM 0x7c, // '|' for BN // new in Unicode 6.3/ICU 52 0x53, // 'S' for FSI 0x69, // 'i' for LRI 0x49, // 'I' for RLI 0x2e // '.' for PDI }; U_CDECL_BEGIN static UCharDirection U_CALLCONV biDiConfUBiDiClassCallback(const void * /*context*/, UChar32 c) { for(int i=0; i1) { errln("\nError on line %d: Resolved paragraph level incorrect at %s", (int)lineNumber, start); printErrorLine(); continue; } start=u_skipWhitespace(end); if(*start!=';') { errorCount++; errln("\nError on line %d: Missing ; separator on line: %s", (int)lineNumber, line); return; } start++; if(!parseLevels(start)) { continue; } start=u_skipWhitespace(start); if(*start==';') { if(!parseOrdering(start+1)) { continue; } } else orderingCount=-1; ubidi_setPara(ubidi.getAlias(), inputString.getBuffer(), inputString.length(), paraLevel, NULL, errorCode); const UBiDiLevel *actualLevels=ubidi_getLevels(ubidi.getAlias(), errorCode); if(errorCode.logIfFailureAndReset("ubidi_setPara() or ubidi_getLevels()")) { errln("Input line %d: %s", (int)lineNumber, line); continue; } UBiDiLevel actualLevel; if((actualLevel=ubidi_getParaLevel(ubidi.getAlias()))!=resolvedParaLevel) { printErrorLine(); errln("\nError on line %d: Wrong resolved paragraph level; expected %d actual %d", (int)lineNumber, resolvedParaLevel, actualLevel); continue; } if(!checkLevels(actualLevels, ubidi_getProcessedLength(ubidi.getAlias()))) { continue; } if(orderingCount>=0 && !checkOrdering(ubidi.getAlias())) { continue; } } } static UChar printLevel(UBiDiLevel level) { if(level=UBIDI_DEFAULT_LTR) { continue; // BiDi control, omitted from expected ordering. } if(visualIndex