2015-07-21 01:37:45 +10:00
|
|
|
#include "format.hpp"
|
|
|
|
|
|
|
|
#include "tap.hpp"
|
|
|
|
|
2016-07-28 16:12:16 +10:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct userobj { };
|
|
|
|
|
|
|
|
static std::ostream&
|
|
|
|
operator<< (std::ostream &os, const userobj&)
|
|
|
|
{
|
|
|
|
return os << "userobj";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-07-21 01:37:45 +10:00
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::TAP::logger tap;
|
2015-07-21 01:37:45 +10:00
|
|
|
|
2018-08-13 16:02:18 +10:00
|
|
|
#define CHECK_RENDER(fmt,res,...) do { \
|
|
|
|
auto val = to_string (cruft::format::printf (fmt)(__VA_ARGS__)); \
|
|
|
|
tap.expect_eq (val, res, "render '%!', # %! == %!", fmt, val, res); \
|
2016-07-28 13:36:23 +10:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
CHECK_RENDER ("foo", "foo");
|
|
|
|
|
|
|
|
CHECK_RENDER ("%i", "1", 1 );
|
|
|
|
CHECK_RENDER ("%3i", " 1", 1 );
|
|
|
|
CHECK_RENDER ("%03i", "001", 1 );
|
|
|
|
CHECK_RENDER ("%.i", "", 0);
|
|
|
|
CHECK_RENDER ("% .i", " ", 0); // zero precision still requires a space
|
|
|
|
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_RENDER ("%hhi", "1", (signed char){1});
|
|
|
|
CHECK_RENDER ("%hi", "1", (signed short){1});
|
|
|
|
CHECK_RENDER ("%li", "1", (signed long){1});
|
|
|
|
CHECK_RENDER ("%lli", "1", (signed long long){1});
|
2017-01-05 19:49:07 +11:00
|
|
|
CHECK_RENDER ("%ji", "1", intmax_t{1});
|
|
|
|
CHECK_RENDER ("%zi", "1", ssize_t{1});
|
|
|
|
CHECK_RENDER ("%ti", "1", ptrdiff_t{1});
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%u", "1", 1u);
|
|
|
|
CHECK_RENDER ("%03u", "001", 1u);
|
|
|
|
CHECK_RENDER ("% u", " 1", 1u);
|
|
|
|
CHECK_RENDER ("% 3u", " 1", 1u);
|
|
|
|
CHECK_RENDER ("% 03u", " 01", 1u);
|
|
|
|
CHECK_RENDER ("%-3u", "1 ", 1u);
|
|
|
|
CHECK_RENDER ("%64u", " 1", 1u);
|
|
|
|
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_RENDER ("%hhu", "1", (unsigned char){1});
|
|
|
|
CHECK_RENDER ("%hu", "1", (unsigned short){1});
|
|
|
|
CHECK_RENDER ("%lu", "1", (unsigned long){1});
|
|
|
|
CHECK_RENDER ("%llu", "1", (unsigned long long){1});
|
2017-01-05 19:49:07 +11:00
|
|
|
CHECK_RENDER ("%ju", "1", uintmax_t{1});
|
|
|
|
CHECK_RENDER ("%zu", "0", size_t{0});
|
|
|
|
CHECK_RENDER ("%zu", "1", size_t{1});
|
|
|
|
CHECK_RENDER ("%!", "1", 1u);
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%o", "1", 01u);
|
|
|
|
CHECK_RENDER ("%o", "13", 013u);
|
|
|
|
CHECK_RENDER ("%o", "13", 013u);
|
|
|
|
CHECK_RENDER ("%#o", "013", 013u);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%x", "1", 0x1u);
|
|
|
|
CHECK_RENDER ("%x", "fe", 0xfeu);
|
|
|
|
CHECK_RENDER ("%X", "FE", 0xFEu);
|
|
|
|
CHECK_RENDER ("%#x", "0xfe", 0xfeu);
|
|
|
|
CHECK_RENDER ("%#X", "0XFE", 0xFEu);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%e", "1.000000e+00", 1.);
|
|
|
|
CHECK_RENDER ("%e", "1.200000e+00", 1.2);
|
|
|
|
CHECK_RENDER ("%e", "1.234568e+00", 1.2345678);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%E", "1.234568E+00", 1.2345678);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%f", "1.000000", 1.);
|
|
|
|
CHECK_RENDER ("%f", "1.200000", 1.2);
|
|
|
|
CHECK_RENDER ("%f", "1.234560", 1.23456);
|
|
|
|
CHECK_RENDER ("%f", "1.234567", 1.234567);
|
|
|
|
CHECK_RENDER ("%f", "1.234568", 1.2345678);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%g", "1", 1.);
|
|
|
|
CHECK_RENDER ("%g", "1.2", 1.2);
|
|
|
|
CHECK_RENDER ("%g", "1.23457", 1.2345678);
|
|
|
|
CHECK_RENDER ("%g", "0.000123457", 0.00012345678);
|
|
|
|
CHECK_RENDER ("%g", "1.23457e-05", 0.000012345678);
|
|
|
|
CHECK_RENDER ("%G", "1.23457E-05", 0.000012345678);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%+e", "+1.234568e+00", 1.2345678);
|
|
|
|
CHECK_RENDER ("%+f", "+1.234568", 1.2345678);
|
|
|
|
CHECK_RENDER ("%+g", "+1.23457", 1.2345678);
|
2018-08-13 16:02:18 +10:00
|
|
|
|
|
|
|
#if !defined(PLATFORM_WIN32)
|
|
|
|
// msys2#xxx: hexfloat output is broken under msys2
|
|
|
|
CHECK_RENDER ("%+a", "+0x1.3c0ca2a5b1d5dp+0", +0x1.3c0ca2a5b1d5dp+0);
|
|
|
|
#endif
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%#.e", "1.e+00", 1.2345678);
|
|
|
|
CHECK_RENDER ("%#.f", "1.", 1.2345678);
|
|
|
|
CHECK_RENDER ("%#.g", "1.", 1.2345678);
|
|
|
|
//CHECK_RENDER ("%#.a", "0x1.p+0", 1.2345678);
|
|
|
|
|
2018-08-13 16:02:18 +10:00
|
|
|
#if !defined(PLATFORM_WIN32)
|
|
|
|
// msys2#xxx: hexfloat output is broken under msys2
|
|
|
|
CHECK_RENDER ("%a", "0x1.3c0ca2a5b1d5dp+0", 0x1.3c0ca2a5b1d5dp+0);
|
|
|
|
CHECK_RENDER ("%A", "0X1.3C0CA2A5B1D5DP+0", 0X1.3C0CA2A5B1D5DP+0);
|
|
|
|
#endif
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%e", "inf", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%E", "INF", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%f", "inf", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%F", "INF", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%g", "inf", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%G", "INF", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%a", "inf", std::numeric_limits<double>::infinity ());
|
|
|
|
CHECK_RENDER ("%A", "INF", std::numeric_limits<double>::infinity ());
|
|
|
|
|
|
|
|
CHECK_RENDER ("%e", "nan", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%E", "NAN", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%f", "nan", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%F", "NAN", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%g", "nan", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%G", "NAN", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%a", "nan", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
CHECK_RENDER ("%A", "NAN", std::numeric_limits<double>::quiet_NaN ());
|
|
|
|
|
|
|
|
CHECK_RENDER ("%.f", "1", 1.2345678);
|
|
|
|
CHECK_RENDER ("%3.f", " 1", 1.2345678);
|
|
|
|
CHECK_RENDER ("%3.2f", "1.23", 1.2345678);
|
|
|
|
CHECK_RENDER ("%3.2f", "1234.57", 1234.5678);
|
|
|
|
|
2016-09-27 15:23:22 +10:00
|
|
|
CHECK_RENDER ("%!", "1", 1.);
|
|
|
|
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_RENDER ("%c", "A", 'A');
|
2016-09-27 15:23:22 +10:00
|
|
|
CHECK_RENDER ("%!", "A", 'A');
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%s", "foo", "foo");
|
2016-07-28 14:14:59 +10:00
|
|
|
CHECK_RENDER ("%s", "foo", std::string ("foo"));
|
|
|
|
CHECK_RENDER ("%s", "foo", const_cast<char*> ("foo"));
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_RENDER ("%.s", "", "foo");
|
|
|
|
CHECK_RENDER ("%.0s", "", "foo");
|
|
|
|
CHECK_RENDER ("%.2s", "fo", "foo");
|
|
|
|
CHECK_RENDER ("%.02s", "fo", "foo");
|
|
|
|
CHECK_RENDER ("%.64s", "foo", "foo");
|
|
|
|
CHECK_RENDER ("%3.1s", " f", "foo");
|
|
|
|
CHECK_RENDER ("%-3.1s", "f ", "foo");
|
2016-09-27 15:23:22 +10:00
|
|
|
CHECK_RENDER ("%!", "foo", "foo");
|
|
|
|
|
2016-07-28 16:12:16 +10:00
|
|
|
CHECK_RENDER ("%!", "userobj", userobj {});
|
2016-07-28 13:36:23 +10:00
|
|
|
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_RENDER ("%p", "0x1234567", reinterpret_cast<void*>(0x01234567));
|
|
|
|
CHECK_RENDER ("%p", "0x1234567", reinterpret_cast<int*> (0x01234567));
|
|
|
|
CHECK_RENDER ("%p", "0x1234567", reinterpret_cast<char*>(0x01234567));
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_RENDER ("%p", "(nil)", nullptr);
|
|
|
|
CHECK_RENDER ("%p", "(nil)", NULL);
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_RENDER ("%!", "0x1234567", reinterpret_cast<void*>(0x01234567));
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_RENDER ("%%", "%");
|
|
|
|
CHECK_RENDER ("%10%", "%");
|
|
|
|
CHECK_RENDER ("%.%", "%");
|
|
|
|
CHECK_RENDER ("% 0-+#12.34%", "%"); // escaped conversions should largely ignore flags, width, and precision.
|
|
|
|
|
|
|
|
// multiple components
|
|
|
|
CHECK_RENDER ("%%%%", "%%");
|
|
|
|
|
|
|
|
CHECK_RENDER (" %%", " %");
|
|
|
|
CHECK_RENDER ("%% ", "% ");
|
|
|
|
CHECK_RENDER ("%% %%", "% %");
|
|
|
|
CHECK_RENDER (" %% %% ", " % % ");
|
|
|
|
|
2016-12-06 13:37:54 +11:00
|
|
|
CHECK_RENDER ("%%%d%%", "%0%", 0);
|
|
|
|
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_RENDER ("%u %u", "1 2", 1u, 2u);
|
|
|
|
|
|
|
|
CHECK_RENDER ("%#o %o", "010 10", 8u, 8u);
|
|
|
|
CHECK_RENDER ("%#o %o %#o", "010 10 010", 8u, 8u, 8u);
|
|
|
|
CHECK_RENDER ("%X%x%X", "FfF", 0xfu, 0xfu, 0xfu);
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
tap.expect_eq (to_string (cruft::format::printf ("%u\n")(1u)), "1\n", "newline");
|
2016-07-28 13:36:23 +10:00
|
|
|
|
2018-01-09 16:28:25 +11:00
|
|
|
#define CHECK_THROW(fmt,except,...) do { \
|
|
|
|
tap.expect_throw<std::exception> ([&] { \
|
2018-08-05 14:42:02 +10:00
|
|
|
to_string (cruft::format::printf (fmt)(__VA_ARGS__)); \
|
2018-01-09 16:28:25 +11:00
|
|
|
}, "exception '%s' for format '%s'", #except, fmt); \
|
2016-07-28 13:36:23 +10:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
CHECK_THROW("%", syntax_error);
|
|
|
|
CHECK_THROW("%_", syntax_error);
|
|
|
|
CHECK_THROW("%_u", syntax_error);
|
|
|
|
|
|
|
|
CHECK_THROW("%u", missing_error);
|
|
|
|
CHECK_THROW("%!", missing_error);
|
|
|
|
|
|
|
|
CHECK_THROW("%d", conversion_error, 1u);
|
|
|
|
CHECK_THROW("%i", conversion_error, 1u);
|
|
|
|
CHECK_THROW("%i", conversion_error, nullptr);
|
|
|
|
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_THROW("%hhi", length_error, (long long){1});
|
|
|
|
CHECK_THROW("%lli", length_error, (signed char){1});
|
2016-07-28 13:36:23 +10:00
|
|
|
|
|
|
|
CHECK_THROW("%u", conversion_error, 1.);
|
|
|
|
CHECK_THROW("%u", conversion_error, "foo");
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_THROW("%u", conversion_error, (void*){0});
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_THROW("%u", conversion_error, 1);
|
|
|
|
CHECK_THROW("%u", conversion_error, nullptr);
|
|
|
|
|
2018-05-03 18:32:08 +10:00
|
|
|
CHECK_THROW("%hhu", length_error, (unsigned long long){1});
|
|
|
|
CHECK_THROW("%llu", length_error, (unsigned char){1});
|
2015-07-21 01:37:45 +10:00
|
|
|
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_THROW("%f", conversion_error, 1u);
|
|
|
|
CHECK_THROW("%f", conversion_error, "foo");
|
|
|
|
CHECK_THROW("%f", conversion_error, nullptr);
|
2016-01-20 16:39:20 +11:00
|
|
|
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_THROW("%s", conversion_error, 1u);
|
|
|
|
CHECK_THROW("%s", conversion_error, '_');
|
|
|
|
CHECK_THROW("%s", conversion_error, nullptr);
|
2016-01-20 16:39:20 +11:00
|
|
|
|
2016-07-28 13:36:23 +10:00
|
|
|
CHECK_THROW("%c", conversion_error, 1u);
|
|
|
|
CHECK_THROW("%c", conversion_error, "foo");
|
2017-05-22 13:55:21 +10:00
|
|
|
|
|
|
|
return tap.status ();
|
2015-07-21 01:37:45 +10:00
|
|
|
}
|