Alien-catch
view release on metacpan or search on metacpan
src/catch.hpp view on Meta::CPAN
#pragma warning(push)
#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
#endif
// We need a dummy global operator<< so we can bring it into Catch namespace later
struct Catch_global_namespace_dummy {};
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
namespace Catch {
// Bring in operator<< from global namespace into Catch namespace
using ::operator<<;
namespace Detail {
extern const std::string unprintableString;
std::string rawMemoryToString( const void *object, std::size_t size );
template<typename T>
std::string rawMemoryToString( const T& object ) {
return rawMemoryToString( &object, sizeof(object) );
}
template<typename T>
class IsStreamInsertable {
template<typename SSS, typename TTT>
static auto test(int)
-> decltype(std::declval<SSS&>() << std::declval<TTT>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
public:
static const bool value = decltype(test<std::ostream, const T&>(0))::value;
};
template<typename E>
std::string convertUnknownEnumToString( E e );
template<typename T>
typename std::enable_if<
!std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
std::string>::type convertUnstreamable( T const& ) {
return Detail::unprintableString;
}
template<typename T>
typename std::enable_if<
!std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
std::string>::type convertUnstreamable(T const& ex) {
return ex.what();
}
template<typename T>
typename std::enable_if<
std::is_enum<T>::value
, std::string>::type convertUnstreamable( T const& value ) {
return convertUnknownEnumToString( value );
}
#if defined(_MANAGED)
//! Convert a CLR string to a utf8 std::string
template<typename T>
std::string clrReferenceToString( T^ ref ) {
if (ref == nullptr)
return std::string("null");
auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
cli::pin_ptr<System::Byte> p = &bytes[0];
return std::string(reinterpret_cast<char const *>(p), bytes->Length);
}
#endif
} // namespace Detail
// If we decide for C++14, change these to enable_if_ts
template <typename T, typename = void>
struct StringMaker {
template <typename Fake = T>
static
typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
convert(const Fake& value) {
ReusableStringStream rss;
// NB: call using the function-like syntax to avoid ambiguity with
// user-defined templated operator<< under clang.
rss.operator<<(value);
return rss.str();
}
template <typename Fake = T>
static
typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
convert( const Fake& value ) {
#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
return Detail::convertUnstreamable(value);
#else
return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
#endif
}
};
namespace Detail {
// This function dispatches all stringification requests inside of Catch.
// Should be preferably called fully qualified, like ::Catch::Detail::stringify
template <typename T>
std::string stringify(const T& e) {
return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
}
template<typename E>
std::string convertUnknownEnumToString( E e ) {
return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
}
#if defined(_MANAGED)
template <typename T>
std::string stringify( T^ e ) {
return ::Catch::StringMaker<T^>::convert(e);
}
#endif
} // namespace Detail
src/catch.hpp view on Meta::CPAN
m_cli = makeCommandLineParser( m_configData );
}
Session::~Session() {
Catch::cleanUp();
}
void Session::showHelp() const {
Catch::cout()
<< "\nCatch v" << libraryVersion() << "\n"
<< m_cli << std::endl
<< "For more detailed usage please see the project docs\n" << std::endl;
}
void Session::libIdentify() {
Catch::cout()
<< std::left << std::setw(16) << "description: " << "A Catch test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
}
int Session::applyCommandLine( int argc, char const * const * argv ) {
if( m_startupExceptions )
return 1;
auto result = m_cli.parse( clara::Args( argc, argv ) );
if( !result ) {
Catch::cerr()
<< Colour( Colour::Red )
<< "\nError(s) in input:\n"
<< Column( result.errorMessage() ).indent( 2 )
<< "\n\n";
Catch::cerr() << "Run with -? for usage\n" << std::endl;
return MaxExitCode;
}
if( m_configData.showHelp )
showHelp();
if( m_configData.libIdentify )
libIdentify();
m_config.reset();
return 0;
}
void Session::useConfigData( ConfigData const& configData ) {
m_configData = configData;
m_config.reset();
}
int Session::run( int argc, char* argv[] ) {
if( m_startupExceptions )
return 1;
int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 )
returnCode = run();
return returnCode;
}
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int Session::run( int argc, wchar_t* const argv[] ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
utf8Argv[ i ] = new char[ bufSize ];
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
}
int returnCode = run( argc, utf8Argv );
for ( int i = 0; i < argc; ++i )
delete [] utf8Argv[ i ];
delete [] utf8Argv;
return returnCode;
}
#endif
int Session::run() {
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
static_cast<void>(std::getchar());
}
int exitCode = runInternal();
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
static_cast<void>(std::getchar());
}
return exitCode;
}
clara::Parser const& Session::cli() const {
return m_cli;
}
void Session::cli( clara::Parser const& newParser ) {
m_cli = newParser;
}
ConfigData& Session::configData() {
return m_configData;
}
Config& Session::config() {
if( !m_config )
m_config = std::make_shared<Config>( m_configData );
return *m_config;
}
int Session::runInternal() {
if( m_startupExceptions )
return 1;
if (m_configData.showHelp || m_configData.libIdentify) {
return 0;
}
CATCH_TRY {
config(); // Force config to be constructed
seedRng( *m_config );
if( m_configData.filenamesAsTags )
applyFilenamesAsTags( *m_config );
// Handle list request
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
auto totals = runTests( m_config );
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
}
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
catch( std::exception& ex ) {
src/catch.hpp view on Meta::CPAN
#include <sstream>
namespace Catch {
WildcardPattern::WildcardPattern( std::string const& pattern,
CaseSensitive::Choice caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
m_pattern( adjustCase( pattern ) )
{
if( startsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 1 );
m_wildcard = WildcardAtStart;
}
if( endsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
}
}
bool WildcardPattern::matches( std::string const& str ) const {
switch( m_wildcard ) {
case NoWildcard:
return m_pattern == adjustCase( str );
case WildcardAtStart:
return endsWith( adjustCase( str ), m_pattern );
case WildcardAtEnd:
return startsWith( adjustCase( str ), m_pattern );
case WildcardAtBothEnds:
return contains( adjustCase( str ), m_pattern );
default:
CATCH_INTERNAL_ERROR( "Unknown enum" );
}
}
std::string WildcardPattern::adjustCase( std::string const& str ) const {
return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
}
}
// end catch_wildcard_pattern.cpp
// start catch_xmlwriter.cpp
#include <iomanip>
using uchar = unsigned char;
namespace Catch {
namespace {
size_t trailingBytes(unsigned char c) {
if ((c & 0xE0) == 0xC0) {
return 2;
}
if ((c & 0xF0) == 0xE0) {
return 3;
}
if ((c & 0xF8) == 0xF0) {
return 4;
}
CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
}
uint32_t headerValue(unsigned char c) {
if ((c & 0xE0) == 0xC0) {
return c & 0x1F;
}
if ((c & 0xF0) == 0xE0) {
return c & 0x0F;
}
if ((c & 0xF8) == 0xF0) {
return c & 0x07;
}
CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
}
void hexEscapeChar(std::ostream& os, unsigned char c) {
os << "\\x"
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(c);
}
} // anonymous namespace
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
: m_str( str ),
m_forWhat( forWhat )
{}
void XmlEncode::encodeTo( std::ostream& os ) const {
// Apostrophe escaping not necessary if we always use " to write attributes
// (see: http://www.w3.org/TR/xml/#syntax)
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
uchar c = m_str[idx];
switch (c) {
case '<': os << "<"; break;
case '&': os << "&"; break;
case '>':
// See: http://www.w3.org/TR/xml/#syntax
if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
os << ">";
else
os << c;
break;
case '\"':
if (m_forWhat == ForAttributes)
os << """;
else
os << c;
break;
default:
// Check for control characters and invalid utf-8
// Escape control characters in standard ascii
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
hexEscapeChar(os, c);
break;
}
// Plain ASCII: Write it to stream
if (c < 0x7F) {
os << c;
break;
}
// UTF-8 territory
// Check if the encoding is valid and if it is not, hex escape bytes.
// Important: We do not check the exact decoded values for validity, only the encoding format
// First check that this bytes is a valid lead byte:
// This means that it is not encoded as 1111 1XXX
// Or as 10XX XXXX
if (c < 0xC0 ||
c >= 0xF8) {
hexEscapeChar(os, c);
break;
}
auto encBytes = trailingBytes(c);
// Are there enough bytes left to avoid accessing out-of-bounds memory?
if (idx + encBytes - 1 >= m_str.size()) {
hexEscapeChar(os, c);
break;
}
// The header is valid, check data
// The next encBytes bytes must together be a valid utf-8
// This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
bool valid = true;
uint32_t value = headerValue(c);
for (std::size_t n = 1; n < encBytes; ++n) {
uchar nc = m_str[idx + n];
valid &= ((nc & 0xC0) == 0x80);
value = (value << 6) | (nc & 0x3F);
}
if (
// Wrong bit pattern of following bytes
(!valid) ||
// Overlong encodings
(value < 0x80) ||
(0x80 <= value && value < 0x800 && encBytes > 2) ||
(0x800 < value && value < 0x10000 && encBytes > 3) ||
// Encoded value out of range
(value >= 0x110000)
) {
hexEscapeChar(os, c);
break;
}
// If we got here, this is in fact a valid(ish) utf-8 sequence
for (std::size_t n = 0; n < encBytes; ++n) {
os << m_str[idx + n];
}
idx += encBytes - 1;
break;
}
}
}
std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
xmlEncode.encodeTo( os );
return os;
}
XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
: m_writer( writer )
{}
XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
: m_writer( other.m_writer ){
other.m_writer = nullptr;
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
if ( m_writer ) {
m_writer->endElement();
}
m_writer = other.m_writer;
other.m_writer = nullptr;
return *this;
}
XmlWriter::ScopedElement::~ScopedElement() {
if( m_writer )
m_writer->endElement();
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
m_writer->writeText( text, indent );
return *this;
}
XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
{
writeDeclaration();
}
XmlWriter::~XmlWriter() {
while( !m_tags.empty() )
endElement();
}
XmlWriter& XmlWriter::startElement( std::string const& name ) {
ensureTagClosed();
newlineIfNecessary();
m_os << m_indent << '<' << name;
m_tags.push_back( name );
m_indent += " ";
m_tagIsOpen = true;
return *this;
}
src/catch.hpp view on Meta::CPAN
return "µs";
case Unit::Milliseconds:
return "ms";
case Unit::Seconds:
return "s";
case Unit::Minutes:
return "m";
default:
return "** internal error **";
}
}
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
return os << duration.value() << " " << duration.unitsAsString();
}
};
} // end anon namespace
class TablePrinter {
std::ostream& m_os;
std::vector<ColumnInfo> m_columnInfos;
std::ostringstream m_oss;
int m_currentColumn = -1;
bool m_isOpen = false;
public:
TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
: m_os( os ),
m_columnInfos( std::move( columnInfos ) ) {}
auto columnInfos() const -> std::vector<ColumnInfo> const& {
return m_columnInfos;
}
void open() {
if (!m_isOpen) {
m_isOpen = true;
*this << RowBreak();
for (auto const& info : m_columnInfos)
*this << info.name << ColumnBreak();
*this << RowBreak();
m_os << Catch::getLineOfChars<'-'>() << "\n";
}
}
void close() {
if (m_isOpen) {
*this << RowBreak();
m_os << std::endl;
m_isOpen = false;
}
}
template<typename T>
friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
tp.m_oss << value;
return tp;
}
friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
auto colStr = tp.m_oss.str();
// This takes account of utf8 encodings
auto strSize = Catch::StringRef(colStr).numberOfCharacters();
tp.m_oss.str("");
tp.open();
if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
tp.m_currentColumn = -1;
tp.m_os << "\n";
}
tp.m_currentColumn++;
auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
? std::string(colInfo.width - (strSize + 2), ' ')
: std::string();
if (colInfo.justification == ColumnInfo::Left)
tp.m_os << colStr << padding << " ";
else
tp.m_os << padding << colStr << " ";
return tp;
}
friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
if (tp.m_currentColumn > 0) {
tp.m_os << "\n";
tp.m_currentColumn = -1;
}
return tp;
}
};
ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
: StreamingReporterBase(config),
m_tablePrinter(new TablePrinter(config.stream(),
{
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
{ "iters", 8, ColumnInfo::Right },
{ "elapsed ns", 14, ColumnInfo::Right },
{ "average", 14, ColumnInfo::Right }
})) {}
ConsoleReporter::~ConsoleReporter() = default;
std::string ConsoleReporter::getDescription() {
return "Reports test results as plain lines of text";
}
void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
AssertionResult const& result = _assertionStats.assertionResult;
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
// Drop out if result was successful but we're not printing them.
if (!includeResults && result.getResultType() != ResultWas::Warning)
return false;
lazyPrint();
( run in 0.412 second using v1.01-cache-2.11-cpan-9e1a9122474 )