try to compile with clang and on osx in travis

This commit is contained in:
Patrick Brosi 2018-07-23 02:46:31 +02:00
parent 1a9482a445
commit df2ab2df77
10 changed files with 485 additions and 269 deletions

View file

@ -1,6 +1,12 @@
language: generic
sudo: false
dist: trusty
language: cpp
os:
- linux
- osx
compiler:
- gcc
- clang
addons:
apt:
@ -21,4 +27,4 @@ script:
notifications:
email:
on_success: never
on_failure: always
on_failure: never

View file

@ -20,7 +20,12 @@ if(OPENMP_FOUND)
endif()
# set compiler flags, see http://stackoverflow.com/questions/7724569/debug-vs-release-in-cmake
set(CMAKE_CXX_FLAGS "-fopenmp -Ofast -fno-signed-zeros -fno-trapping-math -frename-registers -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2")
if(OPENMP_FOUND)
set(CMAKE_CXX_FLAGS "-fopenmp -Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wfatal-errors -Wextra -Wno-implicit-fallthrough -pedantic")
else()
message(WARNING "Configuring without OpenMP!")
set(CMAKE_CXX_FLAGS "-Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wfatal-errors -Wextra -Wno-implicit-fallthrough -pedantic")
endif()
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DLOGLEVEL=3")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")

@ -1 +1 @@
Subproject commit 3a462c37358da19f10e89f77fb7a277d69c6c4dc
Subproject commit eae77cfdfb7eb64f87ddd48204ea9b90d6d5cfd8

View file

@ -29,7 +29,6 @@ class Collector {
public:
Collector(const std::string& evalOutPath, const std::vector<double>& dfBins)
: _noOrigShp(0),
_noMatchShp(0),
_fdSum(0),
_unmatchedSegSum(0),
_unmatchedSegLengthSum(0),
@ -70,7 +69,6 @@ class Collector {
std::map<const Shape*, std::map<const Shape*, std::pair<size_t, double> > >
_dACache;
size_t _noOrigShp;
size_t _noMatchShp;
double _fdSum;
size_t _unmatchedSegSum;

View file

@ -2,7 +2,13 @@
// Chair of Algorithms and Data Structures.
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
#ifdef _OPENMP
#include <omp.h>
#else
#define omp_get_thread_num() 0
#define omp_get_num_procs() 1
#endif
#include <algorithm>
#include <fstream>
#include <limits>
@ -193,8 +199,7 @@ double CombCostFunc::operator()(const router::Edge* from, const router::Node* n,
}
// _____________________________________________________________________________
Router::Router(const trgraph::Graph& g, size_t numThreads)
: _g(g), _cache(numThreads) {
Router::Router(size_t numThreads) : _cache(numThreads) {
for (size_t i = 0; i < numThreads; i++) {
_cache[i] = new Cache();
}

View file

@ -135,7 +135,7 @@ struct CombCostFunc
class Router {
public:
// Init this router with caches for numThreads threads
Router(const trgraph::Graph& g, size_t numThreads);
explicit Router(size_t numThreads);
~Router();
// Find the most likely path through the graph for a node candidate route.
@ -160,8 +160,6 @@ class Router {
size_t getCacheNumber() const;
private:
const trgraph::Graph& _g;
mutable std::vector<Cache*> _cache;
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,

View file

@ -2,7 +2,13 @@
// Chair of Algorithms and Data Structures.
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
#ifdef _OPENMP
#include <omp.h>
#else
#define omp_get_thread_num() 0
#define omp_get_num_procs() 1
#endif
#include <map>
#include <mutex>
#include <unordered_map>
@ -49,7 +55,7 @@ ShapeBuilder::ShapeBuilder(Feed* feed, MOTs mots,
_motCfg(motCfg),
_ecoll(ecoll),
_cfg(cfg),
_crouter(_g, omp_get_num_procs()),
_crouter(omp_get_num_procs()),
_curShpCnt(0) {
_numThreads = _crouter.getCacheNumber();
writeMotStops();

View file

@ -23,6 +23,7 @@ using namespace util::graph;
const lest::test specification[] = {
// ___________________________________________________________________________
{
CASE("atof") {
EXPECT(util::atof("45.534215") == approx(45.534215));
EXPECT(util::atof("5.534") == approx(5.534));
@ -33,9 +34,10 @@ CASE("atof") {
// TODO: more test cases
},
}},
// ___________________________________________________________________________
{
CASE("dirgraph") {
DirGraph<int, int> g;
@ -74,9 +76,10 @@ CASE("dirgraph") {
EXPECT(a->getDeg() == (size_t)1);
// TODO: more test cases
},
}},
// ___________________________________________________________________________
{
CASE("unddirgraph") {
UndirGraph<int, int> g;
@ -118,9 +121,10 @@ CASE("unddirgraph") {
// TODO: more test cases
},
}},
// ___________________________________________________________________________
{
CASE("grid") {
Grid<int, Line, double> g(.5, .5, Box<double>(Point<double>(0, 0), Point<double>(3, 3)));
@ -151,9 +155,10 @@ CASE("grid") {
// TODO: more test cases
},
}},
// ___________________________________________________________________________
{
CASE("densify") {
Line<double> a;
a.push_back(Point<double>(1, 1));
@ -179,9 +184,10 @@ CASE("densify") {
dense = util::geo::simplify(dense, 0.1);
EXPECT(dense.size() == (size_t)3);
},
}},
// ___________________________________________________________________________
{
CASE("summed frechet distance") {
Line<double> a;
a.push_back(Point<double>(1, 1));
@ -203,9 +209,10 @@ CASE("summed frechet distance") {
double fd = util::geo::accFrechetDistC(a, b, 0.1);
EXPECT(fd == approx(2));
},
}},
// ___________________________________________________________________________
{
CASE("frechet distance") {
Line<double> e;
e.push_back(Point<double>(1, 1));
@ -268,9 +275,10 @@ CASE("frechet distance") {
fd = util::geo::frechetDist(g, h, 0.1);
EXPECT(fd == approx(1));
},
}},
// ___________________________________________________________________________
{
CASE("geo box alignment") {
Line<double> a;
a.push_back(Point<double>(1, 1));
@ -304,32 +312,36 @@ CASE("geo box alignment") {
EXPECT(parallelity(box, ml) == approx(0));
ml = rotate(ml, 45);
EXPECT(parallelity(box, ml) == approx(1));
},
}},
// ___________________________________________________________________________
{
CASE("url decode") {
EXPECT("zürich" == util::urlDecode("z%C3%BCrich"));
EXPECT("!@$%^*()" == util::urlDecode("!%40%24%25%5E*()"));
EXPECT("Løkken" == util::urlDecode("L%C3%B8kken"));
EXPECT("á é" == util::urlDecode("%C3%A1%20%C3%A9"));
EXPECT("á é" == util::urlDecode("%C3%A1+%C3%A9"));
},
}},
// ___________________________________________________________________________
{
CASE("json escape") {
EXPECT("Hello\\\\Goodbye!" == util::jsonStringEscape("Hello\\Goodbye!"));
EXPECT("\\\"Hello\\\"" == util::jsonStringEscape("\"Hello\""));
},
}},
// ___________________________________________________________________________
{
CASE("split") {
EXPECT(util::split("hello,again", ',').size() == (size_t)2);
EXPECT(util::split("hello,,again", ',').size() == (size_t)3);
EXPECT(util::split("hello", ',').size() == (size_t)1);
EXPECT(util::split("", ',').size() == (size_t)0);
},
}},
// ___________________________________________________________________________
{
CASE("editdist") {
EXPECT(util::editDist("hello", "mello") == (size_t)1);
EXPECT(util::editDist("mello", "hello") == (size_t)1);
@ -338,15 +350,17 @@ CASE("editdist") {
EXPECT(util::editDist("xabcd", "abcde") == (size_t)2);
EXPECT(util::editDist("abcd", "abcdes") == (size_t)2);
EXPECT(util::editDist("hello", "hello") == (size_t)0);
},
}},
// ___________________________________________________________________________
{
CASE("toString") {
EXPECT(util::toString(34) == "34");
EXPECT(util::toString("34") == "34");
},
}},
// ___________________________________________________________________________
{
CASE("replace") {
std::string a("lorem ipsum ipsum lorem");
@ -380,9 +394,10 @@ CASE("replace") {
EXPECT(!util::replaceAll(b, "", "ee"));
EXPECT(b == "loree aaaau aaaau loree");
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra directed, 1 to all") {
DirGraph<std::string, int> g;
@ -436,9 +451,10 @@ CASE("Edge-based Dijkstra directed, 1 to all") {
int single = EDijkstra::shortestPath(u.first, eBC, cFunc);
EXPECT(single == u.second);
}
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra undirected, edge 1 to 1") {
UndirGraph<std::string, int> g;
@ -494,9 +510,10 @@ CASE("Edge-based Dijkstra undirected, edge 1 to 1") {
cost = EDijkstra::shortestPath(eAB, b, cFunc, &resE, &res);
EXPECT(cost == 0);
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra undirected, edge 1 to n") {
UndirGraph<std::string, int> g;
@ -542,9 +559,10 @@ CASE("Edge-based Dijkstra undirected, edge 1 to n") {
EDijkstra::EList<std::string, int> resE;
int cost = EDijkstra::shortestPath(eAB, tos, cFunc, &resE, &res);
EXPECT(cost == 0);
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra undirected, 1 to n") {
UndirGraph<std::string, int> g;
@ -596,9 +614,10 @@ CASE("Edge-based Dijkstra undirected, 1 to n") {
EXPECT(resE[eDC]->size() == (size_t)3);
EXPECT(res[eED]->size() == (size_t)3);
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra undirected") {
UndirGraph<std::string, int> g;
@ -668,9 +687,10 @@ CASE("Edge-based Dijkstra undirected") {
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
EXPECT(cost == 2);
},
}},
// ___________________________________________________________________________
{
CASE("Edge-based Dijkstra") {
DirGraph<int, int> g;
@ -715,9 +735,10 @@ CASE("Edge-based Dijkstra") {
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
EXPECT(cost == 2);
},
}},
// ___________________________________________________________________________
{
CASE("Dijkstra") {
DirGraph<int, int> g;
@ -779,9 +800,10 @@ CASE("Dijkstra") {
EXPECT(costs[c] == 1);
EXPECT(costs[d] == 2);
EXPECT(costs[x] == 999);
},
}},
// ___________________________________________________________________________
{
CASE("nullable") {
{
util::Nullable<std::string> nullable;
@ -840,9 +862,10 @@ CASE("nullable") {
EXPECT_THROWS(nullable == voidnull);
}
},
}},
// ___________________________________________________________________________
{
CASE("geometry") {
geo::Point<double> a(1, 2);
geo::Point<double> b(2, 3);
@ -1188,7 +1211,7 @@ CASE("geometry") {
EXPECT(geo::contains(geo::Polygon<double>({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}), geo::convexHull(obox)));
}
};
}};
// _____________________________________________________________________________
int main(int argc, char** argv) {

View file

@ -1,13 +1,13 @@
// Copyright 2013, 2014 by Martin Moene
// Copyright 2013-2018 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. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef LEST_LEST_H_INCLUDED
#define LEST_LEST_H_INCLUDED
#ifndef LEST_LEST_HPP_INCLUDED
#define LEST_LEST_HPP_INCLUDED
#include <algorithm>
#include <chrono>
@ -31,14 +31,7 @@
#include <cmath>
#include <cstddef>
#ifdef __clang__
# pragma clang diagnostic ignored "-Wunused-comparison"
# pragma clang diagnostic ignored "-Wunused-value"
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wunused-value"
#endif
#define lest_VERSION "1.22.0"
#define lest_VERSION "1.33.1"
#ifndef lest_FEATURE_AUTO_REGISTER
# define lest_FEATURE_AUTO_REGISTER 0
@ -60,16 +53,71 @@
#define lest_FEATURE_TIME_PRECISION 0
#endif
#ifndef lest_FEATURE_WSTRING
#define lest_FEATURE_WSTRING 1
#endif
#ifdef lest_FEATURE_RTTI
# define lest__cpp_rtti lest_FEATURE_RTTI
#elif defined(__cpp_rtti)
# define lest__cpp_rtti __cpp_rtti
#elif defined(__GXX_RTTI) || defined (_CPPRTTI)
# define lest__cpp_rtti 1
#else
# define lest__cpp_rtti 0
#endif
#if lest_FEATURE_REGEX_SEARCH
# include <regex>
#endif
// Compiler warning suppression:
#ifdef __clang__
# pragma clang diagnostic ignored "-Waggregate-return"
# pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-comparison"
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Waggregate-return"
# pragma GCC diagnostic push
#endif
// Suppress shadow and unused-value warning for sections:
#if defined __clang__
# define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wshadow\"" )
# define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wunused-value\"" )
# define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" )
#elif defined __GNUC__
# define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \
_Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
# define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \
_Pragma( "GCC diagnostic ignored \"-Wunused-value\"" )
# define lest_RESTORE_WARNINGS _Pragma( "GCC diagnostic pop" )
#else
# define lest_SUPPRESS_WSHADOW /*empty*/
# define lest_SUPPRESS_WUNUSED /*empty*/
# define lest_RESTORE_WARNINGS /*empty*/
#endif
#ifdef _MSVC_LANG
# define lest_CPP17_OR_GREATER_MS ( _MSVC_LANG >= 201703L )
#else
# define lest_CPP17_OR_GREATER_MS 0
#endif
# define lest_CPP17_OR_GREATER ( __cplusplus >= 201703L || lest_CPP17_OR_GREATER_MS )
#if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES )
# define MODULE lest_MODULE
# if ! lest_FEATURE_AUTO_REGISTER
# define CASE lest_CASE
# define TEST lest_TEST
# define CASE_ON lest_CASE_ON
# define SCENARIO lest_SCENARIO
# endif
# define SETUP lest_SETUP
@ -81,7 +129,6 @@
# define EXPECT_THROWS lest_EXPECT_THROWS
# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS
# define SCENARIO lest_SCENARIO
# define GIVEN lest_GIVEN
# define WHEN lest_WHEN
# define THEN lest_THEN
@ -89,40 +136,48 @@
# define AND_THEN lest_AND_THEN
#endif
#define lest_SCENARIO( sketch ) lest_CASE( "Scenario: " sketch )
#define lest_GIVEN( context ) lest_SETUP( "Given: " context )
#define lest_WHEN( story ) lest_SECTION( " When: " story )
#define lest_THEN( story ) lest_SECTION( " Then: " story )
#define lest_AND_WHEN( story ) lest_SECTION( " And: " story )
#define lest_AND_THEN( story ) lest_SECTION( " And: " story )
#define lest_MODULE( specification, module ) \
namespace { lest::add_module _( specification, module ); }
#define lest_TEST \
lest_CASE
#if lest_FEATURE_AUTO_REGISTER
#define lest_SCENARIO( specification, sketch ) lest_CASE( specification, lest::text("Scenario: ") + sketch )
#else
#define lest_SCENARIO( sketch ) lest_CASE( lest::text("Scenario: ") + sketch )
#endif
#define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context )
#define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story )
#define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story )
#define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story )
#define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story )
#if lest_FEATURE_AUTO_REGISTER
# define lest_CASE( specification, proposition ) \
void lest_FUNCTION( lest::env & ); \
static void lest_FUNCTION( lest::env & ); \
namespace { lest::add_test lest_REGISTRAR( specification, lest::test( proposition, lest_FUNCTION ) ); } \
void lest_FUNCTION( lest::env & $ )
static void lest_FUNCTION( lest::env & lest_env )
#else
#else // lest_FEATURE_AUTO_REGISTER
# define lest_CASE( proposition, ... ) \
proposition, [__VA_ARGS__]( lest::env & $ )
# define lest_CASE( proposition ) \
proposition, []( lest::env & lest_env )
#endif
# define lest_CASE_ON( proposition, ... ) \
proposition, [__VA_ARGS__]( lest::env & lest_env )
# define lest_MODULE( specification, module ) \
namespace { lest::add_module _( specification, module ); }
#endif //lest_FEATURE_AUTO_REGISTER
#define lest_SETUP( context ) \
for ( int $section = 0, $count = 1; $section < $count; $count -= 0==$section++ )
for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \
for ( lest::ctx lest__ctx_setup( lest_env, context ); lest__ctx_setup; )
#define lest_SECTION( proposition ) \
lest_SUPPRESS_WSHADOW \
static int lest_UNIQUE( id ) = 0; \
if ( lest::guard $run = lest::guard( lest_UNIQUE( id ), $section, $count ) ) \
for ( int $section = 0, $count = 1; $section < $count; $count -= 0==$section++ )
if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \
for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \
for ( lest::ctx lest__ctx_section( lest_env, proposition ); lest__ctx_section; ) \
lest_RESTORE_WARNINGS
#define lest_EXPECT( expr ) \
do { \
@ -130,8 +185,8 @@
{ \
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
else if ( $.pass ) \
lest::report( $.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, $.testing ); \
else if ( lest_env.pass() ) \
lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, lest_env.context() ); \
} \
catch(...) \
{ \
@ -145,8 +200,8 @@
{ \
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
{ \
if ( $.pass ) \
lest::report( $.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, $.testing ); \
if ( lest_env.pass() ) \
lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, lest_env.context() ); \
} \
else \
throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
@ -162,14 +217,16 @@
{ \
try \
{ \
lest_SUPPRESS_WUNUSED \
expr; \
lest_RESTORE_WARNINGS \
} \
catch (...) \
{ \
lest::inform( lest_LOCATION, #expr ); \
} \
if ( $.pass ) \
lest::report( $.os, lest::got_none( lest_LOCATION, #expr ), $.testing ); \
if ( lest_env.pass() ) \
lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \
} while ( lest::is_false() )
#define lest_EXPECT_THROWS( expr ) \
@ -177,12 +234,14 @@
{ \
try \
{ \
lest_SUPPRESS_WUNUSED \
expr; \
lest_RESTORE_WARNINGS \
} \
catch (...) \
{ \
if ( $.pass ) \
lest::report( $.os, lest::got{ lest_LOCATION, #expr }, $.testing ); \
if ( lest_env.pass() ) \
lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr }, lest_env.context() ); \
break; \
} \
throw lest::expected{ lest_LOCATION, #expr }; \
@ -194,12 +253,14 @@
{ \
try \
{ \
lest_SUPPRESS_WUNUSED \
expr; \
lest_RESTORE_WARNINGS \
} \
catch ( excpt & ) \
{ \
if ( $.pass ) \
lest::report( $.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, $.testing ); \
if ( lest_env.pass() ) \
lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, lest_env.context() ); \
break; \
} \
catch (...) {} \
@ -211,7 +272,7 @@
#define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line )
#define lest_UNIQUE3( name, line ) name ## line
#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer()->* expr )
#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr )
#define lest_FUNCTION lest_UNIQUE(__lest_function__ )
#define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ )
@ -220,6 +281,8 @@
namespace lest {
const int exit_max_value = 255;
using text = std::string;
using texts = std::vector<text>;
@ -231,8 +294,8 @@ struct test
std::function<void( env & )> behaviour;
#if lest_FEATURE_AUTO_REGISTER
test( text name, std::function<void( env & )> behaviour )
: name( name ), behaviour( behaviour ) {}
test( text name_, std::function<void( env & )> behaviour_ )
: name( name_), behaviour( behaviour_) {}
#endif
};
@ -266,6 +329,10 @@ struct result
const bool passed;
const text decomposition;
template< typename T >
result( T const & passed_, text decomposition_)
: passed( !!passed_), decomposition( decomposition_) {}
explicit operator bool() { return ! passed; }
};
@ -274,15 +341,15 @@ struct location
const text file;
const int line;
location( text file, int line )
: file( file ), line( line ) {}
location( text file_, int line_)
: file( file_), line( line_) {}
};
struct comment
{
const text info;
comment( text info ) : info( info ) {}
comment( text info_) : info( info_) {}
explicit operator bool() { return ! info.empty(); }
};
@ -294,55 +361,55 @@ struct message : std::runtime_error
~message() throw() {} // GCC 4.6
message( text kind, location where, text expr, text note = "" )
: std::runtime_error( expr ), kind( kind ), where( where ), note( note ) {}
message( text kind_, location where_, text expr_, text note_ = "" )
: std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {}
};
struct failure : message
{
failure( location where, text expr, text decomposition )
: message{ "failed", where, expr + " for " + decomposition } {}
failure( location where_, text expr_, text decomposition_)
: message{ "failed", where_, expr_ + " for " + decomposition_ } {}
};
struct success : message
{
// using message::message; // VC is lagging here
success( text kind, location where, text expr, text note = "" )
: message( kind, where, expr, note ) {}
success( text kind_, location where_, text expr_, text note_ = "" )
: message( kind_, where_, expr_, note_ ) {}
};
struct passing : success
{
passing( location where, text expr, text decomposition )
: success( "passed", where, expr + " for " + decomposition ) {}
passing( location where_, text expr_, text decomposition_ )
: success( "passed", where_, expr_ + " for " + decomposition_) {}
};
struct got_none : success
{
got_none( location where, text expr )
: success( "passed: got no exception", where, expr ) {}
got_none( location where_, text expr_ )
: success( "passed: got no exception", where_, expr_ ) {}
};
struct got : success
{
got( location where, text expr )
: success( "passed: got exception", where, expr ) {}
got( location where_, text expr_)
: success( "passed: got exception", where_, expr_) {}
got( location where, text expr, text excpt )
: success( "passed: got exception " + excpt, where, expr ) {}
got( location where_, text expr_, text excpt_)
: success( "passed: got exception " + excpt_, where_, expr_) {}
};
struct expected : message
{
expected( location where, text expr, text excpt = "" )
: message{ "failed: didn't get exception", where, expr, excpt } {}
expected( location where_, text expr_, text excpt_ = "" )
: message{ "failed: didn't get exception", where_, expr_, excpt_ } {}
};
struct unexpected : message
{
unexpected( location where, text expr, text note = "" )
: message{ "failed: got unexpected exception", where, expr, note } {}
unexpected( location where_, text expr_, text note_ = "" )
: message{ "failed: got unexpected exception", where_, expr_, note_ } {}
};
struct guard
@ -350,8 +417,8 @@ struct guard
int & id;
int const & section;
guard( int & id, int const & section, int & count )
: id( id ), section( section )
guard( int & id_, int const & section_, int & count )
: id( id_), section( section_)
{
if ( section == 0 )
id = count++ - 1;
@ -371,12 +438,12 @@ public:
static approx custom() { return approx( 0 ); }
approx operator()( double magnitude )
approx operator()( double new_magnitude )
{
approx approx ( magnitude );
approx.epsilon( epsilon_ );
approx.scale ( scale_ );
return approx;
approx appr( new_magnitude );
appr.epsilon( epsilon_ );
appr.scale ( scale_ );
return appr;
}
double magnitude() const { return magnitude_; }
@ -387,13 +454,18 @@ public:
friend bool operator == ( double lhs, approx const & rhs )
{
// Thanks to Richard Harris for his help refining this formula.
return std::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (std::max)( std::abs( lhs ), std::abs( rhs.magnitude_ ) ) );
return std::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (std::min)( std::abs( lhs ), std::abs( rhs.magnitude_ ) ) );
}
friend bool operator == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); }
friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); }
friend bool operator != ( approx const & lhs, double rhs ) { return !operator==( rhs, lhs ); }
friend bool operator <= ( double lhs, approx const & rhs ) { return lhs < rhs.magnitude_ || lhs == rhs; }
friend bool operator <= ( approx const & lhs, double rhs ) { return lhs.magnitude_ < rhs || lhs == rhs; }
friend bool operator >= ( double lhs, approx const & rhs ) { return lhs > rhs.magnitude_ || lhs == rhs; }
friend bool operator >= ( approx const & lhs, double rhs ) { return lhs.magnitude_ > rhs || lhs == rhs; }
private:
double epsilon_;
double scale_;
@ -447,23 +519,23 @@ template<typename T>
auto make_memory_string( T const & item ) -> std::string;
#if lest_FEATURE_LITERAL_SUFFIX
inline char const * sfx( char const * text ) { return text; }
inline char const * sfx( char const * txt ) { return txt; }
#else
inline char const * sfx( char const * ) { return ""; }
#endif
inline std::string to_string( std::nullptr_t ) { return "nullptr"; }
inline std::string to_string( std::string const & text ) { return "\"" + text + "\"" ; }
inline std::string to_string( std::wstring const & text ) ;
inline std::string to_string( std::string const & txt ) { return "\"" + txt + "\"" ; }
#if lest_FEATURE_WSTRING
inline std::string to_string( std::wstring const & txt ) ;
#endif
inline std::string to_string( char const * const text ) { return text ? to_string( std::string ( text ) ) : "{null string}"; }
inline std::string to_string( char * const text ) { return text ? to_string( std::string ( text ) ) : "{null string}"; }
inline std::string to_string( wchar_t const * const text ) { return text ? to_string( std::wstring( text ) ) : "{null string}"; }
inline std::string to_string( wchar_t * const text ) { return text ? to_string( std::wstring( text ) ) : "{null string}"; }
inline std::string to_string( char text ) { return "\'" + std::string( 1, text ) + "\'" ; }
inline std::string to_string( signed char text ) { return "\'" + std::string( 1, text ) + "\'" ; }
inline std::string to_string( unsigned char text ) { return "\'" + std::string( 1, text ) + "\'" ; }
inline std::string to_string( char const * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
inline std::string to_string( char * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
#if lest_FEATURE_WSTRING
inline std::string to_string( wchar_t const * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
inline std::string to_string( wchar_t * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
#endif
inline std::string to_string( bool flag ) { return flag ? "true" : "false"; }
@ -478,6 +550,30 @@ inline std::string to_string( unsigned long long value ) { return make_value
inline std::string to_string( double value ) { return make_value_string( value ) ; }
inline std::string to_string( float value ) { return make_value_string( value ) + sfx("f" ); }
inline std::string to_string( signed char chr ) { return to_string( static_cast<char>( chr ) ); }
inline std::string to_string( unsigned char chr ) { return to_string( static_cast<char>( chr ) ); }
inline std::string to_string( char chr )
{
struct Tr { char chr; char const * str; } table[] =
{
{'\r', "'\\r'" }, {'\f', "'\\f'" },
{'\n', "'\\n'" }, {'\t', "'\\t'" },
};
for ( auto tr : table )
{
if ( chr == tr.chr )
return tr.str;
}
auto unprintable = [](char c){ return 0 <= c && c < ' '; };
return unprintable( chr )
? to_string( static_cast<unsigned int>( chr ) )
: "\'" + std::string( 1, chr ) + "\'" ;
}
template< typename T >
struct is_streamable
{
@ -526,12 +622,16 @@ template <typename T, typename R>
using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
template< typename T, typename R >
using ForNonContainer = typename std::enable_if< ! is_container<T>::value, R>::type;
using ForNonContainerNonPointer = typename std::enable_if< ! (is_container<T>::value || std::is_pointer<T>::value), R>::type;
template< typename T >
auto make_enum_string( T const & ) -> ForNonEnum<T, std::string>
auto make_enum_string( T const & item ) -> ForNonEnum<T, std::string>
{
return text("[type: ") + typeid(T).name() + "]";
#if lest__cpp_rtti
return text("[type: ") + typeid(T).name() + "]: " + make_memory_string( item );
#else
return text("[type: (no RTTI)]: ") + make_memory_string( item );
#endif
}
template< typename T >
@ -552,20 +652,6 @@ auto make_string( T const & item ) -> ForStreamable<T, std::string>
std::ostringstream os; os << item; return os.str();
}
template<typename T>
auto make_string( T * p )-> std::string
{
if ( p ) return make_memory_string( p );
else return "NULL";
}
template<typename C, typename R>
auto make_string( R C::* p ) -> std::string
{
if ( p ) return make_memory_string( p );
else return "NULL";
}
template<typename T1, typename T2>
auto make_string( std::pair<T1,T2> const & pair ) -> std::string
{
@ -598,7 +684,36 @@ auto make_string( std::tuple<TS...> const & tuple ) -> std::string
}
template< typename T >
auto to_string( T const & item ) -> ForNonContainer<T, std::string>
inline std::string make_string( T const * ptr )
{
// Note showbase affects the behavior of /integer/ output;
std::ostringstream os;
os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(T*) ) << std::setfill('0') << reinterpret_cast<std::ptrdiff_t>( ptr );
return os.str();
}
template< typename C, typename R >
inline std::string make_string( R C::* ptr )
{
std::ostringstream os;
os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(R C::* ) ) << std::setfill('0') << ptr;
return os.str();
}
template< typename T >
auto to_string( T const * ptr ) -> std::string
{
return ! ptr ? "nullptr" : make_string( ptr );
}
template<typename C, typename R>
auto to_string( R C::* ptr ) -> std::string
{
return ! ptr ? "nullptr" : make_string( ptr );
}
template< typename T >
auto to_string( T const & item ) -> ForNonContainerNonPointer<T, std::string>
{
return make_string( item );
}
@ -616,17 +731,19 @@ auto to_string( C const & cont ) -> ForContainer<C, std::string>
return os.str();
}
#if lest_FEATURE_WSTRING
inline
auto to_string( std::wstring const & text ) -> std::string
auto to_string( std::wstring const & txt ) -> std::string
{
std::string result; result.reserve( text.size() );
std::string result; result.reserve( txt.size() );
for( auto & chr : text )
for( auto & chr : txt )
{
result += chr <= 0xff ? static_cast<char>( chr ) : '?';
}
return to_string( result );
}
#endif
template< typename T >
auto make_value_string( T const & value ) -> std::string
@ -684,9 +801,9 @@ struct expression_lhs
{
const L lhs;
expression_lhs( L lhs ) : lhs( lhs ) {}
expression_lhs( L lhs_) : lhs( lhs_) {}
operator result() { return result{ lhs, to_string( lhs ) }; }
operator result() { return result{ !!lhs, to_string( lhs ) }; }
template< typename R > result operator==( R const & rhs ) { return result{ lhs == rhs, to_string( lhs, "==", rhs ) }; }
template< typename R > result operator!=( R const & rhs ) { return result{ lhs != rhs, to_string( lhs, "!=", rhs ) }; }
@ -699,7 +816,7 @@ struct expression_lhs
struct expression_decomposer
{
template <typename L>
expression_lhs<L const &> operator->* ( L const & operand )
expression_lhs<L const &> operator<< ( L const & operand )
{
return expression_lhs<L const &>( operand );
}
@ -754,7 +871,7 @@ inline std::ostream & operator<<( std::ostream & os, colourise words ) { return
inline text colourise( text words ) { return words; }
#endif
inline text pluralise( int n, text word )
inline text pluralise( text word, int n )
{
return n == 1 ? word : word + "s";
}
@ -814,9 +931,9 @@ inline bool select( text name, texts include )
auto none = []( texts args ) { return args.size() == 0; };
#if lest_FEATURE_REGEX_SEARCH
auto hidden = []( text name ){ return match( { "\\[\\.\\]", "\\[hide\\]" }, name ); };
auto hidden = []( text arg ){ return match( { "\\[\\..*", "\\[hide\\]" }, arg ); };
#else
auto hidden = []( text name ){ return match( { "[.]", "[hide]" }, name ); };
auto hidden = []( text arg ){ return match( { "[.", "[hide]" }, arg ); };
#endif
if ( none( include ) )
@ -864,6 +981,7 @@ struct options
bool pass = false;
bool lexical = false;
bool random = false;
bool verbose = false;
bool version = false;
int repeat = 1;
seed_t seed = 0;
@ -872,24 +990,74 @@ struct options
struct env
{
std::ostream & os;
bool pass;
options opt;
text testing;
std::vector< text > ctx;
env( std::ostream & os, bool pass )
: os( os ), pass( pass ) {}
env( std::ostream & out, options option )
: os( out ), opt( option ), testing(), ctx() {}
env & operator()( text test )
{
testing = test; return *this;
}
bool abort() { return opt.abort; }
bool pass() { return opt.pass; }
void pop() { ctx.pop_back(); }
void push( text proposition ) { ctx.emplace_back( proposition ); }
text context() { return testing + sections(); }
text sections()
{
if ( ! opt.verbose )
return "";
text msg;
for( auto section : ctx )
{
msg += "\n " + section;
}
return msg;
}
};
struct ctx
{
env & environment;
bool once;
ctx( env & environment_, text proposition_ )
: environment( environment_), once( true )
{
environment.push( proposition_);
}
~ctx()
{
#if lest_CPP17_OR_GREATER
if ( std::uncaught_exceptions() == 0 )
#else
if ( ! std::uncaught_exception() )
#endif
{
environment.pop();
}
}
explicit operator bool() { bool result = once; once = false; return result; }
};
struct action
{
std::ostream & os;
action( std::ostream & out ) : os( out ) {}
action( action const & ) = delete;
action( std::ostream & os ) : os( os ) {}
void operator=( action const & ) = delete;
operator int() { return 0; }
bool abort() { return false; }
@ -898,7 +1066,7 @@ struct action
struct print : action
{
print( std::ostream & os ) : action( os ) {}
print( std::ostream & out ) : action( out ) {}
print & operator()( test testing )
{
@ -924,7 +1092,7 @@ struct ptags : action
{
std::set<text> result;
ptags( std::ostream & os ) : action( os ) {}
ptags( std::ostream & out ) : action( out ), result() {}
ptags & operator()( test testing )
{
@ -944,13 +1112,13 @@ struct count : action
{
int n = 0;
count( std::ostream & os ) : action( os ) {}
count( std::ostream & out ) : action( out ) {}
count & operator()( test ) { ++n; return *this; }
~count()
{
os << n << " selected " << pluralise(n, "test") << "\n";
os << n << " selected " << pluralise("test", n) << "\n";
}
};
@ -962,28 +1130,27 @@ struct timer
double elapsed_seconds() const
{
return 1e-6 * std::chrono::duration_cast< std::chrono::microseconds >( time::now() - start ).count();
return 1e-6 * static_cast<double>( std::chrono::duration_cast< std::chrono::microseconds >( time::now() - start ).count() );
}
};
struct times : action
{
env output;
options option;
int selected = 0;
int failures = 0;
timer total;
times( std::ostream & os, options option )
: action( os ), output( os, option.pass ), option( option ), total()
times( std::ostream & out, options option )
: action( out ), output( out, option ), total()
{
os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION );
}
operator int() { return failures; }
bool abort() { return option.abort && failures > 0; }
bool abort() { return output.abort() && failures > 0; }
times & operator()( test testing )
{
@ -1012,16 +1179,15 @@ struct times : action
struct confirm : action
{
env output;
options option;
int selected = 0;
int failures = 0;
confirm( std::ostream & os, options option )
: action( os ), output( os, option.pass ), option( option ) {}
confirm( std::ostream & out, options option )
: action( out ), output( out, option ) {}
operator int() { return failures; }
bool abort() { return option.abort && failures > 0; }
bool abort() { return output.abort() && failures > 0; }
confirm & operator()( test testing )
{
@ -1031,7 +1197,7 @@ struct confirm : action
}
catch( message const & e )
{
++failures; report( os, e, testing.name );
++failures; report( os, e, output.context() );
}
return *this;
}
@ -1040,11 +1206,11 @@ struct confirm : action
{
if ( failures > 0 )
{
os << failures << " out of " << selected << " selected " << pluralise(selected, "test") << " " << colourise( "failed.\n" );
os << failures << " out of " << selected << " selected " << pluralise("test", selected) << " " << colourise( "failed.\n" );
}
else if ( option.pass )
else if ( output.pass() )
{
os << "All " << selected << " selected " << pluralise(selected, "test") << " " << colourise( "passed.\n" );
os << "All " << selected << " selected " << pluralise("test", selected) << " " << colourise( "passed.\n" );
}
}
};
@ -1085,7 +1251,7 @@ inline void shuffle( tests & specification, options option )
inline int stoi( text num )
{
return std::strtol( num.c_str(), NULL, 10 );
return static_cast<int>( std::strtol( num.c_str(), nullptr, 10 ) );
}
inline bool is_number( text arg )
@ -1096,7 +1262,7 @@ inline bool is_number( text arg )
inline seed_t seed( text opt, text arg )
{
if ( is_number( arg ) )
return lest::stoi( arg );
return static_cast<seed_t>( lest::stoi( arg ) );
if ( arg == "time" )
return static_cast<seed_t>( std::chrono::high_resolution_clock::now().time_since_epoch().count() );
@ -1145,6 +1311,7 @@ inline auto split_arguments( texts args ) -> std::tuple<options, texts>
else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; }
else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; }
else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; }
else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; }
else if ( "--version" == opt ) { option.version = true; continue; }
else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; }
else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; continue; }
@ -1171,7 +1338,8 @@ inline int usage( std::ostream & os )
" -l, --list-tests list selected tests\n"
" -p, --pass also report passing tests\n"
" -t, --time list duration of selected tests\n"
" --order=declared use source code test order\n"
" -v, --verbose also report passing or failing sections\n"
" --order=declared use source code test order (default)\n"
" --order=lexical use lexical sort test order\n"
" --order=random use random test order\n"
" --random-seed=n use n for random generator seed\n"
@ -1182,7 +1350,7 @@ inline int usage( std::ostream & os )
"\n"
"Test specification:\n"
" \"@\", \"*\" all tests, unless excluded\n"
" empty all tests, unless tagged [hide] or [.]\n"
" empty all tests, unless tagged [hide] or [.optional-name]\n"
#if lest_FEATURE_REGEX_SEARCH
" \"re\" select tests that match regular expression\n"
" \"!re\" omit tests that match regular expression\n"
@ -1202,7 +1370,7 @@ inline text compiler()
#elif defined (__GNUC__ )
os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
#elif defined ( _MSC_VER )
os << "MSVC " << (_MSC_VER / 100 - 6 ) << " (" << _MSC_VER << ")";
os << "MSVC " << (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) << " (" << _MSC_VER << ")";
#else
os << "[compiler]";
#endif
@ -1251,7 +1419,8 @@ inline int run( tests specification, int argc, char * argv[], std::ostream & os
template< std::size_t N >
int run( test const (&specification)[N], texts arguments, std::ostream & os = std::cout )
{
return run( tests( specification, specification + N ), arguments, os );
std::cout.sync_with_stdio( false );
return (std::min)( run( tests( specification, specification + N ), arguments, os ), exit_max_value );
}
template< std::size_t N >
@ -1268,4 +1437,10 @@ int run( test const (&specification)[N], int argc, char * argv[], std::ostream &
} // namespace lest
#endif // LEST_LEST_H_INCLUDED
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined __GNUC__
# pragma GCC diagnostic pop
#endif
#endif // LEST_LEST_HPP_INCLUDED

@ -1 +1 @@
Subproject commit b87c8262361f72fff05ca0b1320f8a1d9160b5cd
Subproject commit f8e187d07f9d8045bb41883d3e1c7d0ed6f241e4