format: reimplement format rendering
requires literal string arrays, and implements more of the specifier specification. does not implement 'n' or '$' specifiers. falls back to snprintf for real arguments.
This commit is contained in:
parent
f9fb0873d3
commit
8cc4c1e82a
@ -286,8 +286,9 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
constexpr void panic [[noreturn]] (const char*);
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr void panic [[noreturn]] (const char *fmt, const Args&...);
|
||||
template <typename ...Args, size_t N>
|
||||
constexpr
|
||||
void panic [[noreturn]] (const char (&fmt)[N], const Args&...);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
14
debug.ipp
14
debug.ipp
@ -28,9 +28,13 @@
|
||||
namespace util { namespace debug { namespace detail {
|
||||
void panic [[noreturn]] (const char *msg);
|
||||
|
||||
template <typename ...Args>
|
||||
void panic [[noreturn]] (const char *msg, const Args& ...args)
|
||||
{ panic (util::format::render (msg, args...).c_str ()); }
|
||||
template <typename ...Args, size_t N>
|
||||
constexpr
|
||||
void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
|
||||
{
|
||||
auto msg = util::format::render (fmt, args...);
|
||||
panic (msg.c_str ());
|
||||
}
|
||||
|
||||
void not_implemented [[noreturn]] (const char *msg);
|
||||
void unreachable [[noreturn]] (const char *msg);
|
||||
@ -92,10 +96,10 @@ constexpr void panic [[noreturn]] (const char *msg)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename ...Args>
|
||||
template <typename ...Args, size_t N>
|
||||
constexpr
|
||||
void
|
||||
panic [[noreturn]] (const char *fmt, const Args& ...args)
|
||||
panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
|
||||
{
|
||||
! fmt
|
||||
? panic ("unreachable constexpr panic helper")
|
||||
|
56
format.cpp
56
format.cpp
@ -17,3 +17,59 @@
|
||||
#include "format.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace util { namespace format { namespace detail {
|
||||
//-------------------------------------------------------------------------
|
||||
std::ostream&
|
||||
operator<< (std::ostream &os, specifier::repr r)
|
||||
{
|
||||
switch (r) {
|
||||
case specifier::repr::FIXED: return os << "FIXED";
|
||||
case specifier::repr::SCIENTIFIC: return os << "SCIENTIFIC";
|
||||
case specifier::repr::AUTO: return os << "AUTO";
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
std::ostream&
|
||||
operator<< (std::ostream &os, specifier::kind t)
|
||||
{
|
||||
switch (t) {
|
||||
case specifier::kind::UNSIGNED: return os << "UNSIGNED";
|
||||
case specifier::kind::SIGNED: return os << "SIGNED";
|
||||
case specifier::kind::REAL: return os << "REAL";
|
||||
case specifier::kind::STRING: return os << "STRING";
|
||||
case specifier::kind::POINTER: return os << "POINTER";
|
||||
case specifier::kind::CHARACTER: return os << "CHARACTER";
|
||||
case specifier::kind::ESCAPE: return os << "ESCAPE";
|
||||
case specifier::kind::OSTREAM: return os << "OSTREAM";
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
std::ostream&
|
||||
operator<< (std::ostream &os, const specifier &s)
|
||||
{
|
||||
return os << "specifier {"
|
||||
"alternate_form: " << s.alternate_form << ", "
|
||||
"left_adjusted: " << s.left_adjusted << ", "
|
||||
"thousands_grouping: " << s.thousands_grouping << ", "
|
||||
"padding_char: '" << s.padding_char << "', "
|
||||
"positive_char: '" << s.positive_char << "', "
|
||||
"uppercase: " << s.uppercase << ", "
|
||||
"base: " << s.base << ", "
|
||||
"repr: " << s.r << ", "
|
||||
"kind: " << s.k << ", "
|
||||
"width: " << s.width << ", "
|
||||
"precision: " << s.precision << ", "
|
||||
"length: " << s.length <<
|
||||
" }";
|
||||
}
|
||||
} } }
|
||||
|
71
format.hpp
71
format.hpp
@ -11,7 +11,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_FORMAT_HPP
|
||||
@ -20,41 +20,56 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace util {
|
||||
namespace format {
|
||||
template <typename ...Args>
|
||||
std::string
|
||||
render (const std::string &fmt, Args&&...);
|
||||
namespace util { namespace format {
|
||||
//-------------------------------------------------------------------------
|
||||
// render a format string using the provided values.
|
||||
//
|
||||
// we deliberately only take char[] formats so as to promote the use of
|
||||
// only literal strings as format strings.
|
||||
template <typename ...Args, size_t N>
|
||||
std::string
|
||||
render (const char (&fmt)[N], const Args&...);
|
||||
|
||||
class error : public std::runtime_error
|
||||
{ using runtime_error::runtime_error; };
|
||||
//-------------------------------------------------------------------------
|
||||
class error : public std::runtime_error
|
||||
{ using runtime_error::runtime_error; };
|
||||
|
||||
// value-specifier mismatch
|
||||
class value_error : public error
|
||||
{ using error::error; };
|
||||
// value-specifier mismatch
|
||||
class value_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
// malformed format specifier
|
||||
class format_error : public error
|
||||
{ using error::error; };
|
||||
struct conversion_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
template <typename ValueT>
|
||||
class invalid_specifier : public format_error {
|
||||
public:
|
||||
using value_type = ValueT;
|
||||
struct length_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
invalid_specifier (char specifier);
|
||||
// malformed format specifier
|
||||
class syntax_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
char specifier (void) const;
|
||||
template <typename ValueT>
|
||||
class invalid_specifier : error {
|
||||
public:
|
||||
using value_type = ValueT;
|
||||
|
||||
private:
|
||||
char m_specifier;
|
||||
};
|
||||
invalid_specifier (char specifier);
|
||||
|
||||
// missing format specifier
|
||||
class missing_error : public error
|
||||
{ using error::error; };
|
||||
}
|
||||
}
|
||||
char specifier (void) const;
|
||||
|
||||
private:
|
||||
char m_specifier;
|
||||
};
|
||||
|
||||
// missing format specifier
|
||||
class missing_error : public error
|
||||
{
|
||||
public:
|
||||
missing_error ():
|
||||
error ("missing argument for specifier")
|
||||
{ ; }
|
||||
};
|
||||
} }
|
||||
|
||||
#include "format.ipp"
|
||||
|
||||
|
1067
format.ipp
1067
format.ipp
File diff suppressed because it is too large
Load Diff
4
log.hpp
4
log.hpp
@ -61,8 +61,8 @@ namespace util {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void log (level_t, const std::string &msg);
|
||||
|
||||
template <typename ...tail>
|
||||
void log (level_t, const std::string &format, tail&& ..._tail);
|
||||
template <typename ...Args, size_t N>
|
||||
void log (level_t, const char (&fmt)[N], const Args&...);
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
6
log.ipp
6
log.ipp
@ -24,11 +24,11 @@
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace util {
|
||||
template <typename ...tail>
|
||||
template <typename ...Args, size_t N>
|
||||
void
|
||||
log (level_t l, const std::string &format, tail&& ..._tail)
|
||||
log (level_t l, const char (&fmt)[N], const Args& ...args)
|
||||
{
|
||||
log (l, format::render (format, std::forward<tail> (_tail)...));
|
||||
log (l, format::render (fmt, args...));
|
||||
}
|
||||
}
|
||||
|
||||
|
20
maths.cpp
20
maths.cpp
@ -57,26 +57,6 @@ template uint32_t util::log2 (uint32_t);
|
||||
template uint64_t util::log2 (uint64_t);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace util {
|
||||
template <>
|
||||
unsigned
|
||||
digits (const uint32_t &v)
|
||||
{
|
||||
return (v >= 1000000000) ? 10 :
|
||||
(v >= 100000000) ? 9 :
|
||||
(v >= 10000000) ? 8 :
|
||||
(v >= 1000000) ? 7 :
|
||||
(v >= 100000) ? 6 :
|
||||
(v >= 10000) ? 5 :
|
||||
(v >= 1000) ? 4 :
|
||||
(v >= 100) ? 3 :
|
||||
(v >= 10) ? 2 :
|
||||
1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
std::enable_if_t<
|
||||
|
49
maths.hpp
49
maths.hpp
@ -17,10 +17,14 @@
|
||||
#ifndef __MATHS_HPP
|
||||
#define __MATHS_HPP
|
||||
|
||||
#include "./debug.hpp"
|
||||
// DO NOT INCLUDE debug.hpp
|
||||
// it triggers a circular dependency; debug -> format -> maths -> debug
|
||||
// instead, just use cassert
|
||||
|
||||
#include "./types/traits.hpp"
|
||||
#include "./float.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
@ -281,9 +285,40 @@ namespace util {
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
constexpr
|
||||
unsigned
|
||||
digits (const T& value);
|
||||
digits10 (uint32_t v) noexcept
|
||||
{
|
||||
return (v >= 1000000000) ? 10 :
|
||||
(v >= 100000000) ? 9 :
|
||||
(v >= 10000000) ? 8 :
|
||||
(v >= 1000000) ? 7 :
|
||||
(v >= 100000) ? 6 :
|
||||
(v >= 10000) ? 5 :
|
||||
(v >= 1000) ? 4 :
|
||||
(v >= 100) ? 3 :
|
||||
(v >= 10) ? 2 :
|
||||
1;
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueT, typename BaseT>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_integral<ValueT>::value && std::is_unsigned<BaseT>::value,
|
||||
unsigned
|
||||
>
|
||||
digits (ValueT value, BaseT base) noexcept
|
||||
{
|
||||
if (value < 0)
|
||||
return digits (-value, base);
|
||||
|
||||
unsigned tally = 1;
|
||||
while (value /= base)
|
||||
++tally;
|
||||
|
||||
return tally;
|
||||
}
|
||||
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
@ -326,8 +361,8 @@ namespace util {
|
||||
constexpr T
|
||||
gcd (T a, T b)
|
||||
{
|
||||
CHECK_NEZ (a);
|
||||
CHECK_NEZ (b);
|
||||
assert (a);
|
||||
assert (b);
|
||||
|
||||
while (a != b) {
|
||||
if (a > b)
|
||||
@ -506,7 +541,7 @@ namespace util {
|
||||
constexpr T
|
||||
limit (const T val, const U lo, const V hi)
|
||||
{
|
||||
CHECK_LE (lo, hi);
|
||||
assert (lo <= hi);
|
||||
|
||||
return val > hi ? hi:
|
||||
val < lo ? lo:
|
||||
@ -520,7 +555,7 @@ namespace util {
|
||||
T
|
||||
smoothstep (T a, T b, T x)
|
||||
{
|
||||
CHECK_LE(a, b);
|
||||
assert (a <= b);
|
||||
x = limit ((x - a) / (b - a), T{0}, T{1});
|
||||
return x * x * (3 - 2 * x);
|
||||
}
|
||||
|
44
tap.hpp
44
tap.hpp
@ -37,42 +37,42 @@ namespace util { namespace TAP {
|
||||
~logger ();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename ...Args>
|
||||
void expect (bool, const std::string &fmt, Args&&...);
|
||||
template <typename ...Args, size_t N>
|
||||
void expect (bool, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename ...Args>
|
||||
void expect (const std::function<bool(Args...)>&, Args&&..., const std::string& msg);
|
||||
template <typename ...Args, size_t N>
|
||||
void expect (const std::function<bool(Args...)>&, Args&&..., const char (&msg)[N]);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_eq (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_eq (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_neq (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_neq (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_gt (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_gt (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_ge (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_ge (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_lt (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_lt (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_le (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void expect_le (const T&, const U&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void expect_nan (const T&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename ...Args, size_t N>
|
||||
void expect_nan (const T&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void expect_nothrow (T&&, const std::string &fmt, Args&&...);
|
||||
template <typename T, typename ...Args, size_t N>
|
||||
void expect_nothrow (T&&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
template <typename E, typename T, typename ...Args>
|
||||
void expect_throw (T&&, const std::string &fmt, Args&&...);
|
||||
template <typename E, typename T, typename ...Args, size_t N>
|
||||
void expect_throw (T&&, const char (&fmt)[N], Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
void skip (const std::string &msg);
|
||||
|
84
tap.ipp
84
tap.ipp
@ -29,9 +29,9 @@
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ...Args>
|
||||
template <typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect (bool test, const std::string &fmt, Args&&... args)
|
||||
util::TAP::logger::expect (bool test, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
std::cout << (test ? "ok " : "not ok ") << ++m_size
|
||||
<< " - "
|
||||
@ -43,61 +43,42 @@ util::TAP::logger::expect (bool test, const std::string &fmt, Args&&... args)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename... Args>
|
||||
template <typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect (const std::function<bool(Args...)> &test, Args&&... args, const std::string &msg)
|
||||
util::TAP::logger::expect (const std::function<bool(Args...)> &test, Args&&... args, const char (&fmt)[N])
|
||||
{
|
||||
expect (test (std::forward<Args> (args)...), msg);
|
||||
expect (test (std::forward<Args> (args)...), fmt);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect_eq (const T&a, const U &b, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
expect (almost_equal (a, b), fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
template <typename T, typename U, typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect_eq (const T&a, const U &b, const std::string &fmt, Args&&... args)
|
||||
util::TAP::logger::expect_neq (const T&a, const U &b, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
|
||||
return almost_equal (t, u);
|
||||
};
|
||||
|
||||
expect<const T&, const U&> (TEST, a, b, util::format::render (fmt, std::forward<Args> (args)...));
|
||||
expect (!almost_equal (a, b), fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_neq (const T&a, const U &b, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
|
||||
return !almost_equal (t, u);
|
||||
};
|
||||
|
||||
expect<const T&, const U&> (TEST, a, b, util::format::render (fmt, std::forward<Args> (args)...));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define TAP_TEST(SUFFIX,OP) \
|
||||
template <typename T, typename U, typename ...Args> \
|
||||
template <typename T, typename U, typename ...Args, size_t N> \
|
||||
void \
|
||||
util::TAP::logger::expect_ ## SUFFIX (const T &a, \
|
||||
const U &b, \
|
||||
const std::string &fmt, \
|
||||
const char (&fmt)[N], \
|
||||
Args&&... args) \
|
||||
{ \
|
||||
static const std::function< \
|
||||
bool(const T&,const U&) \
|
||||
> TEST = [] (const T&t, const U&u) { return t OP u; }; \
|
||||
\
|
||||
expect<const T&, const U&> ( \
|
||||
TEST, \
|
||||
a, b, \
|
||||
util::format::render ( \
|
||||
fmt, \
|
||||
std::forward<Args> (args)... \
|
||||
) \
|
||||
); \
|
||||
expect ((a) OP (b), fmt, std::forward<Args> (args)...); \
|
||||
}
|
||||
|
||||
TAP_TEST(gt, > )
|
||||
@ -109,23 +90,18 @@ TAP_TEST(le, <=)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
template <typename T, typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect_nan (const T &t, const std::string &fmt, Args&&... args)
|
||||
util::TAP::logger::expect_nan (const T &t, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
bool(*func)(T) = std::isnan;
|
||||
expect<const T&> (
|
||||
std::function<bool(const T&)> (func),
|
||||
t,
|
||||
util::format::render (fmt, std::forward<Args> (args)...)
|
||||
);
|
||||
expect (std::isnan (t), fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
template <typename T, typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&&... args)
|
||||
util::TAP::logger::expect_nothrow (T &&t, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
@ -135,14 +111,14 @@ util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&&... args
|
||||
success = false;
|
||||
}
|
||||
|
||||
expect (success, util::format::render (fmt, std::forward<Args> (args)...));
|
||||
expect (success, fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename E, typename T, typename ...Args>
|
||||
template <typename E, typename T, typename ...Args, size_t N>
|
||||
void
|
||||
util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&&... args)
|
||||
util::TAP::logger::expect_throw (T &&t, const char (&fmt)[N], Args&&... args)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
@ -154,5 +130,5 @@ util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&&... args)
|
||||
success = false;
|
||||
}
|
||||
|
||||
expect (success, util::format::render (fmt, std::forward<Args> (args)...));
|
||||
expect (success, fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
@ -86,13 +86,13 @@ test_bool (util::TAP::logger &tap)
|
||||
for (auto i: positive) {
|
||||
argv[2] = i;
|
||||
p.scan (argv.size (), argv.data ());
|
||||
tap.expect_eq (value, true, i, "read bool, %s", i);
|
||||
tap.expect_eq (value, true, "read bool, %s", i);
|
||||
}
|
||||
|
||||
for (auto i: negative) {
|
||||
argv[2] = i;
|
||||
p.scan (argv.size (), argv.data ());
|
||||
tap.expect_eq (value, false, i, "read bool, %s", i);
|
||||
tap.expect_eq (value, false, "read bool, %s", i);
|
||||
}
|
||||
|
||||
// Check that invalid forms of boolean all throw exceptions
|
||||
|
@ -45,8 +45,8 @@ main (int, char**)
|
||||
};
|
||||
|
||||
for (auto i: TESTS) {
|
||||
tap.expect_eq (util::rgb_to_hsv (i.rgb), i.hsv, i.name);
|
||||
tap.expect_eq (util::hsv_to_rgb (i.hsv), i.rgb, i.name);
|
||||
tap.expect_eq (util::rgb_to_hsv (i.rgb), i.hsv, "rgb-to-hsv %s", i.name);
|
||||
tap.expect_eq (util::hsv_to_rgb (i.hsv), i.rgb, "hsv-to-rgb %s", i.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "tap.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
@ -384,8 +385,6 @@ main ()
|
||||
success = success && std::equal (std::begin (data), std::end (data), std::begin (t.data[j]));
|
||||
};
|
||||
|
||||
std::ostringstream os;
|
||||
os << "ARC4: " << i;
|
||||
tap.expect (success, os.str ());
|
||||
tap.expect (success, "ARC4 %zu", i);
|
||||
}
|
||||
}
|
||||
|
@ -50,17 +50,8 @@ main ()
|
||||
std::array<uint32_t,2> dec (t.enc);
|
||||
gen.decrypt (dec.data (), dec.size ());
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "TEA_enc " << i;
|
||||
tap.expect (enc == t.enc, os.str ());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "TEA_dec " << i;
|
||||
tap.expect (dec == t.dec, os.str ());
|
||||
}
|
||||
tap.expect (enc == t.enc, "TEA_enc %zu", i);
|
||||
tap.expect (dec == t.dec, "TEA_dec %zu", i);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
@ -49,17 +49,8 @@ main ()
|
||||
std::array<uint32_t,2> dec (t.enc);
|
||||
gen.decrypt (dec.data (), dec.size ());
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "XTEA_enc " << i;
|
||||
tap.expect (enc == t.enc, os.str ());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "XTEA_dec " << i;
|
||||
tap.expect (dec == t.dec, os.str ());
|
||||
}
|
||||
tap.expect (enc == t.enc, "XTEA_enc %zu", i);
|
||||
tap.expect (dec == t.dec, "XTEA_dec %zu", i);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
@ -104,17 +104,8 @@ main ()
|
||||
std::vector<uint32_t> dec (enc);
|
||||
gen.decrypt (dec.data (), dec.size ());
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "XXTEA_enc " << i;
|
||||
tap.expect (enc == t.enc, os.str ());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "XXTEA_dec " << i;
|
||||
tap.expect (dec == t.dec, os.str ());
|
||||
}
|
||||
tap.expect (enc == t.enc, "XXTEA_enc %zu", i);
|
||||
tap.expect (dec == t.dec, "XXTEA_dec %zu", i);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
@ -16,19 +16,19 @@ test_simple (util::TAP::logger &tap)
|
||||
std::ostringstream os;
|
||||
os << "fixed<" << type_to_string<T> () << ',' << I << ',' << E << '>';
|
||||
|
||||
tap.expect_eq (lo, lo, os.str () + " self equality");
|
||||
tap.expect_eq (hi, hi, os.str () + " self equality");
|
||||
tap.expect_eq (lo, lo, "%s self equality", os.str ());
|
||||
tap.expect_eq (hi, hi, "%s self equality", os.str ());
|
||||
|
||||
tap.expect_neq (hi, lo, os.str () + " inequality");
|
||||
tap.expect_neq (lo, hi, os.str () + " inequality");
|
||||
tap.expect_neq (hi, lo, "%s inequality", os.str ());
|
||||
tap.expect_neq (lo, hi, "%s inequality", os.str ());
|
||||
|
||||
tap.expect_lt (lo, hi, os.str () + " less than");
|
||||
tap.expect_le (lo, hi, os.str () + " less than equal");
|
||||
tap.expect_le (lo, lo, os.str () + " less than equal");
|
||||
tap.expect_lt (lo, hi, "%s less than", os.str ());
|
||||
tap.expect_le (lo, hi, "%s less than equal", os.str ());
|
||||
tap.expect_le (lo, lo, "%s less than equal", os.str ());
|
||||
|
||||
tap.expect_gt (hi, lo, os.str () + " greater than");
|
||||
tap.expect_ge (lo, lo, os.str () + " greater than equal");
|
||||
tap.expect_ge (hi, lo, os.str () + " greater than equal");
|
||||
tap.expect_gt (hi, lo, "%s greater than", os.str ());
|
||||
tap.expect_ge (lo, lo, "%s greater than equal", os.str ());
|
||||
tap.expect_ge (hi, lo, "%s greater than equal", os.str ());
|
||||
}
|
||||
|
||||
|
||||
|
191
test/format.cpp
191
test/format.cpp
@ -5,25 +5,186 @@
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
util::TAP::logger tap;
|
||||
|
||||
tap.expect_eq (util::format::render ("identity"), "identity"s, "identity literal");
|
||||
tap.expect_eq (util::format::render ("%s", "identity"s), "identity"s, "identity string substitution");
|
||||
tap.expect_eq (util::format::render ("%s", "identity" ), "identity"s, "identity char[] substitution");
|
||||
#define CHECK_RENDER(fmt,res,...) do { \
|
||||
auto val = util::format::render (fmt, ##__VA_ARGS__); \
|
||||
tap.expect_eq (val, res, "render '%s'", fmt); \
|
||||
} while (0)
|
||||
|
||||
tap.expect_throw<util::format::missing_error> ([] (void) {
|
||||
util::format::render ("%s");
|
||||
}, "missing value");
|
||||
CHECK_RENDER ("foo", "foo");
|
||||
|
||||
tap.expect_throw<util::format::invalid_specifier<int>> ([] (void) {
|
||||
util::format::render ("%<", 42);
|
||||
}, "invalid specifier");
|
||||
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
|
||||
|
||||
tap.expect_throw<util::format::format_error> ([] (void) {
|
||||
util::format::render ("%", 42);
|
||||
}, "truncated specifier");
|
||||
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);
|
||||
CHECK_RENDER ("%ji", "1", (intmax_t)1);
|
||||
CHECK_RENDER ("%zi", "1", (ssize_t)1);
|
||||
CHECK_RENDER ("%ti", "1", (ptrdiff_t)1);
|
||||
|
||||
return tap.status ();
|
||||
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);
|
||||
|
||||
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);
|
||||
CHECK_RENDER ("%ju", "1", (uintmax_t)1);
|
||||
CHECK_RENDER ("%zu", "1", (size_t)1);
|
||||
|
||||
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);
|
||||
CHECK_RENDER ("%+a", "+0x1.3c0ca2a5b1d5dp+0", 1.2345678);
|
||||
|
||||
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);
|
||||
|
||||
CHECK_RENDER ("%a", "0x1.3c0ca2a5b1d5dp+0", 1.2345678);
|
||||
CHECK_RENDER ("%A", "0X1.3C0CA2A5B1D5DP+0", 1.2345678);
|
||||
|
||||
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);
|
||||
|
||||
CHECK_RENDER ("%c", "A", 'A');
|
||||
|
||||
CHECK_RENDER ("%s", "foo", "foo");
|
||||
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");
|
||||
|
||||
CHECK_RENDER ("%p", "0x1234567", (void*)0x01234567);
|
||||
CHECK_RENDER ("%p", "0x1234567", (int*)0x01234567);
|
||||
CHECK_RENDER ("%p", "(nil)", nullptr);
|
||||
CHECK_RENDER ("%p", "(nil)", NULL);
|
||||
|
||||
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 (" %% %% ", " % % ");
|
||||
|
||||
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);
|
||||
|
||||
tap.expect_eq (util::format::render ("%u\n", 1u), "1\n", "newline");
|
||||
|
||||
#define CHECK_THROW(fmt,except,...) do { \
|
||||
tap.expect_throw<util::format::except> ([&] { \
|
||||
util::format::render (fmt, ##__VA_ARGS__); \
|
||||
}, "exception '%s' for format '%s'", #except, fmt); \
|
||||
} 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);
|
||||
|
||||
CHECK_THROW("%hhi", length_error, (long long)1);
|
||||
CHECK_THROW("%lli", length_error, (signed char)1);
|
||||
|
||||
CHECK_THROW("%u", conversion_error, 1.);
|
||||
CHECK_THROW("%u", conversion_error, "foo");
|
||||
CHECK_THROW("%u", conversion_error, (void*)0);
|
||||
CHECK_THROW("%u", conversion_error, 1);
|
||||
CHECK_THROW("%u", conversion_error, nullptr);
|
||||
|
||||
CHECK_THROW("%hhu", length_error, (unsigned long long)1);
|
||||
CHECK_THROW("%llu", length_error, (unsigned char)1);
|
||||
|
||||
CHECK_THROW("%f", conversion_error, 1u);
|
||||
CHECK_THROW("%f", conversion_error, "foo");
|
||||
CHECK_THROW("%f", conversion_error, nullptr);
|
||||
|
||||
CHECK_THROW("%s", conversion_error, 1u);
|
||||
CHECK_THROW("%s", conversion_error, '_');
|
||||
CHECK_THROW("%s", conversion_error, nullptr);
|
||||
|
||||
CHECK_THROW("%c", conversion_error, 1u);
|
||||
CHECK_THROW("%c", conversion_error, "foo");
|
||||
|
||||
CHECK_THROW("%!", conversion_error, 1u);
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ main (int, char**)
|
||||
util::TAP::logger tap;
|
||||
|
||||
for (size_t i = 0; i < elems (TESTS); ++i)
|
||||
tap.expect (TESTS[i].fun (TESTS[i].key, TESTS[i].dat, TESTS[i].res), "standard test vector %u", i);
|
||||
tap.expect (TESTS[i].fun (TESTS[i].key, TESTS[i].dat, TESTS[i].res), "standard test vector %zu", i);
|
||||
|
||||
return tap.status ();
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ main(int, char**) {
|
||||
obj.update (reinterpret_cast<const uint8_t*> (i.data), strlen (i.data));
|
||||
obj.finish ();
|
||||
|
||||
tap.expect_eq (obj.digest (), i.output, i.msg);
|
||||
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
|
||||
}
|
||||
|
||||
// Perform 'million-a' check
|
||||
|
@ -66,7 +66,7 @@ main (int, char**)
|
||||
obj.update (reinterpret_cast<const uint8_t*> (i.input), strlen (i.input));
|
||||
obj.finish ();
|
||||
|
||||
tap.expect_eq (obj.digest (), i.output, i.msg);
|
||||
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
@ -55,7 +55,7 @@ main (int, char **) {
|
||||
obj.update (reinterpret_cast<const uint8_t*> (i.input), strlen (i.input));
|
||||
obj.finish ();
|
||||
|
||||
tap.expect_eq (obj.digest (), i.output, i.msg);
|
||||
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
10
test/ip.cpp
10
test/ip.cpp
@ -23,9 +23,8 @@ test_good (util::TAP::logger &tap)
|
||||
{ "127.0.0.1", { 127, 0, 0, 1 }, "localhost" }
|
||||
};
|
||||
|
||||
for (const auto &i: TESTS) {
|
||||
tap.expect_eq (ipv4::ip::parse (i.str), i.ip, i.msg);
|
||||
}
|
||||
for (const auto &i: TESTS)
|
||||
tap.expect_eq (ipv4::ip::parse (i.str), i.ip, "%s", i.msg);
|
||||
}
|
||||
|
||||
|
||||
@ -43,9 +42,8 @@ test_bad (util::TAP::logger &tap)
|
||||
{ "256.0.0.1", "overflow" }
|
||||
};
|
||||
|
||||
for (const auto &i: TESTS) {
|
||||
tap.expect_throw<ipv4::error> ([&] { ipv4::ip::parse (i.str); }, i.msg);
|
||||
}
|
||||
for (const auto &i: TESTS)
|
||||
tap.expect_throw<ipv4::error> ([&] { ipv4::ip::parse (i.str); }, "%s", i.msg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ main (int, char**)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
test.expect (ok, i.name);
|
||||
test.expect (ok, "%s", i.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -33,7 +33,7 @@ main (void)
|
||||
for (const auto &t: TESTS) {
|
||||
constexpr float TOLERANCE = 0.00001f;
|
||||
auto root = util::roots::bisection (t.lo, t.hi, t.func, TOLERANCE);
|
||||
tap.expect_eq (root, t.root, t.msg);
|
||||
tap.expect_eq (root, t.root, "%s", t.msg);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
|
@ -47,7 +47,7 @@ test_polar (util::TAP::logger &tap)
|
||||
auto in_cart = t.cartesian;
|
||||
auto to_cart = util::polar_to_cartesian (t.polar);
|
||||
|
||||
tap.expect_lt ((in_cart - to_cart).magnitude (), 0.00001f, t.desc);
|
||||
tap.expect_lt ((in_cart - to_cart).magnitude (), 0.00001f, "%s", t.desc);
|
||||
|
||||
// Compare polar representations. Make sure to normalise them first.
|
||||
auto in_polar = t.polar;
|
||||
@ -56,7 +56,7 @@ test_polar (util::TAP::logger &tap)
|
||||
in_polar[1] = std::fmod (in_polar[1], 2 * util::PI<float>);
|
||||
to_polar[1] = std::fmod (to_polar[1], 2 * util::PI<float>);
|
||||
|
||||
tap.expect_eq (in_polar, to_polar, t.desc);
|
||||
tap.expect_eq (in_polar, to_polar, "%s", t.desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ main () {
|
||||
for (const auto &i: PARSE_TESTS) {
|
||||
util::version v (i.str);
|
||||
|
||||
tap.expect (std::equal (v.begin (), v.end (), i.parts) && v.release == i.release, i.msg);
|
||||
tap.expect (std::equal (v.begin (), v.end (), i.parts) && v.release == i.release, "%s", i.msg);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user