Skip to content

Commit ea03aea

Browse files
fr_FR windows test fixes
1 parent 6a6f9bf commit ea03aea

File tree

10 files changed

+133
-86
lines changed

10 files changed

+133
-86
lines changed

libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_fr_FR.pass.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
// REQUIRES: locale.fr_FR.UTF-8
1717

18+
// ADDITIONAL_COMPILE_FLAGS: -DFR_MON_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_MON_THOUSANDS_SEP}
19+
1820
// <locale>
1921

2022
// class money_get<charT, InputIterator>
@@ -54,7 +56,8 @@ class my_facetw
5456
};
5557

5658
static std::wstring convert_thousands_sep(std::wstring const& in) {
57-
return LocaleHelpers::convert_thousands_sep_fr_FR(in);
59+
const wchar_t fr_sep = LocaleHelpers::mon_thousands_sep_or_default(FR_MON_THOU_SEP);
60+
return LocaleHelpers::convert_thousands_sep(in, fr_sep);
5861
}
5962
#endif // TEST_HAS_NO_WIDE_CHARACTERS
6063

libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
// REQUIRES: locale.ru_RU.UTF-8
1313

14+
// ADDITIONAL_COMPILE_FLAGS: -DRU_MON_THOU_SEP=%{LOCALE_CONV_RU_RU_UTF_8_MON_THOUSANDS_SEP}
15+
1416
// XFAIL: glibc-old-ru_RU-decimal-point
1517

1618
// <locale>
@@ -52,7 +54,8 @@ class my_facetw
5254
};
5355

5456
static std::wstring convert_thousands_sep(std::wstring const& in) {
55-
return LocaleHelpers::convert_thousands_sep_ru_RU(in);
57+
const wchar_t ru_sep = LocaleHelpers::mon_thousands_sep_or_default(RU_MON_THOU_SEP);
58+
return LocaleHelpers::convert_thousands_sep(in, ru_sep);
5659
}
5760
#endif // TEST_HAS_NO_WIDE_CHARACTERS
5861

libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_fr_FR.pass.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
// REQUIRES: locale.fr_FR.UTF-8
1717

18+
// ADDITIONAL_COMPILE_FLAGS: -DFR_MON_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_MON_THOUSANDS_SEP}
19+
1820
// <locale>
1921

2022
// class money_put<charT, OutputIterator>
@@ -54,7 +56,8 @@ class my_facetw
5456
};
5557

5658
static std::wstring convert_thousands_sep(std::wstring const& in) {
57-
return LocaleHelpers::convert_thousands_sep_fr_FR(in);
59+
const wchar_t fr_sep = LocaleHelpers::mon_thousands_sep_or_default(FR_MON_THOU_SEP);
60+
return LocaleHelpers::convert_thousands_sep(in, fr_sep);
5861
}
5962
#endif // TEST_HAS_NO_WIDE_CHARACTERS
6063

libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
// REQUIRES: locale.ru_RU.UTF-8
1313

14+
// ADDITIONAL_COMPILE_FLAGS: -DRU_MON_THOU_SEP=%{LOCALE_CONV_RU_RU_UTF_8_MON_THOUSANDS_SEP}
15+
1416
// XFAIL: glibc-old-ru_RU-decimal-point
1517

1618
// <locale>
@@ -52,7 +54,8 @@ class my_facetw
5254
};
5355

5456
static std::wstring convert_thousands_sep(std::wstring const& in) {
55-
return LocaleHelpers::convert_thousands_sep_ru_RU(in);
57+
const wchar_t ru_sep = LocaleHelpers::mon_thousands_sep_or_default(RU_MON_THOU_SEP);
58+
return LocaleHelpers::convert_thousands_sep(in, ru_sep);
5659
}
5760
#endif // TEST_HAS_NO_WIDE_CHARACTERS
5861

libcxx/test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
// REQUIRES: locale.ru_RU.UTF-8
1717
// REQUIRES: locale.zh_CN.UTF-8
1818

19+
// ADDITIONAL_COMPILE_FLAGS: -DFR_MON_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_MON_THOUSANDS_SEP}
20+
// ADDITIONAL_COMPILE_FLAGS: -DRU_MON_THOU_SEP=%{LOCALE_CONV_RU_RU_UTF_8_MON_THOUSANDS_SEP}
21+
1922
// <locale>
2023

2124
// class moneypunct_byname<charT, International>
@@ -27,6 +30,7 @@
2730
#include <cassert>
2831

2932
#include "test_macros.h"
33+
#include "locale_helpers.h"
3034
#include "platform_support.h" // locale name macros
3135

3236
class Fnf
@@ -110,17 +114,10 @@ int main(int, char**)
110114
Fnt f(LOCALE_fr_FR_UTF_8, 1);
111115
assert(f.thousands_sep() == ' ');
112116
}
113-
// The below tests work around GLIBC's use of U202F as mon_thousands_sep.
117+
114118
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
115-
#if defined(_CS_GNU_LIBC_VERSION)
116-
const wchar_t fr_sep = glibc_version_less_than("2.27") ? L' ' : L'\u202F';
117-
#elif defined(_WIN32)
118-
const wchar_t fr_sep = L'\u00A0';
119-
#elif defined(_AIX)
120-
const wchar_t fr_sep = L'\u202F';
121-
#else
122-
const wchar_t fr_sep = L' ';
123-
#endif
119+
const wchar_t fr_sep = LocaleHelpers::mon_thousands_sep_or_default(FR_MON_THOU_SEP);
120+
124121
{
125122
Fwf f(LOCALE_fr_FR_UTF_8, 1);
126123
assert(f.thousands_sep() == fr_sep);
@@ -140,19 +137,8 @@ int main(int, char**)
140137
assert(f.thousands_sep() == sep);
141138
}
142139
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
143-
// The below tests work around GLIBC's use of U00A0 as mon_thousands_sep
144-
// and U002E as mon_decimal_point.
145-
// TODO: Fix thousands_sep for 'char'.
146-
// related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006
147-
# if defined(_CS_GNU_LIBC_VERSION)
148-
// FIXME libc++ specifically works around \u00A0 by translating it into
149-
// a regular space.
150-
const wchar_t wsep = glibc_version_less_than("2.27") ? L'\u00A0' : L'\u202F';
151-
# elif defined(_WIN32) || defined(_AIX)
152-
const wchar_t wsep = L'\u00A0';
153-
# else
154-
const wchar_t wsep = L' ';
155-
# endif
140+
const wchar_t wsep = LocaleHelpers::mon_thousands_sep_or_default(RU_MON_THOU_SEP);
141+
156142
{
157143
Fwf f(LOCALE_ru_RU_UTF_8, 1);
158144
assert(f.thousands_sep() == wsep);

libcxx/test/std/localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
// REQUIRES: locale.en_US.UTF-8
1616
// REQUIRES: locale.fr_FR.UTF-8
1717

18+
// ADDITIONAL_COMPILE_FLAGS: -DFR_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_THOUSANDS_SEP}
19+
1820
// <locale>
1921

2022
// template <class charT> class numpunct_byname;
@@ -26,6 +28,7 @@
2628
#include <cassert>
2729

2830
#include "test_macros.h"
31+
#include "locale_helpers.h"
2932
#include "platform_support.h" // locale name macros
3033

3134
int main(int, char**)
@@ -75,16 +78,11 @@ int main(int, char**)
7578
}
7679
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
7780
{
78-
#if defined(_CS_GNU_LIBC_VERSION)
79-
const wchar_t wsep = glibc_version_less_than("2.27") ? L' ' : L'\u202f';
80-
#elif defined(_WIN32)
81-
const wchar_t wsep = L'\u00A0';
82-
#else
83-
const wchar_t wsep = L',';
84-
#endif
85-
typedef wchar_t C;
86-
const std::numpunct<C>& np = std::use_facet<std::numpunct<C> >(l);
87-
assert(np.thousands_sep() == wsep);
81+
const wchar_t wsep = LocaleHelpers::thousands_sep_or_default(FR_THOU_SEP);
82+
83+
typedef wchar_t C;
84+
const std::numpunct<C>& np = std::use_facet<std::numpunct<C> >(l);
85+
assert(np.thousands_sep() == wsep);
8886
}
8987
#endif // TEST_HAS_NO_WIDE_CHARACTERS
9088
}

libcxx/test/std/time/time.duration/time.duration.nonmember/ostream.pass.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
// REQUIRES: locale.fr_FR.UTF-8
1717
// REQUIRES: locale.ja_JP.UTF-8
1818

19+
// ADDITIONAL_COMPILE_FLAGS: -DFR_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_THOUSANDS_SEP}
20+
// ADDITIONAL_COMPILE_FLAGS: -DFR_DEC_POINT=%{LOCALE_CONV_FR_FR_UTF_8_DECIMAL_POINT}
21+
1922
// <chrono>
2023

2124
// template<class Rep, class Period = ratio<1>> class duration;
@@ -33,6 +36,7 @@
3336
#include <sstream>
3437

3538
#include "make_string.h"
39+
#include "locale_helpers.h"
3640
#include "platform_support.h" // locale name macros
3741
#include "test_macros.h"
3842

@@ -88,22 +92,10 @@ static void test_values() {
8892
assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1 000,1235s"));
8993
#endif
9094
} else {
91-
#ifdef _WIN32
92-
assert(stream_fr_FR_locale<CharT>(-1'000'000s) == SV("-1\u00A0000\u00A0000s"));
93-
assert(stream_fr_FR_locale<CharT>(1'000'000s) == SV("1\u00A0000\u00A0000s"));
94-
assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == SV("-1\u00A0000,1235s"));
95-
assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1\u00A0000,1235s"));
96-
#elif defined(__APPLE__)
97-
assert(stream_fr_FR_locale<CharT>(-1'000'000s) == SV("-1000000s"));
98-
assert(stream_fr_FR_locale<CharT>(1'000'000s) == SV("1000000s"));
99-
assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == SV("-1000,1235s"));
100-
assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1000,1235s"));
101-
#else
102-
assert(stream_fr_FR_locale<CharT>(-1'000'000s) == SV("-1\u202f000\u202f000s"));
103-
assert(stream_fr_FR_locale<CharT>(1'000'000s) == SV("1\u202f000\u202f000s"));
104-
assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == SV("-1\u202f000,1235s"));
105-
assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1\u202f000,1235s"));
106-
#endif
95+
assert(stream_fr_FR_locale<CharT>(-1'000'000s) == L"-1" FR_THOU_SEP "000" FR_THOU_SEP "000s");
96+
assert(stream_fr_FR_locale<CharT>(1'000'000s) == L"1" FR_THOU_SEP "000" FR_THOU_SEP "000s");
97+
assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == L"-1" FR_THOU_SEP "000" FR_DEC_POINT "1235s");
98+
assert(stream_fr_FR_locale<CharT>(1'000.123456s) == L"1" FR_THOU_SEP "000" FR_DEC_POINT "1235s");
10799
}
108100

109101
assert(stream_ja_JP_locale<CharT>(-1'000'000s) == SV("-1,000,000s"));

libcxx/test/support/locale_helpers.h

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,6 @@ std::wstring convert_thousands_sep(std::wstring const& in, wchar_t sep) {
4141
return out;
4242
}
4343

44-
// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator.
45-
// This function converts the spaces in string inputs to U+202F if need
46-
// be. FreeBSD's locale data also uses U+202F, since 2018.
47-
// Windows uses U+00A0 NO-BREAK SPACE.
48-
std::wstring convert_thousands_sep_fr_FR(std::wstring const& in) {
49-
#if defined(_CS_GNU_LIBC_VERSION)
50-
if (glibc_version_less_than("2.27"))
51-
return in;
52-
else
53-
return convert_thousands_sep(in, L'\u202F');
54-
#elif defined(__FreeBSD__)
55-
return convert_thousands_sep(in, L'\u202F');
56-
#elif defined(_WIN32)
57-
return convert_thousands_sep(in, L'\u00A0');
58-
#else
59-
return in;
60-
#endif
61-
}
62-
63-
// GLIBC 2.27 uses U+202F NARROW NO-BREAK SPACE as a thousands separator.
64-
// FreeBSD, AIX and Windows use U+00A0 NO-BREAK SPACE.
65-
std::wstring convert_thousands_sep_ru_RU(std::wstring const& in) {
66-
#if defined(TEST_HAS_GLIBC)
67-
return convert_thousands_sep(in, L'\u202F');
68-
# elif defined(__FreeBSD__) || defined(_WIN32) || defined(_AIX)
69-
return convert_thousands_sep(in, L'\u00A0');
70-
# else
71-
return in;
72-
# endif
73-
}
74-
7544
std::wstring negate_en_US(std::wstring s) {
7645
#if defined(_WIN32)
7746
return L"(" + s + L")";
@@ -80,6 +49,12 @@ std::wstring negate_en_US(std::wstring s) {
8049
#endif
8150
}
8251

52+
wchar_t thousands_sep_or_default(std::wstring s) { return !s.empty() ? s[0] : L','; }
53+
54+
wchar_t mon_thousands_sep_or_default(std::wstring s) { return thousands_sep_or_default(s); }
55+
56+
wchar_t decimal_point_or_default(std::wstring s) { return !s.empty() ? s[0] : L'.'; }
57+
8358
#endif // TEST_HAS_NO_WIDE_CHARACTERS
8459

8560
std::string negate_en_US(std::string s) {

libcxx/utils/libcxx/test/features.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from libcxx.test.dsl import *
1010
from lit.BooleanExpression import BooleanExpression
11+
from lit.TestRunner import substitutionsWillEscapeBackslashes
1112
import re
1213
import shutil
1314
import subprocess
@@ -335,15 +336,94 @@ def _getAndroidDeviceApi(cfg):
335336
"fr_CA.ISO8859-1": ["fr_CA.ISO8859-1", "French_Canada.1252"],
336337
"cs_CZ.ISO8859-2": ["cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"],
337338
}
339+
provide_locale_conversions = {
340+
"fr_FR.UTF-8": ["decimal_point", "mon_thousands_sep", "thousands_sep"],
341+
"ru_RU.UTF-8": ["mon_thousands_sep"],
342+
}
338343
for locale, alts in locales.items():
339344
# Note: Using alts directly in the lambda body here will bind it to the value at the
340345
# end of the loop. Assigning it to a default argument works around this issue.
341346
DEFAULT_FEATURES.append(
342347
Feature(
343348
name="locale.{}".format(locale),
344349
when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts),
345-
)
350+
actions=lambda cfg, locale=locale, alts=alts:
351+
_getLocaleFlagsAction(cfg, locale, alts, provide_locale_conversions[locale])
352+
if locale in provide_locale_conversions
353+
and "_LIBCPP_HAS_NO_WIDE_CHARACTERS" not in compilerMacros(cfg) else []
354+
),
355+
)
356+
357+
# Provide environment locale conversions through substitutions to avoid platform specific
358+
# maintenance.
359+
def _getLocaleFlagsAction(cfg, locale, alts, members):
360+
alts_list = ",".join([f'"{l}"' for l in alts])
361+
get_member_list = ",".join([f'lc->{m}' for m in members])
362+
363+
localeconv_info = programOutput(
364+
cfg,
365+
r"""
366+
#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)
367+
#define _CRT_SECURE_NO_WARNINGS
368+
#endif
369+
#include <stdio.h>
370+
#include <locale.h>
371+
#include <stdlib.h>
372+
#include <wchar.h>
373+
374+
// Print each requested locale conversion member on separate lines.
375+
int main() {
376+
const char* locales[] = { %s };
377+
for (int loc_i = 0; loc_i < %d; ++loc_i) {
378+
if (!setlocale(LC_ALL, locales[loc_i])) {
379+
continue; // Choose first locale name that is recognized.
380+
}
381+
382+
lconv* lc = localeconv();
383+
const char* members[] = { %s };
384+
for (size_t m_i = 0; m_i < %d; ++m_i) {
385+
if (!members[m_i]) {
386+
printf("\n"); // member value is an empty string
387+
continue;
388+
}
389+
390+
size_t len = mbstowcs(nullptr, members[m_i], 0);
391+
if (len == static_cast<size_t>(-1)) {
392+
fprintf(stderr, "mbstowcs failed unexpectedly");
393+
return 1;
394+
}
395+
wchar_t* dst = new wchar_t[len + 1]; // Include room for null terminator
396+
size_t ret = mbstowcs(dst, members[m_i], len);
397+
if (ret == static_cast<size_t>(-1)) {
398+
fprintf(stderr, "mbstowcs failed unexpectedly");
399+
return 1;
400+
}
401+
402+
for (size_t i = 0; i < len; ++i) {
403+
printf("\\u%%04x", dst[i]);
404+
}
405+
printf("\n");
406+
delete[] dst;
407+
}
408+
return 0;
409+
}
410+
411+
return 1;
412+
}
413+
""" % (alts_list, len(alts), get_member_list, len(members)),
346414
)
415+
if not substitutionsWillEscapeBackslashes():
416+
# Account for different escaping depending on platform running lit
417+
localeconv_info = localeconv_info.replace("\\", "\\\\")
418+
valid_define_name = re.sub(r"[.-]", "_", locale).upper()
419+
return [
420+
# Provide locale conversion through a substitution.
421+
# Example: %{LOCALE_CONV_FR_FR_UTF_8_THOUSANDS_SEP} = L"\u202f"
422+
AddSubstitution(
423+
f'%{{LOCALE_CONV_{valid_define_name}_{member.upper()}}}',
424+
lambda cfg, value=value: f'\'L"{value}"\''
425+
) for member, value in zip(members, localeconv_info.split('\n'))
426+
]
347427

348428

349429
# Add features representing the target platform name: darwin, linux, windows, etc...

llvm/utils/lit/lit/TestRunner.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,10 @@ def adjust_substitutions(self, substitutions):
16251625
substitutions[existing[0]] = (self.name, value_repl)
16261626

16271627

1628+
def substitutionsWillEscapeBackslashes():
1629+
return kIsWindows
1630+
1631+
16281632
def applySubstitutions(script, substitutions, conditions={}, recursion_limit=None):
16291633
"""
16301634
Apply substitutions to the script. Allow full regular expression syntax.
@@ -1738,7 +1742,7 @@ def processLine(ln):
17381742
# Apply substitutions
17391743
ln = substituteIfElse(escapePercents(ln))
17401744
for a, b in substitutions:
1741-
if kIsWindows:
1745+
if substitutionsWillEscapeBackslashes():
17421746
b = b.replace("\\", "\\\\")
17431747
# re.compile() has a built-in LRU cache with 512 entries. In some
17441748
# test suites lit ends up thrashing that cache, which made e.g.

0 commit comments

Comments
 (0)