You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
5.4 KiB
199 lines
5.4 KiB
// Copyright 2013 by Martin Moene |
|
// |
|
// lest is based on ideas by Kevlin Henney, see video at |
|
// http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus |
|
// |
|
// Distributed under the Boost Software License, Version 1.0: |
|
// |
|
// Permission is hereby granted, free of charge, to any person or organization |
|
// obtaining a copy of the software and accompanying documentation covered by |
|
// this license (the "Software") to use, reproduce, display, distribute, |
|
// execute, and transmit the Software, and to prepare derivative works of the |
|
// Software, and to permit third-parties to whom the Software is furnished to |
|
// do so, all subject to the following: |
|
// |
|
// The copyright notices in the Software and this entire statement, including |
|
// the above license grant, this restriction and the following disclaimer, |
|
// must be included in all copies of the Software, in whole or in part, and |
|
// all derivative works of the Software, unless such copies or derivative |
|
// works are solely in the form of machine-executable object code generated by |
|
// a source language processor. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT |
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE |
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, |
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
#ifndef LEST_LEST_H_INCLUDED |
|
#define LEST_LEST_H_INCLUDED |
|
|
|
#include <functional> |
|
#include <iostream> |
|
#include <stdexcept> |
|
#include <string> |
|
#include <cstddef> |
|
|
|
#ifndef lest_NO_SHORT_ASSERTION_NAMES |
|
# define EXPECT lest_EXPECT |
|
# define EXPECT_THROWS lest_EXPECT_THROWS |
|
# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS |
|
#endif |
|
|
|
#define lest_EXPECT( expr ) \ |
|
try \ |
|
{ \ |
|
if ( ! (expr) ) \ |
|
throw lest::failure{ lest_LOCATION, #expr }; \ |
|
} \ |
|
catch( lest::failure const & ) \ |
|
{ \ |
|
throw ; \ |
|
} \ |
|
catch( std::exception const & e ) \ |
|
{ \ |
|
throw lest::unexpected{ lest_LOCATION, #expr, lest::with_message( e.what() ) }; \ |
|
} \ |
|
catch(...) \ |
|
{ \ |
|
throw lest::unexpected{ lest_LOCATION, #expr, "of unknown type" }; \ |
|
} |
|
|
|
#define lest_EXPECT_THROWS( expr ) \ |
|
for (;;) \ |
|
{ \ |
|
try { lest::serum( expr ); } catch (...) { break; } \ |
|
throw lest::expected{ lest_LOCATION, #expr }; \ |
|
} |
|
|
|
#define lest_EXPECT_THROWS_AS( expr, excpt ) \ |
|
for (;;) \ |
|
{ \ |
|
try { lest::serum( expr ); } catch ( excpt & ) { break; } catch (...) {} \ |
|
throw lest::expected{ lest_LOCATION, #expr, lest::of_type( #excpt ) }; \ |
|
} |
|
|
|
#define lest_LOCATION lest::location{__FILE__, __LINE__} |
|
|
|
namespace lest { |
|
|
|
struct test |
|
{ |
|
const std::string name; |
|
const std::function<void()> behaviour; |
|
}; |
|
|
|
struct location |
|
{ |
|
const std::string file; |
|
const int line; |
|
|
|
location( std::string file, int line ) |
|
: file{ file }, line{ line } {} |
|
}; |
|
|
|
struct comment |
|
{ |
|
const std::string text; |
|
|
|
comment( std::string text ) : text{ text } {} |
|
explicit operator bool() { return ! text.empty(); } |
|
}; |
|
|
|
struct message : std::runtime_error |
|
{ |
|
const std::string kind; |
|
const location where; |
|
const comment note; |
|
|
|
~message() throw() {} // GCC 4.6 |
|
|
|
message( std::string kind, location where, std::string expr, std::string note = "" ) |
|
: std::runtime_error{ expr }, kind{ kind }, where{ where }, note{ note } {} |
|
}; |
|
|
|
struct failure : message |
|
{ |
|
failure( location where, std::string expr ) |
|
: message{ "failed", where, expr } {} |
|
}; |
|
|
|
struct expected : message |
|
{ |
|
expected( location where, std::string expr, std::string excpt = "" ) |
|
: message{ "failed: didn't get exception", where, expr, excpt } {} |
|
}; |
|
|
|
struct unexpected : message |
|
{ |
|
unexpected( location where, std::string expr, std::string note ) |
|
: message{ "failed: got unexpected exception", where, expr, note } {} |
|
}; |
|
|
|
inline bool serum( bool verum ) { return verum; } |
|
|
|
inline std::string with_message( std::string text ) |
|
{ |
|
return "with message \"" + text + "\""; |
|
} |
|
|
|
inline std::string of_type( std::string text ) |
|
{ |
|
return "of type " + text; |
|
} |
|
|
|
inline std::string pluralise( int n, std::string text ) |
|
{ |
|
return n == 1 ? text : text + "s"; |
|
} |
|
|
|
inline std::ostream & operator<<( std::ostream & os, comment note ) |
|
{ |
|
return os << (note ? " " + note.text : "" ); |
|
} |
|
|
|
inline std::ostream & operator<<( std::ostream & os, location where ) |
|
{ |
|
#ifdef __GNUG__ |
|
return os << where.file << ":" << where.line; |
|
#else |
|
return os << where.file << "(" << where.line << ")"; |
|
#endif |
|
} |
|
|
|
inline void report( std::ostream & os, message const & e, std::string test ) |
|
{ |
|
os << e.where << ": " << e.kind << e.note << ": " << test << ": " << e.what() << std::endl; |
|
} |
|
|
|
template<std::size_t N> |
|
int run( test const (&specification)[N], std::ostream & os = std::cout ) |
|
{ |
|
int failures = 0; |
|
|
|
for ( auto & testing : specification ) |
|
{ |
|
try |
|
{ |
|
testing.behaviour(); |
|
} |
|
catch( message const & e ) |
|
{ |
|
++failures; |
|
report( os, e, testing.name ); |
|
} |
|
} |
|
|
|
if ( failures > 0 ) |
|
{ |
|
os << failures << " out of " << N << " " << pluralise(N, "test") << " failed." << std::endl; |
|
} |
|
|
|
return failures; |
|
} |
|
|
|
} // namespace lest |
|
|
|
#endif // LEST_LEST_H_INCLUDED
|
|
|