10b71bf79SMartin Storsjö //===----------------------------------------------------------------------===//
20b71bf79SMartin Storsjö //
30b71bf79SMartin Storsjö // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b71bf79SMartin Storsjö // See https://llvm.org/LICENSE.txt for license information.
50b71bf79SMartin Storsjö // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b71bf79SMartin Storsjö //
70b71bf79SMartin Storsjö //===----------------------------------------------------------------------===//
80b71bf79SMartin Storsjö
9a7f9895cSLouis Dionne // UNSUPPORTED: no-localization
10*ac8c9f1eSLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
11c352fa74SLouis Dionne // UNSUPPORTED: availability-filesystem-missing
120b71bf79SMartin Storsjö // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
130b71bf79SMartin Storsjö
140b71bf79SMartin Storsjö // <filesystem>
150b71bf79SMartin Storsjö
160b71bf79SMartin Storsjö // class path
170b71bf79SMartin Storsjö
180b71bf79SMartin Storsjö // Test constructors, accessors and modifiers that convert from/to various
190b71bf79SMartin Storsjö // character encodings. Constructors and modifiers (append, concat,
200b71bf79SMartin Storsjö // operator/=, operator+=) accept inputs with various character encodings,
210b71bf79SMartin Storsjö // and accessors (*string(), string<>(), u8string()) export the string with
220b71bf79SMartin Storsjö // various encodings.
230b71bf79SMartin Storsjö //
240b71bf79SMartin Storsjö // Some encodings are standardized; char16_t, char32_t and the u8string
250b71bf79SMartin Storsjö // accessor and u8path constructor (and normal functions taking char8_t in
260b71bf79SMartin Storsjö // C++20) convert from/to UTF-16, UTF-32 and UTF-8. wchar_t can be either
270b71bf79SMartin Storsjö // UTF-16 or UTF-32 depending on the size of the wchar_t type, or can be
280b71bf79SMartin Storsjö // left unimplemented.
290b71bf79SMartin Storsjö //
300b71bf79SMartin Storsjö // Plain char is implicitly UTF-8 on posix systems. On Windows, plain char
310b71bf79SMartin Storsjö // is supposed to be in the same encoding as the platform's native file
320b71bf79SMartin Storsjö // system APIs consumes in the functions that take narrow strings as path
330b71bf79SMartin Storsjö // names.
340b71bf79SMartin Storsjö
35*ac8c9f1eSLouis Dionne #include <filesystem>
360b71bf79SMartin Storsjö #include <type_traits>
370b71bf79SMartin Storsjö #include <cassert>
380b71bf79SMartin Storsjö
390b71bf79SMartin Storsjö #include "test_macros.h"
40c352fa74SLouis Dionne
41c352fa74SLouis Dionne #ifdef _WIN32
42c352fa74SLouis Dionne # include <windows.h> // SetFileApisToANSI & friends
43c352fa74SLouis Dionne #endif
44*ac8c9f1eSLouis Dionne namespace fs = std::filesystem;
450b71bf79SMartin Storsjö
460b71bf79SMartin Storsjö // Test conversion with strings that fit within the latin1 charset, that fit
470b71bf79SMartin Storsjö // within one code point in UTF-16, and that can be expressible in certain
480b71bf79SMartin Storsjö // one-byte code pages.
test_latin_unicode()490b71bf79SMartin Storsjö static void test_latin_unicode()
500b71bf79SMartin Storsjö {
510b71bf79SMartin Storsjö const char16_t u16str[] = { 0xe5, 0xe4, 0xf6, 0x00 };
520b71bf79SMartin Storsjö const char32_t u32str[] = { 0xe5, 0xe4, 0xf6, 0x00 };
530b71bf79SMartin Storsjö const char str[] = { char(0xc3), char(0xa5), char(0xc3), char(0xa4), char(0xc3), char(0xb6), 0x00 }; // UTF8, in a regular char string
540b71bf79SMartin Storsjö #if TEST_STD_VER > 17 && defined(__cpp_lib_char8_t)
550b71bf79SMartin Storsjö const char8_t u8str[] = { 0xc3, 0xa5, 0xc3, 0xa4, 0xc3, 0xb6, 0x00 };
560b71bf79SMartin Storsjö #else
570b71bf79SMartin Storsjö const char u8str[] = { char(0xc3), char(0xa5), char(0xc3), char(0xa4), char(0xc3), char(0xb6), 0x00 };
580b71bf79SMartin Storsjö #endif
59f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS
600b71bf79SMartin Storsjö const wchar_t wstr[] = { 0xe5, 0xe4, 0xf6, 0x00 };
610b71bf79SMartin Storsjö #endif
620b71bf79SMartin Storsjö
630b71bf79SMartin Storsjö // Test well-defined conversion between UTF-8, UTF-16 and UTF-32
640b71bf79SMartin Storsjö {
650b71bf79SMartin Storsjö const fs::path p(u16str);
660b71bf79SMartin Storsjö assert(p.u8string() == u8str);
670b71bf79SMartin Storsjö assert(p.u16string() == u16str);
680b71bf79SMartin Storsjö assert(p.u32string() == u32str);
690b71bf79SMartin Storsjö assert(p.string<char16_t>() == u16str);
700b71bf79SMartin Storsjö assert(p.string<char32_t>() == u32str);
710b71bf79SMartin Storsjö }
720b71bf79SMartin Storsjö {
730b71bf79SMartin Storsjö const fs::path p(u32str);
740b71bf79SMartin Storsjö assert(p.u8string() == u8str);
750b71bf79SMartin Storsjö assert(p.u16string() == u16str);
760b71bf79SMartin Storsjö assert(p.u32string() == u32str);
770b71bf79SMartin Storsjö assert(p.string<char16_t>() == u16str);
780b71bf79SMartin Storsjö assert(p.string<char32_t>() == u32str);
790b71bf79SMartin Storsjö }
800b71bf79SMartin Storsjö {
810b71bf79SMartin Storsjö const fs::path p = fs::u8path(str);
820b71bf79SMartin Storsjö assert(p.u8string() == u8str);
830b71bf79SMartin Storsjö assert(p.u16string() == u16str);
840b71bf79SMartin Storsjö assert(p.u32string() == u32str);
850b71bf79SMartin Storsjö assert(p.string<char16_t>() == u16str);
860b71bf79SMartin Storsjö assert(p.string<char32_t>() == u32str);
870b71bf79SMartin Storsjö }
880b71bf79SMartin Storsjö #if TEST_STD_VER > 17 && defined(__cpp_lib_char8_t)
890b71bf79SMartin Storsjö {
900b71bf79SMartin Storsjö // In C++20, the path constructor can unambiguously handle UTF-8 input,
910b71bf79SMartin Storsjö // even if the plain char constructor would treat it as something else.
920b71bf79SMartin Storsjö const fs::path p(u8str);
930b71bf79SMartin Storsjö assert(p.u8string() == u8str);
940b71bf79SMartin Storsjö assert(p.u16string() == u16str);
950b71bf79SMartin Storsjö assert(p.u32string() == u32str);
960b71bf79SMartin Storsjö assert(p.string<char8_t>() == u8str);
970b71bf79SMartin Storsjö assert(p.string<char16_t>() == u16str);
980b71bf79SMartin Storsjö assert(p.string<char32_t>() == u32str);
990b71bf79SMartin Storsjö }
1000b71bf79SMartin Storsjö // Check reading various inputs with string<char8_t>()
1010b71bf79SMartin Storsjö {
1020b71bf79SMartin Storsjö const fs::path p(u16str);
1030b71bf79SMartin Storsjö assert(p.string<char8_t>() == u8str);
1040b71bf79SMartin Storsjö }
1050b71bf79SMartin Storsjö {
1060b71bf79SMartin Storsjö const fs::path p(u32str);
1070b71bf79SMartin Storsjö assert(p.string<char8_t>() == u8str);
1080b71bf79SMartin Storsjö }
1090b71bf79SMartin Storsjö {
1100b71bf79SMartin Storsjö const fs::path p = fs::u8path(str);
1110b71bf79SMartin Storsjö assert(p.string<char8_t>() == u8str);
1120b71bf79SMartin Storsjö }
1130b71bf79SMartin Storsjö #endif
114f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS
1150b71bf79SMartin Storsjö // Test conversion to/from wchar_t.
1160b71bf79SMartin Storsjö {
1170b71bf79SMartin Storsjö const fs::path p(u16str);
1180b71bf79SMartin Storsjö assert(p.wstring() == wstr);
1190b71bf79SMartin Storsjö assert(p.string<wchar_t>() == wstr);
1200b71bf79SMartin Storsjö }
1210b71bf79SMartin Storsjö {
1220b71bf79SMartin Storsjö const fs::path p = fs::u8path(str);
1230b71bf79SMartin Storsjö assert(p.wstring() == wstr);
1240b71bf79SMartin Storsjö assert(p.string<wchar_t>() == wstr);
1250b71bf79SMartin Storsjö }
1260b71bf79SMartin Storsjö {
1270b71bf79SMartin Storsjö const fs::path p(wstr);
1280b71bf79SMartin Storsjö assert(p.wstring() == wstr);
1290b71bf79SMartin Storsjö assert(p.u8string() == u8str);
1300b71bf79SMartin Storsjö assert(p.u16string() == u16str);
1310b71bf79SMartin Storsjö assert(p.u32string() == u32str);
1320b71bf79SMartin Storsjö assert(p.string<wchar_t>() == wstr);
1330b71bf79SMartin Storsjö }
134f4c1258dSLouis Dionne #endif // TEST_HAS_NO_WIDE_CHARACTERS
1350b71bf79SMartin Storsjö #ifndef _WIN32
1360b71bf79SMartin Storsjö // Test conversion to/from regular char-based string. On POSIX, this
1370b71bf79SMartin Storsjö // is implied to convert to/from UTF-8.
1380b71bf79SMartin Storsjö {
1390b71bf79SMartin Storsjö const fs::path p(str);
1400b71bf79SMartin Storsjö assert(p.string() == str);
1410b71bf79SMartin Storsjö assert(p.u16string() == u16str);
1420b71bf79SMartin Storsjö assert(p.string<char>() == str);
1430b71bf79SMartin Storsjö }
1440b71bf79SMartin Storsjö {
1450b71bf79SMartin Storsjö const fs::path p(u16str);
1460b71bf79SMartin Storsjö assert(p.string() == str);
1470b71bf79SMartin Storsjö assert(p.string<char>() == str);
1480b71bf79SMartin Storsjö }
1490b71bf79SMartin Storsjö #else
1500b71bf79SMartin Storsjö // On windows, the narrow char-based input/output is supposed to be
1510b71bf79SMartin Storsjö // in the charset that narrow file IO APIs use. This can either be the
1520b71bf79SMartin Storsjö // current active code page (ACP) or the OEM code page, exposed by
1530b71bf79SMartin Storsjö // the AreFileApisANSI() function, and settable with SetFileApisToANSI() and
1540b71bf79SMartin Storsjö // SetFileApisToOEM(). We can't set which codepage is active within
1550b71bf79SMartin Storsjö // the process, but for some specific known ones, we can check if they
1560b71bf79SMartin Storsjö // behave as expected.
1570b71bf79SMartin Storsjö SetFileApisToANSI();
1580b71bf79SMartin Storsjö if (GetACP() == 1252) {
1590b71bf79SMartin Storsjö const char latin1[] = { char(0xe5), char(0xe4), char(0xf6), 0x00 };
1600b71bf79SMartin Storsjö {
1610b71bf79SMartin Storsjö const fs::path p(wstr);
1620b71bf79SMartin Storsjö assert(p.string() == latin1);
1630b71bf79SMartin Storsjö assert(p.string<char>() == latin1);
1640b71bf79SMartin Storsjö }
1650b71bf79SMartin Storsjö {
1660b71bf79SMartin Storsjö const fs::path p(latin1);
1670b71bf79SMartin Storsjö assert(p.string() == latin1);
1680b71bf79SMartin Storsjö assert(p.wstring() == wstr);
1690b71bf79SMartin Storsjö assert(p.u8string() == u8str);
1700b71bf79SMartin Storsjö assert(p.u16string() == u16str);
1710b71bf79SMartin Storsjö assert(p.string<char>() == latin1);
1720b71bf79SMartin Storsjö assert(p.string<wchar_t>() == wstr);
1730b71bf79SMartin Storsjö }
1740b71bf79SMartin Storsjö }
1750b71bf79SMartin Storsjö SetFileApisToOEM();
1760b71bf79SMartin Storsjö if (GetOEMCP() == 850 || GetOEMCP() == 437) {
1770b71bf79SMartin Storsjö // These chars are identical in both CP 850 and 437
1780b71bf79SMartin Storsjö const char cp850[] = { char(0x86), char(0x84), char(0x94), 0x00 };
1790b71bf79SMartin Storsjö {
1800b71bf79SMartin Storsjö const fs::path p(wstr);
1810b71bf79SMartin Storsjö assert(p.string() == cp850);
1820b71bf79SMartin Storsjö assert(p.string<char>() == cp850);
1830b71bf79SMartin Storsjö }
1840b71bf79SMartin Storsjö {
1850b71bf79SMartin Storsjö const fs::path p(cp850);
1860b71bf79SMartin Storsjö assert(p.string() == cp850);
1870b71bf79SMartin Storsjö assert(p.wstring() == wstr);
1880b71bf79SMartin Storsjö assert(p.u8string() == u8str);
1890b71bf79SMartin Storsjö assert(p.u16string() == u16str);
1900b71bf79SMartin Storsjö assert(p.string<char>() == cp850);
1910b71bf79SMartin Storsjö assert(p.string<wchar_t>() == wstr);
1920b71bf79SMartin Storsjö }
1930b71bf79SMartin Storsjö }
1940b71bf79SMartin Storsjö #endif
1950b71bf79SMartin Storsjö }
1960b71bf79SMartin Storsjö
1970b71bf79SMartin Storsjö // Test conversion with strings that don't fit within one UTF-16 code point.
1980b71bf79SMartin Storsjö // Here, wchar_t can be either UTF-16 or UTF-32 depending on the size on the
1990b71bf79SMartin Storsjö // particular platform.
test_wide_unicode()2000b71bf79SMartin Storsjö static void test_wide_unicode()
2010b71bf79SMartin Storsjö {
2020b71bf79SMartin Storsjö const char16_t u16str[] = { 0xd801, 0xdc37, 0x00 };
2030b71bf79SMartin Storsjö const char32_t u32str[] = { 0x10437, 0x00 };
2040b71bf79SMartin Storsjö #if TEST_STD_VER > 17 && defined(__cpp_lib_char8_t)
2050b71bf79SMartin Storsjö const char8_t u8str[] = { 0xf0, 0x90, 0x90, 0xb7, 0x00 };
2060b71bf79SMartin Storsjö #else
2070b71bf79SMartin Storsjö const char u8str[] = { char(0xf0), char(0x90), char(0x90), char(0xb7), 0x00 };
2080b71bf79SMartin Storsjö #endif
2090b71bf79SMartin Storsjö const char str[] = { char(0xf0), char(0x90), char(0x90), char(0xb7), 0x00 };
2100b71bf79SMartin Storsjö {
2110b71bf79SMartin Storsjö const fs::path p = fs::u8path(str);
2120b71bf79SMartin Storsjö assert(p.u8string() == u8str);
2130b71bf79SMartin Storsjö assert(p.u16string() == u16str);
2140b71bf79SMartin Storsjö assert(p.u32string() == u32str);
2150b71bf79SMartin Storsjö }
2160b71bf79SMartin Storsjö {
2170b71bf79SMartin Storsjö const fs::path p(u16str);
2180b71bf79SMartin Storsjö assert(p.u8string() == u8str);
2190b71bf79SMartin Storsjö assert(p.u16string() == u16str);
2200b71bf79SMartin Storsjö assert(p.u32string() == u32str);
2210b71bf79SMartin Storsjö }
2220b71bf79SMartin Storsjö {
2230b71bf79SMartin Storsjö const fs::path p(u32str);
2240b71bf79SMartin Storsjö assert(p.u8string() == u8str);
2250b71bf79SMartin Storsjö assert(p.u16string() == u16str);
2260b71bf79SMartin Storsjö assert(p.u32string() == u32str);
2270b71bf79SMartin Storsjö }
228f4c1258dSLouis Dionne #if !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
2290b71bf79SMartin Storsjö # if __SIZEOF_WCHAR_T__ == 2
2300b71bf79SMartin Storsjö const wchar_t wstr[] = { 0xd801, 0xdc37, 0x00 };
2310b71bf79SMartin Storsjö # else
2320b71bf79SMartin Storsjö const wchar_t wstr[] = { 0x10437, 0x00 };
2330b71bf79SMartin Storsjö # endif
2340b71bf79SMartin Storsjö // Test conversion to/from wchar_t.
2350b71bf79SMartin Storsjö {
2360b71bf79SMartin Storsjö const fs::path p = fs::u8path(str);
2370b71bf79SMartin Storsjö assert(p.wstring() == wstr);
2380b71bf79SMartin Storsjö }
2390b71bf79SMartin Storsjö {
2400b71bf79SMartin Storsjö const fs::path p(u16str);
2410b71bf79SMartin Storsjö assert(p.wstring() == wstr);
2420b71bf79SMartin Storsjö }
2430b71bf79SMartin Storsjö {
2440b71bf79SMartin Storsjö const fs::path p(u32str);
2450b71bf79SMartin Storsjö assert(p.wstring() == wstr);
2460b71bf79SMartin Storsjö }
2470b71bf79SMartin Storsjö {
2480b71bf79SMartin Storsjö const fs::path p(wstr);
2490b71bf79SMartin Storsjö assert(p.u8string() == u8str);
2500b71bf79SMartin Storsjö assert(p.u16string() == u16str);
2510b71bf79SMartin Storsjö assert(p.u32string() == u32str);
2520b71bf79SMartin Storsjö assert(p.wstring() == wstr);
2530b71bf79SMartin Storsjö }
254f4c1258dSLouis Dionne #endif // !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
2550b71bf79SMartin Storsjö }
2560b71bf79SMartin Storsjö
2570b71bf79SMartin Storsjö // Test appending paths in different encodings.
test_append()2580b71bf79SMartin Storsjö static void test_append()
2590b71bf79SMartin Storsjö {
2600b71bf79SMartin Storsjö const char16_t u16str[] = { 0xd801, 0xdc37, 0x00 };
2610b71bf79SMartin Storsjö const char32_t u32str[] = { 0x10437, 0x00 };
2620b71bf79SMartin Storsjö const char32_t u32ref[] = { 0x10437, fs::path::preferred_separator, 0x10437, fs::path::preferred_separator, 0x10437, 0x00 };
2630b71bf79SMartin Storsjö const char str[] = { char(0xf0), char(0x90), char(0x90), char(0xb7), 0x00 };
2640b71bf79SMartin Storsjö {
2650b71bf79SMartin Storsjö fs::path p = fs::u8path(str) / u16str / u32str;
2660b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2670b71bf79SMartin Storsjö p = fs::u8path(str).append(u16str).append(u32str);
2680b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2690b71bf79SMartin Storsjö p = fs::u8path(str);
2700b71bf79SMartin Storsjö p /= u16str;
2710b71bf79SMartin Storsjö p /= u32str;
2720b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2730b71bf79SMartin Storsjö }
274f4c1258dSLouis Dionne #if !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
2750b71bf79SMartin Storsjö # if __SIZEOF_WCHAR_T__ == 2
2760b71bf79SMartin Storsjö const wchar_t wstr[] = { 0xd801, 0xdc37, 0x00 };
2770b71bf79SMartin Storsjö # else
2780b71bf79SMartin Storsjö const wchar_t wstr[] = { 0x10437, 0x00 };
2790b71bf79SMartin Storsjö # endif
2800b71bf79SMartin Storsjö // Test conversion from wchar_t.
2810b71bf79SMartin Storsjö {
2820b71bf79SMartin Storsjö fs::path p = fs::path(u16str) / wstr / u32str;
2830b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2840b71bf79SMartin Storsjö p = fs::path(u16str).append(wstr).append(u32str);
2850b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2860b71bf79SMartin Storsjö p = fs::path(u16str);
2870b71bf79SMartin Storsjö p /= wstr;
2880b71bf79SMartin Storsjö p /= u32str;
2890b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
2900b71bf79SMartin Storsjö }
291f4c1258dSLouis Dionne #endif // !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
2920b71bf79SMartin Storsjö }
2930b71bf79SMartin Storsjö
test_concat()2940b71bf79SMartin Storsjö static void test_concat()
2950b71bf79SMartin Storsjö {
2960b71bf79SMartin Storsjö const char16_t u16str[] = { 0xd801, 0xdc37, 0x00 };
2970b71bf79SMartin Storsjö const char32_t u32str[] = { 0x10437, 0x00 };
2980b71bf79SMartin Storsjö const char32_t u32ref[] = { 0x10437, 0x10437, 0x10437, 0x00 };
2990b71bf79SMartin Storsjö const char str[] = { char(0xf0), char(0x90), char(0x90), char(0xb7), 0x00 };
3000b71bf79SMartin Storsjö {
3010b71bf79SMartin Storsjö fs::path p = fs::u8path(str);
3020b71bf79SMartin Storsjö p += u16str;
3030b71bf79SMartin Storsjö p += u32str;
3040b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
3050b71bf79SMartin Storsjö p = fs::u8path(str).concat(u16str).concat(u32str);
3060b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
3070b71bf79SMartin Storsjö }
308f4c1258dSLouis Dionne #if !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
3090b71bf79SMartin Storsjö # if __SIZEOF_WCHAR_T__ == 2
3100b71bf79SMartin Storsjö const wchar_t wstr[] = { 0xd801, 0xdc37, 0x00 };
3110b71bf79SMartin Storsjö # else
3120b71bf79SMartin Storsjö const wchar_t wstr[] = { 0x10437, 0x00 };
3130b71bf79SMartin Storsjö # endif
3140b71bf79SMartin Storsjö // Test conversion from wchar_t.
3150b71bf79SMartin Storsjö {
3160b71bf79SMartin Storsjö fs::path p = fs::path(u16str);
3170b71bf79SMartin Storsjö p += wstr;
3180b71bf79SMartin Storsjö p += u32str;
3190b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
3200b71bf79SMartin Storsjö p = fs::path(u16str).concat(wstr).concat(u32str);
3210b71bf79SMartin Storsjö assert(p.u32string() == u32ref);
3220b71bf79SMartin Storsjö }
323f4c1258dSLouis Dionne #endif // !defined(TEST_HAS_NO_WIDE_CHARACTERS) && defined(__SIZEOF_WCHAR_T__)
3240b71bf79SMartin Storsjö }
3250b71bf79SMartin Storsjö
test_append_concat_narrow()3260b71bf79SMartin Storsjö static void test_append_concat_narrow()
3270b71bf79SMartin Storsjö {
3280b71bf79SMartin Storsjö const char16_t u16str[] = { 0xe5, 0x00 };
3290b71bf79SMartin Storsjö const char32_t u32ref_append[] = { 0xe5, fs::path::preferred_separator, 0xe5, 0x00 };
3300b71bf79SMartin Storsjö const char32_t u32ref_concat[] = { 0xe5, 0xe5, 0x00 };
3310b71bf79SMartin Storsjö
3320b71bf79SMartin Storsjö #if TEST_STD_VER > 17 && defined(__cpp_lib_char8_t)
3330b71bf79SMartin Storsjö {
3340b71bf79SMartin Storsjö const char8_t u8str[] = { 0xc3, 0xa5, 0x00 };
3350b71bf79SMartin Storsjö // In C++20, appends of a char8_t string is unambiguously treated as
3360b71bf79SMartin Storsjö // UTF-8.
3370b71bf79SMartin Storsjö fs::path p = fs::path(u16str) / u8str;
3380b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3390b71bf79SMartin Storsjö p = fs::path(u16str).append(u8str);
3400b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3410b71bf79SMartin Storsjö p = fs::path(u16str);
3420b71bf79SMartin Storsjö p /= u8str;
3430b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3440b71bf79SMartin Storsjö p = fs::path(u16str).concat(u8str);
3450b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3460b71bf79SMartin Storsjö p = fs::path(u16str);
3470b71bf79SMartin Storsjö p += u8str;
3480b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3490b71bf79SMartin Storsjö }
3500b71bf79SMartin Storsjö #endif
3510b71bf79SMartin Storsjö #ifndef _WIN32
3520b71bf79SMartin Storsjö // Test appending a regular char-based string. On POSIX, this
3530b71bf79SMartin Storsjö // is implied to convert to/from UTF-8.
3540b71bf79SMartin Storsjö {
3550b71bf79SMartin Storsjö const char str[] = { char(0xc3), char(0xa5), 0x00 }; // UTF8, in a regular char string
3560b71bf79SMartin Storsjö fs::path p = fs::path(u16str) / str;
3570b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3580b71bf79SMartin Storsjö p = fs::path(u16str).append(str);
3590b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3600b71bf79SMartin Storsjö p = fs::path(u16str);
3610b71bf79SMartin Storsjö p /= str;
3620b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3630b71bf79SMartin Storsjö p = fs::path(u16str).concat(str);
3640b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3650b71bf79SMartin Storsjö p = fs::path(u16str);
3660b71bf79SMartin Storsjö p += str;
3670b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3680b71bf79SMartin Storsjö }
3690b71bf79SMartin Storsjö #else
3700b71bf79SMartin Storsjö SetFileApisToANSI();
3710b71bf79SMartin Storsjö if (GetACP() == 1252) {
3720b71bf79SMartin Storsjö const char latin1[] = { char(0xe5), 0x00 };
3730b71bf79SMartin Storsjö fs::path p = fs::path(u16str) / latin1;
3740b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3750b71bf79SMartin Storsjö p = fs::path(u16str).append(latin1);
3760b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3770b71bf79SMartin Storsjö p = fs::path(u16str);
3780b71bf79SMartin Storsjö p /= latin1;
3790b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3800b71bf79SMartin Storsjö p = fs::path(u16str).concat(latin1);
3810b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3820b71bf79SMartin Storsjö p = fs::path(u16str);
3830b71bf79SMartin Storsjö p += latin1;
3840b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3850b71bf79SMartin Storsjö }
3860b71bf79SMartin Storsjö SetFileApisToOEM();
3870b71bf79SMartin Storsjö if (GetOEMCP() == 850 || GetOEMCP() == 437) {
3880b71bf79SMartin Storsjö // This chars is identical in both CP 850 and 437
3890b71bf79SMartin Storsjö const char cp850[] = { char(0x86), 0x00 };
3900b71bf79SMartin Storsjö fs::path p = fs::path(u16str) / cp850;
3910b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3920b71bf79SMartin Storsjö p = fs::path(u16str).append(cp850);
3930b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3940b71bf79SMartin Storsjö p = fs::path(u16str);
3950b71bf79SMartin Storsjö p /= cp850;
3960b71bf79SMartin Storsjö assert(p.u32string() == u32ref_append);
3970b71bf79SMartin Storsjö p = fs::path(u16str).concat(cp850);
3980b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
3990b71bf79SMartin Storsjö p = fs::path(u16str);
4000b71bf79SMartin Storsjö p += cp850;
4010b71bf79SMartin Storsjö assert(p.u32string() == u32ref_concat);
4020b71bf79SMartin Storsjö }
4030b71bf79SMartin Storsjö #endif
4040b71bf79SMartin Storsjö }
4050b71bf79SMartin Storsjö
main(int,char **)4060b71bf79SMartin Storsjö int main(int, char**)
4070b71bf79SMartin Storsjö {
4080b71bf79SMartin Storsjö test_latin_unicode();
4090b71bf79SMartin Storsjö test_wide_unicode();
4100b71bf79SMartin Storsjö test_append();
4110b71bf79SMartin Storsjö test_concat();
4120b71bf79SMartin Storsjö test_append_concat_narrow();
4130b71bf79SMartin Storsjö
4140b71bf79SMartin Storsjö return 0;
4150b71bf79SMartin Storsjö }
416