Index: tests/localization/22.locale.collate.cpp =================================================================== --- tests/localization/22.locale.collate.cpp (revision 1395117) +++ tests/localization/22.locale.collate.cpp (working copy) @@ -43,141 +43,81 @@ #include #include +#define IGNORE 0 +#define STR_SIZE 16 -#if _RWSTD_PATH_SEP == '/' -# define SLASH "/" -#else -# define SLASH "\\" -#endif - -// strings declared extern to work around a SunPro bug (PR #28124) -// get the source root -#define RELPATH "etc" SLASH "nls" -#define TESTS_ETC_PATH "tests" SLASH "etc" - -// the root of the locale directory (RWSTD_LOCALE_ROOT) #define LOCALE_ROOT "RWSTD_LOCALE_ROOT" -const char* locale_root; - -#define LC_COLLATE_SRC "LC_COLLATE.src" -#define LC_COLLATE_CM "LC_COLLATE.cm" -#define TEST_LOCALE_NAME "test.locale" /**************************************************************************/ -// These overloads are necessary in our template -// functions so that we can make a single function call reguardless -// of the charT we are using +// These overloads are necessary in our template functions so that we +// can make a single function call regardless of the charT we are +// using. -int c_strcoll (const char* s1, const char* s2) +int +c_strcoll (const char* s1, const char* s2) { const int ret = std::strcoll(s1, s2); return ret ? ret > 0 ? 1 : -1 : 0; } -std::size_t c_xfrm (char* to, const char* from, std::size_t size) +std::size_t +c_xfrm (char* to, const char* from, std::size_t size) { - char safety_buf [8]; - if (0 == to && 0 == size) { - // prevent buggy implementations (such as MSVC 8) from trying - // to write to the destination buffer even though it's 0 and - // its size is zero (see stdcxx-69) - to = safety_buf; - *to = '\0'; - } - - std::size_t n = std::strxfrm (to, from, size); - - if (to) - n = std::strlen (to); - - return n; + return std::strxfrm (to, from, size); } -std::size_t c_strlen (const char* s1) +std::size_t +c_strlen (const char* s) { - return std::strlen (s1); + return std::strlen (s); } -const char* narrow (char* dst, const char* src) +const char* +narrow (char* to, const char* from) { - if (src == dst || !src || !dst) - return src; + if (from == to || !from || !to) + return from; - std::memcpy (dst, src, std::strlen (src) + 1); - return dst; + std::strcpy (to, from); + + return to; } -const char* widen (char* dst, const char* src) +const char* +widen (char* to, const char* from) { - if (src == dst || !src || !dst) - return src; + if (from == to || !from || !to) + return from; - std::memcpy (dst, src, std::strlen (src) + 1); - return dst; + std::strcpy (to, from); + + return to; } #ifndef _RWSTD_NO_WCHAR_T -int c_strcoll (const wchar_t* s1, const wchar_t* s2) +static int +c_strcoll (const wchar_t* s1, const wchar_t* s2) { const int ret = std::wcscoll(s1, s2); - return ret ? ret > 0 ? 1 : -1 : 0; + return ret < 0 ? -1 : !!ret; } -std::size_t c_xfrm (wchar_t* to, const wchar_t* from, std::size_t size) +static std::size_t +c_xfrm (wchar_t* to, const wchar_t* from, std::size_t size) { -#if !defined (_MSC_VER) || _MSC_VER > 1200 - - wchar_t safety_buf [8]; - if (0 == to && 0 == size) { - // prevent buggy implementations (such as MSVC 8) from trying - // to write to the destination buffer even though it's 0 and - // its size is zero (see stdcxx-69) - to = safety_buf; - *to = L'\0'; - } - - std::size_t n = std::wcsxfrm (to, from, size); - - if (to) - n = std::wcslen (to); - -#else // MSVC 6 and prior - - // working around an MSVC 6.0 libc bug (PR #26437) - - if (to) { - std::size_t n = std::wcsxfrm (to, from, size); - - n = std::wcslen (to); - - return n; - } - - wchar_t tmp [1024]; - - std::size_t n = std::wcslen (from); - - _RWSTD_ASSERT (n < sizeof tmp / sizeof *tmp); - - std::wcscpy (tmp, from); - - std::wcsxfrm (tmp, from, sizeof tmp / sizeof *tmp); - - n = std::wcslen (tmp); - -#endif // MSVC 6 - - return n; + return std::wcsxfrm (to, from, size); } -std::size_t c_strlen (const wchar_t* s1) +static std::size_t +c_strlen (const wchar_t* s1) { return std::wcslen (s1); } -const wchar_t* widen (wchar_t* dst, const char* src) +static const wchar_t* +widen (wchar_t* dst, const char* src) { static wchar_t buf [4096]; @@ -188,7 +128,6 @@ const wchar_t* widen (wchar_t* dst, cons dst = buf; std::size_t len = std::strlen (src); - _RWSTD_ASSERT (len < sizeof buf /sizeof *buf); len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf); @@ -199,7 +138,8 @@ const wchar_t* widen (wchar_t* dst, cons return dst; } -const char* narrow (char* dst, const wchar_t* src) +const char* +narrow (char* dst, const wchar_t* src) { static char buf [4096]; @@ -210,7 +150,6 @@ const char* narrow (char* dst, const wch dst = buf; std::size_t len = std::wcslen (src); - _RWSTD_ASSERT (len < sizeof buf); len = std::wcstombs (dst, src, sizeof buf / sizeof *buf); @@ -226,7 +165,7 @@ const char* narrow (char* dst, const wch /**************************************************************************/ template -/*static*/ void +void gen_str (charT* str, std::size_t size) { // generate a random string with the given size @@ -243,8 +182,8 @@ gen_str (charT* str, std::size_t size) /**************************************************************************/ template -/*static*/ void -check_libc (const char* charTname) +void +test_libc (const char* charTname) { // the libc implementation of the library should act the same as // the c-library. Go through all the locales, generate some random @@ -286,6 +225,7 @@ check_libc (const char* charTname) const std::collate &co = _STD_USE_FACET (std::collate, loc); + co._C_opts |= co._C_use_libc; co._C_opts &= ~co._C_use_libstd; @@ -294,8 +234,6 @@ check_libc (const char* charTname) for (int loop_cntrl = 0; loop_cntrl < 10; loop_cntrl++) { -#define STR_SIZE 16 - charT str1 [STR_SIZE] = { 0 }; charT str2 [STR_SIZE] = { 0 }; @@ -405,19 +343,85 @@ check_libc (const char* charTname) /**************************************************************************/ static const char* -make_test_locale () +create_synthetic_locale () { - // create a temporary locale definition file that exercises as - // many different parts of the collate standard as possible - - char lc_collate_src_path [L_tmpnam + sizeof LC_COLLATE_SRC + 2]; - std::strcpy (lc_collate_src_path, locale_root); - std::strcat (lc_collate_src_path, SLASH); - std::strcat (lc_collate_src_path, LC_COLLATE_SRC); + // Create a synthetic locale to exercises as many different parts + // of the collate standard as possible. - std::FILE *fout = std::fopen (lc_collate_src_path, "w"); + static const char charmap [] = { + // + // Portable character set + // + " \"UTF-8\"\n" + " 1\n 1\n" + "CHARMAP\n" + " \\x00\n \\x01\n \\x02\n \\x03\n \\x04\n" + " \\x05\n \\x06\n \\x07\n" + " \\x08\n" + " \\x09\n" + " \\x0a\n" + " \\x0b\n" + " \\x0c\n" + " \\x0d\n" + " \\x0e\n \\x0f\n \\x10\n \\x11\n \\x12\n \\x13\n" + " \\x14\n \\x15\n \\x16\n \\x17\n \\x18\n \\x19\n" + " \\x1a\n \\x1b\n \\x1c\n \\x1d\n \\x1e\n \\x1f\n" + " \\x20\n" + " \\x21\n" + " \\x22\n" + " \\x23\n" + " \\x24\n" + " \\x25\n" + " \\x26\n" + " \\x27\n" + " \\x28\n" + " \\x29\n" + " \\x2a\n" + " \\x2b\n" + " \\x2c\n" + " \\x2d\n" + " \\x2e\n" + " \\x2f\n" + " \\x30\n" + " \\x31\n" + " \\x32\n" + " \\x33\n" + " \\x34\n" + " \\x35\n" + " \\x36\n" + " \\x37\n" + " \\x38\n" + " \\x39\n" + " \\x3a\n" + " \\x3b\n" + " \\x3c\n" + " \\x3d\n" + " \\x3e\n" + " \\x3f\n" + " \\x40\n" + " \\x41\n \\x42\n \\x43\n \\x44\n \\x45\n \\x46\n \\x47\n" + " \\x48\n \\x49\n \\x4a\n \\x4b\n \\x4c\n \\x4d\n \\x4e\n" + " \\x4f\n

\\x70\n \\x71\n \\x72\n \\x73\n \\x74\n \\x75\n" + " \\x76\n \\x77\n \\x78\n \\x79\n \\x7a\n" + " \\x7b\n" + " \\x7c\n" + " \\x7d\n" + " \\x7e\n" + " \\x7f\n" + "END CHARMAP\n\n" + }; - const char lc_collate_file[] = { + static const char lc_collate [] = { "LC_COLLATE\n" "script \n" "collating-element from \"\"\n" @@ -479,145 +483,17 @@ make_test_locale () "\nEND LC_COLLATE\n" }; - std::fputs (lc_collate_file, fout); - - std::fclose (fout); - - // create a temporary character map file - - char lc_collate_cm_path [L_tmpnam + sizeof LC_COLLATE_CM + 2]; - std::strcpy (lc_collate_cm_path, locale_root); - std::strcat (lc_collate_cm_path, SLASH); - std::strcat (lc_collate_cm_path, LC_COLLATE_CM); - - fout = std::fopen (lc_collate_cm_path, "w"); - pcs_write (fout, 0); - - std::fclose (fout); - - return rw_localedef ("-w", lc_collate_src_path, - lc_collate_cm_path, - TEST_LOCALE_NAME); + return rw_create_locale (charmap, lc_collate); } -/**************************************************************************/ - -template -void -test_hash (const char*, const std::collate&, - const char*, const char*); - -template -void -test_string (const char*, const std::collate&, - const char*, const char*, int); - template void -test_weight_val (const char*, const std::collate&, - charT, int, int, int, int, bool); - -template -/*static*/ void -check_libstd_test_locale (const char* charTname) -{ - rw_info (0, __FILE__, __LINE__, - "libstd std::collate<%s>::transform () " - "collate test database", charTname); - rw_info (0, __FILE__, __LINE__, - "libstd std::collate<%s>::compare () collate test " - "database", charTname); - rw_info (0, __FILE__, __LINE__, - "libstd std::collate<%s>::hash () collate test " - "database", charTname); - - const char* const locname = make_test_locale (); - if (locname) { - - std::locale loc; - - _TRY { - loc = std::locale (locname); - } - _CATCH (...) { - const char* const var = std::getenv (LOCALE_ROOT); - - rw_assert (false, __FILE__, __LINE__, - "std::locale(\"%s\") unexpectedly threw " - "an exception; " LOCALE_ROOT "=%s", - locname, var ? var : "(null)"); - return; - } - - const std::collate &co = - _STD_USE_FACET (std::collate, loc); - co._C_opts |= co._C_use_libstd; - co._C_opts &= ~co._C_use_libc; - -#define IGNORE 0 - - // first lets make sure that each character was given the - // correct weight for each level. - -#undef TEST -#define TEST(ch, w0, w1, w2, w3, w3_is_fp) \ - test_weight_val (charTname, co, charT (ch), w0, w1, w2, w3, w3_is_fp) - - TEST ('a', 6, IGNORE, 2, IGNORE, true); - TEST ('b', 5, IGNORE, 2, IGNORE, true); - TEST ('c', 7, IGNORE, 2, 7, true); - TEST ('d', 8, 6, 2, IGNORE, true); - TEST ('e', 139, IGNORE, 2, IGNORE, true); - TEST ('f', 30, IGNORE, 2, IGNORE, true); - TEST ('g', 58, IGNORE, 2, IGNORE, true); - TEST ('h', 12, IGNORE, 12, 12, false); - TEST ('i', 13, IGNORE, 13, 13, false); - TEST ('j', 14, IGNORE, 14, 14, false); - TEST ('k', 15, IGNORE, 15, 15, false); - TEST ('0', 16, IGNORE, 4, IGNORE, true); - TEST ('1', 17, IGNORE, 4, 16, true); - TEST ('2', 18, IGNORE, 4, IGNORE, true); - TEST ('3', 19, IGNORE, 4, IGNORE, true); - TEST ('l', IGNORE, IGNORE, IGNORE, IGNORE, true); - - // make sure that strings collate the way we expect them to - - // a should collate greater then b - test_string (charTname, co, "a", "b", 1) ; - - // the collating element "er" should collate after 'a' and 'b' - // but before 'c' - test_string (charTname, co, "er", "a", 1); - test_string (charTname, co, "er", "b", 1); - test_string (charTname, co, "er", "c", -1); - - // the collating element "ic" should be equivalent to the letter 'c' - test_string (charTname, co, "ic", "c", 0); - - - // two strings that compare identically must hash - // identically as well. - // since ic and c are equivalent elements string they should hash - // the same - test_hash (charTname, co, "c", "ic"); - } - else - rw_assert (false, __FILE__, __LINE__, - "unable to create a locale database"); -} - -/**************************************************************************/ - -enum { bufsiz = 256 }; - -template -/*static*/ void test_hash (const char* charTname, const std::collate& co, const char* str1, const char* str2) { // convert narrow string to a (possibly) wide representation - charT wstrbuf [bufsiz]; - charT wstrbuf2 [bufsiz]; + charT wstrbuf [256]; + charT wstrbuf2 [256]; const charT* const wstr = widen (wstrbuf, str1); const charT* const wstr2 = widen (wstrbuf2, str2); @@ -634,17 +510,15 @@ test_hash (const char* charTname, const } } -/**************************************************************************/ - template -/*static*/ void +void test_string (const char* charTname, const std::collate& co, const char* str1, const char* str2, int expected_val) { // convert narrow string to a (possibly) wide representation - charT wstrbuf [bufsiz]; - charT wstrbuf2 [bufsiz]; + charT wstrbuf [256]; + charT wstrbuf2 [256]; const charT* const wstr = widen (wstrbuf, str1); const charT* const wstr2 = widen (wstrbuf2, str2); @@ -658,10 +532,8 @@ test_string (const char* charTname, cons charTname, str1, str2, expected_val, ret); } -/**************************************************************************/ - template -/*static*/ void +void test_weight_val (const char* charTname, const std::collate& co, charT ch, int w1a, int w1b, int w2, int w3, bool w3_is_fp) { @@ -710,60 +582,30 @@ test_weight_val (const char* charTname, const String actual = co.transform (&ch, &ch + 1); // make sure the strings are equal - rw_assert (expected != actual, __FILE__, __LINE__, + rw_assert (expected == actual, __FILE__, __LINE__, "collate<%s>::transform (\"%c\", ...) == %{S}, " "got %{S}", charTname, ch, &expected, &actual); } -/**************************************************************************/ - template -/*static*/ void -check_libstd (const char* charTname) +void +test_libstd_synthetic_locale (const char* charTname) { rw_info (0, __FILE__, __LINE__, - "libstd std::collate<%s>::transform () sorting " - "file test", charTname); + "libstd std::collate<%s>::transform () " + "collate test database", charTname); rw_info (0, __FILE__, __LINE__, - "libstd std::collate<%s>::compare () sorting " - "file test", charTname); - - - // This test works by using a series of sorted input files - // we randomize the words in the input files and sort them using - // the proper locale's collate facet. This test will automatically - // generate the required locales. - - static const char* const locales[][3] = { - // - // +-- locale name - // | +-- character set - // | | +-- input file name - // | | | - // V V V - { "cs_CZ", "ISO-8859-2", "collate.cs_CZ.in" }, // Czech, Czech Rep. - { "da_DK", "ISO-8859-1", "collate.da_DK.in" }, // Danish, Denmark - { "en_US", "ISO-8859-1", "collate.en_US.in" }, // English, US - { "hr_HR", "ISO-8859-2", "collate.hr_HR.in" }, // Hungarian, Hungary - { "sv_SE", "ISO-8859-1", "collate.sv_SE.in" }, // Swedish, Sweden - { "th_TH", "TIS-620", "collate.th_TH.in" } // Thai, Thailand - }; - - const std::size_t nlocales = sizeof locales / sizeof *locales; - - typedef std::char_traits Traits; - typedef std::allocator Allocator; - typedef std::basic_string String; + "libstd std::collate<%s>::compare () collate test " + "database", charTname); - for (std::size_t i = 0; i < nlocales; ++i) { + rw_info (0, __FILE__, __LINE__, + "libstd std::collate<%s>::hash () collate test " + "database", charTname); - const char* const locname = - rw_localedef ("-w --no_position", - locales [i][0], locales [i][1], 0); + const char* locname = create_synthetic_locale (); if (locname) { - std::locale loc; _TRY { @@ -776,7 +618,7 @@ check_libstd (const char* charTname) "std::locale(\"%s\") unexpectedly threw " "an exception; " LOCALE_ROOT "=%s", locname, var ? var : "(null)"); - continue; + return; } const std::collate &co = @@ -785,143 +627,173 @@ check_libstd (const char* charTname) co._C_opts |= co._C_use_libstd; co._C_opts &= ~co._C_use_libc; - typedef std::codecvt CodeCvt; - - const CodeCvt &cvt = _STD_USE_FACET (CodeCvt, loc); + // first lets make sure that each character was given the + // correct weight for each level. - cvt._C_opts |= cvt._C_use_libstd; - cvt._C_opts &= ~cvt._C_use_libc; +#undef TEST +#define TEST(ch, w0, w1, w2, w3, w3_is_fp) \ + test_weight_val (charTname, co, charT (ch), w0, w1, w2, w3, w3_is_fp) - // 'in' holds the strings from the input file and is there - // sorting will take place. - String in [1000]; + TEST ('a', 6, IGNORE, 2, IGNORE, true); + TEST ('b', 5, IGNORE, 2, IGNORE, true); + TEST ('c', 7, IGNORE, 2, 7, true); + TEST ('d', 8, 6, 2, IGNORE, true); + TEST ('e', 139, IGNORE, 2, IGNORE, true); + TEST ('f', 30, IGNORE, 2, IGNORE, true); + TEST ('g', 58, IGNORE, 2, IGNORE, true); + TEST ('h', 12, IGNORE, 12, 12, false); + TEST ('i', 13, IGNORE, 13, 13, false); + TEST ('j', 14, IGNORE, 14, 14, false); + TEST ('k', 15, IGNORE, 15, 15, false); + TEST ('0', 16, IGNORE, 4, IGNORE, true); + TEST ('1', 17, IGNORE, 4, 16, true); + TEST ('2', 18, IGNORE, 4, IGNORE, true); + TEST ('3', 19, IGNORE, 4, IGNORE, true); + TEST ('l', IGNORE, IGNORE, IGNORE, IGNORE, true); - // out holds the strings located in the output file - String out [1000]; + // make sure that strings collate the way we expect them to -#define TOPDIR "TOPDIR" /* the TOPDIR environment variable */ + // a should collate greater then b + test_string (charTname, co, "a", "b", 1) ; - const char* in_path = std::getenv (TOPDIR); - if (!in_path || !*in_path) { - std::fprintf (stderr, "TOPDIR not defined or empty"); + // the collating element "er" should collate after 'a' and 'b' + // but before 'c' + test_string (charTname, co, "er", "a", 1); + test_string (charTname, co, "er", "b", 1); + test_string (charTname, co, "er", "c", -1); - std::exit (1); - } + // the collating element "ic" should be equivalent to the letter 'c' + test_string (charTname, co, "ic", "c", 0); - std::string path (in_path); - path += SLASH TESTS_ETC_PATH SLASH; - path += locales [i][2]; - std::FILE* const f = std::fopen (path.c_str (), "r"); - if (!f) { + // two strings that compare identically must hash + // identically as well. + // since ic and c are equivalent elements string they should hash + // the same + test_hash (charTname, co, "c", "ic"); + } + else rw_assert (false, __FILE__, __LINE__, - "file \"%s\" could not be opened", path.c_str ()); - break; + "unable to create a locale database"); } - std::size_t j = 0; - while (1) { - char next_line [bufsiz]; - - if (0 != std::fgets (next_line, bufsiz, f)) { +/**************************************************************************/ - std::size_t line_len = std::strlen (next_line); +static void +init_embedded_nul_string (char* buf, size_t& len) +{ + const char s [] = "Hello, world!"; + size_t n = (std::min) (len - 1, sizeof s / sizeof *s - 1); - // get rid of the newline character - next_line [--line_len] = '\0'; + std::memset (buf, 0, len); + std::memcpy (buf, s, n); - // convert from external to internal encoding - // (both of which might be the same type) - charT to [bufsiz]; - const char* from_next; - charT* to_next; + len = n; +} - static std::mbstate_t initial; - std::mbstate_t mbs = initial; +#ifndef _RWSTD_NO_WCHAR_T - const std::codecvt_base::result res = - cvt.in (mbs, - next_line, next_line + line_len + 1, - from_next, - to, to + sizeof to / sizeof *to, - to_next); +static void +init_embedded_nul_string (wchar_t* buf, size_t& len) +{ + const wchar_t s [] = L"Hello, world!"; + size_t n = (std::min) (len - 1, sizeof s / sizeof *s - 1); - if (cvt.ok == res) { - in [j] = to; - out [j] = to; - } - else if (cvt.noconv == res) { - in [j] = (charT*)next_line; - out [j] = (charT*)next_line; - } + std::memset (buf, 0, len * sizeof *s); + std::memcpy (buf, s, n * sizeof *s); - j++; - } - else - break; + len = n; } - // close the file - std::fclose (f); - // now bubble sort the items in the array - std::size_t idx; - std::size_t idx2; - String tmp; - String tmp2; +#endif // _RWSTD_NO_WCHAR_T - bool flipped; +template +void +do_test_embedded_nul (const char* charTname, const char* locname) +{ + std::locale loc (locname); - if (j > 1) { - idx = 1; - do { - flipped = false; - for (idx2 = j - 1; idx2 >= idx; --idx2) { + charT buf [2][STR_SIZE]; + memset (buf, 0, sizeof buf); - const std::size_t idx1 = idx2 - 1; + size_t len = STR_SIZE; - if (co.compare (in [idx1].c_str (), - in [idx1].c_str () + in [idx1].size (), - in [idx2].c_str (), - in [idx2].c_str () + in [idx2].size ()) - > 0) { - in [idx1].swap (in [idx2]); - flipped = true; - } - } - } while (++idx < j && flipped); - } + init_embedded_nul_string (buf [0], len); + init_embedded_nul_string (buf [1], len); - // the items are sorted now lets make sure that they are sorted - // the same way they are sorted in the output file. - std::size_t nfail = 0; - - for (std::size_t k = 0; k < j; ++k) { + // + // Verify that first buffer compares more: + // |--------0----| = buf [0] + // |----0--------| = buf [1] + // + buf [0][4] = charT (); + buf [1][3] = charT (); - if (in [k] != out [k]) { + typedef std::collate Collate; - nfail++; + const Collate &col = std::use_facet (loc); + int cmp = col.compare (buf [0], buf [0] + len, buf [1], buf [1] + len); + if (cmp <= 0) { rw_assert (false, __FILE__, __LINE__, - "%{S} != %{S} at line %u of %s", - &out [k], &in [k], - k + 1, locales [i][2]); + "collate<%s>::compare (%{*.*Ac}, %{*.*Ac}) " + " > 0, failed in locale (\"%s\")", charTname, + sizeof (charT), sizeof buf [0] / sizeof *buf [0], buf [0], + sizeof (charT), sizeof buf [0] / sizeof *buf [0], buf [1], + locname); + } + init_embedded_nul_string (buf [0], len); + init_embedded_nul_string (buf [1], len); + + // + // Verify that first compare less: + // |----0---0----| = buf [0] + // |----0--------| = buf [1] + // + buf [0][3] = charT (); + buf [0][5] = charT (); + buf [1][3] = charT (); + + cmp = col.compare (buf [0], buf [0] + len, buf [1], buf [1] + len); + + if (cmp >= 0) { + rw_assert (false, __FILE__, __LINE__, + "collate<%s>::compare (%{*.*Ac}, ..., %{*.*Ac}, ...) " + " < 0, failed in locale (\"%s\")", charTname, + sizeof (charT), sizeof buf [0] / sizeof *buf [0], buf [0], + sizeof (charT), sizeof buf [0] / sizeof *buf [0], buf [1], + locname); } } - rw_assert (!nfail, __FILE__, __LINE__, - "collate<%s>::compare() failed %d times", - charTname, nfail); +template +void +test_embedded_nul (const char* charTname) +{ + // Verify that the collate facet correctly handles character + // sequences with embedded NULs. + + rw_info (0, __FILE__, __LINE__, + "std::collate<%s>::compare () with embedded NUL's", charTname); + + const char* locname = rw_locales (LC_COLLATE); + + for (; *locname; locname += std::strlen (locname) + 1) { + try { + do_test_embedded_nul (charTname, locname); + } + catch (...) { + continue; } } } /**************************************************************************/ - template -/*static*/ void -check_hash_eff (const char* charTname) +void +test_hash_collisions (const char* charTname) { // test effectiveness of hash function rw_info (0, __FILE__, __LINE__, @@ -930,10 +802,10 @@ check_hash_eff (const char* charTname) // since the same hash algorithm is used for both byname and non-byname // facets, simply set up a std::locale that uses the "C" locale std::locale loc ("C"); + const std::collate &co = _STD_USE_FACET (std::collate, loc); - int nfail = 0; charT s[100]; @@ -976,147 +848,25 @@ check_hash_eff (const char* charTname) /**************************************************************************/ - -template -/*static*/ void -check_NUL (const char* charTname) -{ - rw_info (0, __FILE__, __LINE__, - "std::collate<%s>::compare() with embedded NULs", charTname); - - // verify that the collate facet correctly handles - // character sequences with embedded NULs - - charT buf_1 [STR_SIZE]; - charT buf_2 [STR_SIZE]; - - bool fail = false; - - unsigned i = 0; - - for (const char* locname = rw_locales (LC_COLLATE); - *locname && !fail; locname += std::strlen (locname) + 1, ++i) { - - std::locale loc; - - _TRY { - loc = std::locale (locname); - } - _CATCH (...) { - continue; - } - - const std::size_t buflen = sizeof buf_1 / sizeof *buf_1 - 1; - - gen_str (buf_1, sizeof buf_1 / sizeof *buf_1); - std::memcpy (buf_2, buf_1, sizeof buf_2); - - // compute a random index into the character buffers - // at which to set the element to NUL; the indices - // are such that (inx_1 > inx_2) always holds - const std::size_t inx_2 = std::rand () % (buflen - 1); - const std::size_t inx_1 = - inx_2 + 1 + std::rand () % (buflen - inx_2 - 1); - - buf_2 [inx_2] = charT (); - - typedef std::collate CollateT; - - const CollateT &col = std::use_facet(loc); - - int cmp = col.compare (buf_1, buf_1 + buflen, buf_2, buf_2 + buflen); - - if (!cmp) { - typedef typename CollateT::string_type StringT; - - const StringT str_1 (buf_1, buflen); - const StringT str_2 (buf_2, buflen); - - fail = true; - - rw_assert (false, __FILE__, __LINE__, - "collate<%s>::compare(%{S}, ..., %{S}, ...) " - "!= 0, got 0 in locale(\"%s\")", charTname, - &str_1, &str_2, locname); - } - - // set the character at the smaller index in both buffers to - // NUL, then set a character at the larger index in the first - // buffer to NUL, compare the two, and verify that the buffers - // compare unequal (buf_1 probably less) - buf_1 [inx_1] = charT (); - buf_1 [inx_2] = charT (); - - cmp = col.compare (buf_1, buf_1 + buflen, buf_2, buf_2 + buflen); - - if (!cmp) { - typedef typename CollateT::string_type StringT; - - const StringT str_1 (buf_1, buflen); - const StringT str_2 (buf_2, buflen); - - fail = true; - - rw_assert (false, __FILE__, __LINE__, - "collate<%s>::compare(%{S}, ..., %{S}, ...) " - "!= 0, got 0 in locale(\"%s\")", charTname, - &str_1, &str_2, locname); - } - } -} - -/**************************************************************************/ - template -/*static*/ void -do_test (const char* charTname) +void +test (const char* charTname) { - check_libstd_test_locale (charTname); - check_libstd (charTname); - check_libc (charTname); - check_NUL (charTname); - check_hash_eff (charTname); + test_libstd_synthetic_locale (charTname); + test_libc (charTname); + test_embedded_nul (charTname); + test_hash_collisions (charTname); } - -#if _RWSTD_PATH_SEP == '/' -# define RM_RF "rm -rf " -#else -# define RM_RF "rmdir /Q /S " -#endif // _RWSTD_PATH_SEP == '/' - - static int -run_test (int /*argc*/, char* /*argv*/ []) +run_test (int, char**) { - // set any additional environment variables defined in - // the RW_PUTENV environment variable (if it exists) - rw_putenv (0); - - // create a temporary directory for files created by the test - char namebuf [L_tmpnam]; - locale_root = std::tmpnam (namebuf); - - char envvar [sizeof LOCALE_ROOT + L_tmpnam] = LOCALE_ROOT "="; - std::strcat (envvar, locale_root); - - rw_system ("mkdir %s", locale_root); - - // set the LOCALE_ROOT variable where std::locale looks - // for locale database files - rw_putenv (envvar); - - do_test ("char"); + test ("char"); #ifndef _RWSTD_NO_WCHAR_T - - do_test ("wchar_t"); - + test ("wchar_t"); #endif // _RWSTD_NO_WCHAR_T - // remove temporary locale databases created by the test - rw_system (RM_RF "%s", locale_root); - return 0; }

\\x50\n \\x51\n \\x52\n \\x53\n \\x54\n \\x55\n" + " \\x56\n \\x57\n \\x58\n \\x59\n \\x5a\n" + " \\x5b\n" + " \\x5c\n" + " \\x5d\n" + " \\x5e\n" + " \\x5f\n" + " \\x60\n" + " \\x61\n \\x62\n \\x63\n \\x64\n \\x65\n \\x66\n \\x67\n" + " \\x68\n \\x69\n \\x6a\n \\x6b\n \\x6c\n \\x6d\n \\x6e\n" + " \\x6f\n