//===----------------------------------------------------------------------===//
// 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 TEST_STD_UTILITIES_FORMAT_FORMAT_FUNCTIONS_FORMAT_TESTS_H
#define TEST_STD_UTILITIES_FORMAT_FORMAT_FUNCTIONS_FORMAT_TESTS_H

#include <format>

#include <algorithm>
#include <cassert>
#include <charconv>
#include <cmath>
#include <cstdint>
#include <iterator>

#include "make_string.h"
#include "string_literal.h"
#include "test_macros.h"

// In this file the following template types are used:
// TestFunction must be callable as check(expected-result, string-to-format, args-to-format...)
// ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)

#define STR(S) MAKE_STRING(CharT, S)
#define SV(S) MAKE_STRING_VIEW(CharT, S)
#define CSTR(S) MAKE_CSTRING(CharT, S)

template <class T>
struct context {};

template <>
struct context<char> {
  using type = std::format_context;
};

#ifndef TEST_HAS_NO_WIDE_CHARACTERS
template <>
struct context<wchar_t> {
  using type = std::wformat_context;
};
#endif

template <class T>
using context_t = typename context<T>::type;

// A user-defined type used to test the handle formatter.
enum class status : uint16_t { foo = 0xAAAA, bar = 0x5555, foobar = 0xAA55 };

// The formatter for a user-defined type used to test the handle formatter.
template <class CharT>
struct std::formatter<status, CharT> {
  int type = 0;

  constexpr auto parse(basic_format_parse_context<CharT>& parse_ctx) -> decltype(parse_ctx.begin()) {
    auto begin = parse_ctx.begin();
    auto end = parse_ctx.end();
    if (begin == end)
      return begin;

    switch (*begin) {
    case CharT('x'):
      break;
    case CharT('X'):
      type = 1;
      break;
    case CharT('s'):
      type = 2;
      break;
    case CharT('}'):
      return begin;
    default:
      throw_format_error("The format-spec type has a type not supported for a status argument");
    }

    ++begin;
    if (begin != end && *begin != CharT('}'))
      throw_format_error("The format-spec should consume the input or end with a '}'");

    return begin;
  }

  template <class Out>
  auto format(status s, basic_format_context<Out, CharT>& ctx) -> decltype(ctx.out()) {
    const char* names[] = {"foo", "bar", "foobar"};
    char buffer[6];
    const char* begin;
    const char* end;
    switch (type) {
    case 0:
      begin = buffer;
      buffer[0] = '0';
      buffer[1] = 'x';
      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
      break;

    case 1:
      begin = buffer;
      buffer[0] = '0';
      buffer[1] = 'X';
      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
      std::transform(static_cast<const char*>(&buffer[2]), end, &buffer[2], [](char c) { return std::toupper(c); });
      break;

    case 2:
      switch (s) {
      case status::foo:
        begin = names[0];
        break;
      case status::bar:
        begin = names[1];
        break;
      case status::foobar:
        begin = names[2];
        break;
      }
      end = begin + strlen(begin);
      break;
    }

    return std::copy(begin, end, ctx.out());
  }

private:
  void throw_format_error(const char* s) {
#ifndef TEST_HAS_NO_EXCEPTIONS
    throw std::format_error(s);
#else
    (void)s;
    std::abort();
#endif
  }
};

template <class CharT>
std::vector<std::basic_string_view<CharT>> invalid_types(std::string valid) {
  std::vector<std::basic_string_view<CharT>> result;

#define CASE(T)                                                                                                        \
case #T[0]:                                                                                                            \
  result.push_back(SV("Invalid formatter type {:" #T "}"));                                                            \
  break;

  for (auto type : "aAbBcdeEfFgGopsxX") {
    if (valid.find(type) != std::string::npos)
      continue;

    switch (type) {
      CASE(a)
      CASE(A)
      CASE(b)
      CASE(B)
      CASE(c)
      CASE(d)
      CASE(e)
      CASE(E)
      CASE(f)
      CASE(F)
      CASE(g)
      CASE(G)
      CASE(o)
      CASE(p)
      CASE(s)
      CASE(x)
      CASE(X)
    case 0:
      break;
    default:
      assert(false && "Add the type to the list of cases.");
    }
  }
#undef CASE

  return result;
}

// Using a const ref for world and universe so a string literal will be a character array.
// When passed as character array W and U have different types.
template <class CharT, class W, class U, class TestFunction, class ExceptionTest>
void format_test_string(const W& world, const U& universe, TestFunction check, ExceptionTest check_exception) {

  // *** Valid input tests ***
  // Unsed argument is ignored. TODO FMT what does the Standard mandate?
  check.template operator()<"hello {}">(SV("hello world"), world, universe);
  check.template operator()<"hello {} and {}">(SV("hello world and universe"), world, universe);
  check.template operator()<"hello {0}">(SV("hello world"), world, universe);
  check.template operator()<"hello {1}">(SV("hello universe"), world, universe);
  check.template operator()<"hello {1} and {0}">(SV("hello universe and world"), world, universe);

  check.template operator()<"hello {:_>}">(SV("hello world"), world);
  check.template operator()<"hello {:>8}">(SV("hello    world"), world);
  check.template operator()<"hello {:_>8}">(SV("hello ___world"), world);
  check.template operator()<"hello {:_^8}">(SV("hello _world__"), world);
  check.template operator()<"hello {:_<8}">(SV("hello world___"), world);

  check.template operator()<"hello {:>>8}">(SV("hello >>>world"), world);
  check.template operator()<"hello {:<>8}">(SV("hello <<<world"), world);
  check.template operator()<"hello {:^>8}">(SV("hello ^^^world"), world);

  check.template operator()<"hello {:$>{}}">(SV("hello $world"), world, 6);
  check.template operator()<"hello {0:$>{1}}">(SV("hello $world"), world, 6);
  check.template operator()<"hello {1:$>{0}}">(SV("hello $world"), 6, world);

  check.template operator()<"hello {:.5}">(SV("hello world"), world);
  check.template operator()<"hello {:.5}">(SV("hello unive"), universe);

  check.template operator()<"hello {:.{}}">(SV("hello univer"), universe, 6);
  check.template operator()<"hello {0:.{1}}">(SV("hello univer"), universe, 6);
  check.template operator()<"hello {1:.{0}}">(SV("hello univer"), 6, universe);

  check.template operator()<"hello {:%^7.7}">(SV("hello %world%"), world);
  check.template operator()<"hello {:%^7.7}">(SV("hello univers"), universe);
  check.template operator()<"hello {:%^{}.{}}">(SV("hello %world%"), world, 7, 7);
  check.template operator()<"hello {0:%^{1}.{2}}">(SV("hello %world%"), world, 7, 7);
  check.template operator()<"hello {0:%^{2}.{1}}">(SV("hello %world%"), world, 7, 7);
  check.template operator()<"hello {1:%^{0}.{2}}">(SV("hello %world%"), 7, world, 7);

  check.template operator()<"hello {:_>s}">(SV("hello world"), world);
  check.template operator()<"hello {:$>{}s}">(SV("hello $world"), world, 6);
  check.template operator()<"hello {:.5s}">(SV("hello world"), world);
  check.template operator()<"hello {:.{}s}">(SV("hello univer"), universe, 6);
  check.template operator()<"hello {:%^7.7s}">(SV("hello %world%"), world);

  check.template operator()<"hello {:#>8.3s}">(SV("hello #####uni"), universe);
  check.template operator()<"hello {:#^8.3s}">(SV("hello ##uni###"), universe);
  check.template operator()<"hello {:#<8.3s}">(SV("hello uni#####"), universe);

  // *** sign ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("hello {:-}"), world);

  // *** alternate form ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("hello {:#}"), world);

  // *** zero-padding ***
  check_exception("A format-spec width field shouldn't have a leading zero", SV("hello {:0}"), world);

  // *** width ***
#ifdef _LIBCPP_VERSION
  // This limit isn't specified in the Standard.
  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
  check_exception("The numeric value of the format-spec is too large", SV("{:2147483648}"), world);
  check_exception("The numeric value of the format-spec is too large", SV("{:5000000000}"), world);
  check_exception("The numeric value of the format-spec is too large", SV("{:10000000000}"), world);
#endif

  check_exception("A format-spec width field replacement should have a positive value", SV("hello {:{}}"), world, 0);
  check_exception("A format-spec arg-id replacement shouldn't have a negative value", SV("hello {:{}}"), world, -1);
  check_exception("A format-spec arg-id replacement exceeds the maximum supported value", SV("hello {:{}}"), world,
                  unsigned(-1));
  check_exception("Argument index out of bounds", SV("hello {:{}}"), world);
  check_exception("A format-spec arg-id replacement argument isn't an integral type", SV("hello {:{}}"), world,
                  universe);
  check_exception("Using manual argument numbering in automatic argument numbering mode", SV("hello {:{0}}"), world, 1);
  check_exception("Using automatic argument numbering in manual argument numbering mode", SV("hello {0:{}}"), world, 1);
  // Arg-id may not have leading zeros.
  check_exception("Invalid arg-id", SV("hello {0:{01}}"), world, 1);

  // *** precision ***
#ifdef _LIBCPP_VERSION
  // This limit isn't specified in the Standard.
  static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test.");
  check_exception("The numeric value of the format-spec is too large", SV("{:.2147483648}"), world);
  check_exception("The numeric value of the format-spec is too large", SV("{:.5000000000}"), world);
  check_exception("The numeric value of the format-spec is too large", SV("{:.10000000000}"), world);
#endif

  // Precision 0 allowed, but not useful for string arguments.
  check.template operator()<"hello {:.{}}">(SV("hello "), world, 0);
  // Precision may have leading zeros. Secondly tests the value is still base 10.
  check.template operator()<"hello {:.000010}">(SV("hello 0123456789"), STR("0123456789abcdef"));
  check_exception("A format-spec arg-id replacement shouldn't have a negative value", SV("hello {:.{}}"), world, -1);
  check_exception("A format-spec arg-id replacement exceeds the maximum supported value", SV("hello {:.{}}"), world,
                  ~0u);
  check_exception("Argument index out of bounds", SV("hello {:.{}}"), world);
  check_exception("A format-spec arg-id replacement argument isn't an integral type", SV("hello {:.{}}"), world,
                  universe);
  check_exception("Using manual argument numbering in automatic argument numbering mode", SV("hello {:.{0}}"), world,
                  1);
  check_exception("Using automatic argument numbering in manual argument numbering mode", SV("hello {0:.{}}"), world,
                  1);
  // Arg-id may not have leading zeros.
  check_exception("Invalid arg-id", SV("hello {0:.{01}}"), world, 1);

  // *** locale-specific form ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("hello {:L}"), world);

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("s"))
    check_exception("The format-spec type has a type not supported for a string argument", fmt, world);
}

template <class CharT, class TestFunction>
void format_test_string_unicode([[maybe_unused]] TestFunction check) {
  // unicode.pass.cpp and ascii.pass.cpp have additional tests.
#ifndef TEST_HAS_NO_UNICODE
  // Make sure all possible types are tested. For clarity don't use macros.
  if constexpr (std::same_as<CharT, char>) {
    const char* c_string = "aßc";
    check.template operator()<"{:*^5}">(SV("*aßc*"), c_string);
    check.template operator()<"{:*^4.2}">(SV("*aß*"), c_string);

    check.template operator()<"{:*^5}">(SV("*aßc*"), const_cast<char*>(c_string));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), const_cast<char*>(c_string));

    check.template operator()<"{:*^5}">(SV("*aßc*"), "aßc");
    check.template operator()<"{:*^4.2}">(SV("*aß*"), "aßc");

    check.template operator()<"{:*^5}">(SV("*aßc*"), std::string("aßc"));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), std::string("aßc"));

    check.template operator()<"{:*^5}">(SV("*aßc*"), std::string_view("aßc"));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), std::string_view("aßc"));
  }
#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
  else {
    const wchar_t* c_string = L"aßc";
    check.template operator()<"{:*^5}">(SV("*aßc*"), c_string);
    check.template operator()<"{:*^4.2}">(SV("*aß*"), c_string);

    check.template operator()<"{:*^5}">(SV("*aßc*"), const_cast<wchar_t*>(c_string));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), const_cast<wchar_t*>(c_string));

    check.template operator()<"{:*^5}">(SV("*aßc*"), L"aßc");
    check.template operator()<"{:*^4.2}">(SV("*aß*"), L"aßc");

    check.template operator()<"{:*^5}">(SV("*aßc*"), std::wstring(L"aßc"));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), std::wstring(L"aßc"));

    check.template operator()<"{:*^5}">(SV("*aßc*"), std::wstring_view(L"aßc"));
    check.template operator()<"{:*^4.2}">(SV("*aß*"), std::wstring_view(L"aßc"));
  }
#  endif // TEST_HAS_NO_WIDE_CHARACTERS

  // ß requires one column
  check.template operator()<"{}">(SV("aßc"), STR("aßc"));

  check.template operator()<"{:.3}">(SV("aßc"), STR("aßc"));
  check.template operator()<"{:.2}">(SV("aß"), STR("aßc"));
  check.template operator()<"{:.1}">(SV("a"), STR("aßc"));

  check.template operator()<"{:3.3}">(SV("aßc"), STR("aßc"));
  check.template operator()<"{:2.2}">(SV("aß"), STR("aßc"));
  check.template operator()<"{:1.1}">(SV("a"), STR("aßc"));

  check.template operator()<"{:-<6}">(SV("aßc---"), STR("aßc"));
  check.template operator()<"{:-^6}">(SV("-aßc--"), STR("aßc"));
  check.template operator()<"{:->6}">(SV("---aßc"), STR("aßc"));

  // \u1000 requires two columns
  check.template operator()<"{}">(SV("a\u1110c"), STR("a\u1110c"));

  check.template operator()<"{:.4}">(SV("a\u1100c"), STR("a\u1100c"));
  check.template operator()<"{:.3}">(SV("a\u1100"), STR("a\u1100c"));
  check.template operator()<"{:.2}">(SV("a"), STR("a\u1100c"));
  check.template operator()<"{:.1}">(SV("a"), STR("a\u1100c"));

  check.template operator()<"{:-<4.4}">(SV("a\u1100c"), STR("a\u1100c"));
  check.template operator()<"{:-<3.3}">(SV("a\u1100"), STR("a\u1100c"));
  check.template operator()<"{:-<2.2}">(SV("a-"), STR("a\u1100c"));
  check.template operator()<"{:-<1.1}">(SV("a"), STR("a\u1100c"));

  check.template operator()<"{:-<7}">(SV("a\u1110c---"), STR("a\u1110c"));
  check.template operator()<"{:-^7}">(SV("-a\u1110c--"), STR("a\u1110c"));
  check.template operator()<"{:->7}">(SV("---a\u1110c"), STR("a\u1110c"));

  // Examples used in P1868R2
  check.template operator()<"{:*^3}">(SV("*\u0041*"), STR("\u0041")); // { LATIN CAPITAL LETTER A }
  check.template operator()<"{:*^3}">(SV("*\u00c1*"), STR("\u00c1")); // { LATIN CAPITAL LETTER A WITH ACUTE }
  check.template operator()<"{:*^3}">(
      SV("*\u0041\u0301*"),
      STR("\u0041\u0301")); // { LATIN CAPITAL LETTER A } { COMBINING ACUTE ACCENT }
  check.template operator()<"{:*^3}">(SV("*\u0132*"), STR("\u0132")); // { LATIN CAPITAL LIGATURE IJ }
  check.template operator()<"{:*^3}">(SV("*\u0394*"), STR("\u0394")); // { GREEK CAPITAL LETTER DELTA }

  check.template operator()<"{:*^3}">(SV("*\u0429*"), STR("\u0429"));         // { CYRILLIC CAPITAL LETTER SHCHA }
  check.template operator()<"{:*^3}">(SV("*\u05d0*"), STR("\u05d0"));         // { HEBREW LETTER ALEF }
  check.template operator()<"{:*^3}">(SV("*\u0634*"), STR("\u0634"));         // { ARABIC LETTER SHEEN }
  check.template operator()<"{:*^4}">(SV("*\u3009*"), STR("\u3009"));         // { RIGHT-POINTING ANGLE BRACKET }
  check.template operator()<"{:*^4}">(SV("*\u754c*"), STR("\u754c"));         // { CJK Unified Ideograph-754C }
  check.template operator()<"{:*^4}">(SV("*\U0001f921*"), STR("\U0001f921")); // { UNICORN FACE }
  check.template operator()<"{:*^4}">(
      SV("*\U0001f468\u200d\U0001F469\u200d\U0001F467\u200d\U0001F466*"),
      STR("\U0001f468\u200d\U0001F469\u200d\U0001F467\u200d\U0001F466")); // { Family: Man, Woman, Girl, Boy }
#endif // TEST_HAS_NO_UNICODE
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_string_tests(TestFunction check, ExceptionTest check_exception) {
  std::basic_string<CharT> world = STR("world");
  std::basic_string<CharT> universe = STR("universe");

  // Test a string literal in a way it won't decay to a pointer.
  if constexpr (std::same_as<CharT, char>)
    format_test_string<CharT>("world", "universe", check, check_exception);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
  else
    format_test_string<CharT>(L"world", L"universe", check, check_exception);
#endif

  format_test_string<CharT>(world.c_str(), universe.c_str(), check, check_exception);
  format_test_string<CharT>(const_cast<CharT*>(world.c_str()), const_cast<CharT*>(universe.c_str()), check,
                            check_exception);
  format_test_string<CharT>(std::basic_string_view<CharT>(world), std::basic_string_view<CharT>(universe), check,
                            check_exception);
  format_test_string<CharT>(world, universe, check, 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.template operator()<"answer is '{:7}'">(SV("answer is 'true   '"), true);
  check.template operator()<"answer is '{:>7}'">(SV("answer is '   true'"), true);
  check.template operator()<"answer is '{:<7}'">(SV("answer is 'true   '"), true);
  check.template operator()<"answer is '{:^7}'">(SV("answer is ' true  '"), true);

  check.template operator()<"answer is '{:8s}'">(SV("answer is 'false   '"), false);
  check.template operator()<"answer is '{:>8s}'">(SV("answer is '   false'"), false);
  check.template operator()<"answer is '{:<8s}'">(SV("answer is 'false   '"), false);
  check.template operator()<"answer is '{:^8s}'">(SV("answer is ' false  '"), false);

  check.template operator()<"answer is '{:->7}'">(SV("answer is '---true'"), true);
  check.template operator()<"answer is '{:-<7}'">(SV("answer is 'true---'"), true);
  check.template operator()<"answer is '{:-^7}'">(SV("answer is '-true--'"), true);

  check.template operator()<"answer is '{:->8s}'">(SV("answer is '---false'"), false);
  check.template operator()<"answer is '{:-<8s}'">(SV("answer is 'false---'"), false);
  check.template operator()<"answer is '{:-^8s}'">(SV("answer is '-false--'"), false);

  // *** Sign ***
  check_exception("A sign field isn't allowed in this format-spec", SV("{:-}"), true);
  check_exception("A sign field isn't allowed in this format-spec", SV("{:+}"), true);
  check_exception("A sign field isn't allowed in this format-spec", SV("{: }"), true);

  check_exception("A sign field isn't allowed in this format-spec", SV("{:-s}"), true);
  check_exception("A sign field isn't allowed in this format-spec", SV("{:+s}"), true);
  check_exception("A sign field isn't allowed in this format-spec", SV("{: s}"), true);

  // *** alternate form ***
  check_exception("An alternate form field isn't allowed in this format-spec", SV("{:#}"), true);
  check_exception("An alternate form field isn't allowed in this format-spec", SV("{:#s}"), true);

  // *** zero-padding ***
  check_exception("A zero-padding field isn't allowed in this format-spec", SV("{:0}"), true);
  check_exception("A zero-padding field isn't allowed in this format-spec", SV("{:0s}"), true);

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42}"), true);

  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.s}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0s}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42s}"), true);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("bBdosxX"))
    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.template operator()<"answer is '{:<1d}'">(SV("answer is '1'"), true);
  check.template operator()<"answer is '{:<2d}'">(SV("answer is '1 '"), true);
  check.template operator()<"answer is '{:<2d}'">(SV("answer is '0 '"), false);

  check.template operator()<"answer is '{:6d}'">(SV("answer is '     1'"), true);
  check.template operator()<"answer is '{:>6d}'">(SV("answer is '     1'"), true);
  check.template operator()<"answer is '{:<6d}'">(SV("answer is '1     '"), true);
  check.template operator()<"answer is '{:^6d}'">(SV("answer is '  1   '"), true);

  check.template operator()<"answer is '{:*>6d}'">(SV("answer is '*****0'"), false);
  check.template operator()<"answer is '{:*<6d}'">(SV("answer is '0*****'"), false);
  check.template operator()<"answer is '{:*^6d}'">(SV("answer is '**0***'"), false);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>06d}'">(SV("answer is '     1'"), true);
  check.template operator()<"answer is '{:<06d}'">(SV("answer is '1     '"), true);
  check.template operator()<"answer is '{:^06d}'">(SV("answer is '  1   '"), true);

  // *** Sign ***
  check.template operator()<"answer is {:d}">(SV("answer is 1"), true);
  check.template operator()<"answer is {:-d}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:+d}">(SV("answer is +1"), true);
  check.template operator()<"answer is {: d}">(SV("answer is  0"), false);

  // *** alternate form ***
  check.template operator()<"answer is {:+#d}">(SV("answer is +1"), true);
  check.template operator()<"answer is {:+b}">(SV("answer is +1"), true);
  check.template operator()<"answer is {:+#b}">(SV("answer is +0b1"), true);
  check.template operator()<"answer is {:+#B}">(SV("answer is +0B1"), true);
  check.template operator()<"answer is {:+o}">(SV("answer is +1"), true);
  check.template operator()<"answer is {:+#o}">(SV("answer is +01"), true);
  check.template operator()<"answer is {:+x}">(SV("answer is +1"), true);
  check.template operator()<"answer is {:+#x}">(SV("answer is +0x1"), true);
  check.template operator()<"answer is {:+X}">(SV("answer is +1"), true);
  check.template operator()<"answer is {:+#X}">(SV("answer is +0X1"), true);

  check.template operator()<"answer is {:#d}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:b}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:#b}">(SV("answer is 0b0"), false);
  check.template operator()<"answer is {:#B}">(SV("answer is 0B0"), false);
  check.template operator()<"answer is {:o}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:#o}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:x}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:#x}">(SV("answer is 0x0"), false);
  check.template operator()<"answer is {:X}">(SV("answer is 0"), false);
  check.template operator()<"answer is {:#X}">(SV("answer is 0X0"), false);

  // *** zero-padding & width ***
  check.template operator()<"answer is {:+#012d}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+012b}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+#012b}">(SV("answer is +0b000000001"), true);
  check.template operator()<"answer is {:+#012B}">(SV("answer is +0B000000001"), true);
  check.template operator()<"answer is {:+012o}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+#012o}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+012x}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+#012x}">(SV("answer is +0x000000001"), true);
  check.template operator()<"answer is {:+012X}">(SV("answer is +00000000001"), true);
  check.template operator()<"answer is {:+#012X}">(SV("answer is +0X000000001"), true);

  check.template operator()<"answer is {:#012d}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:012b}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:#012b}">(SV("answer is 0b0000000000"), false);
  check.template operator()<"answer is {:#012B}">(SV("answer is 0B0000000000"), false);
  check.template operator()<"answer is {:012o}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:#012o}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:012x}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:#012x}">(SV("answer is 0x0000000000"), false);
  check.template operator()<"answer is {:012X}">(SV("answer is 000000000000"), false);
  check.template operator()<"answer is {:#012X}">(SV("answer is 0X0000000000"), false);

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0}"), true);
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.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) {
  // *** align-fill & width ***
  check.template operator()<"answer is '{:<1}'">(SV("answer is '42'"), I(42));
  check.template operator()<"answer is '{:<2}'">(SV("answer is '42'"), I(42));
  check.template operator()<"answer is '{:<3}'">(SV("answer is '42 '"), I(42));

  check.template operator()<"answer is '{:7}'">(SV("answer is '     42'"), I(42));
  check.template operator()<"answer is '{:>7}'">(SV("answer is '     42'"), I(42));
  check.template operator()<"answer is '{:<7}'">(SV("answer is '42     '"), I(42));
  check.template operator()<"answer is '{:^7}'">(SV("answer is '  42   '"), I(42));

  check.template operator()<"answer is '{:*>7}'">(SV("answer is '*****42'"), I(42));
  check.template operator()<"answer is '{:*<7}'">(SV("answer is '42*****'"), I(42));
  check.template operator()<"answer is '{:*^7}'">(SV("answer is '**42***'"), I(42));

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07}'">(SV("answer is '     42'"), I(42));
  check.template operator()<"answer is '{:<07}'">(SV("answer is '42     '"), I(42));
  check.template operator()<"answer is '{:^07}'">(SV("answer is '  42   '"), I(42));

  // *** Sign ***
  if constexpr (std::signed_integral<I>)
    check.template operator()<"answer is {}">(SV("answer is -42"), I(-42));
  check.template operator()<"answer is {}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {}">(SV("answer is 42"), I(42));

  if constexpr (std::signed_integral<I>)
    check.template operator()<"answer is {:-}">(SV("answer is -42"), I(-42));
  check.template operator()<"answer is {:-}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:-}">(SV("answer is 42"), I(42));

  if constexpr (std::signed_integral<I>)
    check.template operator()<"answer is {:+}">(SV("answer is -42"), I(-42));
  check.template operator()<"answer is {:+}">(SV("answer is +0"), I(0));
  check.template operator()<"answer is {:+}">(SV("answer is +42"), I(42));

  if constexpr (std::signed_integral<I>)
    check.template operator()<"answer is {: }">(SV("answer is -42"), I(-42));
  check.template operator()<"answer is {: }">(SV("answer is  0"), I(0));
  check.template operator()<"answer is {: }">(SV("answer is  42"), I(42));

  // *** alternate form ***
  if constexpr (std::signed_integral<I>) {
    check.template operator()<"answer is {:#}">(SV("answer is -42"), I(-42));
    check.template operator()<"answer is {:#d}">(SV("answer is -42"), I(-42));
    check.template operator()<"answer is {:b}">(SV("answer is -101010"), I(-42));
    check.template operator()<"answer is {:#b}">(SV("answer is -0b101010"), I(-42));
    check.template operator()<"answer is {:#B}">(SV("answer is -0B101010"), I(-42));
    check.template operator()<"answer is {:o}">(SV("answer is -52"), I(-42));
    check.template operator()<"answer is {:#o}">(SV("answer is -052"), I(-42));
    check.template operator()<"answer is {:x}">(SV("answer is -2a"), I(-42));
    check.template operator()<"answer is {:#x}">(SV("answer is -0x2a"), I(-42));
    check.template operator()<"answer is {:X}">(SV("answer is -2A"), I(-42));
    check.template operator()<"answer is {:#X}">(SV("answer is -0X2A"), I(-42));
  }
  check.template operator()<"answer is {:#}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:#d}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:b}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:#b}">(SV("answer is 0b0"), I(0));
  check.template operator()<"answer is {:#B}">(SV("answer is 0B0"), I(0));
  check.template operator()<"answer is {:o}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:#o}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:x}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:#x}">(SV("answer is 0x0"), I(0));
  check.template operator()<"answer is {:X}">(SV("answer is 0"), I(0));
  check.template operator()<"answer is {:#X}">(SV("answer is 0X0"), I(0));

  check.template operator()<"answer is {:+#}">(SV("answer is +42"), I(42));
  check.template operator()<"answer is {:+#d}">(SV("answer is +42"), I(42));
  check.template operator()<"answer is {:+b}">(SV("answer is +101010"), I(42));
  check.template operator()<"answer is {:+#b}">(SV("answer is +0b101010"), I(42));
  check.template operator()<"answer is {:+#B}">(SV("answer is +0B101010"), I(42));
  check.template operator()<"answer is {:+o}">(SV("answer is +52"), I(42));
  check.template operator()<"answer is {:+#o}">(SV("answer is +052"), I(42));
  check.template operator()<"answer is {:+x}">(SV("answer is +2a"), I(42));
  check.template operator()<"answer is {:+#x}">(SV("answer is +0x2a"), I(42));
  check.template operator()<"answer is {:+X}">(SV("answer is +2A"), I(42));
  check.template operator()<"answer is {:+#X}">(SV("answer is +0X2A"), I(42));

  // *** zero-padding & width ***
  if constexpr (std::signed_integral<I>) {
    check.template operator()<"answer is {:#012}">(SV("answer is -00000000042"), I(-42));
    check.template operator()<"answer is {:#012d}">(SV("answer is -00000000042"), I(-42));
    check.template operator()<"answer is {:012b}">(SV("answer is -00000101010"), I(-42));
    check.template operator()<"answer is {:#012b}">(SV("answer is -0b000101010"), I(-42));
    check.template operator()<"answer is {:#012B}">(SV("answer is -0B000101010"), I(-42));
    check.template operator()<"answer is {:012o}">(SV("answer is -00000000052"), I(-42));
    check.template operator()<"answer is {:#012o}">(SV("answer is -00000000052"), I(-42));
    check.template operator()<"answer is {:012x}">(SV("answer is -0000000002a"), I(-42));
    check.template operator()<"answer is {:#012x}">(SV("answer is -0x00000002a"), I(-42));
    check.template operator()<"answer is {:012X}">(SV("answer is -0000000002A"), I(-42));
    check.template operator()<"answer is {:#012X}">(SV("answer is -0X00000002A"), I(-42));
  }

  check.template operator()<"answer is {:#012}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:#012d}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:012b}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:#012b}">(SV("answer is 0b0000000000"), I(0));
  check.template operator()<"answer is {:#012B}">(SV("answer is 0B0000000000"), I(0));
  check.template operator()<"answer is {:012o}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:#012o}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:012x}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:#012x}">(SV("answer is 0x0000000000"), I(0));
  check.template operator()<"answer is {:012X}">(SV("answer is 000000000000"), I(0));
  check.template operator()<"answer is {:#012X}">(SV("answer is 0X0000000000"), I(0));

  check.template operator()<"answer is {:+#012}">(SV("answer is +00000000042"), I(42));
  check.template operator()<"answer is {:+#012d}">(SV("answer is +00000000042"), I(42));
  check.template operator()<"answer is {:+012b}">(SV("answer is +00000101010"), I(42));
  check.template operator()<"answer is {:+#012b}">(SV("answer is +0b000101010"), I(42));
  check.template operator()<"answer is {:+#012B}">(SV("answer is +0B000101010"), I(42));
  check.template operator()<"answer is {:+012o}">(SV("answer is +00000000052"), I(42));
  check.template operator()<"answer is {:+#012o}">(SV("answer is +00000000052"), I(42));
  check.template operator()<"answer is {:+012x}">(SV("answer is +0000000002a"), I(42));
  check.template operator()<"answer is {:+#012x}">(SV("answer is +0x00000002a"), I(42));
  check.template operator()<"answer is {:+012X}">(SV("answer is +0000000002A"), I(42));
  check.template operator()<"answer is {:+#012X}">(SV("answer is +0X00000002A"), I(42));

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), I(0));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0}"), I(0));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42}"), I(0));

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("bBcdoxX"))
    check_exception("The format-spec type has a type not supported for an integer argument", fmt, 42);
}

template <class I, class CharT, class TestFunction, class ExceptionTest>
void format_test_integer_as_char(TestFunction check, ExceptionTest check_exception) {
  // *** align-fill & width ***
  check.template operator()<"answer is '{:6c}'">(SV("answer is '*     '"), I(42));
  check.template operator()<"answer is '{:>6c}'">(SV("answer is '     *'"), I(42));
  check.template operator()<"answer is '{:<6c}'">(SV("answer is '*     '"), I(42));
  check.template operator()<"answer is '{:^6c}'">(SV("answer is '  *   '"), I(42));

  check.template operator()<"answer is '{:->6c}'">(SV("answer is '-----*'"), I(42));
  check.template operator()<"answer is '{:-<6c}'">(SV("answer is '*-----'"), I(42));
  check.template operator()<"answer is '{:-^6c}'">(SV("answer is '--*---'"), I(42));

  // *** Sign ***
  check.template operator()<"answer is {:c}">(SV("answer is *"), I(42));
  check_exception("A sign field isn't allowed in this format-spec", SV("answer is {:-c}"), I(42));
  check_exception("A sign field isn't allowed in this format-spec", SV("answer is {:+c}"), I(42));
  check_exception("A sign field isn't allowed in this format-spec", SV("answer is {: c}"), I(42));

  // *** alternate form ***
  check_exception("An alternate form field isn't allowed in this format-spec", SV("answer is {:#c}"), I(42));

  // *** zero-padding & width ***
  check_exception("A zero-padding field isn't allowed in this format-spec", SV("answer is {:01c}"), I(42));

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.c}"), I(0));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0c}"), I(0));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42c}"), I(0));

  // *** locale-specific form ***
  // Note it has no effect but it's allowed.
  check.template operator()<"answer is '{:Lc}'">(SV("answer is '*'"), I(42));

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("bBcdoxX"))
    check_exception("The format-spec type has a type not supported for an integer argument", fmt, I(42));

  // *** Validate range ***
  // The code has some duplications to keep the if statement readable.
  if constexpr (std::signed_integral<CharT>) {
    if constexpr (std::signed_integral<I> && sizeof(I) > sizeof(CharT)) {
      check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::min());
      check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
    } else if constexpr (std::unsigned_integral<I> && sizeof(I) >= sizeof(CharT)) {
      check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
    }
  } else if constexpr (sizeof(I) > sizeof(CharT)) {
    check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
  }
}

template <class I, class CharT, class TestFunction, class ExceptionTest>
void format_test_integer(TestFunction check, ExceptionTest check_exception) {
  format_test_integer_as_integer<I, CharT>(check, check_exception);
  format_test_integer_as_char<I, CharT>(check, check_exception);
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_signed_integer(TestFunction check, ExceptionTest check_exception) {
  format_test_integer<signed char, CharT>(check, check_exception);
  format_test_integer<short, CharT>(check, check_exception);
  format_test_integer<int, CharT>(check, check_exception);
  format_test_integer<long, CharT>(check, check_exception);
  format_test_integer<long long, CharT>(check, check_exception);
#ifndef TEST_HAS_NO_INT128
  format_test_integer<__int128_t, CharT>(check, check_exception);
#endif
  // *** check the minma and maxima ***
  check.template operator()<"{:#b}">(SV("-0b10000000"), std::numeric_limits<int8_t>::min());
  check.template operator()<"{:#o}">(SV("-0200"), std::numeric_limits<int8_t>::min());
  check.template operator()<"{:#}">(SV("-128"), std::numeric_limits<int8_t>::min());
  check.template operator()<"{:#x}">(SV("-0x80"), std::numeric_limits<int8_t>::min());

  check.template operator()<"{:#b}">(SV("-0b1000000000000000"), std::numeric_limits<int16_t>::min());
  check.template operator()<"{:#o}">(SV("-0100000"), std::numeric_limits<int16_t>::min());
  check.template operator()<"{:#}">(SV("-32768"), std::numeric_limits<int16_t>::min());
  check.template operator()<"{:#x}">(SV("-0x8000"), std::numeric_limits<int16_t>::min());

  check.template operator()<"{:#b}">(SV("-0b10000000000000000000000000000000"), std::numeric_limits<int32_t>::min());
  check.template operator()<"{:#o}">(SV("-020000000000"), std::numeric_limits<int32_t>::min());
  check.template operator()<"{:#}">(SV("-2147483648"), std::numeric_limits<int32_t>::min());
  check.template operator()<"{:#x}">(SV("-0x80000000"), std::numeric_limits<int32_t>::min());

  check.template operator()<"{:#b}">(SV("-0b1000000000000000000000000000000000000000000000000000000000000000"),
                                     std::numeric_limits<int64_t>::min());
  check.template operator()<"{:#o}">(SV("-01000000000000000000000"), std::numeric_limits<int64_t>::min());
  check.template operator()<"{:#}">(SV("-9223372036854775808"), std::numeric_limits<int64_t>::min());
  check.template operator()<"{:#x}">(SV("-0x8000000000000000"), std::numeric_limits<int64_t>::min());

#ifndef TEST_HAS_NO_INT128
  check.template operator()<"{:#b}">(
      SV("-0b1000000000000000000000000000000000000000000000000000000000000000"
         "0000000000000000000000000000000000000000000000000000000000000000"),
      std::numeric_limits<__int128_t>::min());
  check.template
  operator()<"{:#o}">(SV("-02000000000000000000000000000000000000000000"), std::numeric_limits<__int128_t>::min());
  check.template
  operator()<"{:#}">(SV("-170141183460469231731687303715884105728"), std::numeric_limits<__int128_t>::min());
  check.template operator()<"{:#x}">(SV("-0x80000000000000000000000000000000"), std::numeric_limits<__int128_t>::min());
#endif

  check.template operator()<"{:#b}">(SV("0b1111111"), std::numeric_limits<int8_t>::max());
  check.template operator()<"{:#o}">(SV("0177"), std::numeric_limits<int8_t>::max());
  check.template operator()<"{:#}">(SV("127"), std::numeric_limits<int8_t>::max());
  check.template operator()<"{:#x}">(SV("0x7f"), std::numeric_limits<int8_t>::max());

  check.template operator()<"{:#b}">(SV("0b111111111111111"), std::numeric_limits<int16_t>::max());
  check.template operator()<"{:#o}">(SV("077777"), std::numeric_limits<int16_t>::max());
  check.template operator()<"{:#}">(SV("32767"), std::numeric_limits<int16_t>::max());
  check.template operator()<"{:#x}">(SV("0x7fff"), std::numeric_limits<int16_t>::max());

  check.template operator()<"{:#b}">(SV("0b1111111111111111111111111111111"), std::numeric_limits<int32_t>::max());
  check.template operator()<"{:#o}">(SV("017777777777"), std::numeric_limits<int32_t>::max());
  check.template operator()<"{:#}">(SV("2147483647"), std::numeric_limits<int32_t>::max());
  check.template operator()<"{:#x}">(SV("0x7fffffff"), std::numeric_limits<int32_t>::max());

  check.template operator()<"{:#b}">(SV("0b111111111111111111111111111111111111111111111111111111111111111"),
                                     std::numeric_limits<int64_t>::max());
  check.template operator()<"{:#o}">(SV("0777777777777777777777"), std::numeric_limits<int64_t>::max());
  check.template operator()<"{:#}">(SV("9223372036854775807"), std::numeric_limits<int64_t>::max());
  check.template operator()<"{:#x}">(SV("0x7fffffffffffffff"), std::numeric_limits<int64_t>::max());

#ifndef TEST_HAS_NO_INT128
  check.template operator()<"{:#b}">(
      SV("0b111111111111111111111111111111111111111111111111111111111111111"
         "1111111111111111111111111111111111111111111111111111111111111111"),
      std::numeric_limits<__int128_t>::max());
  check.template
  operator()<"{:#o}">(SV("01777777777777777777777777777777777777777777"), std::numeric_limits<__int128_t>::max());
  check.template
  operator()<"{:#}">(SV("170141183460469231731687303715884105727"), std::numeric_limits<__int128_t>::max());
  check.template operator()<"{:#x}">(SV("0x7fffffffffffffffffffffffffffffff"), std::numeric_limits<__int128_t>::max());
#endif
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_unsigned_integer(TestFunction check, ExceptionTest check_exception) {
  format_test_integer<unsigned char, CharT>(check, check_exception);
  format_test_integer<unsigned short, CharT>(check, check_exception);
  format_test_integer<unsigned, CharT>(check, check_exception);
  format_test_integer<unsigned long, CharT>(check, check_exception);
  format_test_integer<unsigned long long, CharT>(check, check_exception);
#ifndef TEST_HAS_NO_INT128
  format_test_integer<__uint128_t, CharT>(check, check_exception);
#endif
  // *** test the maxima ***
  check.template operator()<"{:#b}">(SV("0b11111111"), std::numeric_limits<uint8_t>::max());
  check.template operator()<"{:#o}">(SV("0377"), std::numeric_limits<uint8_t>::max());
  check.template operator()<"{:#}">(SV("255"), std::numeric_limits<uint8_t>::max());
  check.template operator()<"{:#x}">(SV("0xff"), std::numeric_limits<uint8_t>::max());

  check.template operator()<"{:#b}">(SV("0b1111111111111111"), std::numeric_limits<uint16_t>::max());
  check.template operator()<"{:#o}">(SV("0177777"), std::numeric_limits<uint16_t>::max());
  check.template operator()<"{:#}">(SV("65535"), std::numeric_limits<uint16_t>::max());
  check.template operator()<"{:#x}">(SV("0xffff"), std::numeric_limits<uint16_t>::max());

  check.template operator()<"{:#b}">(SV("0b11111111111111111111111111111111"), std::numeric_limits<uint32_t>::max());
  check.template operator()<"{:#o}">(SV("037777777777"), std::numeric_limits<uint32_t>::max());
  check.template operator()<"{:#}">(SV("4294967295"), std::numeric_limits<uint32_t>::max());
  check.template operator()<"{:#x}">(SV("0xffffffff"), std::numeric_limits<uint32_t>::max());

  check.template operator()<"{:#b}">(SV("0b1111111111111111111111111111111111111111111111111111111111111111"),
                                     std::numeric_limits<uint64_t>::max());
  check.template operator()<"{:#o}">(SV("01777777777777777777777"), std::numeric_limits<uint64_t>::max());
  check.template operator()<"{:#}">(SV("18446744073709551615"), std::numeric_limits<uint64_t>::max());
  check.template operator()<"{:#x}">(SV("0xffffffffffffffff"), std::numeric_limits<uint64_t>::max());

#ifndef TEST_HAS_NO_INT128
  check.template operator()<"{:#b}">(
      SV("0b1111111111111111111111111111111111111111111111111111111111111111"
         "1111111111111111111111111111111111111111111111111111111111111111"),
      std::numeric_limits<__uint128_t>::max());
  check.template
  operator()<"{:#o}">(SV("03777777777777777777777777777777777777777777"), std::numeric_limits<__uint128_t>::max());
  check.template
  operator()<"{:#}">(SV("340282366920938463463374607431768211455"), std::numeric_limits<__uint128_t>::max());
  check.template operator()<"{:#x}">(SV("0xffffffffffffffffffffffffffffffff"), std::numeric_limits<__uint128_t>::max());
#endif
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_char(TestFunction check, ExceptionTest check_exception) {

  // ***** Char type *****
  // *** align-fill & width ***
  check.template operator()<"answer is '{:6}'">(SV("answer is '*     '"), CharT('*'));

  check.template operator()<"answer is '{:>6}'">(SV("answer is '     *'"), CharT('*'));
  check.template operator()<"answer is '{:<6}'">(SV("answer is '*     '"), CharT('*'));
  check.template operator()<"answer is '{:^6}'">(SV("answer is '  *   '"), CharT('*'));

  check.template operator()<"answer is '{:6c}'">(SV("answer is '*     '"), CharT('*'));
  check.template operator()<"answer is '{:>6c}'">(SV("answer is '     *'"), CharT('*'));
  check.template operator()<"answer is '{:<6c}'">(SV("answer is '*     '"), CharT('*'));
  check.template operator()<"answer is '{:^6c}'">(SV("answer is '  *   '"), CharT('*'));

  check.template operator()<"answer is '{:->6}'">(SV("answer is '-----*'"), CharT('*'));
  check.template operator()<"answer is '{:-<6}'">(SV("answer is '*-----'"), CharT('*'));
  check.template operator()<"answer is '{:-^6}'">(SV("answer is '--*---'"), CharT('*'));

  check.template operator()<"answer is '{:->6c}'">(SV("answer is '-----*'"), CharT('*'));
  check.template operator()<"answer is '{:-<6c}'">(SV("answer is '*-----'"), CharT('*'));
  check.template operator()<"answer is '{:-^6c}'">(SV("answer is '--*---'"), CharT('*'));

  // *** Sign ***
  check_exception("A sign field isn't allowed in this format-spec", SV("{:-}"), CharT('*'));
  check_exception("A sign field isn't allowed in this format-spec", SV("{:+}"), CharT('*'));
  check_exception("A sign field isn't allowed in this format-spec", SV("{: }"), CharT('*'));

  check_exception("A sign field isn't allowed in this format-spec", SV("{:-c}"), CharT('*'));
  check_exception("A sign field isn't allowed in this format-spec", SV("{:+c}"), CharT('*'));
  check_exception("A sign field isn't allowed in this format-spec", SV("{: c}"), CharT('*'));

  // *** alternate form ***
  check_exception("An alternate form field isn't allowed in this format-spec", SV("{:#}"), CharT('*'));
  check_exception("An alternate form field isn't allowed in this format-spec", SV("{:#c}"), CharT('*'));

  // *** zero-padding ***
  check_exception("A zero-padding field isn't allowed in this format-spec", SV("{:0}"), CharT('*'));
  check_exception("A zero-padding field isn't allowed in this format-spec", SV("{:0c}"), CharT('*'));

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42}"), CharT('*'));

  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.c}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0c}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42c}"), CharT('*'));

  // *** locale-specific form ***
  // Note it has no effect but it's allowed.
  check.template operator()<"answer is '{:L}'">(SV("answer is '*'"), '*');
  check.template operator()<"answer is '{:Lc}'">(SV("answer is '*'"), '*');

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("bBcdoxX"))
    check_exception("The format-spec type has a type not supported for a char argument", fmt, CharT('*'));
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_char_as_integer(TestFunction check, ExceptionTest check_exception) {
  // *** align-fill & width ***
  check.template operator()<"answer is '{:<1d}'">(SV("answer is '42'"), CharT('*'));

  check.template operator()<"answer is '{:<2d}'">(SV("answer is '42'"), CharT('*'));
  check.template operator()<"answer is '{:<3d}'">(SV("answer is '42 '"), CharT('*'));

  check.template operator()<"answer is '{:7d}'">(SV("answer is '     42'"), CharT('*'));
  check.template operator()<"answer is '{:>7d}'">(SV("answer is '     42'"), CharT('*'));
  check.template operator()<"answer is '{:<7d}'">(SV("answer is '42     '"), CharT('*'));
  check.template operator()<"answer is '{:^7d}'">(SV("answer is '  42   '"), CharT('*'));

  check.template operator()<"answer is '{:*>7d}'">(SV("answer is '*****42'"), CharT('*'));
  check.template operator()<"answer is '{:*<7d}'">(SV("answer is '42*****'"), CharT('*'));
  check.template operator()<"answer is '{:*^7d}'">(SV("answer is '**42***'"), CharT('*'));

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07d}'">(SV("answer is '     42'"), CharT('*'));
  check.template operator()<"answer is '{:<07d}'">(SV("answer is '42     '"), CharT('*'));
  check.template operator()<"answer is '{:^07d}'">(SV("answer is '  42   '"), CharT('*'));

  // *** Sign ***
  check.template operator()<"answer is {:d}">(SV("answer is 42"), CharT('*'));
  check.template operator()<"answer is {:-d}">(SV("answer is 42"), CharT('*'));
  check.template operator()<"answer is {:+d}">(SV("answer is +42"), CharT('*'));
  check.template operator()<"answer is {: d}">(SV("answer is  42"), CharT('*'));

  // *** alternate form ***
  check.template operator()<"answer is {:+#d}">(SV("answer is +42"), CharT('*'));
  check.template operator()<"answer is {:+b}">(SV("answer is +101010"), CharT('*'));
  check.template operator()<"answer is {:+#b}">(SV("answer is +0b101010"), CharT('*'));
  check.template operator()<"answer is {:+#B}">(SV("answer is +0B101010"), CharT('*'));
  check.template operator()<"answer is {:+o}">(SV("answer is +52"), CharT('*'));
  check.template operator()<"answer is {:+#o}">(SV("answer is +052"), CharT('*'));
  check.template operator()<"answer is {:+x}">(SV("answer is +2a"), CharT('*'));
  check.template operator()<"answer is {:+#x}">(SV("answer is +0x2a"), CharT('*'));
  check.template operator()<"answer is {:+X}">(SV("answer is +2A"), CharT('*'));
  check.template operator()<"answer is {:+#X}">(SV("answer is +0X2A"), CharT('*'));

  // *** zero-padding & width ***
  check.template operator()<"answer is {:+#012d}">(SV("answer is +00000000042"), CharT('*'));
  check.template operator()<"answer is {:+012b}">(SV("answer is +00000101010"), CharT('*'));
  check.template operator()<"answer is {:+#012b}">(SV("answer is +0b000101010"), CharT('*'));
  check.template operator()<"answer is {:+#012B}">(SV("answer is +0B000101010"), CharT('*'));
  check.template operator()<"answer is {:+012o}">(SV("answer is +00000000052"), CharT('*'));
  check.template operator()<"answer is {:+#012o}">(SV("answer is +00000000052"), CharT('*'));
  check.template operator()<"answer is {:+012x}">(SV("answer is +0000000002a"), CharT('*'));
  check.template operator()<"answer is {:+#012x}">(SV("answer is +0x00000002a"), CharT('*'));
  check.template operator()<"answer is {:+012X}">(SV("answer is +0000000002A"), CharT('*'));

  check.template operator()<"answer is {:+#012X}">(SV("answer is +0X00000002A"), CharT('*'));

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.d}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.0d}"), CharT('*'));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.42d}"), CharT('*'));

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("bBcdoxX"))
    check_exception("The format-spec type has a type not supported for a char argument", fmt, '*');
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_hex_lower_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // Test whether the hexadecimal letters are the proper case.
  // The precision is too large for float, so two tests are used.
  check.template operator()<"answer is '{:a}'">(SV("answer is '1.abcp+0'"), F(0x1.abcp+0));
  check.template operator()<"answer is '{:a}'">(SV("answer is '1.defp+0'"), F(0x1.defp+0));

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7a}'">(SV("answer is '   1p-2'"), F(0.25));
  check.template operator()<"answer is '{:>7a}'">(SV("answer is '   1p-2'"), F(0.25));
  check.template operator()<"answer is '{:<7a}'">(SV("answer is '1p-2   '"), F(0.25));
  check.template operator()<"answer is '{:^7a}'">(SV("answer is ' 1p-2  '"), F(0.25));

  check.template operator()<"answer is '{:->7a}'">(SV("answer is '---1p-3'"), F(125e-3));
  check.template operator()<"answer is '{:-<7a}'">(SV("answer is '1p-3---'"), F(125e-3));
  check.template operator()<"answer is '{:-^7a}'">(SV("answer is '-1p-3--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6a}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6a}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6a}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7a}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7a}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7a}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6a}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6a}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6a}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7a}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7a}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7a}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07a}'">(SV("answer is '   1p-2'"), F(0.25));
  check.template operator()<"answer is '{:<07a}'">(SV("answer is '1p-2   '"), F(0.25));
  check.template operator()<"answer is '{:^07a}'">(SV("answer is ' 1p-2  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:a}'">(SV("answer is '0p+0'"), F(0));
  check.template operator()<"answer is '{:-a}'">(SV("answer is '0p+0'"), F(0));
  check.template operator()<"answer is '{:+a}'">(SV("answer is '+0p+0'"), F(0));
  check.template operator()<"answer is '{: a}'">(SV("answer is ' 0p+0'"), F(0));

  check.template operator()<"answer is '{:a}'">(SV("answer is '-0p+0'"), F(-0.));
  check.template operator()<"answer is '{:-a}'">(SV("answer is '-0p+0'"), F(-0.));
  check.template operator()<"answer is '{:+a}'">(SV("answer is '-0p+0'"), F(-0.));
  check.template operator()<"answer is '{: a}'">(SV("answer is '-0p+0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+a}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: a}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+a}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: a}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: a}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form ***
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:a}'">(SV("answer is '0p+0'"), F(0));
  check.template operator()<"answer is '{:#a}'">(SV("answer is '0.p+0'"), F(0));

  check.template operator()<"answer is '{:.0a}'">(SV("answer is '1p+1'"), F(2.5));
  check.template operator()<"answer is '{:#.0a}'">(SV("answer is '1.p+1'"), F(2.5));
  check.template operator()<"answer is '{:#a}'">(SV("answer is '1.4p+1'"), F(2.5));

  check.template operator()<"answer is '{:#a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#a}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:04a}'">(SV("answer is '1p-5'"), 0.03125);
  check.template operator()<"answer is '{:+05a}'">(SV("answer is '+1p-5'"), 0.03125);
  check.template operator()<"answer is '{:+06a}'">(SV("answer is '+01p-5'"), 0.03125);

  check.template operator()<"answer is '{:07a}'">(SV("answer is '0001p-5'"), 0.03125);
  check.template operator()<"answer is '{:-07a}'">(SV("answer is '0001p-5'"), 0.03125);
  check.template operator()<"answer is '{:+07a}'">(SV("answer is '+001p-5'"), 0.03125);
  check.template operator()<"answer is '{: 07a}'">(SV("answer is ' 001p-5'"), 0.03125);

  check.template operator()<"answer is '{:010a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010a}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010a}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010a}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010a}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010a}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010a}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010a}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010a}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010a}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010a}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  // See format_test_floating_point_hex_lower_case_precision

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_hex_upper_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // Test whether the hexadecimal letters are the proper case.
  // The precision is too large for float, so two tests are used.
  check.template operator()<"answer is '{:A}'">(SV("answer is '1.ABCP+0'"), F(0x1.abcp+0));
  check.template operator()<"answer is '{:A}'">(SV("answer is '1.DEFP+0'"), F(0x1.defp+0));

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7A}'">(SV("answer is '   1P-2'"), F(0.25));
  check.template operator()<"answer is '{:>7A}'">(SV("answer is '   1P-2'"), F(0.25));
  check.template operator()<"answer is '{:<7A}'">(SV("answer is '1P-2   '"), F(0.25));
  check.template operator()<"answer is '{:^7A}'">(SV("answer is ' 1P-2  '"), F(0.25));

  check.template operator()<"answer is '{:->7A}'">(SV("answer is '---1P-3'"), F(125e-3));
  check.template operator()<"answer is '{:-<7A}'">(SV("answer is '1P-3---'"), F(125e-3));
  check.template operator()<"answer is '{:-^7A}'">(SV("answer is '-1P-3--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6A}'">(SV("answer is '***INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6A}'">(SV("answer is 'INF***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6A}'">(SV("answer is '*INF**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7A}'">(SV("answer is '###-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7A}'">(SV("answer is '-INF###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7A}'">(SV("answer is '#-INF##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6A}'">(SV("answer is '^^^NAN'"), nan_pos);
  check.template operator()<"answer is '{:^<6A}'">(SV("answer is 'NAN^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6A}'">(SV("answer is '^NAN^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7A}'">(SV("answer is '000-NAN'"), nan_neg);
  check.template operator()<"answer is '{:0<7A}'">(SV("answer is '-NAN000'"), nan_neg);
  check.template operator()<"answer is '{:0^7A}'">(SV("answer is '0-NAN00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07A}'">(SV("answer is '   1P-2'"), F(0.25));
  check.template operator()<"answer is '{:<07A}'">(SV("answer is '1P-2   '"), F(0.25));
  check.template operator()<"answer is '{:^07A}'">(SV("answer is ' 1P-2  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:A}'">(SV("answer is '0P+0'"), F(0));
  check.template operator()<"answer is '{:-A}'">(SV("answer is '0P+0'"), F(0));
  check.template operator()<"answer is '{:+A}'">(SV("answer is '+0P+0'"), F(0));
  check.template operator()<"answer is '{: A}'">(SV("answer is ' 0P+0'"), F(0));

  check.template operator()<"answer is '{:A}'">(SV("answer is '-0P+0'"), F(-0.));
  check.template operator()<"answer is '{:-A}'">(SV("answer is '-0P+0'"), F(-0.));
  check.template operator()<"answer is '{:+A}'">(SV("answer is '-0P+0'"), F(-0.));
  check.template operator()<"answer is '{: A}'">(SV("answer is '-0P+0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+A}'">(SV("answer is '+INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: A}'">(SV("answer is ' INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:-A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:+A}'">(SV("answer is '+NAN'"), nan_pos);
  check.template operator()<"answer is '{: A}'">(SV("answer is ' NAN'"), nan_pos);

  check.template operator()<"answer is '{:A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:-A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:+A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{: A}'">(SV("answer is '-NAN'"), nan_neg);

  // *** alternate form ***
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:A}'">(SV("answer is '0P+0'"), F(0));
  check.template operator()<"answer is '{:#A}'">(SV("answer is '0.P+0'"), F(0));

  check.template operator()<"answer is '{:.0A}'">(SV("answer is '1P+1'"), F(2.5));
  check.template operator()<"answer is '{:#.0A}'">(SV("answer is '1.P+1'"), F(2.5));
  check.template operator()<"answer is '{:#A}'">(SV("answer is '1.4P+1'"), F(2.5));

  check.template operator()<"answer is '{:#A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:#A}'">(SV("answer is '-NAN'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:04A}'">(SV("answer is '1P-5'"), 0.03125);
  check.template operator()<"answer is '{:+05A}'">(SV("answer is '+1P-5'"), 0.03125);
  check.template operator()<"answer is '{:+06A}'">(SV("answer is '+01P-5'"), 0.03125);

  check.template operator()<"answer is '{:07A}'">(SV("answer is '0001P-5'"), 0.03125);
  check.template operator()<"answer is '{:-07A}'">(SV("answer is '0001P-5'"), 0.03125);
  check.template operator()<"answer is '{:+07A}'">(SV("answer is '+001P-5'"), 0.03125);
  check.template operator()<"answer is '{: 07A}'">(SV("answer is ' 001P-5'"), 0.03125);

  check.template operator()<"answer is '{:010A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010A}'">(SV("answer is '      +INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010A}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010A}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010A}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010A}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010A}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:-010A}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:+010A}'">(SV("answer is '      +NAN'"), nan_pos);
  check.template operator()<"answer is '{: 010A}'">(SV("answer is '       NAN'"), nan_pos);

  check.template operator()<"answer is '{:010A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:-010A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:+010A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{: 010A}'">(SV("answer is '      -NAN'"), nan_neg);

  // *** precision ***
  // See format_test_floating_point_hex_upper_case_precision

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_hex_lower_case_precision(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:14.6a}'">(SV("answer is '   1.000000p-2'"), F(0.25));
  check.template operator()<"answer is '{:>14.6a}'">(SV("answer is '   1.000000p-2'"), F(0.25));
  check.template operator()<"answer is '{:<14.6a}'">(SV("answer is '1.000000p-2   '"), F(0.25));
  check.template operator()<"answer is '{:^14.6a}'">(SV("answer is ' 1.000000p-2  '"), F(0.25));

  check.template operator()<"answer is '{:->14.6a}'">(SV("answer is '---1.000000p-3'"), F(125e-3));
  check.template operator()<"answer is '{:-<14.6a}'">(SV("answer is '1.000000p-3---'"), F(125e-3));
  check.template operator()<"answer is '{:-^14.6a}'">(SV("answer is '-1.000000p-3--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6.6a}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6.6a}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6.6a}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7.6a}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7.6a}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7.6a}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6.6a}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6.6a}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6.6a}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7.6a}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7.6a}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7.6a}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>014.6a}'">(SV("answer is '   1.000000p-2'"), F(0.25));
  check.template operator()<"answer is '{:<014.6a}'">(SV("answer is '1.000000p-2   '"), F(0.25));
  check.template operator()<"answer is '{:^014.6a}'">(SV("answer is ' 1.000000p-2  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:.6a}'">(SV("answer is '0.000000p+0'"), F(0));
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is '0.000000p+0'"), F(0));
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '+0.000000p+0'"), F(0));
  check.template operator()<"answer is '{: .6a}'">(SV("answer is ' 0.000000p+0'"), F(0));

  check.template operator()<"answer is '{:.6a}'">(SV("answer is '-0.000000p+0'"), F(-0.));
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is '-0.000000p+0'"), F(-0.));
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '-0.000000p+0'"), F(-0.));
  check.template operator()<"answer is '{: .6a}'">(SV("answer is '-0.000000p+0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:.6a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6a}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: .6a}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:.6a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-.6a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+.6a}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: .6a}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form ***
  check.template operator()<"answer is '{:#.6a}'">(SV("answer is '1.400000p+1'"), F(2.5));

  check.template operator()<"answer is '{:#.6a}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#.6a}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#.6a}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#.6a}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:011.6a}'">(SV("answer is '1.000000p-5'"), 0.03125);
  check.template operator()<"answer is '{:+012.6a}'">(SV("answer is '+1.000000p-5'"), 0.03125);
  check.template operator()<"answer is '{:+013.6a}'">(SV("answer is '+01.000000p-5'"), 0.03125);

  check.template operator()<"answer is '{:014.6a}'">(SV("answer is '0001.000000p-5'"), 0.03125);
  check.template operator()<"answer is '{:-014.6a}'">(SV("answer is '0001.000000p-5'"), 0.03125);
  check.template operator()<"answer is '{:+014.6a}'">(SV("answer is '+001.000000p-5'"), 0.03125);
  check.template operator()<"answer is '{: 014.6a}'">(SV("answer is ' 001.000000p-5'"), 0.03125);

  check.template operator()<"answer is '{:010.6a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6a}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6a}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6a}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6a}'">(SV("answer is '      -inf'"),
                                                      -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6a}'">(SV("answer is '      -inf'"),
                                                      -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6a}'">(SV("answer is '      -inf'"),
                                                      -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6a}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010.6a}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010.6a}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010.6a}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010.6a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010.6a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010.6a}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010.6a}'">(SV("answer is '      -nan'"), nan_neg);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_hex_upper_case_precision(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:14.6A}'">(SV("answer is '   1.000000P-2'"), F(0.25));
  check.template operator()<"answer is '{:>14.6A}'">(SV("answer is '   1.000000P-2'"), F(0.25));
  check.template operator()<"answer is '{:<14.6A}'">(SV("answer is '1.000000P-2   '"), F(0.25));
  check.template operator()<"answer is '{:^14.6A}'">(SV("answer is ' 1.000000P-2  '"), F(0.25));

  check.template operator()<"answer is '{:->14.6A}'">(SV("answer is '---1.000000P-3'"), F(125e-3));
  check.template operator()<"answer is '{:-<14.6A}'">(SV("answer is '1.000000P-3---'"), F(125e-3));
  check.template operator()<"answer is '{:-^14.6A}'">(SV("answer is '-1.000000P-3--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6.6A}'">(SV("answer is '***INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6.6A}'">(SV("answer is 'INF***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6.6A}'">(SV("answer is '*INF**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7.6A}'">(SV("answer is '###-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7.6A}'">(SV("answer is '-INF###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7.6A}'">(SV("answer is '#-INF##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6.6A}'">(SV("answer is '^^^NAN'"), nan_pos);
  check.template operator()<"answer is '{:^<6.6A}'">(SV("answer is 'NAN^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6.6A}'">(SV("answer is '^NAN^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7.6A}'">(SV("answer is '000-NAN'"), nan_neg);
  check.template operator()<"answer is '{:0<7.6A}'">(SV("answer is '-NAN000'"), nan_neg);
  check.template operator()<"answer is '{:0^7.6A}'">(SV("answer is '0-NAN00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>014.6A}'">(SV("answer is '   1.000000P-2'"), F(0.25));
  check.template operator()<"answer is '{:<014.6A}'">(SV("answer is '1.000000P-2   '"), F(0.25));
  check.template operator()<"answer is '{:^014.6A}'">(SV("answer is ' 1.000000P-2  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:.6A}'">(SV("answer is '0.000000P+0'"), F(0));
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is '0.000000P+0'"), F(0));
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '+0.000000P+0'"), F(0));
  check.template operator()<"answer is '{: .6A}'">(SV("answer is ' 0.000000P+0'"), F(0));

  check.template operator()<"answer is '{:.6A}'">(SV("answer is '-0.000000P+0'"), F(-0.));
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is '-0.000000P+0'"), F(-0.));
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '-0.000000P+0'"), F(-0.));
  check.template operator()<"answer is '{: .6A}'">(SV("answer is '-0.000000P+0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:.6A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '+INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6A}'">(SV("answer is ' INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '+NAN'"), nan_pos);
  check.template operator()<"answer is '{: .6A}'">(SV("answer is ' NAN'"), nan_pos);

  check.template operator()<"answer is '{:.6A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:-.6A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:+.6A}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{: .6A}'">(SV("answer is '-NAN'"), nan_neg);

  // *** alternate form ***
  check.template operator()<"answer is '{:#.6A}'">(SV("answer is '1.400000P+1'"), F(2.5));

  check.template operator()<"answer is '{:#.6A}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#.6A}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#.6A}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:#.6A}'">(SV("answer is '-NAN'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:011.6A}'">(SV("answer is '1.000000P-5'"), 0.03125);
  check.template operator()<"answer is '{:+012.6A}'">(SV("answer is '+1.000000P-5'"), 0.03125);
  check.template operator()<"answer is '{:+013.6A}'">(SV("answer is '+01.000000P-5'"), 0.03125);

  check.template operator()<"answer is '{:014.6A}'">(SV("answer is '0001.000000P-5'"), 0.03125);
  check.template operator()<"answer is '{:-014.6A}'">(SV("answer is '0001.000000P-5'"), 0.03125);
  check.template operator()<"answer is '{:+014.6A}'">(SV("answer is '+001.000000P-5'"), 0.03125);
  check.template operator()<"answer is '{: 014.6A}'">(SV("answer is ' 001.000000P-5'"), 0.03125);

  check.template operator()<"answer is '{:010.6A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6A}'">(SV("answer is '      +INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6A}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6A}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6A}'">(SV("answer is '      -INF'"),
                                                      -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6A}'">(SV("answer is '      -INF'"),
                                                      -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6A}'">(SV("answer is '      -INF'"),
                                                      -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6A}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:-010.6A}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:+010.6A}'">(SV("answer is '      +NAN'"), nan_pos);
  check.template operator()<"answer is '{: 010.6A}'">(SV("answer is '       NAN'"), nan_pos);

  check.template operator()<"answer is '{:010.6A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:-010.6A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:+010.6A}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{: 010.6A}'">(SV("answer is '      -NAN'"), nan_neg);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_scientific_lower_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:15e}'">(SV("answer is '   2.500000e-01'"), F(0.25));
  check.template operator()<"answer is '{:>15e}'">(SV("answer is '   2.500000e-01'"), F(0.25));
  check.template operator()<"answer is '{:<15e}'">(SV("answer is '2.500000e-01   '"), F(0.25));
  check.template operator()<"answer is '{:^15e}'">(SV("answer is ' 2.500000e-01  '"), F(0.25));

  check.template operator()<"answer is '{:->15e}'">(SV("answer is '---1.250000e-01'"), F(125e-3));
  check.template operator()<"answer is '{:-<15e}'">(SV("answer is '1.250000e-01---'"), F(125e-3));
  check.template operator()<"answer is '{:-^15e}'">(SV("answer is '-1.250000e-01--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6e}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6e}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6e}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7e}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7e}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7e}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6e}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6e}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6e}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7e}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7e}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7e}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>015e}'">(SV("answer is '   2.500000e-01'"), F(0.25));
  check.template operator()<"answer is '{:<015e}'">(SV("answer is '2.500000e-01   '"), F(0.25));
  check.template operator()<"answer is '{:^015e}'">(SV("answer is ' 2.500000e-01  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:e}'">(SV("answer is '0.000000e+00'"), F(0));
  check.template operator()<"answer is '{:-e}'">(SV("answer is '0.000000e+00'"), F(0));
  check.template operator()<"answer is '{:+e}'">(SV("answer is '+0.000000e+00'"), F(0));
  check.template operator()<"answer is '{: e}'">(SV("answer is ' 0.000000e+00'"), F(0));

  check.template operator()<"answer is '{:e}'">(SV("answer is '-0.000000e+00'"), F(-0.));
  check.template operator()<"answer is '{:-e}'">(SV("answer is '-0.000000e+00'"), F(-0.));
  check.template operator()<"answer is '{:+e}'">(SV("answer is '-0.000000e+00'"), F(-0.));
  check.template operator()<"answer is '{: e}'">(SV("answer is '-0.000000e+00'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:e}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-e}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+e}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: e}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:e}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-e}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+e}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: e}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:e}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-e}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+e}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: e}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:e}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-e}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+e}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: e}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0e}'">(SV("answer is '0e+00'"), F(0));
  check.template operator()<"answer is '{:#.0e}'">(SV("answer is '0.e+00'"), F(0));

  check.template operator()<"answer is '{:#e}'">(SV("answer is '0.000000e+00'"), F(0));
  check.template operator()<"answer is '{:#e}'">(SV("answer is '2.500000e+00'"), F(2.5));

  check.template operator()<"answer is '{:#e}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#e}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#e}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#e}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:07e}'">(SV("answer is '3.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{:+07e}'">(SV("answer is '+3.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{:+08e}'">(SV("answer is '+3.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{:+09e}'">(SV("answer is '+3.125000e-02'"), 0.03125);

  check.template operator()<"answer is '{:014e}'">(SV("answer is '003.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{:-014e}'">(SV("answer is '003.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{:+014e}'">(SV("answer is '+03.125000e-02'"), 0.03125);
  check.template operator()<"answer is '{: 014e}'">(SV("answer is ' 03.125000e-02'"), 0.03125);

  check.template operator()<"answer is '{:010e}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010e}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010e}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010e}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010e}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010e}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010e}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010e}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010e}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010e}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010e}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010e}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010e}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010e}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010e}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010e}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0e}'">(SV("answer is '3e-02'"), 0.03125);
  check.template operator()<"answer is '{:.1e}'">(SV("answer is '3.1e-02'"), 0.03125);
  check.template operator()<"answer is '{:.3e}'">(SV("answer is '3.125e-02'"), 0.03125);
  check.template operator()<"answer is '{:.10e}'">(SV("answer is '3.1250000000e-02'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_scientific_upper_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:15E}'">(SV("answer is '   2.500000E-01'"), F(0.25));
  check.template operator()<"answer is '{:>15E}'">(SV("answer is '   2.500000E-01'"), F(0.25));
  check.template operator()<"answer is '{:<15E}'">(SV("answer is '2.500000E-01   '"), F(0.25));
  check.template operator()<"answer is '{:^15E}'">(SV("answer is ' 2.500000E-01  '"), F(0.25));

  check.template operator()<"answer is '{:->15E}'">(SV("answer is '---1.250000E-01'"), F(125e-3));
  check.template operator()<"answer is '{:-<15E}'">(SV("answer is '1.250000E-01---'"), F(125e-3));
  check.template operator()<"answer is '{:-^15E}'">(SV("answer is '-1.250000E-01--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6E}'">(SV("answer is '***INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6E}'">(SV("answer is 'INF***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6E}'">(SV("answer is '*INF**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7E}'">(SV("answer is '###-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7E}'">(SV("answer is '-INF###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7E}'">(SV("answer is '#-INF##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6E}'">(SV("answer is '^^^NAN'"), nan_pos);
  check.template operator()<"answer is '{:^<6E}'">(SV("answer is 'NAN^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6E}'">(SV("answer is '^NAN^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7E}'">(SV("answer is '000-NAN'"), nan_neg);
  check.template operator()<"answer is '{:0<7E}'">(SV("answer is '-NAN000'"), nan_neg);
  check.template operator()<"answer is '{:0^7E}'">(SV("answer is '0-NAN00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>015E}'">(SV("answer is '   2.500000E-01'"), F(0.25));
  check.template operator()<"answer is '{:<015E}'">(SV("answer is '2.500000E-01   '"), F(0.25));
  check.template operator()<"answer is '{:^015E}'">(SV("answer is ' 2.500000E-01  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:E}'">(SV("answer is '0.000000E+00'"), F(0));
  check.template operator()<"answer is '{:-E}'">(SV("answer is '0.000000E+00'"), F(0));
  check.template operator()<"answer is '{:+E}'">(SV("answer is '+0.000000E+00'"), F(0));
  check.template operator()<"answer is '{: E}'">(SV("answer is ' 0.000000E+00'"), F(0));

  check.template operator()<"answer is '{:E}'">(SV("answer is '-0.000000E+00'"), F(-0.));
  check.template operator()<"answer is '{:-E}'">(SV("answer is '-0.000000E+00'"), F(-0.));
  check.template operator()<"answer is '{:+E}'">(SV("answer is '-0.000000E+00'"), F(-0.));
  check.template operator()<"answer is '{: E}'">(SV("answer is '-0.000000E+00'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:E}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-E}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+E}'">(SV("answer is '+INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: E}'">(SV("answer is ' INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:E}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-E}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+E}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: E}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:E}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:-E}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:+E}'">(SV("answer is '+NAN'"), nan_pos);
  check.template operator()<"answer is '{: E}'">(SV("answer is ' NAN'"), nan_pos);

  check.template operator()<"answer is '{:E}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:-E}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:+E}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{: E}'">(SV("answer is '-NAN'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0E}'">(SV("answer is '0E+00'"), F(0));
  check.template operator()<"answer is '{:#.0E}'">(SV("answer is '0.E+00'"), F(0));

  check.template operator()<"answer is '{:#E}'">(SV("answer is '0.000000E+00'"), F(0));
  check.template operator()<"answer is '{:#E}'">(SV("answer is '2.500000E+00'"), F(2.5));

  check.template operator()<"answer is '{:#E}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#E}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#E}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:#E}'">(SV("answer is '-NAN'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:07E}'">(SV("answer is '3.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{:+07E}'">(SV("answer is '+3.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{:+08E}'">(SV("answer is '+3.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{:+09E}'">(SV("answer is '+3.125000E-02'"), 0.03125);

  check.template operator()<"answer is '{:014E}'">(SV("answer is '003.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{:-014E}'">(SV("answer is '003.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{:+014E}'">(SV("answer is '+03.125000E-02'"), 0.03125);
  check.template operator()<"answer is '{: 014E}'">(SV("answer is ' 03.125000E-02'"), 0.03125);

  check.template operator()<"answer is '{:010E}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010E}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010E}'">(SV("answer is '      +INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010E}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010E}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010E}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010E}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010E}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010E}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:-010E}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:+010E}'">(SV("answer is '      +NAN'"), nan_pos);
  check.template operator()<"answer is '{: 010E}'">(SV("answer is '       NAN'"), nan_pos);

  check.template operator()<"answer is '{:010E}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:-010E}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:+010E}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{: 010E}'">(SV("answer is '      -NAN'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0E}'">(SV("answer is '3E-02'"), 0.03125);
  check.template operator()<"answer is '{:.1E}'">(SV("answer is '3.1E-02'"), 0.03125);
  check.template operator()<"answer is '{:.3E}'">(SV("answer is '3.125E-02'"), 0.03125);
  check.template operator()<"answer is '{:.10E}'">(SV("answer is '3.1250000000E-02'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_fixed_lower_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:11f}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:>11f}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:<11f}'">(SV("answer is '0.250000   '"), F(0.25));
  check.template operator()<"answer is '{:^11f}'">(SV("answer is ' 0.250000  '"), F(0.25));

  check.template operator()<"answer is '{:->11f}'">(SV("answer is '---0.125000'"), F(125e-3));
  check.template operator()<"answer is '{:-<11f}'">(SV("answer is '0.125000---'"), F(125e-3));
  check.template operator()<"answer is '{:-^11f}'">(SV("answer is '-0.125000--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6f}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6f}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6f}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7f}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7f}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7f}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6f}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6f}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6f}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7f}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7f}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7f}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>011f}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:<011f}'">(SV("answer is '0.250000   '"), F(0.25));
  check.template operator()<"answer is '{:^011f}'">(SV("answer is ' 0.250000  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:f}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:-f}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:+f}'">(SV("answer is '+0.000000'"), F(0));
  check.template operator()<"answer is '{: f}'">(SV("answer is ' 0.000000'"), F(0));

  check.template operator()<"answer is '{:f}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{:-f}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{:+f}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{: f}'">(SV("answer is '-0.000000'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:f}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-f}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+f}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: f}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:f}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-f}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+f}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: f}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:f}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-f}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+f}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: f}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:f}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-f}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+f}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: f}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0f}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:#.0f}'">(SV("answer is '0.'"), F(0));

  check.template operator()<"answer is '{:#f}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:#f}'">(SV("answer is '2.500000'"), F(2.5));

  check.template operator()<"answer is '{:#f}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#f}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#f}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#f}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:07f}'">(SV("answer is '0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+07f}'">(SV("answer is '+0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+08f}'">(SV("answer is '+0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+09f}'">(SV("answer is '+0.031250'"), 0.03125);

  check.template operator()<"answer is '{:010f}'">(SV("answer is '000.031250'"), 0.03125);
  check.template operator()<"answer is '{:-010f}'">(SV("answer is '000.031250'"), 0.03125);
  check.template operator()<"answer is '{:+010f}'">(SV("answer is '+00.031250'"), 0.03125);
  check.template operator()<"answer is '{: 010f}'">(SV("answer is ' 00.031250'"), 0.03125);

  check.template operator()<"answer is '{:010f}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010f}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010f}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010f}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010f}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010f}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010f}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010f}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010f}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010f}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010f}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010f}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010f}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010f}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010f}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010f}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0f}'">(SV("answer is '0'"), 0.03125);
  check.template operator()<"answer is '{:.1f}'">(SV("answer is '0.0'"), 0.03125);
  check.template operator()<"answer is '{:.5f}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.10f}'">(SV("answer is '0.0312500000'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_fixed_upper_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:11F}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:>11F}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:<11F}'">(SV("answer is '0.250000   '"), F(0.25));
  check.template operator()<"answer is '{:^11F}'">(SV("answer is ' 0.250000  '"), F(0.25));

  check.template operator()<"answer is '{:->11F}'">(SV("answer is '---0.125000'"), F(125e-3));
  check.template operator()<"answer is '{:-<11F}'">(SV("answer is '0.125000---'"), F(125e-3));
  check.template operator()<"answer is '{:-^11F}'">(SV("answer is '-0.125000--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6F}'">(SV("answer is '***INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6F}'">(SV("answer is 'INF***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6F}'">(SV("answer is '*INF**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7F}'">(SV("answer is '###-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7F}'">(SV("answer is '-INF###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7F}'">(SV("answer is '#-INF##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6F}'">(SV("answer is '^^^NAN'"), nan_pos);
  check.template operator()<"answer is '{:^<6F}'">(SV("answer is 'NAN^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6F}'">(SV("answer is '^NAN^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7F}'">(SV("answer is '000-NAN'"), nan_neg);
  check.template operator()<"answer is '{:0<7F}'">(SV("answer is '-NAN000'"), nan_neg);
  check.template operator()<"answer is '{:0^7F}'">(SV("answer is '0-NAN00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>011F}'">(SV("answer is '   0.250000'"), F(0.25));
  check.template operator()<"answer is '{:<011F}'">(SV("answer is '0.250000   '"), F(0.25));
  check.template operator()<"answer is '{:^011F}'">(SV("answer is ' 0.250000  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:F}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:-F}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:+F}'">(SV("answer is '+0.000000'"), F(0));
  check.template operator()<"answer is '{: F}'">(SV("answer is ' 0.000000'"), F(0));

  check.template operator()<"answer is '{:F}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{:-F}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{:+F}'">(SV("answer is '-0.000000'"), F(-0.));
  check.template operator()<"answer is '{: F}'">(SV("answer is '-0.000000'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:F}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-F}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+F}'">(SV("answer is '+INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: F}'">(SV("answer is ' INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:F}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-F}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+F}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: F}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:F}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:-F}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:+F}'">(SV("answer is '+NAN'"), nan_pos);
  check.template operator()<"answer is '{: F}'">(SV("answer is ' NAN'"), nan_pos);

  check.template operator()<"answer is '{:F}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:-F}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:+F}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{: F}'">(SV("answer is '-NAN'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0F}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:#.0F}'">(SV("answer is '0.'"), F(0));

  check.template operator()<"answer is '{:#F}'">(SV("answer is '0.000000'"), F(0));
  check.template operator()<"answer is '{:#F}'">(SV("answer is '2.500000'"), F(2.5));

  check.template operator()<"answer is '{:#F}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#F}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#F}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:#F}'">(SV("answer is '-NAN'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:07F}'">(SV("answer is '0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+07F}'">(SV("answer is '+0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+08F}'">(SV("answer is '+0.031250'"), 0.03125);
  check.template operator()<"answer is '{:+09F}'">(SV("answer is '+0.031250'"), 0.03125);

  check.template operator()<"answer is '{:010F}'">(SV("answer is '000.031250'"), 0.03125);
  check.template operator()<"answer is '{:-010F}'">(SV("answer is '000.031250'"), 0.03125);
  check.template operator()<"answer is '{:+010F}'">(SV("answer is '+00.031250'"), 0.03125);
  check.template operator()<"answer is '{: 010F}'">(SV("answer is ' 00.031250'"), 0.03125);

  check.template operator()<"answer is '{:010F}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010F}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010F}'">(SV("answer is '      +INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010F}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010F}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010F}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010F}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010F}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010F}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:-010F}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:+010F}'">(SV("answer is '      +NAN'"), nan_pos);
  check.template operator()<"answer is '{: 010F}'">(SV("answer is '       NAN'"), nan_pos);

  check.template operator()<"answer is '{:010F}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:-010F}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:+010F}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{: 010F}'">(SV("answer is '      -NAN'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0F}'">(SV("answer is '0'"), 0.03125);
  check.template operator()<"answer is '{:.1F}'">(SV("answer is '0.0'"), 0.03125);
  check.template operator()<"answer is '{:.5F}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.10F}'">(SV("answer is '0.0312500000'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_general_lower_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7g}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:>7g}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<7g}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^7g}'">(SV("answer is ' 0.25  '"), F(0.25));

  check.template operator()<"answer is '{:->8g}'">(SV("answer is '---0.125'"), F(125e-3));
  check.template operator()<"answer is '{:-<8g}'">(SV("answer is '0.125---'"), F(125e-3));
  check.template operator()<"answer is '{:-^8g}'">(SV("answer is '-0.125--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6g}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6g}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6g}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7g}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7g}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7g}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6g}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6g}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6g}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7g}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7g}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7g}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07g}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<07g}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^07g}'">(SV("answer is ' 0.25  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:g}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:-g}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:+g}'">(SV("answer is '+0'"), F(0));
  check.template operator()<"answer is '{: g}'">(SV("answer is ' 0'"), F(0));

  check.template operator()<"answer is '{:g}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:-g}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:+g}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{: g}'">(SV("answer is '-0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:g}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-g}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+g}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: g}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:g}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-g}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+g}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: g}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:g}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-g}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+g}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: g}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:g}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-g}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+g}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: g}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0g}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:#.0g}'">(SV("answer is '0.'"), F(0));

  check.template operator()<"answer is '{:#g}'">(SV("answer is '0.'"), F(0));
  check.template operator()<"answer is '{:#g}'">(SV("answer is '2.5'"), F(2.5));

  check.template operator()<"answer is '{:#g}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#g}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#g}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#g}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:06g}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+06g}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+07g}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+08g}'">(SV("answer is '+0.03125'"), 0.03125);

  check.template operator()<"answer is '{:09g}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:-09g}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:+09g}'">(SV("answer is '+00.03125'"), 0.03125);
  check.template operator()<"answer is '{: 09g}'">(SV("answer is ' 00.03125'"), 0.03125);

  check.template operator()<"answer is '{:010g}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010g}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010g}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010g}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010g}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010g}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010g}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010g}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010g}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010g}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010g}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010g}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010g}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010g}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010g}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010g}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0g}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.1g}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.2g}'">(SV("answer is '0.031'"), 0.03125);
  check.template operator()<"answer is '{:.3g}'">(SV("answer is '0.0312'"), 0.03125);
  check.template operator()<"answer is '{:.4g}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.5g}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.10g}'">(SV("answer is '0.03125'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_general_upper_case(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7G}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:>7G}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<7G}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^7G}'">(SV("answer is ' 0.25  '"), F(0.25));

  check.template operator()<"answer is '{:->8G}'">(SV("answer is '---0.125'"), F(125e-3));
  check.template operator()<"answer is '{:-<8G}'">(SV("answer is '0.125---'"), F(125e-3));
  check.template operator()<"answer is '{:-^8G}'">(SV("answer is '-0.125--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6G}'">(SV("answer is '***INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6G}'">(SV("answer is 'INF***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6G}'">(SV("answer is '*INF**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7G}'">(SV("answer is '###-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7G}'">(SV("answer is '-INF###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7G}'">(SV("answer is '#-INF##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6G}'">(SV("answer is '^^^NAN'"), nan_pos);
  check.template operator()<"answer is '{:^<6G}'">(SV("answer is 'NAN^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6G}'">(SV("answer is '^NAN^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7G}'">(SV("answer is '000-NAN'"), nan_neg);
  check.template operator()<"answer is '{:0<7G}'">(SV("answer is '-NAN000'"), nan_neg);
  check.template operator()<"answer is '{:0^7G}'">(SV("answer is '0-NAN00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07G}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<07G}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^07G}'">(SV("answer is ' 0.25  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:G}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:-G}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:+G}'">(SV("answer is '+0'"), F(0));
  check.template operator()<"answer is '{: G}'">(SV("answer is ' 0'"), F(0));

  check.template operator()<"answer is '{:G}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:-G}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:+G}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{: G}'">(SV("answer is '-0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:G}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-G}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+G}'">(SV("answer is '+INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: G}'">(SV("answer is ' INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:G}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-G}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+G}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: G}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:G}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:-G}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:+G}'">(SV("answer is '+NAN'"), nan_pos);
  check.template operator()<"answer is '{: G}'">(SV("answer is ' NAN'"), nan_pos);

  check.template operator()<"answer is '{:G}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:-G}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{:+G}'">(SV("answer is '-NAN'"), nan_neg);
  check.template operator()<"answer is '{: G}'">(SV("answer is '-NAN'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0G}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:#.0G}'">(SV("answer is '0.'"), F(0));

  check.template operator()<"answer is '{:#G}'">(SV("answer is '0.'"), F(0));
  check.template operator()<"answer is '{:#G}'">(SV("answer is '2.5'"), F(2.5));

  check.template operator()<"answer is '{:#G}'">(SV("answer is 'INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#G}'">(SV("answer is '-INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#G}'">(SV("answer is 'NAN'"), nan_pos);
  check.template operator()<"answer is '{:#G}'">(SV("answer is '-NAN'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:06G}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+06G}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+07G}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+08G}'">(SV("answer is '+0.03125'"), 0.03125);

  check.template operator()<"answer is '{:09G}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:-09G}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:+09G}'">(SV("answer is '+00.03125'"), 0.03125);
  check.template operator()<"answer is '{: 09G}'">(SV("answer is ' 00.03125'"), 0.03125);

  check.template operator()<"answer is '{:010G}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010G}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010G}'">(SV("answer is '      +INF'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010G}'">(SV("answer is '       INF'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010G}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010G}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010G}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010G}'">(SV("answer is '      -INF'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010G}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:-010G}'">(SV("answer is '       NAN'"), nan_pos);
  check.template operator()<"answer is '{:+010G}'">(SV("answer is '      +NAN'"), nan_pos);
  check.template operator()<"answer is '{: 010G}'">(SV("answer is '       NAN'"), nan_pos);

  check.template operator()<"answer is '{:010G}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:-010G}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{:+010G}'">(SV("answer is '      -NAN'"), nan_neg);
  check.template operator()<"answer is '{: 010G}'">(SV("answer is '      -NAN'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0G}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.1G}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.2G}'">(SV("answer is '0.031'"), 0.03125);
  check.template operator()<"answer is '{:.3G}'">(SV("answer is '0.0312'"), 0.03125);
  check.template operator()<"answer is '{:.4G}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.5G}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.10G}'">(SV("answer is '0.03125'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_default(TestFunction check) {
  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:>7}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<7}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^7}'">(SV("answer is ' 0.25  '"), F(0.25));

  check.template operator()<"answer is '{:->8}'">(SV("answer is '---0.125'"), F(125e-3));
  check.template operator()<"answer is '{:-<8}'">(SV("answer is '0.125---'"), F(125e-3));
  check.template operator()<"answer is '{:-^8}'">(SV("answer is '-0.125--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<07}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^07}'">(SV("answer is ' 0.25  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:-}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:+}'">(SV("answer is '+0'"), F(0));
  check.template operator()<"answer is '{: }'">(SV("answer is ' 0'"), F(0));

  check.template operator()<"answer is '{:}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:-}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:+}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{: }'">(SV("answer is '-0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: }'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: }'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: }'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: }'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form ***
  check.template operator()<"answer is '{:#}'">(SV("answer is '0.'"), F(0));
  check.template operator()<"answer is '{:#}'">(SV("answer is '2.5'"), F(2.5));

  check.template operator()<"answer is '{:#}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:07}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+07}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+08}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+09}'">(SV("answer is '+00.03125'"), 0.03125);

  check.template operator()<"answer is '{:010}'">(SV("answer is '0000.03125'"), 0.03125);
  check.template operator()<"answer is '{:-010}'">(SV("answer is '0000.03125'"), 0.03125);
  check.template operator()<"answer is '{:+010}'">(SV("answer is '+000.03125'"), 0.03125);
  check.template operator()<"answer is '{: 010}'">(SV("answer is ' 000.03125'"), 0.03125);

  check.template operator()<"answer is '{:010}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  // See format_test_floating_point_default_precision

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction>
void format_test_floating_point_default_precision(TestFunction check) {

  auto nan_pos = std::numeric_limits<F>::quiet_NaN(); // "nan"
  auto nan_neg = std::copysign(nan_pos, -1.0);        // "-nan"

  // *** align-fill & width ***
  check.template operator()<"answer is '{:7.6}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:>7.6}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<7.6}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^7.6}'">(SV("answer is ' 0.25  '"), F(0.25));

  check.template operator()<"answer is '{:->8.6}'">(SV("answer is '---0.125'"), F(125e-3));
  check.template operator()<"answer is '{:-<8.6}'">(SV("answer is '0.125---'"), F(125e-3));
  check.template operator()<"answer is '{:-^8.6}'">(SV("answer is '-0.125--'"), F(125e-3));

  check.template operator()<"answer is '{:*>6.6}'">(SV("answer is '***inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*<6.6}'">(SV("answer is 'inf***'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:*^6.6}'">(SV("answer is '*inf**'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#>7.6}'">(SV("answer is '###-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#<7.6}'">(SV("answer is '-inf###'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#^7.6}'">(SV("answer is '#-inf##'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:^>6.6}'">(SV("answer is '^^^nan'"), nan_pos);
  check.template operator()<"answer is '{:^<6.6}'">(SV("answer is 'nan^^^'"), nan_pos);
  check.template operator()<"answer is '{:^^6.6}'">(SV("answer is '^nan^^'"), nan_pos);

  check.template operator()<"answer is '{:0>7.6}'">(SV("answer is '000-nan'"), nan_neg);
  check.template operator()<"answer is '{:0<7.6}'">(SV("answer is '-nan000'"), nan_neg);
  check.template operator()<"answer is '{:0^7.6}'">(SV("answer is '0-nan00'"), nan_neg);

  // Test whether zero padding is ignored
  check.template operator()<"answer is '{:>07.6}'">(SV("answer is '   0.25'"), F(0.25));
  check.template operator()<"answer is '{:<07.6}'">(SV("answer is '0.25   '"), F(0.25));
  check.template operator()<"answer is '{:^07.6}'">(SV("answer is ' 0.25  '"), F(0.25));

  // *** Sign ***
  check.template operator()<"answer is '{:.6}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:-.6}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '+0'"), F(0));
  check.template operator()<"answer is '{: .6}'">(SV("answer is ' 0'"), F(0));

  check.template operator()<"answer is '{:.6}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:-.6}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '-0'"), F(-0.));
  check.template operator()<"answer is '{: .6}'">(SV("answer is '-0'"), F(-0.));

  // [format.string.std]/5 The sign option applies to floating-point infinity and NaN.
  check.template operator()<"answer is '{:.6}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '+inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6}'">(SV("answer is ' inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-.6}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: .6}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:.6}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:-.6}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '+nan'"), nan_pos);
  check.template operator()<"answer is '{: .6}'">(SV("answer is ' nan'"), nan_pos);

  check.template operator()<"answer is '{:.6}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:-.6}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{:+.6}'">(SV("answer is '-nan'"), nan_neg);
  check.template operator()<"answer is '{: .6}'">(SV("answer is '-nan'"), nan_neg);

  // *** alternate form **
  // When precision is zero there's no decimal point except when the alternate form is specified.
  check.template operator()<"answer is '{:.0}'">(SV("answer is '0'"), F(0));
  check.template operator()<"answer is '{:#.0}'">(SV("answer is '0.'"), F(0));

  check.template operator()<"answer is '{:#.6}'">(SV("answer is '0.'"), F(0));
  check.template operator()<"answer is '{:#.6}'">(SV("answer is '2.5'"), F(2.5));

  check.template operator()<"answer is '{:#.6}'">(SV("answer is 'inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:#.6}'">(SV("answer is '-inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:#.6}'">(SV("answer is 'nan'"), nan_pos);
  check.template operator()<"answer is '{:#.6}'">(SV("answer is '-nan'"), nan_neg);

  // *** zero-padding & width ***
  check.template operator()<"answer is '{:06.6}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+06.6}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+07.6}'">(SV("answer is '+0.03125'"), 0.03125);
  check.template operator()<"answer is '{:+08.6}'">(SV("answer is '+0.03125'"), 0.03125);

  check.template operator()<"answer is '{:09.6}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:-09.6}'">(SV("answer is '000.03125'"), 0.03125);
  check.template operator()<"answer is '{:+09.6}'">(SV("answer is '+00.03125'"), 0.03125);
  check.template operator()<"answer is '{: 09.6}'">(SV("answer is ' 00.03125'"), 0.03125);

  check.template operator()<"answer is '{:010.6}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6}'">(SV("answer is '      +inf'"), std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6}'">(SV("answer is '       inf'"), std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:-010.6}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{:+010.6}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());
  check.template operator()<"answer is '{: 010.6}'">(SV("answer is '      -inf'"), -std::numeric_limits<F>::infinity());

  check.template operator()<"answer is '{:010.6}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:-010.6}'">(SV("answer is '       nan'"), nan_pos);
  check.template operator()<"answer is '{:+010.6}'">(SV("answer is '      +nan'"), nan_pos);
  check.template operator()<"answer is '{: 010.6}'">(SV("answer is '       nan'"), nan_pos);

  check.template operator()<"answer is '{:010.6}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:-010.6}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{:+010.6}'">(SV("answer is '      -nan'"), nan_neg);
  check.template operator()<"answer is '{: 010.6}'">(SV("answer is '      -nan'"), nan_neg);

  // *** precision ***
  check.template operator()<"answer is '{:.0}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.1}'">(SV("answer is '0.03'"), 0.03125);
  check.template operator()<"answer is '{:.2}'">(SV("answer is '0.031'"), 0.03125);
  check.template operator()<"answer is '{:.3}'">(SV("answer is '0.0312'"), 0.03125);
  check.template operator()<"answer is '{:.4}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.5}'">(SV("answer is '0.03125'"), 0.03125);
  check.template operator()<"answer is '{:.10}'">(SV("answer is '0.03125'"), 0.03125);

  // *** locale-specific form ***
  // See locale-specific_form.pass.cpp
}

template <class F, class CharT, class TestFunction, class ExceptionTest>
void format_test_floating_point(TestFunction check, ExceptionTest check_exception) {
  format_test_floating_point_hex_lower_case<F, CharT>(check);
  format_test_floating_point_hex_upper_case<F, CharT>(check);
  format_test_floating_point_hex_lower_case_precision<F, CharT>(check);
  format_test_floating_point_hex_upper_case_precision<F, CharT>(check);

  format_test_floating_point_scientific_lower_case<F, CharT>(check);
  format_test_floating_point_scientific_upper_case<F, CharT>(check);

  format_test_floating_point_fixed_lower_case<F, CharT>(check);
  format_test_floating_point_fixed_upper_case<F, CharT>(check);

  format_test_floating_point_general_lower_case<F, CharT>(check);
  format_test_floating_point_general_upper_case<F, CharT>(check);

  format_test_floating_point_default<F, CharT>(check);
  format_test_floating_point_default_precision<F, CharT>(check);

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("aAeEfFgG"))
    check_exception("The format-spec type has a type not supported for a floating-point argument", fmt, F(1));
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_floating_point(TestFunction check, ExceptionTest check_exception) {
  format_test_floating_point<float, CharT>(check, check_exception);
  format_test_floating_point<double, CharT>(check, check_exception);
  format_test_floating_point<long double, CharT>(check, check_exception);
}

template <class P, class CharT, class TestFunction, class ExceptionTest>
void format_test_pointer(TestFunction check, ExceptionTest check_exception) {
  // *** align-fill & width ***
  check.template operator()<"answer is '{:6}'">(SV("answer is '   0x0'"), P(nullptr));
  check.template operator()<"answer is '{:>6}'">(SV("answer is '   0x0'"), P(nullptr));
  check.template operator()<"answer is '{:<6}'">(SV("answer is '0x0   '"), P(nullptr));
  check.template operator()<"answer is '{:^6}'">(SV("answer is ' 0x0  '"), P(nullptr));

  check.template operator()<"answer is '{:->6}'">(SV("answer is '---0x0'"), P(nullptr));
  check.template operator()<"answer is '{:-<6}'">(SV("answer is '0x0---'"), P(nullptr));
  check.template operator()<"answer is '{:-^6}'">(SV("answer is '-0x0--'"), P(nullptr));

  // *** Sign ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:-}"), P(nullptr));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:+}"), P(nullptr));
  check_exception("The format-spec should consume the input or end with a '}'", SV("{: }"), P(nullptr));

  // *** alternate form ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:#}"), P(nullptr));

  // *** zero-padding ***
  check_exception("A format-spec width field shouldn't have a leading zero", SV("{:0}"), P(nullptr));

  // *** precision ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:.}"), P(nullptr));

  // *** locale-specific form ***
  check_exception("The format-spec should consume the input or end with a '}'", SV("{:L}"), P(nullptr));

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("p"))
    check_exception("The format-spec type has a type not supported for a pointer argument", fmt, P(nullptr));
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_handle(TestFunction check, ExceptionTest check_exception) {
  // *** Valid permuatations ***
  check.template operator()<"answer is '{}'">(SV("answer is '0xaaaa'"), status::foo);
  check.template operator()<"answer is '{:x}'">(SV("answer is '0xaaaa'"), status::foo);
  check.template operator()<"answer is '{:X}'">(SV("answer is '0XAAAA'"), status::foo);
  check.template operator()<"answer is '{:s}'">(SV("answer is 'foo'"), status::foo);

  check.template operator()<"answer is '{}'">(SV("answer is '0x5555'"), status::bar);
  check.template operator()<"answer is '{:x}'">(SV("answer is '0x5555'"), status::bar);
  check.template operator()<"answer is '{:X}'">(SV("answer is '0X5555'"), status::bar);
  check.template operator()<"answer is '{:s}'">(SV("answer is 'bar'"), status::bar);

  check.template operator()<"answer is '{}'">(SV("answer is '0xaa55'"), status::foobar);
  check.template operator()<"answer is '{:x}'">(SV("answer is '0xaa55'"), status::foobar);
  check.template operator()<"answer is '{:X}'">(SV("answer is '0XAA55'"), status::foobar);
  check.template operator()<"answer is '{:s}'">(SV("answer is 'foobar'"), status::foobar);

  // P2418 Changed the argument from a const reference to a forwarding reference.
  // This mainly affects handle classes, however since we use an abstraction
  // layer here it's "tricky" to verify whether this test would do the "right"
  // thing. So these tests are done separately.

  // *** type ***
  for (const auto& fmt : invalid_types<CharT>("xXs"))
    check_exception("The format-spec type has a type not supported for a status argument", fmt, status::foo);
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_test_pointer(TestFunction check, ExceptionTest check_exception) {
  format_test_pointer<std::nullptr_t, CharT>(check, check_exception);
  format_test_pointer<void*, CharT>(check, check_exception);
  format_test_pointer<const void*, CharT>(check, check_exception);
}

template <class CharT, class TestFunction, class ExceptionTest>
void format_tests(TestFunction check, ExceptionTest check_exception) {
  // *** Test escaping  ***

  check.template operator()<"{{">(SV("{"));
  check.template operator()<"}}">(SV("}"));

  // *** Test argument ID ***
  check.template operator()<"hello {0:} {1:}">(SV("hello false true"), false, true);
  check.template operator()<"hello {1:} {0:}">(SV("hello true false"), false, true);

  // *** Test many arguments ***

  // [format.args]/1
  // An instance of basic_format_args provides access to formatting arguments.
  // Implementations should optimize the representation of basic_format_args
  // for a small number of formatting arguments.
  //
  // These's no guidances what "a small number of formatting arguments" is.
  // - fmtlib uses a 15 elements
  // - libc++ uses 12 elements
  // - MSVC STL uses a different approach regardless of the number of arguments
  // - libstdc++ has no implementation yet
  // fmtlib and libc++ use a similar approach, this approach can support 16
  // elements (based on design choices both support less elements). This test
  // makes sure "the large number of formatting arguments" code path is tested.
  check.template operator()<"{}{}{}{}{}{}{}{}{}{}\t{}{}{}{}{}{}{}{}{}{}">(SV("1234567890\t1234567890"), 1, 2, 3, 4, 5,
                                                                          6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);

  // ** Test invalid format strings ***
  check_exception("The format string terminates at a '{'", SV("{"));
  check_exception("The replacement field misses a terminating '}'", SV("{:"), 42);

  check_exception("The format string contains an invalid escape sequence", SV("}"));
  check_exception("The format string contains an invalid escape sequence", SV("{:}-}"), 42);

  check_exception("The format string contains an invalid escape sequence", SV("} "));

  check_exception("The arg-id of the format-spec starts with an invalid character", SV("{-"), 42);
  check_exception("Argument index out of bounds", SV("hello {}"));
  check_exception("Argument index out of bounds", SV("hello {0}"));
  check_exception("Argument index out of bounds", SV("hello {1}"), 42);

  // *** Test char format argument ***
  // The `char` to `wchar_t` formatting is tested separately.
  check.template operator()<"hello {}{}{}{}{}{}{}">(
      SV("hello 09azAZ!"), CharT('0'), CharT('9'), CharT('a'), CharT('z'), CharT('A'), CharT('Z'), CharT('!'));
  format_test_char<CharT>(check, check_exception);
  format_test_char_as_integer<CharT>(check, check_exception);

  // *** Test string format argument ***
  {
    CharT buffer[] = {CharT('0'), CharT('9'), CharT('a'), CharT('z'), CharT('A'), CharT('Z'), CharT('!'), 0};
    CharT* data = buffer;
    check.template operator()<"hello {}">(SV("hello 09azAZ!"), data);
  }
  {
    CharT buffer[] = {CharT('0'), CharT('9'), CharT('a'), CharT('z'), CharT('A'), CharT('Z'), CharT('!'), 0};
    const CharT* data = buffer;
    check.template operator()<"hello {}">(SV("hello 09azAZ!"), data);
  }
  {
    std::basic_string<CharT> data = STR("world");
    check.template operator()<"hello {}">(SV("hello world"), data);
  }
  {
    std::basic_string<CharT> buffer = STR("world");
    std::basic_string_view<CharT> data = buffer;
    check.template operator()<"hello {}">(SV("hello world"), data);
  }
  format_string_tests<CharT>(check, check_exception);

  // *** Test Boolean format argument ***
  check.template operator()<"hello {} {}">(SV("hello false true"), false, true);

  format_test_bool<CharT>(check, check_exception);
  format_test_bool_as_integer<CharT>(check, check_exception);

  // *** Test signed integral format argument ***
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<signed char>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<short>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<int>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<long>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<long long>(42));
#ifndef TEST_HAS_NO_INT128
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<__int128_t>(42));
#endif
  format_test_signed_integer<CharT>(check, check_exception);

  // ** Test unsigned integral format argument ***
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned char>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned short>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned long>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned long long>(42));
#ifndef TEST_HAS_NO_INT128
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<__uint128_t>(42));
#endif
  format_test_unsigned_integer<CharT>(check, check_exception);

  // *** Test floating point format argument ***
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<float>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<double>(42));
  check.template operator()<"hello {}">(SV("hello 42"), static_cast<long double>(42));
  format_test_floating_point<CharT>(check, check_exception);

  // *** Test pointer formater argument ***
  check.template operator()<"hello {}">(SV("hello 0x0"), nullptr);
  check.template operator()<"hello {}">(SV("hello 0x42"), reinterpret_cast<void*>(0x42));
  check.template operator()<"hello {}">(SV("hello 0x42"), reinterpret_cast<const void*>(0x42));
  format_test_pointer<CharT>(check, check_exception);

  // *** Test handle formatter argument ***
  format_test_handle<CharT>(check, check_exception);
}

#ifndef TEST_HAS_NO_WIDE_CHARACTERS
template <class TestFunction>
void format_tests_char_to_wchar_t(TestFunction check) {
  using CharT = wchar_t;
  check.template operator()<"hello {}{}{}{}{}">(SV("hello 09azA"), '0', '9', 'a', 'z', 'A');
}
#endif

#endif
