refactor test framework files

This commit is contained in:
Vinnie Falco 2022-08-14 13:21:20 -07:00
parent 35982f4d47
commit daf605409a
17 changed files with 1251 additions and 1489 deletions

File diff suppressed because it is too large Load Diff

View File

@ -9,23 +9,572 @@
#include "test_suite.hpp"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <vector>
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <debugapi.h>
#include <crtdbg.h>
#include <sstream>
#endif
namespace test_suite {
//----------------------------------------------------------
//
// debug_stream
//
//----------------------------------------------------------
#ifdef _MSC_VER
namespace detail {
class debug_streambuf
: public std::stringbuf
{
std::ostream& os_;
bool dbg_;
void
write(char const* s)
{
if(dbg_)
::OutputDebugStringA(s);
os_ << s;
}
public:
explicit
debug_streambuf(
std::ostream& os)
: os_(os)
, dbg_(::IsDebuggerPresent() != 0)
{
}
~debug_streambuf()
{
sync();
}
int sync() override
{
write(this->str().c_str());
this->str("");
return 0;
}
};
} // detail
//------------------------------------------------
/** std::ostream with Visual Studio IDE redirection.
Instances of this stream wrap a specified
`ostream` (such as `cout` or `cerr`). If a
debugger is attached when the stream is
created, output will additionally copied
to the debugger's output window.
*/
class debug_stream : public std::ostream
{
detail::debug_streambuf buf_;
public:
/** Construct a stream.
@param os The output stream to wrap.
*/
explicit
debug_stream(
std::ostream& os)
: std::ostream(&buf_)
, buf_(os)
{
if(os.flags() & std::ios::unitbuf)
std::unitbuf(*this);
}
};
#else
using debug_stream = std::ostream&;
#endif
//----------------------------------------------------------
//
// suite
//
//----------------------------------------------------------
any_suite::
~any_suite() = default;
//----------------------------------------------------------
suites&
suites::
instance() noexcept
{
class suites_impl : public suites
{
std::vector<any_suite const*> v_;
public:
void
insert(any_suite const& t) override
{
v_.push_back(&t);
}
iterator
begin() const noexcept override
{
if(! v_.empty())
return &v_[0];
return nullptr;
}
iterator
end() const noexcept override
{
if(! v_.empty())
return &v_[0] + v_.size();
return nullptr;
}
void
sort() override
{
std::sort(
v_.begin(),
v_.end(),
[]( any_suite const* p0,
any_suite const* p1)
{
auto s0 = p0->name();
auto n0 = std::strlen(s0);
auto s1 = p1->name();
auto n1 = std::strlen(s1);
return std::lexicographical_compare(
s0, s0 + n0, s1, s1 + n1);
});
}
};
static suites_impl impl;
return impl;
}
//----------------------------------------------------------
//
// runner
//
//----------------------------------------------------------
any_runner*&
any_runner::
instance_impl() noexcept
{
static any_runner* p = nullptr;
return p;
}
any_runner&
any_runner::
instance() noexcept
{
return *instance_impl();
}
any_runner::
any_runner() noexcept
: prev_(instance_impl())
{
instance_impl() = this;
}
any_runner::
~any_runner()
{
instance_impl() = prev_;
}
//----------------------------------------------------------
//
// implementation
//
//----------------------------------------------------------
namespace detail {
bool
test_impl(
bool cond,
char const* expr,
char const* func,
char const* file,
int line)
{
return any_runner::instance().test(
cond, expr, func, file, line);
}
void
throw_failed_impl(
const char* expr,
char const* excep,
char const* func,
char const* file,
int line)
{
std::stringstream ss;
ss <<
"expression '" << expr <<
"' didn't throw '" << excep <<
"' in function '" << func <<
"'";
any_runner::instance().test(false, ss.str().c_str(),
func, file, line);
}
void
no_throw_failed_impl(
const char* expr,
char const* excep,
char const* func,
char const* file,
int line)
{
std::stringstream ss;
ss <<
"expression '" << expr <<
"' threw '" << excep <<
"' in function '" << func <<
"'";
any_runner::instance().test(false, ss.str().c_str(),
func, file, line);
}
void
no_throw_failed_impl(
const char* expr,
char const* func,
char const* file,
int line)
{
std::stringstream ss;
ss <<
"expression '" << expr <<
"' threw in function '" << func << "'";
any_runner::instance().test(false, ss.str().c_str(),
func, file, line);
}
//----------------------------------------------------------
//
// simple_runner
//
//----------------------------------------------------------
using clock_type =
std::chrono::steady_clock;
struct elapsed
{
clock_type::duration d;
};
std::ostream&
operator<<(
std::ostream& os,
elapsed const& e)
{
using namespace std::chrono;
auto const ms = duration_cast<
milliseconds>(e.d);
if(ms < seconds{1})
{
os << ms.count() << "ms";
}
else
{
std::streamsize width{
os.width()};
std::streamsize precision{
os.precision()};
os << std::fixed <<
std::setprecision(1) <<
(ms.count() / 1000.0) << "s";
os.precision(precision);
os.width(width);
}
return os;
}
//----------------------------------------------------------
//
// log_type
//
//----------------------------------------------------------
std::ostream&
detail::
log_type::
stream() noexcept
{
struct buffer : std::stringbuf
{
int
sync() override
{
auto const& s = this->str();
if(s.size() > 0)
any_runner::instance().note(s.c_str());
this->str("");
return 0;
}
};
struct ostream : std::ostream
{
buffer buf_;
ostream()
: std::ostream(&buf_)
{
}
~ostream()
{
buf_.sync();
}
};
static ostream ss;
return ss;
}
} // detail
} // test_suite
//------------------------------------------------
namespace test_suite {
namespace detail {
class simple_runner : public any_runner
{
struct summary
{
char const* name;
clock_type::time_point start;
clock_type::duration elapsed;
std::atomic<std::size_t> failed;
std::atomic<std::size_t> total;
summary(summary const& other) noexcept
: name(other.name)
, start(other.start)
, elapsed(other.elapsed)
, failed(other.failed.load())
, total(other.total.load())
{
}
explicit
summary(char const* name_) noexcept
: name(name_)
, start(clock_type::now())
, failed(0)
, total(0)
{
}
};
summary all_;
std::ostream& log_;
std::vector<summary> v_;
public:
explicit
simple_runner(
std::ostream& os)
: all_("(all)")
, log_(os)
{
std::unitbuf(log_);
v_.reserve(256);
}
~simple_runner()
{
log_ <<
elapsed{clock_type::now() -
all_.start } << ", " <<
v_.size() << " suites, " <<
all_.failed.load() << " failures, " <<
all_.total.load() << " total." <<
std::endl;
}
// true if no failures
bool
success() const noexcept
{
return all_.failed.load() == 0;
}
void
run(any_suite const& test) override
{
v_.emplace_back(test.name());
log_ << test.name() << "\n";
test.run();
v_.back().elapsed =
clock_type::now() -
v_.back().start;
}
void
note(char const* msg) override
{
log_ << msg << "\n";
}
char const*
filename(
char const* file)
{
auto const p0 = file;
auto p = p0 + std::strlen(file);
while(p-- != p0)
{
#ifdef _MSC_VER
if(*p == '\\')
#else
if(*p == '/')
#endif
break;
}
return p + 1;
}
bool test(bool, char const*, char const*, char const*, int) override;
};
//----------------------------------------------------------
bool
simple_runner::
test(
bool cond,
char const* expr,
char const* func,
char const* file,
int line)
{
auto const id = ++all_.total;
++v_.back().total;
if(cond)
return true;
++all_.failed;
++v_.back().failed;
(void)func;
log_ <<
"#" << id << " " <<
filename(file) << "(" << line << ") "
"failed: '" << expr << "'"
//" in " << func <<
"\n";
log_.flush();
return false;
}
//----------------------------------------------------------
int
run(std::ostream& out,
int argc, char const* const* argv)
{
if(argc == 2)
{
std::string arg(argv[1]);
if(arg == "-h" || arg == "--help")
{
log <<
"Usage:\n"
" " << argv[0] << ": { <suite-name>... }" <<
std::endl;
return EXIT_SUCCESS;
}
}
simple_runner any_runner(out);
suites::instance().sort();
if(argc == 1)
{
for(any_suite const* sp :
suites::instance())
any_runner.run(*sp);
}
else
{
std::vector<std::string> args;
args.reserve(argc - 1);
for(int i = 0; i < argc - 1; ++i)
args.push_back(argv[i + 1]);
for(auto const& e : suites::instance())
{
std::string s(e->name());
if(std::find_if(
args.begin(), args.end(),
[&](std::string const& arg)
{
if(arg.size() > s.size())
return false;
return s.compare(
s.size() - arg.size(),
arg.size(),
arg.data(),
arg.size()) == 0;
}) != args.end())
{
any_runner.run(*e);
}
}
}
return any_runner.success() ?
EXIT_SUCCESS : EXIT_FAILURE;
}
} // detail
} // test_suite
//------------------------------------------------
// Simple main used to produce stand
// alone executables that run unit tests.
int main(int argc, char const* const* argv)
{
#ifdef _MSC_VER
{
int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flags |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(flags);
}
int flags = _CrtSetDbgFlag(
_CRTDBG_REPORT_FLAG);
flags |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(flags);
#endif
::test_suite::debug_stream log(std::cerr);
return ::test_suite::run(log, argc, argv);
return ::test_suite::detail::run(log, argc, argv);
}

514
extra/test_suite.hpp Normal file
View File

@ -0,0 +1,514 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
//
// Official repository: https://github.com/CPPAlliance/url
//
#ifndef BOOST_URL_EXTRA_TEST_SUITE_HPP
#define BOOST_URL_EXTRA_TEST_SUITE_HPP
#if defined(_MSC_VER)
# pragma once
#endif
#include <boost/current_function.hpp>
#include <cctype>
#include <sstream>
#include <type_traits>
// This is a derivative work
// Copyright 2002-2018 Peter Dimov
// Copyright (c) 2002, 2009, 2014 Peter Dimov
// Copyright (2) Beman Dawes 2010, 2011
// Copyright (3) Ion Gaztanaga 2013
//
// Copyright 2018 Glen Joseph Fernandes
// (glenjofe@gmail.com)
namespace test_suite {
//------------------------------------------------
struct any_suite
{
virtual ~any_suite() = 0;
virtual char const* name() const noexcept = 0;
virtual void run() const = 0;
};
//------------------------------------------------
struct suites
{
using iterator = any_suite const* const*;
virtual void insert(any_suite const&) = 0;
virtual iterator begin() const noexcept = 0;
virtual iterator end() const noexcept = 0;
// DEPRECATED
virtual void sort() = 0;
static suites& instance() noexcept;
};
//------------------------------------------------
template<class T>
class suite : public any_suite
{
char const* name_;
public:
explicit
suite(char const* name) noexcept
: name_(name)
{
suites::instance().insert(*this);
}
char const*
name() const noexcept override
{
return name_;
}
void
run() const override
{
T().run();
}
};
//------------------------------------------------
class any_runner
{
any_runner* prev_;
static any_runner*&
instance_impl() noexcept;
public:
static any_runner& instance() noexcept;
any_runner() noexcept;
~any_runner();
virtual void run(any_suite const& test) = 0;
virtual void note(char const* msg) = 0;
virtual bool test(bool cond,
char const* expr, char const* func,
char const* file, int line) = 0;
};
//------------------------------------------------
namespace detail {
// In the comparisons below, it is possible that
// T and U are signed and unsigned integer types,
// which generates warnings in some compilers.
// A cleaner fix would require common_type trait
// or some meta-programming, which would introduce
// a dependency on Boost.TypeTraits. To avoid
// the dependency we just disable the warnings.
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wsign-compare")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wsign-compare"
# endif
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4389)
#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-compare"
#endif
template<class...>
struct make_void
{
using type = void;
};
template<class... Ts>
using void_t = typename make_void<Ts...>::type;
template <class T, class = void>
struct is_streamable : std::false_type
{};
template <class T>
struct is_streamable<
T, void_t<decltype(std::declval<
std::ostream&>() << std::declval<T&>())
> > : std::true_type
{};
template <class T>
auto
test_output_impl(T const& v) ->
typename std::enable_if<
is_streamable<T>::value,
T const&>::type
{
return v;
}
template <class T>
auto
test_output_impl(T const&) ->
typename std::enable_if<
! is_streamable<T>::value,
std::string>::type
{
return "?";
}
// specialize test output for char pointers to avoid printing as cstring
template<class T>
const void* test_output_impl(T volatile* v) { return const_cast<T*>(v); }
inline const void* test_output_impl(const char* v) { return v; }
inline const void* test_output_impl(const unsigned char* v) { return v; }
inline const void* test_output_impl(const signed char* v) { return v; }
inline const void* test_output_impl(char* v) { return v; }
inline const void* test_output_impl(unsigned char* v) { return v; }
inline const void* test_output_impl(signed char* v) { return v; }
inline const void* test_output_impl(std::nullptr_t) { return nullptr; }
// print chars as numeric
inline int test_output_impl( signed char const& v ) { return v; }
inline unsigned test_output_impl( unsigned char const& v ) { return v; }
// Whether wchar_t is signed is implementation-defined
template<bool Signed> struct lwt_long_type {};
template<> struct lwt_long_type<true> { typedef long type; };
template<> struct lwt_long_type<false> { typedef unsigned long type; };
inline lwt_long_type<
(static_cast<wchar_t>(-1) < static_cast<wchar_t>(0))
>::type test_output_impl( wchar_t const& v ) { return v; }
#if !defined( BOOST_NO_CXX11_CHAR16_T )
inline unsigned long test_output_impl( char16_t const& v ) { return v; }
#endif
#if !defined( BOOST_NO_CXX11_CHAR32_T )
inline unsigned long test_output_impl( char32_t const& v ) { return v; }
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4996)
#endif
inline std::string test_output_impl( char const& v )
{
if( std::isprint( static_cast<unsigned char>( v ) ) )
{
return std::string( 1, v );
}
else
{
char buffer[ 8 ];
std::sprintf( buffer, "\\x%02X", static_cast<unsigned char>( v ) );
return buffer;
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wsign-compare")
# pragma clang diagnostic pop
# endif
#elif defined(_MSC_VER)
# pragma warning(pop)
#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
# pragma GCC diagnostic pop
#endif
bool
test_impl(
bool cond,
char const* expr,
char const* func,
char const* file,
int line);
void
throw_failed_impl(
const char* expr,
char const* excep,
char const* func,
char const* file,
int line);
void
no_throw_failed_impl(
const char* expr,
char const* excep,
char const* func,
char const* file,
int line);
void
no_throw_failed_impl(
const char* expr,
char const* func,
char const* file,
int line);
// In the comparisons below, it is possible that
// T and U are signed and unsigned integer types,
// which generates warnings in some compilers.
// A cleaner fix would require common_type trait
// or some meta-programming, which would introduce
// a dependency on Boost.TypeTraits. To avoid
// the dependency we just disable the warnings.
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wsign-compare")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wsign-compare"
# endif
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4389)
#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-compare"
#endif
struct lw_test_eq
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t == u; }
};
struct lw_test_ne
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t != u; }
};
struct lw_test_lt
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t < u; }
};
struct lw_test_le
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t <= u; }
};
struct lw_test_gt
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t > u; }
};
struct lw_test_ge
{
template <typename T, typename U>
bool operator()(const T& t, const U& u) const { return t >= u; }
};
// lwt_predicate_name
template<class T> char const * lwt_predicate_name( T const& )
{
return "~=";
}
inline char const * lwt_predicate_name( lw_test_eq const& )
{
return "==";
}
inline char const * lwt_predicate_name( lw_test_ne const& )
{
return "!=";
}
inline char const * lwt_predicate_name( lw_test_lt const& )
{
return "<";
}
inline char const * lwt_predicate_name( lw_test_le const& )
{
return "<=";
}
inline char const * lwt_predicate_name( lw_test_gt const& )
{
return ">";
}
inline char const * lwt_predicate_name( lw_test_ge const& )
{
return ">=";
}
//------------------------------------------------
template<class Pred, class T, class U>
bool
test_with_impl(
Pred pred,
char const* expr1,
char const* expr2,
char const* func,
char const* file,
int line,
T const& t, U const& u)
{
if(pred(t, u))
{
any_runner::instance().test(true, "", func, file, line);
return true;
}
std::stringstream ss;
ss <<
"'" << test_output_impl(t) << "' " <<
lwt_predicate_name(pred) <<
" '" << test_output_impl(u) << "' (" <<
expr1 << "' " <<
lwt_predicate_name(pred) <<
" '" << expr2 << "')";
any_runner::instance().test(false, ss.str().c_str(), func, file, line);
return false;
}
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wsign-compare")
# pragma clang diagnostic pop
# endif
#elif defined(_MSC_VER)
# pragma warning(pop)
#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
# pragma GCC diagnostic pop
#endif
//----------------------------------------------------------
struct log_type
{
template<class T>
friend
std::ostream&
operator<<(
log_type const&, T&& t)
{
return stream() << t;
}
private:
static std::ostream& stream() noexcept;
};
//----------------------------------------------------------
} // detail
/** Log output to the current suite
*/
constexpr detail::log_type log{};
#define BOOST_TEST(expr) ( \
::test_suite::detail::test_impl( \
(expr) ? true : false, #expr, \
BOOST_CURRENT_FUNCTION, __FILE__, __LINE__ ) )
#define BOOST_ERROR(msg) \
::test_suite::detail::test_impl( \
false, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__ )
#define BOOST_TEST_WITH(expr1,expr2,predicate) ( \
::test_suite::detail::test_with_impl( \
predicate, #expr1, #expr2, BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__, expr1, expr2) )
#define BOOST_TEST_EQ(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_eq() )
#define BOOST_TEST_NE(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_ne() )
#define BOOST_TEST_LT(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_lt() )
#define BOOST_TEST_LE(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_le() )
#define BOOST_TEST_GT(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_gt() )
#define BOOST_TEST_GE(expr1,expr2) \
BOOST_TEST_WITH( expr1, expr2, \
::test_suite::detail::lw_test_ge() )
#define BOOST_TEST_PASS() BOOST_TEST(true)
#define BOOST_TEST_FAIL() BOOST_TEST(false)
#define BOOST_TEST_NOT(expr) BOOST_TEST(!(expr))
#ifndef BOOST_NO_EXCEPTIONS
# define BOOST_TEST_THROWS( expr, ex ) \
try { \
(void)(expr); \
::test_suite::detail::throw_failed_impl( \
#expr, #ex, BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__); \
} \
catch(ex const&) { \
BOOST_TEST_PASS(); \
} \
catch(...) { \
::test_suite::detail::throw_failed_impl( \
#expr, #ex, BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__); \
}
//
#else
#define BOOST_TEST_THROWS( expr, ex )
#endif
#ifndef BOOST_NO_EXCEPTIONS
# define BOOST_TEST_NO_THROW( expr ) \
try { \
(void)(expr); \
BOOST_TEST_PASS(); \
} catch (const std::exception& e) { \
::test_suite::detail::no_throw_failed_impl( \
#expr, e.what(), BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__); \
} catch (...) { \
::test_suite::detail::no_throw_failed_impl( \
#expr, BOOST_CURRENT_FUNCTION, \
__FILE__, __LINE__); \
}
//
#else
# define BOOST_TEST_NO_THROW( expr ) ( [&]{ expr; return true; }() )
#endif
#define TEST_SUITE(type, name) \
static ::test_suite::suite<type> type##_(name)
} // test_suite
#endif

View File

@ -13,6 +13,7 @@ if(NOT TARGET boost_url_all_tests)
set_property(TARGET boost_url_all_tests PROPERTY FOLDER Dependencies)
endif()
add_subdirectory(extra)
add_subdirectory(limits)
add_subdirectory(unit)
#add_subdirectory(wpt)

View File

@ -7,5 +7,6 @@
# Official repository: https://github.com/vinniefalco/url
#
build-project extra ;
build-project limits ;
build-project unit ;

41
test/extra/CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
#
# Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
# Copyright (c) 2021 DMitry Arkhipov (grisumbras@gmail.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)
#
# Official repository: https://github.com/CPPAlliance/url
#
set(TEST_FILES
Jamfile
test_suite.cpp
)
file(GLOB_RECURSE SUITE_FILES CONFIGURE_DEPENDS
../../extra/*.cpp
../../extra/*.hpp
../../extra/*.ipp
)
#set(SUITE_FILES ../../extra/test_main.cpp ../../extra/test_suite.hpp)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${TEST_FILES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../extra PREFIX "_extra" FILES ${SUITE_FILES})
add_executable(boost_url_extra ${TEST_FILES} ${SUITE_FILES})
target_include_directories(boost_url_extra PRIVATE . ../../extra)
if (BOOST_URL_FIND_PACKAGE_BOOST)
target_link_libraries(boost_url_extra PRIVATE Boost::headers)
else()
target_link_libraries(boost_url_extra PRIVATE
Boost::align
Boost::config
Boost::core
Boost::optional
Boost::type_traits
Boost::system
Boost::variant2)
endif()
add_test(NAME boost_url_extra COMMAND boost_url_extra)
add_dependencies(boost_url_all_tests boost_url_extra)

28
test/extra/Jamfile Normal file
View File

@ -0,0 +1,28 @@
#
# Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
#
# Official repository: https://github.com/CPPAlliance/url
#
import testing ;
project
: requirements
$(c11-requires)
<source>../../extra/test_main.cpp
<include>.
<include>../../extra
;
local SOURCES =
test_suite.cpp
;
for local f in $(SOURCES)
{
run $(f) ../../extra/test_main.cpp ;
}

12
test/extra/test_suite.cpp Normal file
View File

@ -0,0 +1,12 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
//
// Official repository: https://github.com/CPPAlliance/url
//
// Test that header file is self-contained.
#include "test_suite.hpp"

View File

@ -7,13 +7,13 @@
# Official repository: https://github.com/CPPAlliance/url
#
set(TEST_MAIN ../../extra/test_main.cpp)
set(SUITE_FILES ../../extra/test_main.cpp ../../extra/test_suite.hpp)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES limits.cpp Jamfile)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../extra PREFIX "_extra" FILES ${TEST_MAIN})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../extra PREFIX "_extra" FILES ${SUITE_FILES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../src PREFIX "_extra" FILES ../../src/src.cpp)
add_executable(boost_url_limits limits.cpp Jamfile ${TEST_MAIN} ../../src/src.cpp)
target_include_directories(boost_url_limits PRIVATE ../../include ../../extra/include ../../..)
add_executable(boost_url_limits limits.cpp Jamfile ${SUITE_FILES} ../../src/src.cpp)
target_include_directories(boost_url_limits PRIVATE ../../include ../../extra ../../..)
target_compile_definitions(boost_url_limits PRIVATE
BOOST_URL_MAX_SIZE=16
BOOST_URL_NO_LIB=1

View File

@ -14,7 +14,7 @@ project
$(c11-requires)
<source>../../extra/test_main.cpp
<include>.
<include>../../extra/include
<include>../../extra
;
run limits.cpp ../../extra/test_main.cpp /boost/url//url_sources

View File

@ -88,12 +88,12 @@ set(BOOST_URL_TESTS_FILES
rfc/uri_reference_rule.cpp
)
set(TEST_MAIN ../../extra/test_main.cpp)
set(SUITE_FILES ../../extra/test_main.cpp ../../extra/test_suite.hpp)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${BOOST_URL_TESTS_FILES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../extra PREFIX "_extra" FILES ${TEST_MAIN})
add_executable(boost_url_tests ${BOOST_URL_TESTS_FILES} ${TEST_MAIN})
target_include_directories(boost_url_tests PRIVATE . ../../extra/include)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../../extra PREFIX "_extra" FILES ${SUITE_FILES})
add_executable(boost_url_tests ${BOOST_URL_TESTS_FILES} ${SUITE_FILES})
target_include_directories(boost_url_tests PRIVATE . ../../extra)
# The include dependencies are found in the CMakeLists.txt
# of the root project directory.
# See: BOOST_URL_UNIT_TEST_LIBRARIES

View File

@ -16,7 +16,7 @@ project
<library>/boost/filesystem//boost_filesystem/<warnings>off
<source>../../extra/test_main.cpp
<include>.
<include>../../extra/include
<include>../../extra
;

View File

@ -11,6 +11,7 @@
#include <boost/url/grammar/type_traits.hpp>
#include <string>
#include <vector>
#include "test_suite.hpp"

View File

@ -196,66 +196,21 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = false;
{
BOOST_TEST_CHECKPOINT();
good("", "");
}
{
BOOST_TEST_CHECKPOINT();
good("%20", " ");
}
{
BOOST_TEST_CHECKPOINT();
good("A", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%41", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%42", "B");
}
{
BOOST_TEST_CHECKPOINT();
good("A%42", "AB");
}
{
BOOST_TEST_CHECKPOINT();
good("A%20%42", "A B");
}
{
BOOST_TEST_CHECKPOINT();
good("%00", "\0");
}
{
BOOST_TEST_CHECKPOINT();
good("+", "+");
}
{
BOOST_TEST_CHECKPOINT();
good("A%00+", "A\0+");
}
{
BOOST_TEST_CHECKPOINT();
bad("B");
}
{
BOOST_TEST_CHECKPOINT();
bad("%");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1x");
}
{
BOOST_TEST_CHECKPOINT();
bad("%%");
}
good("", "");
good("%20", " ");
good("A", "A");
good("%41", "A");
good("%42", "B");
good("A%42", "AB");
good("A%20%42", "A B");
good("%00", "\0");
good("+", "+");
good("A%00+", "A\0+");
bad("B");
bad("%");
bad("%1");
bad("%1x");
bad("%%");
}
{
@ -264,66 +219,21 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = false;
{
BOOST_TEST_CHECKPOINT();
good("", "");
}
{
BOOST_TEST_CHECKPOINT();
good("%20", " ");
}
{
BOOST_TEST_CHECKPOINT();
good("A", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%41", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%42", "B");
}
{
BOOST_TEST_CHECKPOINT();
good("A%42", "AB");
}
{
BOOST_TEST_CHECKPOINT();
good("A%20%42", "A B");
}
{
BOOST_TEST_CHECKPOINT();
good("+", "+");
}
{
BOOST_TEST_CHECKPOINT();
bad("B");
}
{
BOOST_TEST_CHECKPOINT();
bad("%00");
}
{
BOOST_TEST_CHECKPOINT();
bad("%");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1x");
}
{
BOOST_TEST_CHECKPOINT();
bad("%%");
}
{
BOOST_TEST_CHECKPOINT();
bad("A%00+");
}
good("", "");
good("%20", " ");
good("A", "A");
good("%41", "A");
good("%42", "B");
good("A%42", "AB");
good("A%20%42", "A B");
good("+", "+");
bad("B");
bad("%00");
bad("%");
bad("%1");
bad("%1x");
bad("%%");
bad("A%00+");
}
{
@ -332,66 +242,21 @@ public:
opt.non_normal_is_error = true;
opt.plus_to_space = false;
{
BOOST_TEST_CHECKPOINT();
good("", "");
}
{
BOOST_TEST_CHECKPOINT();
good("%20", " ");
}
{
BOOST_TEST_CHECKPOINT();
good("A", "A");
}
{
BOOST_TEST_CHECKPOINT();
bad("%41");
}
{
BOOST_TEST_CHECKPOINT();
good("%42", "B");
}
{
BOOST_TEST_CHECKPOINT();
good("A%42", "AB");
}
{
BOOST_TEST_CHECKPOINT();
good("A%20%42", "A B");
}
{
BOOST_TEST_CHECKPOINT();
good("%00", "\0");
}
{
BOOST_TEST_CHECKPOINT();
good("+", "+");
}
{
BOOST_TEST_CHECKPOINT();
good("A%00+", "A\0+");
}
{
BOOST_TEST_CHECKPOINT();
bad("B");
}
{
BOOST_TEST_CHECKPOINT();
bad("%");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1x");
}
{
BOOST_TEST_CHECKPOINT();
bad("%%");
}
good("", "");
good("%20", " ");
good("A", "A");
bad("%41");
good("%42", "B");
good("A%42", "AB");
good("A%20%42", "A B");
good("%00", "\0");
good("+", "+");
good("A%00+", "A\0+");
bad("B");
bad("%");
bad("%1");
bad("%1x");
bad("%%");
}
{
@ -400,66 +265,21 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = false;
{
BOOST_TEST_CHECKPOINT();
good("", "");
}
{
BOOST_TEST_CHECKPOINT();
good("%20", " ");
}
{
BOOST_TEST_CHECKPOINT();
good("A", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%41", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%42", "B");
}
{
BOOST_TEST_CHECKPOINT();
good("A%42", "AB");
}
{
BOOST_TEST_CHECKPOINT();
good("A%20%42", "A B");
}
{
BOOST_TEST_CHECKPOINT();
good("%00", "\0");
}
{
BOOST_TEST_CHECKPOINT();
good("+", "+");
}
{
BOOST_TEST_CHECKPOINT();
good("A%00+", "A\0+");
}
{
BOOST_TEST_CHECKPOINT();
bad("B");
}
{
BOOST_TEST_CHECKPOINT();
bad("%");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1x");
}
{
BOOST_TEST_CHECKPOINT();
bad("%%");
}
good("", "");
good("%20", " ");
good("A", "A");
good("%41", "A");
good("%42", "B");
good("A%42", "AB");
good("A%20%42", "A B");
good("%00", "\0");
good("+", "+");
good("A%00+", "A\0+");
bad("B");
bad("%");
bad("%1");
bad("%1x");
bad("%%");
}
{
@ -468,66 +288,21 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = true;
{
BOOST_TEST_CHECKPOINT();
good("", "");
}
{
BOOST_TEST_CHECKPOINT();
good("%20", " ");
}
{
BOOST_TEST_CHECKPOINT();
good("A", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%41", "A");
}
{
BOOST_TEST_CHECKPOINT();
good("%42", "B");
}
{
BOOST_TEST_CHECKPOINT();
good("A%42", "AB");
}
{
BOOST_TEST_CHECKPOINT();
good("A%20%42", "A B");
}
{
BOOST_TEST_CHECKPOINT();
good("%00", "\0");
}
{
BOOST_TEST_CHECKPOINT();
good("+", " ");
}
{
BOOST_TEST_CHECKPOINT();
bad("B");
}
{
BOOST_TEST_CHECKPOINT();
bad("%");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1");
}
{
BOOST_TEST_CHECKPOINT();
bad("%1x");
}
{
BOOST_TEST_CHECKPOINT();
bad("%%");
}
{
BOOST_TEST_CHECKPOINT();
good("A%00+", "A\0 ");
}
good("", "");
good("%20", " ");
good("A", "A");
good("%41", "A");
good("%42", "B");
good("A%42", "AB");
good("A%20%42", "A B");
good("%00", "\0");
good("+", " ");
bad("B");
bad("%");
bad("%1");
bad("%1x");
bad("%%");
good("A%00+", "A\0 ");
}
{
@ -536,22 +311,10 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = true;
{
BOOST_TEST_CHECKPOINT();
good("\0", "\0");
}
{
BOOST_TEST_CHECKPOINT();
good("A\0", "A\0");
}
{
BOOST_TEST_CHECKPOINT();
good("%41\0", "A\0");
}
{
BOOST_TEST_CHECKPOINT();
good("%41%00", "A\0");
}
good("\0", "\0");
good("A\0", "A\0");
good("%41\0", "A\0");
good("%41%00", "A\0");
}
{
@ -560,22 +323,10 @@ public:
opt.non_normal_is_error = false;
opt.plus_to_space = true;
{
BOOST_TEST_CHECKPOINT();
bad("\0");
}
{
BOOST_TEST_CHECKPOINT();
bad("A\0");
}
{
BOOST_TEST_CHECKPOINT();
bad("%41\0");
}
{
BOOST_TEST_CHECKPOINT();
bad("%41%00");
}
bad("\0");
bad("A\0");
bad("%41\0");
bad("%41%00");
}
}

View File

@ -1,4 +1,4 @@
//
//
// Copyright (c) 2022 Alan Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying

View File

@ -13,8 +13,11 @@
#include <boost/url/url_view.hpp>
#include <boost/url/rfc/detail/charsets.hpp>
#include "test_suite.hpp"
#include <algorithm>
#include <iomanip>
#include <sstream>
namespace boost {

View File

@ -20,7 +20,7 @@ set(F
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "" FILES ${F})
add_executable(boost_wpt_tests ${F})
target_include_directories(boost_wpt_tests PRIVATE . ../../extra/include)
target_include_directories(boost_wpt_tests PRIVATE . ../../extra)
target_link_libraries(boost_wpt_tests PRIVATE Boost::url Boost::json)
add_test(NAME boost_url_tests COMMAND boost_url_tests)
add_dependencies(tests boost_url_tests)