[libc++][format] Adds bool formatter.
Implements the formatter for Boolean types. [format.formatter.spec]/2.3 For each charT, for each cv-unqualified arithmetic type ArithmeticT other than char, wchar_t, char8_t, char16_t, or char32_t, a specialization ``` template<> struct formatter<ArithmeticT, charT>; ``` This removes the stub implemented in D96664. Implements parts of: - P0645 Text Formatting - P1652 Printf corner cases in std::format Completes: - P1868 width: clarifying units of width and precision in std::format Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D103670
This commit is contained in:
parent
49e736d845
commit
7fb9f99f3b
|
@ -171,7 +171,7 @@
|
|||
"`P1460 <https://wg21.link/P1460>`__","LWG","Mandating the Standard Library: Clause 20 - Utilities library","Prague","* *",""
|
||||
"`P1739 <https://wg21.link/P1739>`__","LWG","Avoid template bloat for safe_ranges in combination with ""subrange-y"" view adaptors","Prague","* *",""
|
||||
"`P1831 <https://wg21.link/P1831>`__","LWG","Deprecating volatile: library","Prague","* *",""
|
||||
"`P1868 <https://wg21.link/P1868>`__","LWG","width: clarifying units of width and precision in std::format","Prague","|In Progress|",""
|
||||
"`P1868 <https://wg21.link/P1868>`__","LWG","width: clarifying units of width and precision in std::format","Prague","|Complete|","14.0"
|
||||
"`P1908 <https://wg21.link/P1908>`__","CWG","Reserving Attribute Namespaces for Future Use","Prague","* *",""
|
||||
"`P1937 <https://wg21.link/P1937>`__","CWG","Fixing inconsistencies between constexpr and consteval functions","Prague","* *",""
|
||||
"`P1956 <https://wg21.link/P1956>`__","LWG","On the names of low-level bit manipulation functions","Prague","|Complete|","12.0"
|
||||
|
|
|
|
@ -140,6 +140,7 @@ set(files
|
|||
__format/format_parse_context.h
|
||||
__format/format_string.h
|
||||
__format/formatter.h
|
||||
__format/formatter_bool.h
|
||||
__format/formatter_char.h
|
||||
__format/formatter_integer.h
|
||||
__format/formatter_integral.h
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 _LIBCPP___FORMAT_FORMATTER_BOOL_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_BOOL_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__config>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_integral.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <string_view>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
|
||||
// TODO FMT Remove this once we require compilers with proper C++20 support.
|
||||
// If the compiler has no concepts support, the format header will be disabled.
|
||||
// Without concepts support enable_if needs to be used and that too much effort
|
||||
// to support compilers with partial C++20 support.
|
||||
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
namespace __format_spec {
|
||||
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __parser_bool : public __parser_integral<_CharT> {
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx)
|
||||
-> decltype(__parse_ctx.begin()) {
|
||||
auto __it = __parser_integral<_CharT>::__parse(__parse_ctx);
|
||||
|
||||
switch (this->__type) {
|
||||
case _Flags::_Type::__default:
|
||||
this->__type = _Flags::_Type::__string;
|
||||
[[fallthrough]];
|
||||
case _Flags::_Type::__string:
|
||||
this->__handle_bool();
|
||||
break;
|
||||
|
||||
case _Flags::_Type::__char:
|
||||
this->__handle_char();
|
||||
break;
|
||||
|
||||
case _Flags::_Type::__binary_lower_case:
|
||||
case _Flags::_Type::__binary_upper_case:
|
||||
case _Flags::_Type::__octal:
|
||||
case _Flags::_Type::__decimal:
|
||||
case _Flags::_Type::__hexadecimal_lower_case:
|
||||
case _Flags::_Type::__hexadecimal_upper_case:
|
||||
this->__handle_integer();
|
||||
break;
|
||||
|
||||
default:
|
||||
__throw_format_error(
|
||||
"The format-spec type has a type not supported for a bool argument");
|
||||
}
|
||||
|
||||
return __it;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings;
|
||||
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
|
||||
static constexpr string_view __true{"true"};
|
||||
static constexpr string_view __false{"false"};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
|
||||
static constexpr wstring_view __true{L"true"};
|
||||
static constexpr wstring_view __false{L"false"};
|
||||
};
|
||||
|
||||
template <class _CharT>
|
||||
using __formatter_bool = __formatter_integral<__parser_bool<_CharT>>;
|
||||
|
||||
} //namespace __format_spec
|
||||
|
||||
// [format.formatter.spec]/2.3
|
||||
// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
|
||||
// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
|
||||
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<bool, _CharT>
|
||||
: public __format_spec::__formatter_bool<_CharT> {
|
||||
using _Base = __format_spec::__formatter_bool<_CharT>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI auto format(bool __value, auto& __ctx)
|
||||
-> decltype(__ctx.out()) {
|
||||
if (this->__type != __format_spec::_Flags::_Type::__string)
|
||||
return _Base::format(static_cast<unsigned char>(__value), __ctx);
|
||||
|
||||
if (this->__width_needs_substitution())
|
||||
this->__substitute_width_arg_id(__ctx.arg(this->__width));
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
if (this->__locale_specific_form) {
|
||||
const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
|
||||
basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
|
||||
return __formatter::__write_unicode(
|
||||
__ctx.out(), basic_string_view<_CharT>{__str}, this->__width, -1,
|
||||
this->__fill, this->__alignment);
|
||||
}
|
||||
#endif
|
||||
basic_string_view<_CharT> __str =
|
||||
__value ? __format_spec::__bool_strings<_CharT>::__true
|
||||
: __format_spec::__bool_strings<_CharT>::__false;
|
||||
|
||||
// The output only uses ASCII so every character is one column.
|
||||
unsigned __size = __str.size();
|
||||
if (__size >= this->__width)
|
||||
return _VSTD::copy(__str.begin(), __str.end(), __ctx.out());
|
||||
|
||||
return __formatter::__write(__ctx.out(), __str.begin(), __str.end(), __size,
|
||||
this->__width, this->__fill, this->__alignment);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
|
|
@ -279,6 +279,7 @@ namespace std {
|
|||
#include <__format/format_parse_context.h>
|
||||
#include <__format/format_string.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_bool.h>
|
||||
#include <__format/formatter_char.h>
|
||||
#include <__format/formatter_integer.h>
|
||||
#include <__format/formatter_string.h>
|
||||
|
@ -389,28 +390,6 @@ private:
|
|||
// These specializations are helper stubs and not proper formatters.
|
||||
// TODO FMT Implement the proper formatter specializations.
|
||||
|
||||
// [format.formatter.spec]/2.3
|
||||
// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
|
||||
// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
|
||||
|
||||
// Boolean.
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
|
||||
// TODO FMT Implement
|
||||
return __parse_ctx.begin();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
auto format(bool __b, auto& __ctx) -> decltype(__ctx.out()) {
|
||||
// TODO FMT Implement using formatting arguments
|
||||
auto __out_it = __ctx.out();
|
||||
*__out_it++ = _CharT('0') + __b;
|
||||
return __out_it;
|
||||
}
|
||||
};
|
||||
|
||||
// Floating point types.
|
||||
// TODO FMT There are no replacements for the floating point stubs due to not
|
||||
// having floating point support in std::to_chars yet. These stubs aren't
|
||||
|
|
|
@ -450,6 +450,7 @@ module std [system] {
|
|||
module format_parse_context { private header "__format/format_parse_context.h" }
|
||||
module format_string { private header "__format/format_string.h" }
|
||||
module formatter { private header "__format/formatter.h" }
|
||||
module formatter_bool { private header "__format/formatter_bool.h" }
|
||||
module formatter_char { private header "__format/formatter_char.h" }
|
||||
module formatter_integer { private header "__format/formatter_integer.h" }
|
||||
module formatter_integral { private header "__format/formatter_integral.h" }
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__format/formatter_bool.h'}}
|
||||
#include <__format/formatter_bool.h>
|
|
@ -0,0 +1,452 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// <format>
|
||||
|
||||
// Tests the parsing of the format string as specified in [format.string.std].
|
||||
// It validates whether the std-format-spec is valid for a boolean type.
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include "concepts_precision.h"
|
||||
#include "test_macros.h"
|
||||
#include "make_string.h"
|
||||
#include "test_exception.h"
|
||||
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
using namespace std::__format_spec;
|
||||
|
||||
template <class CharT>
|
||||
using Parser = __parser_bool<CharT>;
|
||||
|
||||
template <class CharT>
|
||||
struct Expected {
|
||||
CharT fill = CharT(' ');
|
||||
_Flags::_Alignment alignment = _Flags::_Alignment::__left;
|
||||
_Flags::_Sign sign = _Flags::_Sign::__default;
|
||||
bool alternate_form = false;
|
||||
bool zero_padding = false;
|
||||
uint32_t width = 0;
|
||||
bool width_as_arg = false;
|
||||
bool locale_specific_form = false;
|
||||
_Flags::_Type type = _Flags::_Type::__string;
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(Expected<CharT> expected, size_t size,
|
||||
std::basic_string_view<CharT> fmt) {
|
||||
// Initialize parser with sufficient arguments to avoid the parsing to fail
|
||||
// due to insufficient arguments.
|
||||
std::basic_format_parse_context<CharT> parse_ctx(fmt,
|
||||
std::__format::__number_max);
|
||||
auto begin = parse_ctx.begin();
|
||||
auto end = parse_ctx.end();
|
||||
Parser<CharT> parser;
|
||||
auto it = parser.parse(parse_ctx);
|
||||
|
||||
assert(begin == parse_ctx.begin());
|
||||
assert(end == parse_ctx.end());
|
||||
|
||||
assert(begin + size == it);
|
||||
assert(parser.__fill == expected.fill);
|
||||
assert(parser.__alignment == expected.alignment);
|
||||
assert(parser.__sign == expected.sign);
|
||||
assert(parser.__alternate_form == expected.alternate_form);
|
||||
assert(parser.__zero_padding == expected.zero_padding);
|
||||
assert(parser.__width == expected.width);
|
||||
assert(parser.__width_as_arg == expected.width_as_arg);
|
||||
assert(parser.__locale_specific_form == expected.locale_specific_form);
|
||||
assert(parser.__type == expected.type);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(Expected<CharT> expected, size_t size, const CharT* f) {
|
||||
// The format-spec is valid if completely consumed or terminates at a '}'.
|
||||
// The valid inputs all end with a '}'. The test is executed twice:
|
||||
// - first with the terminating '}',
|
||||
// - second consuming the entire input.
|
||||
std::basic_string_view<CharT> fmt{f};
|
||||
assert(fmt.back() == CharT('}') && "Pre-condition failure");
|
||||
|
||||
test(expected, size, fmt);
|
||||
fmt.remove_suffix(1);
|
||||
test(expected, size, fmt);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_as_string() {
|
||||
|
||||
test({}, 1, CSTR("s}"));
|
||||
|
||||
// *** Align-fill ***
|
||||
test({.alignment = _Flags::_Alignment::__left}, 1, CSTR("<}"));
|
||||
test({.alignment = _Flags::_Alignment::__center}, 1, "^}");
|
||||
test({.alignment = _Flags::_Alignment::__right}, 1, ">}");
|
||||
|
||||
test({.alignment = _Flags::_Alignment::__left}, 2, CSTR("<s}"));
|
||||
test({.alignment = _Flags::_Alignment::__center}, 2, "^s}");
|
||||
test({.alignment = _Flags::_Alignment::__right}, 2, ">s}");
|
||||
|
||||
test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 2,
|
||||
CSTR("L<}"));
|
||||
test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 2,
|
||||
CSTR("#^}"));
|
||||
test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 2,
|
||||
CSTR("0>}"));
|
||||
|
||||
test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 3,
|
||||
CSTR("L<s}"));
|
||||
test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 3,
|
||||
CSTR("#^s}"));
|
||||
test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 3,
|
||||
CSTR("0>s}"));
|
||||
|
||||
// *** Sign ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"A sign field isn't allowed in this format-spec", CSTR("-}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A sign field isn't allowed in this format-spec", CSTR("-s}"));
|
||||
|
||||
// *** Alternate form ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"An alternate form field isn't allowed in this format-spec", CSTR("#}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"An alternate form field isn't allowed in this format-spec", CSTR("#s}"));
|
||||
|
||||
// *** Zero padding ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"A zero-padding field isn't allowed in this format-spec", CSTR("0}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A zero-padding field isn't allowed in this format-spec", CSTR("0s}"));
|
||||
|
||||
// *** Width ***
|
||||
test({.width = 0, .width_as_arg = false}, 0, CSTR("}"));
|
||||
test({.width = 1, .width_as_arg = false}, 1, CSTR("1}"));
|
||||
test({.width = 10, .width_as_arg = false}, 2, CSTR("10}"));
|
||||
test({.width = 1000, .width_as_arg = false}, 4, CSTR("1000}"));
|
||||
test({.width = 1000000, .width_as_arg = false}, 7, CSTR("1000000}"));
|
||||
|
||||
test({.width = 0, .width_as_arg = true}, 2, CSTR("{}}"));
|
||||
test({.width = 0, .width_as_arg = true}, 3, CSTR("{0}}"));
|
||||
test({.width = 1, .width_as_arg = true}, 3, CSTR("{1}}"));
|
||||
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec width field shouldn't have a leading zero", CSTR("00"));
|
||||
|
||||
static_assert(std::__format::__number_max == 2'147'483'647,
|
||||
"Update the assert and the test.");
|
||||
test({.width = 2'147'483'647, .width_as_arg = false}, 10,
|
||||
CSTR("2147483647}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large", CSTR("2147483648"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large", CSTR("5000000000"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large", CSTR("10000000000"));
|
||||
|
||||
test_exception<Parser<CharT>>("End of input while parsing format-spec arg-id",
|
||||
CSTR("{"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec arg-id should terminate at a '}'", CSTR("{0"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The arg-id of the format-spec starts with an invalid character",
|
||||
CSTR("{a"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec arg-id should terminate at a '}'", CSTR("{1"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec arg-id should terminate at a '}'", CSTR("{9"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec arg-id should terminate at a '}'", CSTR("{9:"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"A format-spec arg-id should terminate at a '}'", CSTR("{9a"));
|
||||
|
||||
static_assert(std::__format::__number_max == 2'147'483'647,
|
||||
"Update the assert and the test.");
|
||||
// Note the static_assert tests whether the arg-id is valid.
|
||||
// Therefore the following should be true arg-id < __format::__number_max.
|
||||
test({.width = 2'147'483'646, .width_as_arg = true}, 12,
|
||||
CSTR("{2147483646}}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large",
|
||||
CSTR("{2147483648}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large",
|
||||
CSTR("{5000000000}"));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The numeric value of the format-spec is too large",
|
||||
CSTR("{10000000000}"));
|
||||
|
||||
// *** Precision ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR("."));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR(".1"));
|
||||
|
||||
// *** Locale-specific form ***
|
||||
test({.locale_specific_form = true}, 1, CSTR("L}"));
|
||||
test({.locale_specific_form = true}, 2, CSTR("Ls}"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_as_char() {
|
||||
|
||||
test({.type = _Flags::_Type::__char}, 1, CSTR("c}"));
|
||||
|
||||
// *** Align-fill ***
|
||||
test({.alignment = _Flags::_Alignment::__left, .type = _Flags::_Type::__char},
|
||||
2, CSTR("<c}"));
|
||||
test({.alignment = _Flags::_Alignment::__center,
|
||||
.type = _Flags::_Type::__char},
|
||||
2, "^c}");
|
||||
test(
|
||||
{.alignment = _Flags::_Alignment::__right, .type = _Flags::_Type::__char},
|
||||
2, ">c}");
|
||||
|
||||
test({.fill = CharT('L'),
|
||||
.alignment = _Flags::_Alignment::__left,
|
||||
.type = _Flags::_Type::__char},
|
||||
3, CSTR("L<c}"));
|
||||
test({.fill = CharT('#'),
|
||||
.alignment = _Flags::_Alignment::__center,
|
||||
.type = _Flags::_Type::__char},
|
||||
3, CSTR("#^c}"));
|
||||
test({.fill = CharT('0'),
|
||||
.alignment = _Flags::_Alignment::__right,
|
||||
.type = _Flags::_Type::__char},
|
||||
3, CSTR("0>c}"));
|
||||
|
||||
// *** Sign ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"A sign field isn't allowed in this format-spec", CSTR("-c}"));
|
||||
|
||||
// *** Alternate form ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"An alternate form field isn't allowed in this format-spec", CSTR("#c}"));
|
||||
|
||||
// *** Zero padding ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"A zero-padding field isn't allowed in this format-spec", CSTR("0c}"));
|
||||
|
||||
// *** Width ***
|
||||
test({.width = 0, .width_as_arg = false, .type = _Flags::_Type::__char}, 1,
|
||||
CSTR("c}"));
|
||||
test({.width = 1, .width_as_arg = false, .type = _Flags::_Type::__char}, 2,
|
||||
CSTR("1c}"));
|
||||
test({.width = 10, .width_as_arg = false, .type = _Flags::_Type::__char}, 3,
|
||||
CSTR("10c}"));
|
||||
test({.width = 1000, .width_as_arg = false, .type = _Flags::_Type::__char}, 5,
|
||||
CSTR("1000c}"));
|
||||
test({.width = 1000000, .width_as_arg = false, .type = _Flags::_Type::__char},
|
||||
8, CSTR("1000000c}"));
|
||||
|
||||
test({.width = 0, .width_as_arg = true, .type = _Flags::_Type::__char}, 3,
|
||||
CSTR("{}c}"));
|
||||
test({.width = 0, .width_as_arg = true, .type = _Flags::_Type::__char}, 4,
|
||||
CSTR("{0}c}"));
|
||||
test({.width = 1, .width_as_arg = true, .type = _Flags::_Type::__char}, 4,
|
||||
CSTR("{1}c}"));
|
||||
|
||||
// *** Precision ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR("."));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR(".1"));
|
||||
|
||||
// *** Locale-specific form ***
|
||||
test({.locale_specific_form = true, .type = _Flags::_Type::__char}, 2,
|
||||
CSTR("Lc}"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_as_integer() {
|
||||
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
1, CSTR("d}"));
|
||||
|
||||
// *** Align-fill ***
|
||||
test({.alignment = _Flags::_Alignment::__left,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("<d}"));
|
||||
test({.alignment = _Flags::_Alignment::__center,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, "^d}");
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, ">d}");
|
||||
|
||||
test({.fill = CharT('L'),
|
||||
.alignment = _Flags::_Alignment::__left,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("L<d}"));
|
||||
test({.fill = CharT('#'),
|
||||
.alignment = _Flags::_Alignment::__center,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("#^d}"));
|
||||
test({.fill = CharT('0'),
|
||||
.alignment = _Flags::_Alignment::__right,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("0>d}"));
|
||||
|
||||
// *** Sign ***
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.sign = _Flags::_Sign::__minus,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("-d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.sign = _Flags::_Sign::__plus,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("+d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.sign = _Flags::_Sign::__space,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR(" d}"));
|
||||
|
||||
// *** Alternate form ***
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.alternate_form = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("#d}"));
|
||||
|
||||
// *** Zero padding ***
|
||||
test({.alignment = _Flags::_Alignment::__default,
|
||||
.zero_padding = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("0d}"));
|
||||
test({.alignment = _Flags::_Alignment::__center,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("^0d}"));
|
||||
|
||||
// *** Width ***
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 0,
|
||||
.width_as_arg = false,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
1, CSTR("d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 1,
|
||||
.width_as_arg = false,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("1d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 10,
|
||||
.width_as_arg = false,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("10d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 1000,
|
||||
.width_as_arg = false,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
5, CSTR("1000d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 1000000,
|
||||
.width_as_arg = false,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
8, CSTR("1000000d}"));
|
||||
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 0,
|
||||
.width_as_arg = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
3, CSTR("{}d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 0,
|
||||
.width_as_arg = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
4, CSTR("{0}d}"));
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.width = 1,
|
||||
.width_as_arg = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
4, CSTR("{1}d}"));
|
||||
|
||||
// *** Precision ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR("."));
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR(".1"));
|
||||
|
||||
// *** Locale-specific form ***
|
||||
test({.alignment = _Flags::_Alignment::__right,
|
||||
.locale_specific_form = true,
|
||||
.type = _Flags::_Type::__decimal},
|
||||
2, CSTR("Ld}"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test() {
|
||||
Parser<CharT> parser;
|
||||
|
||||
assert(parser.__fill == CharT(' '));
|
||||
assert(parser.__alignment == _Flags::_Alignment::__default);
|
||||
assert(parser.__sign == _Flags::_Sign::__default);
|
||||
assert(parser.__alternate_form == false);
|
||||
assert(parser.__zero_padding == false);
|
||||
assert(parser.__width == 0);
|
||||
assert(parser.__width_as_arg == false);
|
||||
static_assert(!has_precision<decltype(parser)>);
|
||||
static_assert(!has_precision_as_arg<decltype(parser)>);
|
||||
assert(parser.__locale_specific_form == false);
|
||||
assert(parser.__type == _Flags::_Type::__default);
|
||||
|
||||
test({}, 0, CSTR("}"));
|
||||
|
||||
test_as_string<CharT>();
|
||||
test_as_char<CharT>();
|
||||
test_as_integer<CharT>();
|
||||
|
||||
// *** Type ***
|
||||
{
|
||||
const char* expected =
|
||||
"The format-spec type has a type not supported for a bool argument";
|
||||
test_exception<Parser<CharT>>(expected, CSTR("A}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("E}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("F}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("G}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("a}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("e}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("f}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("g}"));
|
||||
test_exception<Parser<CharT>>(expected, CSTR("p}"));
|
||||
}
|
||||
|
||||
// **** General ***
|
||||
test_exception<Parser<CharT>>(
|
||||
"The format-spec should consume the input or end with a '}'", CSTR("ss"));
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<char>();
|
||||
test<wchar_t>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
#ifndef _WIN32
|
||||
// Make sure the parsers match the expectations. The layout of the
|
||||
// subobjects is chosen to minimize the size required.
|
||||
static_assert(sizeof(Parser<char>) == 2 * sizeof(uint32_t));
|
||||
static_assert(
|
||||
sizeof(Parser<wchar_t>) ==
|
||||
(sizeof(wchar_t) <= 2 ? 2 * sizeof(uint32_t) : 3 * sizeof(uint32_t)));
|
||||
#endif
|
||||
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -67,8 +67,8 @@ void test_termination_condition(StringT expected, StringT f, bool arg) {
|
|||
|
||||
template <class CharT>
|
||||
void test_boolean() {
|
||||
test_termination_condition(STR("1"), STR("}"), true);
|
||||
test_termination_condition(STR("0"), STR("}"), false);
|
||||
test_termination_condition(STR("true"), STR("}"), true);
|
||||
test_termination_condition(STR("false"), STR("}"), false);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)
|
||||
|
||||
#define STR(S) MAKE_STRING(CharT, S)
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
std::vector<std::basic_string<CharT>> invalid_types(std::string valid) {
|
||||
|
@ -260,6 +261,238 @@ void format_string_tests(TestFunction check, ExceptionTest check_exception) {
|
|||
format_test_string_unicode<CharT>(check);
|
||||
}
|
||||
|
||||
template <class CharT, class TestFunction, class ExceptionTest>
|
||||
void format_test_bool(TestFunction check, ExceptionTest check_exception) {
|
||||
|
||||
// *** align-fill & width ***
|
||||
check(STR("answer is 'true '"), STR("answer is '{:7}'"), true);
|
||||
check(STR("answer is ' true'"), STR("answer is '{:>7}'"), true);
|
||||
check(STR("answer is 'true '"), STR("answer is '{:<7}'"), true);
|
||||
check(STR("answer is ' true '"), STR("answer is '{:^7}'"), true);
|
||||
|
||||
check(STR("answer is 'false '"), STR("answer is '{:8s}'"), false);
|
||||
check(STR("answer is ' false'"), STR("answer is '{:>8s}'"), false);
|
||||
check(STR("answer is 'false '"), STR("answer is '{:<8s}'"), false);
|
||||
check(STR("answer is ' false '"), STR("answer is '{:^8s}'"), false);
|
||||
|
||||
check(STR("answer is '---true'"), STR("answer is '{:->7}'"), true);
|
||||
check(STR("answer is 'true---'"), STR("answer is '{:-<7}'"), true);
|
||||
check(STR("answer is '-true--'"), STR("answer is '{:-^7}'"), true);
|
||||
|
||||
check(STR("answer is '---false'"), STR("answer is '{:->8s}'"), false);
|
||||
check(STR("answer is 'false---'"), STR("answer is '{:-<8s}'"), false);
|
||||
check(STR("answer is '-false--'"), STR("answer is '{:-^8s}'"), false);
|
||||
|
||||
// *** Sign ***
|
||||
check_exception("A sign field isn't allowed in this format-spec", STR("{:-}"),
|
||||
true);
|
||||
check_exception("A sign field isn't allowed in this format-spec", STR("{:+}"),
|
||||
true);
|
||||
check_exception("A sign field isn't allowed in this format-spec", STR("{: }"),
|
||||
true);
|
||||
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{:-s}"), true);
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{:+s}"), true);
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{: s}"), true);
|
||||
|
||||
// *** alternate form ***
|
||||
check_exception("An alternate form field isn't allowed in this format-spec",
|
||||
STR("{:#}"), true);
|
||||
check_exception("An alternate form field isn't allowed in this format-spec",
|
||||
STR("{:#s}"), true);
|
||||
|
||||
// *** zero-padding ***
|
||||
check_exception("A zero-padding field isn't allowed in this format-spec",
|
||||
STR("{:0}"), true);
|
||||
check_exception("A zero-padding field isn't allowed in this format-spec",
|
||||
STR("{:0s}"), true);
|
||||
|
||||
// *** precision ***
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.0}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.42}"), true);
|
||||
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.s}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.0s}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.42s}"), true);
|
||||
|
||||
// *** locale-specific form ***
|
||||
// See locale-specific_form.pass.cpp
|
||||
|
||||
// *** type ***
|
||||
for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
|
||||
check_exception(
|
||||
"The format-spec type has a type not supported for a bool argument",
|
||||
fmt, true);
|
||||
}
|
||||
|
||||
template <class CharT, class TestFunction, class ExceptionTest>
|
||||
void format_test_bool_as_char(TestFunction check,
|
||||
ExceptionTest check_exception) {
|
||||
// *** align-fill & width ***
|
||||
check(STR("answer is '\1 '"), STR("answer is '{:6c}'"), true);
|
||||
check(STR("answer is ' \1'"), STR("answer is '{:>6c}'"), true);
|
||||
check(STR("answer is '\1 '"), STR("answer is '{:<6c}'"), true);
|
||||
check(STR("answer is ' \1 '"), STR("answer is '{:^6c}'"), true);
|
||||
|
||||
check(STR("answer is '-----\1'"), STR("answer is '{:->6c}'"), true);
|
||||
check(STR("answer is '\1-----'"), STR("answer is '{:-<6c}'"), true);
|
||||
check(STR("answer is '--\1---'"), STR("answer is '{:-^6c}'"), true);
|
||||
|
||||
check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
|
||||
STR("answer is '{:6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
|
||||
STR("answer is '{:6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is ' \0'"), 18),
|
||||
STR("answer is '{:>6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is '\0 '"), 18),
|
||||
STR("answer is '{:<6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is ' \0 '"), 18),
|
||||
STR("answer is '{:^6c}'"), false);
|
||||
|
||||
check(std::basic_string<CharT>(CSTR("answer is '-----\0'"), 18),
|
||||
STR("answer is '{:->6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is '\0-----'"), 18),
|
||||
STR("answer is '{:-<6c}'"), false);
|
||||
check(std::basic_string<CharT>(CSTR("answer is '--\0---'"), 18),
|
||||
STR("answer is '{:-^6c}'"), false);
|
||||
|
||||
// *** Sign ***
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{:-c}"), true);
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{:+c}"), true);
|
||||
check_exception("A sign field isn't allowed in this format-spec",
|
||||
STR("{: c}"), true);
|
||||
|
||||
// *** alternate form ***
|
||||
check_exception("An alternate form field isn't allowed in this format-spec",
|
||||
STR("{:#c}"), true);
|
||||
|
||||
// *** zero-padding ***
|
||||
check_exception("A zero-padding field isn't allowed in this format-spec",
|
||||
STR("{:0c}"), true);
|
||||
|
||||
// *** precision ***
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.c}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.0c}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.42c}"), true);
|
||||
|
||||
// *** locale-specific form ***
|
||||
// Note it has no effect but it's allowed.
|
||||
check(STR("answer is '*'"), STR("answer is '{:Lc}'"), '*');
|
||||
|
||||
// *** type ***
|
||||
for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
|
||||
check_exception(
|
||||
"The format-spec type has a type not supported for a bool argument",
|
||||
fmt, true);
|
||||
}
|
||||
|
||||
template <class CharT, class TestFunction, class ExceptionTest>
|
||||
void format_test_bool_as_integer(TestFunction check,
|
||||
ExceptionTest check_exception) {
|
||||
// *** align-fill & width ***
|
||||
check(STR("answer is '1'"), STR("answer is '{:<1d}'"), true);
|
||||
check(STR("answer is '1 '"), STR("answer is '{:<2d}'"), true);
|
||||
check(STR("answer is '0 '"), STR("answer is '{:<2d}'"), false);
|
||||
|
||||
check(STR("answer is ' 1'"), STR("answer is '{:6d}'"), true);
|
||||
check(STR("answer is ' 1'"), STR("answer is '{:>6d}'"), true);
|
||||
check(STR("answer is '1 '"), STR("answer is '{:<6d}'"), true);
|
||||
check(STR("answer is ' 1 '"), STR("answer is '{:^6d}'"), true);
|
||||
|
||||
check(STR("answer is '*****0'"), STR("answer is '{:*>6d}'"), false);
|
||||
check(STR("answer is '0*****'"), STR("answer is '{:*<6d}'"), false);
|
||||
check(STR("answer is '**0***'"), STR("answer is '{:*^6d}'"), false);
|
||||
|
||||
// Test whether zero padding is ignored
|
||||
check(STR("answer is ' 1'"), STR("answer is '{:>06d}'"), true);
|
||||
check(STR("answer is '1 '"), STR("answer is '{:<06d}'"), true);
|
||||
check(STR("answer is ' 1 '"), STR("answer is '{:^06d}'"), true);
|
||||
|
||||
// *** Sign ***
|
||||
check(STR("answer is 1"), STR("answer is {:d}"), true);
|
||||
check(STR("answer is 0"), STR("answer is {:-d}"), false);
|
||||
check(STR("answer is +1"), STR("answer is {:+d}"), true);
|
||||
check(STR("answer is 0"), STR("answer is {: d}"), false);
|
||||
|
||||
// *** alternate form ***
|
||||
check(STR("answer is +1"), STR("answer is {:+#d}"), true);
|
||||
check(STR("answer is +1"), STR("answer is {:+b}"), true);
|
||||
check(STR("answer is +0b1"), STR("answer is {:+#b}"), true);
|
||||
check(STR("answer is +0B1"), STR("answer is {:+#B}"), true);
|
||||
check(STR("answer is +1"), STR("answer is {:+o}"), true);
|
||||
check(STR("answer is +01"), STR("answer is {:+#o}"), true);
|
||||
check(STR("answer is +1"), STR("answer is {:+x}"), true);
|
||||
check(STR("answer is +0x1"), STR("answer is {:+#x}"), true);
|
||||
check(STR("answer is +1"), STR("answer is {:+X}"), true);
|
||||
check(STR("answer is +0X1"), STR("answer is {:+#X}"), true);
|
||||
|
||||
check(STR("answer is 0"), STR("answer is {:#d}"), false);
|
||||
check(STR("answer is 0"), STR("answer is {:b}"), false);
|
||||
check(STR("answer is 0b0"), STR("answer is {:#b}"), false);
|
||||
check(STR("answer is 0B0"), STR("answer is {:#B}"), false);
|
||||
check(STR("answer is 0"), STR("answer is {:o}"), false);
|
||||
check(STR("answer is 0"), STR("answer is {:#o}"), false);
|
||||
check(STR("answer is 0"), STR("answer is {:x}"), false);
|
||||
check(STR("answer is 0x0"), STR("answer is {:#x}"), false);
|
||||
check(STR("answer is 0"), STR("answer is {:X}"), false);
|
||||
check(STR("answer is 0X0"), STR("answer is {:#X}"), false);
|
||||
|
||||
// *** zero-padding & width ***
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+#012d}"), true);
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+012b}"), true);
|
||||
check(STR("answer is +0b000000001"), STR("answer is {:+#012b}"), true);
|
||||
check(STR("answer is +0B000000001"), STR("answer is {:+#012B}"), true);
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+012o}"), true);
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+#012o}"), true);
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+012x}"), true);
|
||||
check(STR("answer is +0x000000001"), STR("answer is {:+#012x}"), true);
|
||||
check(STR("answer is +00000000001"), STR("answer is {:+012X}"), true);
|
||||
check(STR("answer is +0X000000001"), STR("answer is {:+#012X}"), true);
|
||||
|
||||
check(STR("answer is 000000000000"), STR("answer is {:#012d}"), false);
|
||||
check(STR("answer is 000000000000"), STR("answer is {:012b}"), false);
|
||||
check(STR("answer is 0b0000000000"), STR("answer is {:#012b}"), false);
|
||||
check(STR("answer is 0B0000000000"), STR("answer is {:#012B}"), false);
|
||||
check(STR("answer is 000000000000"), STR("answer is {:012o}"), false);
|
||||
check(STR("answer is 000000000000"), STR("answer is {:#012o}"), false);
|
||||
check(STR("answer is 000000000000"), STR("answer is {:012x}"), false);
|
||||
check(STR("answer is 0x0000000000"), STR("answer is {:#012x}"), false);
|
||||
check(STR("answer is 000000000000"), STR("answer is {:012X}"), false);
|
||||
check(STR("answer is 0X0000000000"), STR("answer is {:#012X}"), false);
|
||||
|
||||
// *** precision ***
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.0}"), true);
|
||||
check_exception("The format-spec should consume the input or end with a '}'",
|
||||
STR("{:.42}"), true);
|
||||
|
||||
// *** locale-specific form ***
|
||||
// See locale-specific_form.pass.cpp
|
||||
|
||||
// *** type ***
|
||||
for (const auto& fmt : invalid_types<CharT>("bBcdosxX"))
|
||||
check_exception(
|
||||
"The format-spec type has a type not supported for a bool argument",
|
||||
fmt, true);
|
||||
}
|
||||
|
||||
template <class I, class CharT, class TestFunction, class ExceptionTest>
|
||||
void format_test_integer_as_integer(TestFunction check,
|
||||
ExceptionTest check_exception) {
|
||||
|
@ -743,8 +976,8 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
|
|||
check(STR("}"), STR("}}"));
|
||||
|
||||
// *** Test argument ID ***
|
||||
check(STR("hello 01"), STR("hello {0:}{1:}"), false, true);
|
||||
check(STR("hello 10"), STR("hello {1:}{0:}"), false, true);
|
||||
check(STR("hello false true"), STR("hello {0:} {1:}"), false, true);
|
||||
check(STR("hello true false"), STR("hello {1:} {0:}"), false, true);
|
||||
|
||||
// ** Test invalid format strings ***
|
||||
check_exception("The format string terminates at a '{'", STR("{"));
|
||||
|
@ -799,7 +1032,11 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
|
|||
format_string_tests<CharT>(check, check_exception);
|
||||
|
||||
// *** Test Boolean format argument ***
|
||||
check(STR("hello 01"), STR("hello {}{}"), false, true);
|
||||
check(STR("hello false true"), STR("hello {} {}"), false, true);
|
||||
|
||||
format_test_bool<CharT>(check, check_exception);
|
||||
format_test_bool_as_char<CharT>(check, check_exception);
|
||||
format_test_bool_as_integer<CharT>(check, check_exception);
|
||||
|
||||
// *** Test signed integral format argument ***
|
||||
check(STR("hello 42"), STR("hello {}"), static_cast<signed char>(42));
|
||||
|
|
|
@ -56,8 +56,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
|
|||
CharT out[4096];
|
||||
CharT* it = std::format_to(out, std::locale(), fmt, args...);
|
||||
assert(std::distance(out, it) == int(expected.size()));
|
||||
*it = '\0';
|
||||
assert(out == expected);
|
||||
// Convert to std::string since output contains '\0' for boolean tests.
|
||||
assert(std::basic_string<CharT>(out, it) == expected);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
|
|||
CharT out[4096];
|
||||
CharT* it = std::format_to(out, fmt, args...);
|
||||
assert(std::distance(out, it) == int(expected.size()));
|
||||
*it = '\0';
|
||||
assert(out == expected);
|
||||
// Convert to std::string since output contains '\0' for boolean tests.
|
||||
assert(std::basic_string<CharT>(out, it) == expected);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -227,6 +227,56 @@ void test(std::basic_string<CharT> expected, std::locale loc,
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE
|
||||
template <class CharT>
|
||||
struct numpunct_unicode;
|
||||
|
||||
template <>
|
||||
struct numpunct_unicode<char> : std::numpunct<char> {
|
||||
string_type do_truename() const override { return "gültig"; }
|
||||
string_type do_falsename() const override { return "ungültig"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct numpunct_unicode<wchar_t> : std::numpunct<wchar_t> {
|
||||
string_type do_truename() const override { return L"gültig"; }
|
||||
string_type do_falsename() const override { return L"ungültig"; }
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class CharT>
|
||||
void test_bool() {
|
||||
std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
|
||||
|
||||
std::locale::global(std::locale(LOCALE_en_US_UTF_8));
|
||||
assert(std::locale().name() == LOCALE_en_US_UTF_8);
|
||||
test(STR("true"), STR("{:L}"), true);
|
||||
test(STR("false"), STR("{:L}"), false);
|
||||
|
||||
test(STR("yes"), loc, STR("{:L}"), true);
|
||||
test(STR("no"), loc, STR("{:L}"), false);
|
||||
|
||||
std::locale::global(loc);
|
||||
test(STR("yes"), STR("{:L}"), true);
|
||||
test(STR("no"), STR("{:L}"), false);
|
||||
|
||||
test(STR("true"), std::locale(LOCALE_en_US_UTF_8), STR("{:L}"), true);
|
||||
test(STR("false"), std::locale(LOCALE_en_US_UTF_8), STR("{:L}"), false);
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE
|
||||
std::locale loc_unicode =
|
||||
std::locale(std::locale(), new numpunct_unicode<CharT>());
|
||||
|
||||
test(STR("gültig"), loc_unicode, STR("{:L}"), true);
|
||||
test(STR("ungültig"), loc_unicode, STR("{:L}"), false);
|
||||
|
||||
test(STR("gültig "), loc_unicode, STR("{:9L}"), true);
|
||||
test(STR("gültig!!!"), loc_unicode, STR("{:!<9L}"), true);
|
||||
test(STR("_gültig__"), loc_unicode, STR("{:_^9L}"), true);
|
||||
test(STR(" gültig"), loc_unicode, STR("{:>9L}"), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void test_integer() {
|
||||
std::locale loc = std::locale(std::locale(), new numpunct<CharT>());
|
||||
|
@ -557,6 +607,7 @@ void test_integer() {
|
|||
|
||||
template <class CharT>
|
||||
void test() {
|
||||
test_bool<CharT>();
|
||||
test_integer<CharT>();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
|
|||
std::make_format_args<std::basic_format_context<CharT*, CharT>>(
|
||||
args...));
|
||||
assert(std::distance(out, it) == int(expected.size()));
|
||||
*it = '\0';
|
||||
assert(out == expected);
|
||||
// Convert to std::string since output contains '\0' for boolean tests.
|
||||
assert(std::basic_string<CharT>(out, it) == expected);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
|
|||
std::make_format_args<std::basic_format_context<CharT*, CharT>>(
|
||||
args...));
|
||||
assert(std::distance(out, it) == int(expected.size()));
|
||||
*it = '\0';
|
||||
assert(out == expected);
|
||||
// Convert to std::string since output contains '\0' for boolean tests.
|
||||
assert(std::basic_string<CharT>(out, it) == expected);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue