[libcxx] [test] Fix get/put long_double_ru_RU on Glibc, FreeBSD and Windows

Note, reducing ios.width() in put_long_double instead of using variable
padding, when using a variable width symbol. Some of those tests didn't
actually trigger any padding in the existing form, with a longer
currency symbol; reduce the width so there's no actual padding with the
slightly shorter currency symbol either.

The tests for the international currency symbol use the same amount of
padding on all platforms, so they still exercise the padding properly.

Differential Revision: https://reviews.llvm.org/D120317
This commit is contained in:
Martin Storsjö 2022-02-22 13:23:53 +02:00
parent 47f4cd9c3d
commit df1e43c496
6 changed files with 170 additions and 157 deletions

View File

@ -28,6 +28,7 @@
#include <cassert>
#include "test_iterators.h"
#include "locale_helpers.h"
#include "platform_support.h" // locale name macros
#include "test_macros.h"
@ -52,36 +53,8 @@ public:
: Fw(refs) {}
};
// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator.
// This function converts the spaces in string inputs to U+202F if need
// be. FreeBSD's locale data also uses U+202F, since 2018.
// Windows uses U+00A0 NO-BREAK SPACE.
static std::wstring convert_thousands_sep(std::wstring const& in) {
#if defined(_CS_GNU_LIBC_VERSION) || defined(__FreeBSD__) || defined(_WIN32)
#if defined(_CS_GNU_LIBC_VERSION)
if (glibc_version_less_than("2.27"))
return in;
#endif
std::wstring out;
unsigned I = 0;
bool seen_decimal = false;
for (; I < in.size(); ++I) {
if (seen_decimal || in[I] != L' ') {
seen_decimal |= in[I] == L',';
out.push_back(in[I]);
continue;
}
assert(in[I] == L' ');
#if defined(_WIN32)
out.push_back(L'\u00A0');
#else
out.push_back(L'\u202F');
#endif
}
return out;
#else
return in;
#endif
return LocaleHelpers::convert_thousands_sep_fr_FR(in);
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS

View File

@ -9,14 +9,6 @@
// NetBSD does not support LC_MONETARY at the moment
// XFAIL: netbsd
// Failure related to GLIBC's use of U00A0 as mon_thousands_sep
// and U002E as mon_decimal_point.
// TODO: U00A0 should be investigated.
// Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006
// XFAIL: linux
// XFAIL: LIBCXX-WINDOWS-FIXME
// REQUIRES: locale.ru_RU.UTF-8
// <locale>
@ -33,6 +25,7 @@
#include "test_macros.h"
#include "test_iterators.h"
#include "locale_helpers.h"
#include "platform_support.h" // locale name macros
typedef std::money_get<char, cpp17_input_iterator<const char*> > Fn;
@ -55,7 +48,11 @@ public:
explicit my_facetw(std::size_t refs = 0)
: Fw(refs) {}
};
#endif
static std::wstring convert_thousands_sep(std::wstring const& in) {
return LocaleHelpers::convert_thousands_sep_ru_RU(in);
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS
int main(int, char**)
{
@ -71,6 +68,7 @@ int main(int, char**)
ios.imbue(std::locale(ios.getloc(),
new std::moneypunct_byname<wchar_t, true>(loc_name)));
#endif
std::string symbol(LocaleHelpers::currency_symbol_ru_RU());
{
const my_facet f(1);
// char, national
@ -130,7 +128,7 @@ int main(int, char**)
assert(ex == -123456789);
}
{ // zero, showbase
std::string v = "0,00 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "0,00 " + symbol;
typedef cpp17_input_iterator<const char*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -141,7 +139,7 @@ int main(int, char**)
assert(ex == 0);
}
{ // zero, showbase
std::string v = "0,00 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "0,00 " + symbol;
std::showbase(ios);
typedef cpp17_input_iterator<const char*> I;
long double ex;
@ -154,7 +152,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative one, showbase
std::string v = "-0,01 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "-0,01 " + symbol;
typedef cpp17_input_iterator<const char*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -165,7 +163,7 @@ int main(int, char**)
assert(ex == -1);
}
{ // negative one, showbase
std::string v = "-0,01 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "-0,01 " + symbol;
std::showbase(ios);
typedef cpp17_input_iterator<const char*> I;
long double ex;
@ -178,7 +176,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // positive, showbase
std::string v = "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "1 234 567,89 " + symbol;
typedef cpp17_input_iterator<const char*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -189,7 +187,7 @@ int main(int, char**)
assert(ex == 123456789);
}
{ // positive, showbase
std::string v = "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "1 234 567,89 " + symbol;
std::showbase(ios);
typedef cpp17_input_iterator<const char*> I;
long double ex;
@ -202,7 +200,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "-1 234 567,89 " + symbol;
std::showbase(ios);
typedef cpp17_input_iterator<const char*> I;
long double ex;
@ -382,7 +380,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "-1 234 567,89 " + symbol;
std::showbase(ios);
typedef cpp17_input_iterator<const char*> I;
long double ex;
@ -394,7 +392,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".";
std::string v = "-1 234 567,89 " + symbol;
typedef cpp17_input_iterator<const char*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -406,6 +404,7 @@ int main(int, char**)
}
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
std::wstring wsymbol(LocaleHelpers::currency_symbol_ru_RU());
{
const my_facetw f(1);
// wchar_t, national
@ -432,7 +431,7 @@ int main(int, char**)
assert(ex == -1);
}
{ // positive
std::wstring v = L"1 234 567,89 ";
std::wstring v = convert_thousands_sep(L"1 234 567,89 ");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -443,7 +442,7 @@ int main(int, char**)
assert(ex == 123456789);
}
{ // negative
std::wstring v = L"-1 234 567,89 ";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 ");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -465,7 +464,7 @@ int main(int, char**)
assert(ex == -123456789);
}
{ // zero, showbase
std::wstring v = L"0,00 \x440\x443\x431"".";
std::wstring v = L"0,00 " + wsymbol;
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -476,7 +475,7 @@ int main(int, char**)
assert(ex == 0);
}
{ // zero, showbase
std::wstring v = L"0,00 \x440\x443\x431"".";
std::wstring v = L"0,00 " + wsymbol;
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -489,7 +488,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative one, showbase
std::wstring v = L"-0,01 \x440\x443\x431"".";
std::wstring v = L"-0,01 " + wsymbol;
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -500,7 +499,7 @@ int main(int, char**)
assert(ex == -1);
}
{ // negative one, showbase
std::wstring v = L"-0,01 \x440\x443\x431"".";
std::wstring v = L"-0,01 " + wsymbol;
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -513,7 +512,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // positive, showbase
std::wstring v = L"1 234 567,89 \x440\x443\x431"".";
std::wstring v = convert_thousands_sep(L"1 234 567,89 ") + wsymbol;
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -524,7 +523,7 @@ int main(int, char**)
assert(ex == 123456789);
}
{ // positive, showbase
std::wstring v = L"1 234 567,89 \x440\x443\x431"".";
std::wstring v = convert_thousands_sep(L"1 234 567,89 ") + wsymbol;
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -537,7 +536,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 \x440\x443\x431"".";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol;
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -550,7 +549,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 RUB";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB");
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -562,7 +561,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 RUB";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -599,7 +598,7 @@ int main(int, char**)
assert(ex == -1);
}
{ // positive
std::wstring v = L"1 234 567,89 ";
std::wstring v = convert_thousands_sep(L"1 234 567,89 ");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -610,7 +609,7 @@ int main(int, char**)
assert(ex == 123456789);
}
{ // negative
std::wstring v = L"-1 234 567,89 ";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 ");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -680,7 +679,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // positive, showbase
std::wstring v = L"1 234 567,89 RUB";
std::wstring v = convert_thousands_sep(L"1 234 567,89 RUB");
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;
@ -691,7 +690,7 @@ int main(int, char**)
assert(ex == 123456789);
}
{ // positive, showbase
std::wstring v = L"1 234 567,89 RUB";
std::wstring v = convert_thousands_sep(L"1 234 567,89 RUB");
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -704,7 +703,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 RUB";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB");
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -717,7 +716,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 \x440\x443\x431"".";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol;
std::showbase(ios);
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
@ -729,7 +728,7 @@ int main(int, char**)
std::noshowbase(ios);
}
{ // negative, showbase
std::wstring v = L"-1 234 567,89 \x440\x443\x431"".";
std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol;
typedef cpp17_input_iterator<const wchar_t*> I;
long double ex;
std::ios_base::iostate err = std::ios_base::goodbit;

View File

@ -28,6 +28,7 @@
#include <cassert>
#include "test_iterators.h"
#include "locale_helpers.h"
#include "platform_support.h" // locale name macros
#include "test_macros.h"
@ -52,38 +53,8 @@ public:
: Fw(refs) {}
};
// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator.
// This function converts the spaces in string inputs to U+202F if need
// be. FreeBSD's locale data also uses U+202F, since 2018.
// Windows uses U+00A0 NO-BREAK SPACE.
static std::wstring convert_thousands_sep(std::wstring const& in) {
#if defined(_CS_GNU_LIBC_VERSION) || defined(__FreeBSD__) || defined(_WIN32)
#if defined(_CS_GNU_LIBC_VERSION)
if (glibc_version_less_than("2.27"))
return in;
#endif
std::wstring out;
unsigned I = 0;
bool seen_num_start = false;
bool seen_decimal = false;
for (; I < in.size(); ++I) {
seen_decimal |= in[I] == L',';
seen_num_start |= in[I] == '-' || std::iswdigit(in[I]);
if (seen_decimal || !seen_num_start || in[I] != L' ') {
out.push_back(in[I]);
continue;
}
assert(in[I] == L' ');
#if defined(_WIN32)
out.push_back(L'\u00A0');
#else
out.push_back(L'\u202F');
#endif
}
return out;
#else
return in;
#endif
return LocaleHelpers::convert_thousands_sep_fr_FR(in);
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS

View File

@ -9,14 +9,6 @@
// NetBSD does not support LC_MONETARY at the moment
// XFAIL: netbsd
// Failure related to GLIBC's use of U00A0 as mon_thousands_sep
// and U002E as mon_decimal_point.
// TODO: U00A0 should be investigated.
// Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006
// XFAIL: linux
// XFAIL: LIBCXX-WINDOWS-FIXME
// REQUIRES: locale.ru_RU.UTF-8
// <locale>
@ -33,6 +25,7 @@
#include "test_macros.h"
#include "test_iterators.h"
#include "locale_helpers.h"
#include "platform_support.h" // locale name macros
typedef std::money_put<char, cpp17_output_iterator<char*> > Fn;
@ -55,7 +48,11 @@ public:
explicit my_facetw(std::size_t refs = 0)
: Fw(refs) {}
};
#endif
static std::wstring convert_thousands_sep(std::wstring const& in) {
return LocaleHelpers::convert_thousands_sep_ru_RU(in);
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS
int main(int, char**)
{
@ -72,6 +69,7 @@ int main(int, char**)
new std::moneypunct_byname<wchar_t, true>(loc_name)));
#endif
{
std::string symbol(LocaleHelpers::currency_symbol_ru_RU());
const my_facet f(1);
// char, national
{ // zero
@ -108,7 +106,7 @@ int main(int, char**)
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, '*', v);
std::string ex(str, iter.base());
assert(ex == "0,00 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "0,00 " + symbol);
}
{ // negative one, showbase
long double v = -1;
@ -116,7 +114,7 @@ int main(int, char**)
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, '*', v);
std::string ex(str, iter.base());
assert(ex == "-0,01 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "-0,01 " + symbol);
}
{ // positive, showbase
long double v = 123456789;
@ -124,7 +122,7 @@ int main(int, char**)
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, '*', v);
std::string ex(str, iter.base());
assert(ex == "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "1 234 567,89 " + symbol);
}
{ // negative, showbase
long double v = -123456789;
@ -132,39 +130,39 @@ int main(int, char**)
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, '*', v);
std::string ex(str, iter.base());
assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "-1 234 567,89 " + symbol);
}
{ // negative, showbase, left
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::left(ios);
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, ' ', v);
std::string ex(str, iter.base());
assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "-1 234 567,89 " + symbol);
assert(ios.width() == 0);
}
{ // negative, showbase, internal
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::internal(ios);
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, ' ', v);
std::string ex(str, iter.base());
assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "-1 234 567,89 " + symbol);
assert(ios.width() == 0);
}
{ // negative, showbase, right
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::right(ios);
char str[100];
cpp17_output_iterator<char*> iter = f.put(cpp17_output_iterator<char*>(str), false, ios, ' ', v);
std::string ex(str, iter.base());
assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1"".");
assert(ex == "-1 234 567,89 " + symbol);
assert(ios.width() == 0);
}
@ -267,6 +265,7 @@ int main(int, char**)
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
std::wstring symbol(LocaleHelpers::currency_symbol_ru_RU());
const my_facetw f(1);
// wchar_t, national
std::noshowbase(ios);
@ -290,14 +289,14 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"1 234 567,89");
assert(ex == convert_thousands_sep(L"1 234 567,89"));
}
{ // negative
long double v = -123456789;
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89");
assert(ex == convert_thousands_sep(L"-1 234 567,89"));
}
{ // zero, showbase
long double v = 0;
@ -305,7 +304,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"0,00 \x440\x443\x431"".");
assert(ex == L"0,00 " + symbol);
}
{ // negative one, showbase
long double v = -1;
@ -313,7 +312,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"-0,01 \x440\x443\x431"".");
assert(ex == L"-0,01 " + symbol);
}
{ // positive, showbase
long double v = 123456789;
@ -321,7 +320,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"1 234 567,89 \x440\x443\x431"".");
assert(ex == convert_thousands_sep(L"1 234 567,89 ") + symbol);
}
{ // negative, showbase
long double v = -123456789;
@ -329,39 +328,39 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 \x440\x443\x431"".");
assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol);
}
{ // negative, showbase, left
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::left(ios);
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 \x440\x443\x431"". ");
assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol);
assert(ios.width() == 0);
}
{ // negative, showbase, internal
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::internal(ios);
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 \x440\x443\x431"".");
assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol);
assert(ios.width() == 0);
}
{ // negative, showbase, right
long double v = -123456789;
std::showbase(ios);
ios.width(20);
ios.width(15);
std::right(ios);
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), false, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L" -1 234 567,89 \x440\x443\x431"".");
assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol);
assert(ios.width() == 0);
}
@ -387,14 +386,14 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"1 234 567,89");
assert(ex == convert_thousands_sep(L"1 234 567,89"));
}
{ // negative
long double v = -123456789;
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89");
assert(ex == convert_thousands_sep(L"-1 234 567,89"));
}
{ // zero, showbase
long double v = 0;
@ -418,7 +417,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"1 234 567,89 RUB");
assert(ex == convert_thousands_sep(L"1 234 567,89 RUB"));
}
{ // negative, showbase
long double v = -123456789;
@ -426,7 +425,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, '*', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 RUB");
assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB"));
}
{ // negative, showbase, left
long double v = -123456789;
@ -436,7 +435,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 RUB ");
assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB "));
assert(ios.width() == 0);
}
{ // negative, showbase, internal
@ -447,7 +446,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L"-1 234 567,89 RUB");
assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB"));
assert(ios.width() == 0);
}
{ // negative, showbase, right
@ -458,7 +457,7 @@ int main(int, char**)
wchar_t str[100];
cpp17_output_iterator<wchar_t*> iter = f.put(cpp17_output_iterator<wchar_t*>(str), true, ios, ' ', v);
std::wstring ex(str, iter.base());
assert(ex == L" -1 234 567,89 RUB");
assert(ex == convert_thousands_sep(L" -1 234 567,89 RUB"));
assert(ios.width() == 0);
}
}

View File

@ -25,6 +25,7 @@
#include <cassert>
#include "test_macros.h"
#include "locale_helpers.h"
#include "platform_support.h" // locale name macros
class Fnf
@ -140,19 +141,7 @@ int main(int, char**)
{
Fnf f(LOCALE_ru_RU_UTF_8, 1);
#if defined(_CS_GNU_LIBC_VERSION)
// GLIBC <= 2.23 uses currency_symbol="<U0440><U0443><U0431>"
// GLIBC >= 2.24 uses currency_symbol="<U20BD>"
// See also: http://www.fileformat.info/info/unicode/char/20bd/index.htm
if (!glibc_version_less_than("2.24"))
assert(f.curr_symbol() == " \xE2\x82\xBD"); // \u20BD
else
assert(f.curr_symbol() == " \xD1\x80\xD1\x83\xD0\xB1"); // \u0440\u0443\u0431
#elif defined(_WIN32) || defined(__FreeBSD__)
assert(f.curr_symbol() == " \xE2\x82\xBD"); // \u20BD
#else
assert(f.curr_symbol() == " \xD1\x80\xD1\x83\xD0\xB1."); // \u0440\u0443\u0431.
#endif
assert(f.curr_symbol() == " " + static_cast<std::string>(LocaleHelpers::currency_symbol_ru_RU()));
}
{
Fnt f(LOCALE_ru_RU_UTF_8, 1);
@ -161,16 +150,7 @@ int main(int, char**)
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
Fwf f(LOCALE_ru_RU_UTF_8, 1);
#if defined(_CS_GNU_LIBC_VERSION)
if (!glibc_version_less_than("2.24"))
assert(f.curr_symbol() == L" \u20BD");
else
assert(f.curr_symbol() == L" \u0440\u0443\u0431");
#elif defined(_WIN32) || defined(__FreeBSD__)
assert(f.curr_symbol() == L" \u20BD");
#else
assert(f.curr_symbol() == L" \u0440\u0443\u0431.");
#endif
assert(f.curr_symbol() == L" " + static_cast<std::wstring>(LocaleHelpers::currency_symbol_ru_RU()));
}
{

View File

@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H
#define LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H
#include <string>
#include "platform_support.h"
#include "test_macros.h"
#include "make_string.h"
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
#include <cwctype>
#endif // TEST_HAS_NO_WIDE_CHARACTERS
namespace LocaleHelpers {
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
std::wstring convert_thousands_sep(std::wstring const& in, wchar_t sep) {
std::wstring out;
bool seen_num_start = false;
bool seen_decimal = false;
for (unsigned i = 0; i < in.size(); ++i) {
seen_decimal |= in[i] == L',';
seen_num_start |= in[i] == L'-' || std::iswdigit(in[i]);
if (seen_decimal || !seen_num_start || in[i] != L' ') {
out.push_back(in[i]);
continue;
}
assert(in[i] == L' ');
out.push_back(sep);
}
return out;
}
// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator.
// This function converts the spaces in string inputs to U+202F if need
// be. FreeBSD's locale data also uses U+202F, since 2018.
// Windows uses U+00A0 NO-BREAK SPACE.
std::wstring convert_thousands_sep_fr_FR(std::wstring const& in) {
#if defined(_CS_GNU_LIBC_VERSION)
if (glibc_version_less_than("2.27"))
return in;
else
return convert_thousands_sep(in, L'\u202F');
#elif defined(__FreeBSD__)
return convert_thousands_sep(in, L'\u202F');
#elif defined(_WIN32)
return convert_thousands_sep(in, L'\u00A0');
#else
return in;
#endif
}
// GLIBC 2.27 uses U+202F NARROW NO-BREAK SPACE as a thousands separator.
// FreeBSD and Windows use U+00A0 NO-BREAK SPACE.
std::wstring convert_thousands_sep_ru_RU(std::wstring const& in) {
#if defined(TEST_HAS_GLIBC)
return convert_thousands_sep(in, L'\u202F');
#elif defined(__FreeBSD__) || defined(_WIN32)
return convert_thousands_sep(in, L'\u00A0');
#else
return in;
#endif
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS
MultiStringType currency_symbol_ru_RU() {
#if defined(_CS_GNU_LIBC_VERSION)
if (glibc_version_less_than("2.24"))
return MKSTR("\u0440\u0443\u0431");
else
return MKSTR("\u20BD"); // U+20BD RUBLE SIGN
#elif defined(_WIN32) || defined(__FreeBSD__)
return MKSTR("\u20BD"); // U+20BD RUBLE SIGN
#else
return MKSTR("\u0440\u0443\u0431.");
#endif
}
} // namespace LocaleHelpers
#endif // LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H