forked from boostorg/beast
Refactor unit_test logging:
The log member is changed to derive from std::ostream. A new class dstream is derived from std::ostream to support redirection to the Visual Studio Output Window if a debugger is attached. Obsolete classes abstract_ostream and its derived variants are removed.
This commit is contained in:
@@ -1,20 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_ABSTRACT_OSTREAM_HPP
|
|
||||||
#define BEAST_UNIT_TEST_ABSTRACT_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <beast/unit_test/basic_abstract_ostream.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
/** An abstract ostream for `char`. */
|
|
||||||
using abstract_ostream = basic_abstract_ostream <char>;
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,85 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP
|
|
||||||
#define BEAST_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <beast/unit_test/basic_scoped_ostream.hpp>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
/** Abstraction for an output stream similar to std::basic_ostream. */
|
|
||||||
template <
|
|
||||||
class CharT,
|
|
||||||
class Traits = std::char_traits <CharT>
|
|
||||||
>
|
|
||||||
class basic_abstract_ostream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using string_type = std::basic_string <CharT, Traits>;
|
|
||||||
using scoped_stream_type = basic_scoped_ostream <CharT, Traits>;
|
|
||||||
|
|
||||||
basic_abstract_ostream() = default;
|
|
||||||
|
|
||||||
virtual
|
|
||||||
~basic_abstract_ostream() = default;
|
|
||||||
|
|
||||||
basic_abstract_ostream (basic_abstract_ostream const&) = default;
|
|
||||||
basic_abstract_ostream& operator= (
|
|
||||||
basic_abstract_ostream const&) = default;
|
|
||||||
|
|
||||||
/** Returns `true` if the stream is active.
|
|
||||||
Inactive streams do not produce output.
|
|
||||||
*/
|
|
||||||
/** @{ */
|
|
||||||
virtual
|
|
||||||
bool
|
|
||||||
active() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit
|
|
||||||
operator bool() const
|
|
||||||
{
|
|
||||||
return active();
|
|
||||||
}
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/** Called to output each string. */
|
|
||||||
virtual
|
|
||||||
void
|
|
||||||
write (string_type const& s) = 0;
|
|
||||||
|
|
||||||
scoped_stream_type
|
|
||||||
operator<< (std::ostream& manip (std::ostream&))
|
|
||||||
{
|
|
||||||
return scoped_stream_type (manip,
|
|
||||||
[this](string_type const& s)
|
|
||||||
{
|
|
||||||
this->write (s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
scoped_stream_type
|
|
||||||
operator<< (T const& t)
|
|
||||||
{
|
|
||||||
return scoped_stream_type (t,
|
|
||||||
[this](string_type const& s)
|
|
||||||
{
|
|
||||||
this->write (s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,136 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP
|
|
||||||
#define BEAST_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
// gcc libstd++ doesn't have move constructors for basic_ostringstream
|
|
||||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
|
|
||||||
//
|
|
||||||
#ifndef BEAST_NO_STDLIB_STREAM_MOVE
|
|
||||||
# ifdef __GLIBCXX__
|
|
||||||
# define BEAST_NO_STDLIB_STREAM_MOVE 1
|
|
||||||
# else
|
|
||||||
# define BEAST_NO_STDLIB_STREAM_MOVE 0
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
template <
|
|
||||||
class CharT,
|
|
||||||
class Traits
|
|
||||||
>
|
|
||||||
class basic_abstract_ostream;
|
|
||||||
|
|
||||||
/** Scoped output stream that forwards to a functor upon destruction. */
|
|
||||||
template <
|
|
||||||
class CharT,
|
|
||||||
class Traits = std::char_traits <CharT>,
|
|
||||||
class Allocator = std::allocator <CharT>
|
|
||||||
>
|
|
||||||
class basic_scoped_ostream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using handler_t = std::function <void (
|
|
||||||
std::basic_string <CharT, Traits, Allocator> const&)>;
|
|
||||||
|
|
||||||
using stream_type = std::basic_ostringstream <
|
|
||||||
CharT, Traits, Allocator>;
|
|
||||||
|
|
||||||
handler_t m_handler;
|
|
||||||
|
|
||||||
#if BEAST_NO_STDLIB_STREAM_MOVE
|
|
||||||
std::unique_ptr <stream_type> m_ss;
|
|
||||||
|
|
||||||
stream_type& stream()
|
|
||||||
{
|
|
||||||
return *m_ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
stream_type m_ss;
|
|
||||||
|
|
||||||
stream_type& stream()
|
|
||||||
{
|
|
||||||
return m_ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
using string_type = std::basic_string <CharT, Traits>;
|
|
||||||
|
|
||||||
// Disallow copy since that would duplicate the output
|
|
||||||
basic_scoped_ostream (basic_scoped_ostream const&) = delete;
|
|
||||||
basic_scoped_ostream& operator= (basic_scoped_ostream const) = delete;
|
|
||||||
|
|
||||||
template <class Handler>
|
|
||||||
explicit basic_scoped_ostream (Handler&& handler)
|
|
||||||
: m_handler (std::forward <Handler> (handler))
|
|
||||||
#if BEAST_NO_STDLIB_STREAM_MOVE
|
|
||||||
, m_ss (new stream_type())
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T, class Handler>
|
|
||||||
basic_scoped_ostream (T const& t, Handler&& handler)
|
|
||||||
: m_handler (std::forward <Handler> (handler))
|
|
||||||
#if BEAST_NO_STDLIB_STREAM_MOVE
|
|
||||||
, m_ss (new stream_type())
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
stream() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_scoped_ostream (basic_abstract_ostream <
|
|
||||||
CharT, Traits>& ostream)
|
|
||||||
: m_handler (
|
|
||||||
[&](string_type const& s)
|
|
||||||
{
|
|
||||||
ostream.write (s);
|
|
||||||
})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_scoped_ostream (basic_scoped_ostream&& other)
|
|
||||||
: m_handler (std::move (other.m_handler))
|
|
||||||
, m_ss (std::move (other.m_ss))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~basic_scoped_ostream()
|
|
||||||
{
|
|
||||||
auto const& s (stream().str());
|
|
||||||
if (! s.empty())
|
|
||||||
m_handler (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_scoped_ostream&
|
|
||||||
operator<< (std::ostream& manip (std::ostream&))
|
|
||||||
{
|
|
||||||
stream() << manip;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
basic_scoped_ostream&
|
|
||||||
operator<< (T const& t)
|
|
||||||
{
|
|
||||||
stream() << t;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_BASIC_STD_OSTREAM_HPP
|
|
||||||
#define BEAST_UNIT_TEST_BASIC_STD_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <beast/unit_test/basic_abstract_ostream.hpp>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
/** Wraps an existing std::basic_ostream as an abstract_ostream. */
|
|
||||||
template <
|
|
||||||
class CharT,
|
|
||||||
class Traits = std::char_traits <CharT>
|
|
||||||
>
|
|
||||||
class basic_std_ostream
|
|
||||||
: public basic_abstract_ostream <CharT, Traits>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using typename basic_abstract_ostream <CharT, Traits>::string_type;
|
|
||||||
|
|
||||||
std::reference_wrapper <std::ostream> m_stream;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit basic_std_ostream (
|
|
||||||
std::basic_ostream <CharT, Traits>& stream)
|
|
||||||
: m_stream (stream)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
write (string_type const& s) override
|
|
||||||
{
|
|
||||||
m_stream.get() << s << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using std_ostream = basic_std_ostream <char>;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Returns a basic_std_ostream using template argument deduction. */
|
|
||||||
template <
|
|
||||||
class CharT,
|
|
||||||
class Traits = std::char_traits <CharT>
|
|
||||||
>
|
|
||||||
basic_std_ostream <CharT, Traits>
|
|
||||||
make_std_ostream (std::basic_ostream <CharT, Traits>& stream)
|
|
||||||
{
|
|
||||||
return basic_std_ostream <CharT, Traits> (stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,78 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_DEBUG_OSTREAM_HPP
|
|
||||||
#define BEAST_UNIT_TEST_DEBUG_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <beast/unit_test/abstract_ostream.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# ifndef WIN32_LEAN_AND_MEAN // VC_EXTRALEAN
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
# undef WIN32_LEAN_AND_MEAN
|
|
||||||
# else
|
|
||||||
#include <windows.h>
|
|
||||||
# endif
|
|
||||||
# ifdef min
|
|
||||||
# undef min
|
|
||||||
# endif
|
|
||||||
# ifdef max
|
|
||||||
# undef max
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
/** A basic_abstract_ostream that redirects output to an attached debugger. */
|
|
||||||
class debug_ostream
|
|
||||||
: public abstract_ostream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
bool m_debugger;
|
|
||||||
|
|
||||||
public:
|
|
||||||
debug_ostream()
|
|
||||||
: m_debugger (IsDebuggerPresent() != FALSE)
|
|
||||||
{
|
|
||||||
// Note that the check for an attached debugger is made only
|
|
||||||
// during construction time, for efficiency. A stream created before
|
|
||||||
// the debugger is attached will not have output redirected.
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
write (string_type const& s) override
|
|
||||||
{
|
|
||||||
if (m_debugger)
|
|
||||||
{
|
|
||||||
OutputDebugStringA ((s + "\n").c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << s << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
class debug_ostream
|
|
||||||
: public abstract_ostream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
write (string_type const& s) override
|
|
||||||
{
|
|
||||||
std::cout << s << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -73,8 +73,8 @@ public:
|
|||||||
int
|
int
|
||||||
sync() override
|
sync() override
|
||||||
{
|
{
|
||||||
write(str().c_str());
|
write(this->str().c_str());
|
||||||
str("");
|
this->str("");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -107,8 +107,8 @@ public:
|
|||||||
int
|
int
|
||||||
sync() override
|
sync() override
|
||||||
{
|
{
|
||||||
write(str().c_str());
|
write(this->str().c_str());
|
||||||
str("");
|
this->str("");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -130,7 +130,7 @@ class basic_dstream
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
basic_dstream()
|
basic_dstream()
|
||||||
: std::basic_ostream<CharT, Traits>(&member)
|
: std::basic_ostream<CharT, Traits>(&this->member)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -15,7 +15,8 @@ namespace unit_test {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class = void>
|
/// Holds test suites registered during static initialization.
|
||||||
|
inline
|
||||||
suite_list&
|
suite_list&
|
||||||
global_suites()
|
global_suites()
|
||||||
{
|
{
|
||||||
@@ -23,26 +24,20 @@ global_suites()
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Suite>
|
template<class Suite>
|
||||||
struct insert_suite
|
struct insert_suite
|
||||||
{
|
{
|
||||||
template <class = void>
|
insert_suite(char const* name, char const* module,
|
||||||
insert_suite (char const* name, char const* module,
|
char const* library, bool manual)
|
||||||
char const* library, bool manual);
|
{
|
||||||
|
global_suites().insert<Suite>(
|
||||||
|
name, module, library, manual);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Suite>
|
|
||||||
template <class>
|
|
||||||
insert_suite<Suite>::insert_suite (char const* name,
|
|
||||||
char const* module, char const* library, bool manual)
|
|
||||||
{
|
|
||||||
global_suites().insert <Suite> (
|
|
||||||
name, module, library, manual);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
/** Holds suites registered during static initialization. */
|
/// Holds test suites registered during static initialization.
|
||||||
inline
|
inline
|
||||||
suite_list const&
|
suite_list const&
|
||||||
global_suites()
|
global_suites()
|
||||||
|
@@ -6,12 +6,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <beast/unit_test/amount.hpp>
|
#include <beast/unit_test/amount.hpp>
|
||||||
|
#include <beast/unit_test/dstream.hpp>
|
||||||
#include <beast/unit_test/global_suites.hpp>
|
#include <beast/unit_test/global_suites.hpp>
|
||||||
#include <beast/unit_test/match.hpp>
|
#include <beast/unit_test/match.hpp>
|
||||||
#include <beast/unit_test/reporter.hpp>
|
#include <beast/unit_test/reporter.hpp>
|
||||||
#include <beast/unit_test/suite.hpp>
|
#include <beast/unit_test/suite.hpp>
|
||||||
#include <beast/unit_test/debug_ostream.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -25,11 +26,10 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
|
static
|
||||||
std::string
|
std::string
|
||||||
prefix(suite_info const& s)
|
prefix(suite_info const& s)
|
||||||
{
|
{
|
||||||
@@ -38,32 +38,34 @@ prefix(suite_info const& s)
|
|||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Log>
|
static
|
||||||
void
|
void
|
||||||
print(Log& log, suite_list const& c)
|
print(std::ostream& os, suite_list const& c)
|
||||||
{
|
{
|
||||||
std::size_t manual = 0;
|
std::size_t manual = 0;
|
||||||
for(auto const& s : c)
|
for(auto const& s : c)
|
||||||
{
|
{
|
||||||
log <<
|
os << prefix (s) << s.full_name() << '\n';
|
||||||
prefix (s) <<
|
|
||||||
s.full_name();
|
|
||||||
if(s.manual())
|
if(s.manual())
|
||||||
++manual;
|
++manual;
|
||||||
}
|
}
|
||||||
log <<
|
os <<
|
||||||
amount(c.size(), "suite") << " total, " <<
|
amount(c.size(), "suite") << " total, " <<
|
||||||
amount(manual, "manual suite")
|
amount(manual, "manual suite") <<
|
||||||
|
'\n'
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Log>
|
// Print the list of suites
|
||||||
|
// Used with the --print command line option
|
||||||
|
static
|
||||||
void
|
void
|
||||||
print(Log& log)
|
print(std::ostream& os)
|
||||||
{
|
{
|
||||||
log << "------------------------------------------";
|
os << "------------------------------------------\n";
|
||||||
print(log, global_suites());
|
print(os, global_suites());
|
||||||
log << "------------------------------------------";
|
os << "------------------------------------------" <<
|
||||||
|
std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
@@ -97,11 +99,11 @@ int main(int ac, char const* av[])
|
|||||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||||
po::notify(vm);
|
po::notify(vm);
|
||||||
|
|
||||||
beast::debug_ostream log;
|
dstream log;
|
||||||
|
|
||||||
if(vm.count("help"))
|
if(vm.count("help"))
|
||||||
{
|
{
|
||||||
log << desc;
|
log << desc << std::endl;
|
||||||
}
|
}
|
||||||
else if(vm.count("print"))
|
else if(vm.count("print"))
|
||||||
{
|
{
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_UNIT_TEST_PRINT_H_INCLUDED
|
|
||||||
#define BEAST_UNIT_TEST_PRINT_H_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/unit_test/amount.hpp>
|
|
||||||
#include <beast/unit_test/results.hpp>
|
|
||||||
#include <beast/unit_test/abstract_ostream.hpp>
|
|
||||||
#include <beast/unit_test/basic_std_ostream.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace unit_test {
|
|
||||||
|
|
||||||
/** Write test results to the specified output stream. */
|
|
||||||
/** @{ */
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
print (results const& r, abstract_ostream& stream)
|
|
||||||
{
|
|
||||||
for (auto const& s : r)
|
|
||||||
{
|
|
||||||
for (auto const& c : s)
|
|
||||||
{
|
|
||||||
stream <<
|
|
||||||
s.name() <<
|
|
||||||
(c.name().empty() ? "" : ("." + c.name()));
|
|
||||||
|
|
||||||
std::size_t i (1);
|
|
||||||
for (auto const& t : c.tests)
|
|
||||||
{
|
|
||||||
if (! t.pass)
|
|
||||||
stream <<
|
|
||||||
"#" << i <<
|
|
||||||
" failed: " << t.reason;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stream <<
|
|
||||||
amount (r.size(), "suite") << ", " <<
|
|
||||||
amount (r.cases(), "case") << ", " <<
|
|
||||||
amount (r.total(), "test") << " total, " <<
|
|
||||||
amount (r.failed(), "failure")
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
print (results const& r, std::ostream& stream = std::cout)
|
|
||||||
{
|
|
||||||
auto s (make_std_ostream (stream));
|
|
||||||
print (r, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // unit_test
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include <beast/unit_test/amount.hpp>
|
#include <beast/unit_test/amount.hpp>
|
||||||
#include <beast/unit_test/recorder.hpp>
|
#include <beast/unit_test/recorder.hpp>
|
||||||
#include <beast/unit_test/abstract_ostream.hpp>
|
|
||||||
#include <beast/unit_test/basic_std_ostream.hpp>
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -30,7 +28,7 @@ namespace detail {
|
|||||||
/** A simple test runner that writes everything to a stream in real time.
|
/** A simple test runner that writes everything to a stream in real time.
|
||||||
The totals are output when the object is destroyed.
|
The totals are output when the object is destroyed.
|
||||||
*/
|
*/
|
||||||
template <class = void>
|
template<class = void>
|
||||||
class reporter : public runner
|
class reporter : public runner
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -42,7 +40,11 @@ private:
|
|||||||
std::size_t total = 0;
|
std::size_t total = 0;
|
||||||
std::size_t failed = 0;
|
std::size_t failed = 0;
|
||||||
|
|
||||||
case_results (std::string const& name_ = "");
|
explicit
|
||||||
|
case_results(std::string name_ = "")
|
||||||
|
: name(std::move(name_))
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct suite_results
|
struct suite_results
|
||||||
@@ -51,14 +53,16 @@ private:
|
|||||||
std::size_t cases = 0;
|
std::size_t cases = 0;
|
||||||
std::size_t total = 0;
|
std::size_t total = 0;
|
||||||
std::size_t failed = 0;
|
std::size_t failed = 0;
|
||||||
typename clock_type::time_point start =
|
typename clock_type::time_point start = clock_type::now();
|
||||||
clock_type::now();
|
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
suite_results (std::string const& name_ = "");
|
suite_results(std::string const& name_ = "")
|
||||||
|
: name(std::move(name_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
add (case_results const& r);
|
add(case_results const& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct results
|
struct results
|
||||||
@@ -76,35 +80,30 @@ private:
|
|||||||
std::size_t total = 0;
|
std::size_t total = 0;
|
||||||
std::size_t failed = 0;
|
std::size_t failed = 0;
|
||||||
std::vector<run_time> top;
|
std::vector<run_time> top;
|
||||||
typename clock_type::time_point start =
|
typename clock_type::time_point start = clock_type::now();
|
||||||
clock_type::now();
|
|
||||||
|
|
||||||
void
|
void
|
||||||
add (suite_results const& r);
|
add (suite_results const& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
boost::optional <std_ostream> std_ostream_;
|
std::ostream& os_;
|
||||||
std::reference_wrapper <beast::abstract_ostream> stream_;
|
|
||||||
results results_;
|
results results_;
|
||||||
suite_results suite_results_;
|
suite_results suite_results_;
|
||||||
case_results case_results_;
|
case_results case_results_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
reporter (reporter const&) = delete;
|
reporter(reporter const&) = delete;
|
||||||
reporter& operator= (reporter const&) = delete;
|
reporter& operator=(reporter const&) = delete;
|
||||||
|
|
||||||
~reporter();
|
~reporter();
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
reporter (std::ostream& stream = std::cout);
|
reporter(std::ostream& os = std::cout);
|
||||||
|
|
||||||
explicit
|
|
||||||
reporter (beast::abstract_ostream& stream);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static
|
static
|
||||||
std::string
|
std::string
|
||||||
fmtdur (typename clock_type::duration const& d);
|
fmtdur(typename clock_type::duration const& d);
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
@@ -137,42 +136,27 @@ private:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
reporter<_>::case_results::case_results (
|
|
||||||
std::string const& name_)
|
|
||||||
: name (name_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _>
|
|
||||||
reporter<_>::suite_results::suite_results (
|
|
||||||
std::string const& name_)
|
|
||||||
: name (name_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _>
|
|
||||||
void
|
void
|
||||||
reporter<_>::suite_results::add (case_results const& r)
|
reporter<_>::
|
||||||
|
suite_results::add(case_results const& r)
|
||||||
{
|
{
|
||||||
++cases;
|
++cases;
|
||||||
total += r.total;
|
total += r.total;
|
||||||
failed += r.failed;
|
failed += r.failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::results::add (
|
reporter<_>::
|
||||||
suite_results const& r)
|
results::add(suite_results const& r)
|
||||||
{
|
{
|
||||||
++suites;
|
++suites;
|
||||||
total += r.total;
|
total += r.total;
|
||||||
cases += r.cases;
|
cases += r.cases;
|
||||||
failed += r.failed;
|
failed += r.failed;
|
||||||
|
auto const elapsed = clock_type::now() - r.start;
|
||||||
auto const elapsed =
|
if (elapsed >= std::chrono::seconds{1})
|
||||||
clock_type::now() - r.start;
|
|
||||||
if (elapsed >= std::chrono::seconds(1))
|
|
||||||
{
|
{
|
||||||
auto const iter = std::lower_bound(top.begin(),
|
auto const iter = std::lower_bound(top.begin(),
|
||||||
top.end(), elapsed,
|
top.end(), elapsed,
|
||||||
@@ -196,50 +180,40 @@ reporter<_>::results::add (
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
reporter<_>::reporter (
|
reporter<_>::
|
||||||
std::ostream& stream)
|
reporter(std::ostream& os)
|
||||||
: std_ostream_ (std::ref (stream))
|
: os_(os)
|
||||||
, stream_ (*std_ostream_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
reporter<_>::~reporter()
|
reporter<_>::~reporter()
|
||||||
{
|
{
|
||||||
if (results_.top.size() > 0)
|
if(results_.top.size() > 0)
|
||||||
{
|
{
|
||||||
stream_.get() << "Longest suite times:";
|
os_ << "Longest suite times:\n";
|
||||||
for (auto const& i : results_.top)
|
for(auto const& i : results_.top)
|
||||||
stream_.get() << std::setw(8) <<
|
os_ << std::setw(8) <<
|
||||||
fmtdur(i.second) << " " << i.first;
|
fmtdur(i.second) << " " << i.first << '\n';
|
||||||
}
|
}
|
||||||
auto const elapsed =
|
auto const elapsed = clock_type::now() - results_.start;
|
||||||
clock_type::now() - results_.start;
|
os_ <<
|
||||||
stream_.get() <<
|
|
||||||
fmtdur(elapsed) << ", " <<
|
fmtdur(elapsed) << ", " <<
|
||||||
amount (results_.suites, "suite") << ", " <<
|
amount{results_.suites, "suite"} << ", " <<
|
||||||
amount (results_.cases, "case") << ", " <<
|
amount{results_.cases, "case"} << ", " <<
|
||||||
amount (results_.total, "test") << " total, " <<
|
amount{results_.total, "test"} << " total, " <<
|
||||||
amount (results_.failed, "failure");
|
amount{results_.failed, "failure"} <<
|
||||||
|
std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
reporter<_>::reporter (
|
|
||||||
abstract_ostream& stream)
|
|
||||||
: stream_ (stream)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _>
|
|
||||||
std::string
|
std::string
|
||||||
reporter<_>::fmtdur (
|
reporter<_>::fmtdur(typename clock_type::duration const& d)
|
||||||
typename clock_type::duration const& d)
|
|
||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto const ms =
|
auto const ms = duration_cast<milliseconds>(d);
|
||||||
duration_cast<milliseconds>(d);
|
if (ms < seconds{1})
|
||||||
if (ms < seconds(1))
|
|
||||||
return std::to_string(ms.count()) + "ms";
|
return std::to_string(ms.count()) + "ms";
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::fixed << std::setprecision(1) <<
|
ss << std::fixed << std::setprecision(1) <<
|
||||||
@@ -247,67 +221,67 @@ reporter<_>::fmtdur (
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_suite_begin (
|
reporter<_>::
|
||||||
suite_info const& info)
|
on_suite_begin(suite_info const& info)
|
||||||
{
|
{
|
||||||
suite_results_ = suite_results (info.full_name());
|
suite_results_ = suite_results{info.full_name()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_suite_end()
|
reporter<_>::on_suite_end()
|
||||||
{
|
{
|
||||||
results_.add (suite_results_);
|
results_.add(suite_results_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_case_begin (
|
reporter<_>::
|
||||||
std::string const& name)
|
on_case_begin(std::string const& name)
|
||||||
{
|
{
|
||||||
case_results_ = case_results (name);
|
case_results_ = case_results (name);
|
||||||
|
os_ <<
|
||||||
stream_.get() <<
|
|
||||||
suite_results_.name <<
|
suite_results_.name <<
|
||||||
(case_results_.name.empty() ?
|
(case_results_.name.empty() ?
|
||||||
"" : (" " + case_results_.name));
|
"" : (" " + case_results_.name)) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_case_end()
|
reporter<_>::
|
||||||
|
on_case_end()
|
||||||
{
|
{
|
||||||
suite_results_.add (case_results_);
|
suite_results_.add(case_results_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_pass()
|
reporter<_>::
|
||||||
|
on_pass()
|
||||||
{
|
{
|
||||||
++case_results_.total;
|
++case_results_.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_fail (
|
reporter<_>::
|
||||||
std::string const& reason)
|
on_fail(std::string const& reason)
|
||||||
{
|
{
|
||||||
++case_results_.failed;
|
++case_results_.failed;
|
||||||
++case_results_.total;
|
++case_results_.total;
|
||||||
stream_.get() <<
|
os_ <<
|
||||||
"#" << case_results_.total <<
|
"#" << case_results_.total << " failed" <<
|
||||||
" failed" <<
|
(reason.empty() ? "" : ": ") << reason << std::endl;
|
||||||
(reason.empty() ? "" : ": ") << reason;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
reporter<_>::on_log (
|
reporter<_>::
|
||||||
std::string const& s)
|
on_log(std::string const& s)
|
||||||
{
|
{
|
||||||
stream_.get() << s;
|
os_ << s;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
@@ -9,9 +9,9 @@
|
|||||||
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
|
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/unit_test/suite_info.hpp>
|
#include <beast/unit_test/suite_info.hpp>
|
||||||
#include <beast/unit_test/abstract_ostream.hpp>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -23,28 +23,6 @@ namespace unit_test {
|
|||||||
*/
|
*/
|
||||||
class runner
|
class runner
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
// Reroutes log output to the runner
|
|
||||||
class stream_t : public abstract_ostream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
runner& owner_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
stream_t() = delete;
|
|
||||||
stream_t& operator= (stream_t const&) = delete;
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
stream_t (runner& owner);
|
|
||||||
|
|
||||||
void
|
|
||||||
write (string_type const& s) override
|
|
||||||
{
|
|
||||||
owner_.log (s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
stream_t stream_;
|
|
||||||
std::string arg_;
|
std::string arg_;
|
||||||
bool default_ = false;
|
bool default_ = false;
|
||||||
bool failed_ = false;
|
bool failed_ = false;
|
||||||
@@ -52,21 +30,20 @@ private:
|
|||||||
std::recursive_mutex mutex_;
|
std::recursive_mutex mutex_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
runner() = default;
|
||||||
virtual ~runner() = default;
|
virtual ~runner() = default;
|
||||||
runner (runner const&) = default;
|
runner(runner const&) = delete;
|
||||||
runner& operator= (runner const&) = default;
|
runner& operator=(runner const&) = delete;
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
runner();
|
|
||||||
|
|
||||||
/** Set the argument string.
|
/** Set the argument string.
|
||||||
|
|
||||||
The argument string is available to suites and
|
The argument string is available to suites and
|
||||||
allows for customization of the test. Each suite
|
allows for customization of the test. Each suite
|
||||||
defines its own syntax for the argumnet string.
|
defines its own syntax for the argumnet string.
|
||||||
The same argument is passed to all suites.
|
The same argument is passed to all suites.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
arg (std::string const& s)
|
arg(std::string const& s)
|
||||||
{
|
{
|
||||||
arg_ = s;
|
arg_ = s;
|
||||||
}
|
}
|
||||||
@@ -81,7 +58,7 @@ public:
|
|||||||
/** Run the specified suite.
|
/** Run the specified suite.
|
||||||
@return `true` if any conditions failed.
|
@return `true` if any conditions failed.
|
||||||
*/
|
*/
|
||||||
template <class = void>
|
template<class = void>
|
||||||
bool
|
bool
|
||||||
run (suite_info const& s);
|
run (suite_info const& s);
|
||||||
|
|
||||||
@@ -124,69 +101,63 @@ public:
|
|||||||
bool
|
bool
|
||||||
run_each_if (SequenceContainer const& c, Pred pred = Pred{});
|
run_each_if (SequenceContainer const& c, Pred pred = Pred{});
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
//
|
//
|
||||||
// Overrides
|
// Overrides
|
||||||
//
|
//
|
||||||
|
|
||||||
/** Called when a new suite starts. */
|
/// Called when a new suite starts.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_suite_begin (suite_info const&)
|
on_suite_begin(suite_info const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a suite ends. */
|
/// Called when a suite ends.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_suite_end()
|
on_suite_end()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a new case starts. */
|
/// Called when a new case starts.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_case_begin (std::string const&)
|
on_case_begin(std::string const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a new case ends. */
|
/// Called when a new case ends.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_case_end()
|
on_case_end()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called for each passing condition. */
|
/// Called for each passing condition.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_pass ()
|
on_pass()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called for each failing condition. */
|
/// Called for each failing condition.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_fail (std::string const&)
|
on_fail(std::string const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a test logs output. */
|
/// Called when a test logs output.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_log (std::string const&)
|
on_log(std::string const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class suite;
|
friend class suite;
|
||||||
|
|
||||||
abstract_ostream&
|
|
||||||
stream()
|
|
||||||
{
|
|
||||||
return stream_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new testcase.
|
// Start a new testcase.
|
||||||
template <class = void>
|
template <class = void>
|
||||||
void
|
void
|
||||||
@@ -207,20 +178,6 @@ private:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class>
|
|
||||||
runner::stream_t::stream_t (runner& owner)
|
|
||||||
: owner_ (owner)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
runner::runner()
|
|
||||||
: stream_ (*this)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
template <class>
|
||||||
bool
|
bool
|
||||||
runner::run (suite_info const& s)
|
runner::run (suite_info const& s)
|
||||||
|
@@ -9,15 +9,23 @@
|
|||||||
#define BEAST_UNIT_TEST_SUITE_HPP
|
#define BEAST_UNIT_TEST_SUITE_HPP
|
||||||
|
|
||||||
#include <beast/unit_test/runner.hpp>
|
#include <beast/unit_test/runner.hpp>
|
||||||
#include <string>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
class thread;
|
class thread;
|
||||||
|
|
||||||
|
enum abort_t
|
||||||
|
{
|
||||||
|
no_abort_on_fail,
|
||||||
|
abort_on_fail
|
||||||
|
};
|
||||||
|
|
||||||
/** A testsuite class.
|
/** A testsuite class.
|
||||||
|
|
||||||
Derived classes execute a series of testcases, where each testcase is
|
Derived classes execute a series of testcases, where each testcase is
|
||||||
a series of pass/fail tests. To provide a unit test using this class,
|
a series of pass/fail tests. To provide a unit test using this class,
|
||||||
derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a
|
derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a
|
||||||
@@ -25,13 +33,6 @@ class thread;
|
|||||||
*/
|
*/
|
||||||
class suite
|
class suite
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
enum abort_t
|
|
||||||
{
|
|
||||||
no_abort_on_fail,
|
|
||||||
abort_on_fail
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool abort_ = false;
|
bool abort_ = false;
|
||||||
bool aborted_ = false;
|
bool aborted_ = false;
|
||||||
@@ -44,95 +45,100 @@ private:
|
|||||||
char const*
|
char const*
|
||||||
what() const noexcept override
|
what() const noexcept override
|
||||||
{
|
{
|
||||||
return "suite aborted";
|
return "test suite aborted";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
template<class CharT, class Traits, class Allocator>
|
||||||
// Memberspace
|
class log_buf
|
||||||
class log_t
|
: public std::basic_stringbuf<CharT, Traits, Allocator>
|
||||||
{
|
{
|
||||||
private:
|
suite& suite_;
|
||||||
friend class suite;
|
|
||||||
suite* suite_ = nullptr;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
log_t () = default;
|
explicit
|
||||||
|
log_buf(suite& self)
|
||||||
|
: suite_(self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
~log_buf()
|
||||||
abstract_ostream::scoped_stream_type
|
{
|
||||||
operator<< (T const& t);
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the raw stream used for output. */
|
int
|
||||||
abstract_ostream&
|
sync() override
|
||||||
stream();
|
{
|
||||||
|
auto const& s = this->str();
|
||||||
|
if(s.size() > 0)
|
||||||
|
suite_.runner_->on_log(s);
|
||||||
|
this->str("");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
class CharT,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>
|
||||||
|
>
|
||||||
|
class log_os : public std::basic_ostream<CharT, Traits>
|
||||||
|
{
|
||||||
|
log_buf<CharT, Traits, Allocator> buf_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
log_os(suite& self)
|
||||||
|
: std::basic_ostream<CharT, Traits>(&buf_)
|
||||||
|
, buf_(self)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
private:
|
|
||||||
|
|
||||||
class scoped_testcase;
|
class scoped_testcase;
|
||||||
|
|
||||||
// Memberspace
|
|
||||||
class testcase_t
|
class testcase_t
|
||||||
{
|
{
|
||||||
private:
|
suite& suite_;
|
||||||
friend class suite;
|
|
||||||
suite* suite_ = nullptr;
|
|
||||||
std::stringstream ss_;
|
std::stringstream ss_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
testcase_t() = default;
|
explicit
|
||||||
|
testcase_t(suite& self)
|
||||||
|
: suite_(self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/** Open a new testcase.
|
/** Open a new testcase.
|
||||||
A testcase is a series of evaluated test conditions. A test suite
|
|
||||||
may have multiple test cases. A test is associated with the last
|
A testcase is a series of evaluated test conditions. A test
|
||||||
opened testcase. When the test first runs, a default unnamed
|
suite may have multiple test cases. A test is associated with
|
||||||
case is opened. Tests with only one case may omit the call
|
the last opened testcase. When the test first runs, a default
|
||||||
to testcase.
|
unnamed case is opened. Tests with only one case may omit the
|
||||||
@param abort If `true`, the suite will be stopped on first failure.
|
call to testcase.
|
||||||
|
|
||||||
|
@param abort Determines if suite continues running after a failure.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
operator() (std::string const& name,
|
operator()(std::string const& name,
|
||||||
abort_t abort = no_abort_on_fail);
|
abort_t abort = no_abort_on_fail);
|
||||||
|
|
||||||
/** Stream style composition of testcase names. */
|
|
||||||
/** @{ */
|
|
||||||
scoped_testcase
|
scoped_testcase
|
||||||
operator() (abort_t abort);
|
operator()(abort_t abort);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
scoped_testcase
|
scoped_testcase
|
||||||
operator<< (T const& t);
|
operator<<(T const& t);
|
||||||
/** @} */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Type for scoped stream logging.
|
/** Logging output stream.
|
||||||
To use this type, declare a local variable of the type
|
|
||||||
on the stack in derived class member function and construct
|
|
||||||
it from log.stream();
|
|
||||||
|
|
||||||
@code
|
Text sent to the log output stream will be forwarded to
|
||||||
|
the output stream associated with the runner.
|
||||||
scoped_stream ss (log.stream();
|
|
||||||
|
|
||||||
ss << "Hello" << std::endl;
|
|
||||||
ss << "world" << std::endl;
|
|
||||||
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
Streams constructed in this fashion will not have the line
|
|
||||||
ending automatically appended.
|
|
||||||
|
|
||||||
Thread safety:
|
|
||||||
|
|
||||||
The scoped_stream may only be used by one thread.
|
|
||||||
Multiline output sent to the stream will be atomically
|
|
||||||
written to the underlying abstract_Ostream
|
|
||||||
*/
|
*/
|
||||||
using scoped_stream = abstract_ostream::scoped_stream_type;
|
log_os<char> log;
|
||||||
|
|
||||||
/** Memberspace for logging. */
|
|
||||||
log_t log;
|
|
||||||
|
|
||||||
/** Memberspace for declaring test cases. */
|
/** Memberspace for declaring test cases. */
|
||||||
testcase_t testcase;
|
testcase_t testcase;
|
||||||
@@ -145,6 +151,12 @@ public:
|
|||||||
return *p_this_suite();
|
return *p_this_suite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suite()
|
||||||
|
: log(*this)
|
||||||
|
, testcase(*this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/** Invokes the test using the specified runner.
|
/** Invokes the test using the specified runner.
|
||||||
Data members are set up here instead of the constructor as a
|
Data members are set up here instead of the constructor as a
|
||||||
convenience to writing the derived class to avoid repetition of
|
convenience to writing the derived class to avoid repetition of
|
||||||
@@ -272,84 +284,51 @@ private:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline
|
|
||||||
abstract_ostream::scoped_stream_type
|
|
||||||
suite::log_t::operator<< (T const& t)
|
|
||||||
{
|
|
||||||
return suite_->runner_->stream() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the raw stream used for output. */
|
|
||||||
inline
|
|
||||||
abstract_ostream&
|
|
||||||
suite::log_t::stream()
|
|
||||||
{
|
|
||||||
return suite_->runner_->stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Helper for streaming testcase names
|
// Helper for streaming testcase names
|
||||||
class suite::scoped_testcase
|
class suite::scoped_testcase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
suite* suite_;
|
suite& suite_;
|
||||||
std::stringstream* ss_;
|
std::stringstream& ss_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~scoped_testcase();
|
scoped_testcase& operator=(scoped_testcase const&) = delete;
|
||||||
|
|
||||||
scoped_testcase (suite* s, std::stringstream* ss);
|
~scoped_testcase()
|
||||||
|
{
|
||||||
|
auto const& name = ss_.str();
|
||||||
|
if(! name.empty())
|
||||||
|
suite_.runner_->testcase (name);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
scoped_testcase(suite& self, std::stringstream& ss)
|
||||||
scoped_testcase (suite* s, std::stringstream* ss, T const& t);
|
: suite_(self)
|
||||||
|
, ss_(ss)
|
||||||
|
{
|
||||||
|
ss_.clear();
|
||||||
|
ss_.str({});
|
||||||
|
}
|
||||||
|
|
||||||
scoped_testcase& operator= (scoped_testcase const&) = delete;
|
template<class T>
|
||||||
|
scoped_testcase(suite& self,
|
||||||
|
std::stringstream& ss, T const& t)
|
||||||
|
: suite_(self)
|
||||||
|
, ss_(ss)
|
||||||
|
{
|
||||||
|
ss_.clear();
|
||||||
|
ss_.str({});
|
||||||
|
ss_ << t;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
scoped_testcase&
|
scoped_testcase&
|
||||||
operator<< (T const& t);
|
operator<<(T const& t)
|
||||||
|
{
|
||||||
|
ss_ << t;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
|
||||||
suite::scoped_testcase::~scoped_testcase()
|
|
||||||
{
|
|
||||||
auto const& name (ss_->str());
|
|
||||||
if (! name.empty())
|
|
||||||
suite_->runner_->testcase (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss)
|
|
||||||
: suite_ (s)
|
|
||||||
, ss_ (ss)
|
|
||||||
{
|
|
||||||
ss_->clear();
|
|
||||||
ss_->str({});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline
|
|
||||||
suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss, T const& t)
|
|
||||||
: suite_ (s)
|
|
||||||
, ss_ (ss)
|
|
||||||
{
|
|
||||||
ss_->clear();
|
|
||||||
ss_->str({});
|
|
||||||
*ss_ << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline
|
|
||||||
suite::scoped_testcase&
|
|
||||||
suite::scoped_testcase::operator<< (T const& t)
|
|
||||||
{
|
|
||||||
*ss_ << t;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -357,16 +336,16 @@ void
|
|||||||
suite::testcase_t::operator() (std::string const& name,
|
suite::testcase_t::operator() (std::string const& name,
|
||||||
abort_t abort)
|
abort_t abort)
|
||||||
{
|
{
|
||||||
suite_->abort_ = abort == abort_on_fail;
|
suite_.abort_ = abort == abort_on_fail;
|
||||||
suite_->runner_->testcase (name);
|
suite_.runner_->testcase (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
suite::scoped_testcase
|
suite::scoped_testcase
|
||||||
suite::testcase_t::operator() (abort_t abort)
|
suite::testcase_t::operator() (abort_t abort)
|
||||||
{
|
{
|
||||||
suite_->abort_ = abort == abort_on_fail;
|
suite_.abort_ = abort == abort_on_fail;
|
||||||
return { suite_, &ss_ };
|
return { suite_, ss_ };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -374,7 +353,7 @@ inline
|
|||||||
suite::scoped_testcase
|
suite::scoped_testcase
|
||||||
suite::testcase_t::operator<< (T const& t)
|
suite::testcase_t::operator<< (T const& t)
|
||||||
{
|
{
|
||||||
return { suite_, &ss_, t };
|
return { suite_, ss_, t };
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -511,8 +490,6 @@ void
|
|||||||
suite::run (runner& r)
|
suite::run (runner& r)
|
||||||
{
|
{
|
||||||
runner_ = &r;
|
runner_ = &r;
|
||||||
log.suite_ = this;
|
|
||||||
testcase.suite_ = this;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP
|
#ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP
|
||||||
#define BEAST_UNIT_TEST_SUITE_INFO_HPP
|
#define BEAST_UNIT_TEST_SUITE_INFO_HPP
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -20,19 +21,28 @@ class runner;
|
|||||||
/** Associates a unit test type with metadata. */
|
/** Associates a unit test type with metadata. */
|
||||||
class suite_info
|
class suite_info
|
||||||
{
|
{
|
||||||
private:
|
using run_type = std::function<void(runner&)>;
|
||||||
using run_type = std::function <void (runner&)>;
|
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string module_;
|
std::string module_;
|
||||||
std::string library_;
|
std::string library_;
|
||||||
bool m_manual;
|
bool manual_;
|
||||||
run_type m_run;
|
run_type run_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <class = void>
|
suite_info(
|
||||||
suite_info (std::string const& name, std::string const& module,
|
std::string name,
|
||||||
std::string const& library, bool manual, run_type run);
|
std::string module,
|
||||||
|
std::string library,
|
||||||
|
bool manual,
|
||||||
|
run_type run)
|
||||||
|
: name_(std::move(name))
|
||||||
|
, module_(std::move(module))
|
||||||
|
, library_(std::move(library))
|
||||||
|
, manual_(manual)
|
||||||
|
, run_(std::move(run))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string const&
|
std::string const&
|
||||||
name() const
|
name() const
|
||||||
@@ -52,61 +62,58 @@ public:
|
|||||||
return library_;
|
return library_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns `true` if this suite only runs manually. */
|
/// Returns `true` if this suite only runs manually.
|
||||||
bool
|
bool
|
||||||
manual() const
|
manual() const
|
||||||
{
|
{
|
||||||
return m_manual;
|
return manual_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the canonical suite name as a string. */
|
/// Return the canonical suite name as a string.
|
||||||
template <class = void>
|
|
||||||
std::string
|
std::string
|
||||||
full_name() const;
|
full_name() const
|
||||||
|
|
||||||
/** Run a new instance of the associated test suite. */
|
|
||||||
void
|
|
||||||
run (runner& r) const
|
|
||||||
{
|
{
|
||||||
m_run (r);
|
return library_ + "." + module_ + "." + name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a new instance of the associated test suite.
|
||||||
|
void
|
||||||
|
run(runner& r) const
|
||||||
|
{
|
||||||
|
run_ (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator<(suite_info const& lhs, suite_info const& rhs)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
std::tie(lhs.library_, lhs.module_, lhs.name_) <
|
||||||
|
std::tie(rhs.library_, rhs.module_, rhs.name_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class>
|
/// Convenience for producing suite_info for a given test type.
|
||||||
suite_info::suite_info (std::string const& name, std::string const& module,
|
template<class Suite>
|
||||||
std::string const& library, bool manual, run_type run)
|
|
||||||
: name_ (name)
|
|
||||||
, module_ (module)
|
|
||||||
, library_ (library)
|
|
||||||
, m_manual (manual)
|
|
||||||
, m_run (std::move (run))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
std::string
|
|
||||||
suite_info::full_name() const
|
|
||||||
{
|
|
||||||
return library_ + "." + module_ + "." + name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
operator< (suite_info const& lhs, suite_info const& rhs)
|
|
||||||
{
|
|
||||||
return lhs.full_name() < rhs.full_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience for producing suite_info for a given test type. */
|
|
||||||
template <class Suite>
|
|
||||||
suite_info
|
suite_info
|
||||||
make_suite_info (std::string const& name, std::string const& module,
|
make_suite_info(
|
||||||
std::string const& library, bool manual)
|
std::string name,
|
||||||
|
std::string module,
|
||||||
|
std::string library,
|
||||||
|
bool manual)
|
||||||
{
|
{
|
||||||
return suite_info(name, module, library, manual,
|
return suite_info(
|
||||||
[](runner& r) { return Suite{}(r); });
|
std::move(name),
|
||||||
|
std::move(module),
|
||||||
|
std::move(library),
|
||||||
|
manual,
|
||||||
|
[](runner& r)
|
||||||
|
{
|
||||||
|
Suite{}(r);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
|
@@ -18,23 +18,27 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
/** A container of test suites. */
|
/// A container of test suites.
|
||||||
class suite_list
|
class suite_list
|
||||||
: public detail::const_container <std::set <suite_info>>
|
: public detail::const_container <std::set <suite_info>>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::unordered_set <std::string> names_;
|
std::unordered_set<std::string> names_;
|
||||||
std::unordered_set <std::type_index> classes_;
|
std::unordered_set<std::type_index> classes_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Insert a suite into the set.
|
/** Insert a suite into the set.
|
||||||
|
|
||||||
The suite must not already exist.
|
The suite must not already exist.
|
||||||
*/
|
*/
|
||||||
template <class Suite>
|
template <class Suite>
|
||||||
void
|
void
|
||||||
insert (char const* name, char const* module, char const* library,
|
insert(
|
||||||
|
char const* name,
|
||||||
|
char const* module,
|
||||||
|
char const* library,
|
||||||
bool manual);
|
bool manual);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,7 +46,10 @@ public:
|
|||||||
|
|
||||||
template <class Suite>
|
template <class Suite>
|
||||||
void
|
void
|
||||||
suite_list::insert (char const* name, char const* module, char const* library,
|
suite_list::insert(
|
||||||
|
char const* name,
|
||||||
|
char const* module,
|
||||||
|
char const* library,
|
||||||
bool manual)
|
bool manual)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@@ -59,9 +66,8 @@ suite_list::insert (char const* name, char const* module, char const* library,
|
|||||||
assert (result.second); // Duplicate type
|
assert (result.second); // Duplicate type
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
cont().emplace(make_suite_info<Suite>(
|
||||||
cont().emplace (std::move (make_suite_info <Suite> (
|
name, module, library, manual));
|
||||||
name, module, library, manual)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
|
@@ -85,7 +85,7 @@ public:
|
|||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using clock_type = std::chrono::high_resolution_clock;
|
using clock_type = std::chrono::high_resolution_clock;
|
||||||
log << name;
|
log << name << std::endl;
|
||||||
for(std::size_t trial = 1; trial <= repeat; ++trial)
|
for(std::size_t trial = 1; trial <= repeat; ++trial)
|
||||||
{
|
{
|
||||||
auto const t0 = clock_type::now();
|
auto const t0 = clock_type::now();
|
||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
auto const elapsed = clock_type::now() - t0;
|
auto const elapsed = clock_type::now() - t0;
|
||||||
log <<
|
log <<
|
||||||
"Trial " << trial << ": " <<
|
"Trial " << trial << ": " <<
|
||||||
duration_cast<milliseconds>(elapsed).count() << " ms";
|
duration_cast<milliseconds>(elapsed).count() << " ms" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,10 +109,10 @@ public:
|
|||||||
static std::size_t constexpr Repeat = 50;
|
static std::size_t constexpr Repeat = 50;
|
||||||
|
|
||||||
log << "sizeof(request parser) == " <<
|
log << "sizeof(request parser) == " <<
|
||||||
sizeof(basic_parser_v1<true, null_parser<true>>);
|
sizeof(basic_parser_v1<true, null_parser<true>>) << '\n';
|
||||||
|
|
||||||
log << "sizeof(response parser) == " <<
|
log << "sizeof(response parser) == " <<
|
||||||
sizeof(basic_parser_v1<false, null_parser<true>>);
|
sizeof(basic_parser_v1<false, null_parser<true>>)<< '\n';
|
||||||
|
|
||||||
testcase << "Parser speed test, " <<
|
testcase << "Parser speed test, " <<
|
||||||
((Repeat * size_ + 512) / 1024) << "KB in " <<
|
((Repeat * size_ + 512) / 1024) << "KB in " <<
|
||||||
|
Reference in New Issue
Block a user