blob: b91ae6fd449d0fad3e3774a686bd637a6b3a1062 [file] [log] [blame]
// { dg-do run { target c++26 } }
// { dg-options "-fexec-charset=UTF-8" }
#include <filesystem>
#include <format>
#include <testsuite_hooks.h>
using std::filesystem::path;
template<typename... Args>
bool
is_format_string_for(const char* str, Args&&... args)
{
try {
(void) std::vformat(str, std::make_format_args(args...));
return true;
} catch (const std::format_error&) {
return false;
}
}
template<typename... Args>
bool
is_format_string_for(const wchar_t* str, Args&&... args)
{
try {
(void) std::vformat(str, std::make_wformat_args(args...));
return true;
} catch (const std::format_error&) {
return false;
}
}
void
test_format_spec()
{
// [fs.path.fmtr.funcs]
// \nontermdef{path-format-spec}\br
// \opt{fill-and-align} \opt{width} \opt{\terminal{?}} \opt{\terminal{g}}
path p;
VERIFY( is_format_string_for("{}", p) );
VERIFY( is_format_string_for("{:}", p) );
VERIFY( is_format_string_for("{:?}", p) );
VERIFY( is_format_string_for("{:g}", p) );
VERIFY( is_format_string_for("{:?g}", p) );
VERIFY( is_format_string_for("{:?g}", p) );
VERIFY( is_format_string_for("{:F^32?g}", p) );
VERIFY( is_format_string_for("{:G<{}?g}", p, 32) );
VERIFY( is_format_string_for(L"{:G<{}?g}", p, 32) );
VERIFY( ! is_format_string_for("{:g?}", p) );
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
#define WFMT(S) WIDEN_(_FCharT, S)
#define WPATH(S) WIDEN_(_PCharT, S)
template<typename _FCharT, typename _PCharT>
void
test_format()
{
std::basic_string<_FCharT> res;
res = std::format(WFMT("{}"), path(WPATH("/usr/include")));
VERIFY( res == WFMT("/usr/include") );
res = std::format(WFMT("{:.<10}"), path(WPATH("foo/bar")));
VERIFY( res == WFMT("foo/bar...") );
res = std::format(WFMT("{}"), path(WPATH("foo///bar")));
VERIFY( res == WFMT("foo///bar") );
res = std::format(WFMT("{:g}"), path(WPATH("foo///bar")));
VERIFY( res == WFMT("foo/bar") );
res = std::format(WFMT("{}"), path(WPATH("/path/with/new\nline")));
VERIFY( res == WFMT("/path/with/new\nline") );
res = std::format(WFMT("{:?}"), path(WPATH("multi\nline")));
VERIFY( res == WFMT("\"multi\\nline\"") );
res = std::format(WFMT("{:?g}"), path(WPATH("mu///lti\nli///ne")));
VERIFY( res == WFMT("\"mu/lti\\nli/ne\"") );
res = std::format(WFMT("{}"),
path(WPATH("\u0428\u0447\u0443\u0447\u044B\u043D\u0448\u0447\u044B\u043D\u0430")));
VERIFY( res == WFMT("\u0428\u0447\u0443\u0447\u044B\u043D\u0448\u0447\u044B\u043D\u0430"));
if constexpr (path::preferred_separator == L'\\')
{
res = std::format(WFMT("{}"), path(WPATH("C:\\foo\\bar")));
VERIFY( res == WFMT("C:\\foo\\bar") );
res = std::format(WFMT("{:g}"), path(WPATH("C:\\foo\\bar")));
VERIFY( res == WFMT("C:/foo/bar") );
}
}
void
test_format_invalid()
{
if constexpr (std::is_same_v<path::value_type, char>)
{
std::wstring res;
std::string_view seq = "\xf0\x9f\xa6\x84"; // \U0001F984
path p(seq.substr(1));
res = std::format(L"{}", p);
VERIFY( res == L"\uFFFD\uFFFD\uFFFD" );
res = std::format(L"{:?}", p);
VERIFY( res == LR"("\x{9f}\x{a6}\x{84}")" );
}
else
{
std::string res;
path p(L"\xd800");
res = std::format("{}", p);
VERIFY( res == "\uFFFD" );
res = std::format("{:?}", p);
VERIFY( res == "\"\\x{d800}\"" );
path p2(L"///\xd800");
res = std::format("{}", p2);
VERIFY( res == "///\uFFFD" );
res = std::format("{:g}", p2);
VERIFY( res == "/\uFFFD" );
res = std::format("{:?}", p2);
VERIFY( res == "\"///\\x{d800}\"" );
res = std::format("{:?g}", p2);
VERIFY( res == "\"/\\x{d800}\"" );
res = std::format("{:C>14?g}", p2);
VERIFY( res == "CCC\"/\\x{d800}\"" );
}
}
int main()
{
test_format_spec();
test_format<char, char>();
test_format<char, wchar_t>();
test_format<wchar_t, char>();
test_format<wchar_t, wchar_t>();
test_format_invalid();
}