try to compile with clang and on osx in travis
This commit is contained in:
parent
1a9482a445
commit
df2ab2df77
10 changed files with 485 additions and 269 deletions
14
.travis.yml
14
.travis.yml
|
@ -1,6 +1,12 @@
|
||||||
language: generic
|
language: cpp
|
||||||
sudo: false
|
|
||||||
dist: trusty
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
@ -21,4 +27,4 @@ script:
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
on_success: never
|
on_success: never
|
||||||
on_failure: always
|
on_failure: never
|
||||||
|
|
|
@ -20,7 +20,12 @@ if(OPENMP_FOUND)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# set compiler flags, see http://stackoverflow.com/questions/7724569/debug-vs-release-in-cmake
|
# 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_DEBUG "-Og -g -DLOGLEVEL=3")
|
||||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
|
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3a462c37358da19f10e89f77fb7a277d69c6c4dc
|
Subproject commit eae77cfdfb7eb64f87ddd48204ea9b90d6d5cfd8
|
|
@ -29,7 +29,6 @@ class Collector {
|
||||||
public:
|
public:
|
||||||
Collector(const std::string& evalOutPath, const std::vector<double>& dfBins)
|
Collector(const std::string& evalOutPath, const std::vector<double>& dfBins)
|
||||||
: _noOrigShp(0),
|
: _noOrigShp(0),
|
||||||
_noMatchShp(0),
|
|
||||||
_fdSum(0),
|
_fdSum(0),
|
||||||
_unmatchedSegSum(0),
|
_unmatchedSegSum(0),
|
||||||
_unmatchedSegLengthSum(0),
|
_unmatchedSegLengthSum(0),
|
||||||
|
@ -70,7 +69,6 @@ class Collector {
|
||||||
std::map<const Shape*, std::map<const Shape*, std::pair<size_t, double> > >
|
std::map<const Shape*, std::map<const Shape*, std::pair<size_t, double> > >
|
||||||
_dACache;
|
_dACache;
|
||||||
size_t _noOrigShp;
|
size_t _noOrigShp;
|
||||||
size_t _noMatchShp;
|
|
||||||
|
|
||||||
double _fdSum;
|
double _fdSum;
|
||||||
size_t _unmatchedSegSum;
|
size_t _unmatchedSegSum;
|
||||||
|
|
|
@ -2,7 +2,13 @@
|
||||||
// Chair of Algorithms and Data Structures.
|
// Chair of Algorithms and Data Structures.
|
||||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
|
#else
|
||||||
|
#define omp_get_thread_num() 0
|
||||||
|
#define omp_get_num_procs() 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#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)
|
Router::Router(size_t numThreads) : _cache(numThreads) {
|
||||||
: _g(g), _cache(numThreads) {
|
|
||||||
for (size_t i = 0; i < numThreads; i++) {
|
for (size_t i = 0; i < numThreads; i++) {
|
||||||
_cache[i] = new Cache();
|
_cache[i] = new Cache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ struct CombCostFunc
|
||||||
class Router {
|
class Router {
|
||||||
public:
|
public:
|
||||||
// Init this router with caches for numThreads threads
|
// Init this router with caches for numThreads threads
|
||||||
Router(const trgraph::Graph& g, size_t numThreads);
|
explicit Router(size_t numThreads);
|
||||||
~Router();
|
~Router();
|
||||||
|
|
||||||
// Find the most likely path through the graph for a node candidate route.
|
// Find the most likely path through the graph for a node candidate route.
|
||||||
|
@ -160,8 +160,6 @@ class Router {
|
||||||
size_t getCacheNumber() const;
|
size_t getCacheNumber() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const trgraph::Graph& _g;
|
|
||||||
|
|
||||||
mutable std::vector<Cache*> _cache;
|
mutable std::vector<Cache*> _cache;
|
||||||
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
||||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||||
|
|
|
@ -2,7 +2,13 @@
|
||||||
// Chair of Algorithms and Data Structures.
|
// Chair of Algorithms and Data Structures.
|
||||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
|
#else
|
||||||
|
#define omp_get_thread_num() 0
|
||||||
|
#define omp_get_num_procs() 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -49,7 +55,7 @@ ShapeBuilder::ShapeBuilder(Feed* feed, MOTs mots,
|
||||||
_motCfg(motCfg),
|
_motCfg(motCfg),
|
||||||
_ecoll(ecoll),
|
_ecoll(ecoll),
|
||||||
_cfg(cfg),
|
_cfg(cfg),
|
||||||
_crouter(_g, omp_get_num_procs()),
|
_crouter(omp_get_num_procs()),
|
||||||
_curShpCnt(0) {
|
_curShpCnt(0) {
|
||||||
_numThreads = _crouter.getCacheNumber();
|
_numThreads = _crouter.getCacheNumber();
|
||||||
writeMotStops();
|
writeMotStops();
|
||||||
|
|
|
@ -23,6 +23,7 @@ using namespace util::graph;
|
||||||
const lest::test specification[] = {
|
const lest::test specification[] = {
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("atof") {
|
CASE("atof") {
|
||||||
EXPECT(util::atof("45.534215") == approx(45.534215));
|
EXPECT(util::atof("45.534215") == approx(45.534215));
|
||||||
EXPECT(util::atof("5.534") == approx(5.534));
|
EXPECT(util::atof("5.534") == approx(5.534));
|
||||||
|
@ -33,9 +34,10 @@ CASE("atof") {
|
||||||
|
|
||||||
|
|
||||||
// TODO: more test cases
|
// TODO: more test cases
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("dirgraph") {
|
CASE("dirgraph") {
|
||||||
DirGraph<int, int> g;
|
DirGraph<int, int> g;
|
||||||
|
|
||||||
|
@ -74,9 +76,10 @@ CASE("dirgraph") {
|
||||||
EXPECT(a->getDeg() == (size_t)1);
|
EXPECT(a->getDeg() == (size_t)1);
|
||||||
|
|
||||||
// TODO: more test cases
|
// TODO: more test cases
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("unddirgraph") {
|
CASE("unddirgraph") {
|
||||||
UndirGraph<int, int> g;
|
UndirGraph<int, int> g;
|
||||||
|
|
||||||
|
@ -118,9 +121,10 @@ CASE("unddirgraph") {
|
||||||
|
|
||||||
// TODO: more test cases
|
// TODO: more test cases
|
||||||
|
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("grid") {
|
CASE("grid") {
|
||||||
Grid<int, Line, double> g(.5, .5, Box<double>(Point<double>(0, 0), Point<double>(3, 3)));
|
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
|
// TODO: more test cases
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("densify") {
|
CASE("densify") {
|
||||||
Line<double> a;
|
Line<double> a;
|
||||||
a.push_back(Point<double>(1, 1));
|
a.push_back(Point<double>(1, 1));
|
||||||
|
@ -179,9 +184,10 @@ CASE("densify") {
|
||||||
|
|
||||||
dense = util::geo::simplify(dense, 0.1);
|
dense = util::geo::simplify(dense, 0.1);
|
||||||
EXPECT(dense.size() == (size_t)3);
|
EXPECT(dense.size() == (size_t)3);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("summed frechet distance") {
|
CASE("summed frechet distance") {
|
||||||
Line<double> a;
|
Line<double> a;
|
||||||
a.push_back(Point<double>(1, 1));
|
a.push_back(Point<double>(1, 1));
|
||||||
|
@ -203,9 +209,10 @@ CASE("summed frechet distance") {
|
||||||
|
|
||||||
double fd = util::geo::accFrechetDistC(a, b, 0.1);
|
double fd = util::geo::accFrechetDistC(a, b, 0.1);
|
||||||
EXPECT(fd == approx(2));
|
EXPECT(fd == approx(2));
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("frechet distance") {
|
CASE("frechet distance") {
|
||||||
Line<double> e;
|
Line<double> e;
|
||||||
e.push_back(Point<double>(1, 1));
|
e.push_back(Point<double>(1, 1));
|
||||||
|
@ -268,9 +275,10 @@ CASE("frechet distance") {
|
||||||
fd = util::geo::frechetDist(g, h, 0.1);
|
fd = util::geo::frechetDist(g, h, 0.1);
|
||||||
|
|
||||||
EXPECT(fd == approx(1));
|
EXPECT(fd == approx(1));
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("geo box alignment") {
|
CASE("geo box alignment") {
|
||||||
Line<double> a;
|
Line<double> a;
|
||||||
a.push_back(Point<double>(1, 1));
|
a.push_back(Point<double>(1, 1));
|
||||||
|
@ -304,32 +312,36 @@ CASE("geo box alignment") {
|
||||||
EXPECT(parallelity(box, ml) == approx(0));
|
EXPECT(parallelity(box, ml) == approx(0));
|
||||||
ml = rotate(ml, 45);
|
ml = rotate(ml, 45);
|
||||||
EXPECT(parallelity(box, ml) == approx(1));
|
EXPECT(parallelity(box, ml) == approx(1));
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("url decode") {
|
CASE("url decode") {
|
||||||
EXPECT("zürich" == util::urlDecode("z%C3%BCrich"));
|
EXPECT("zürich" == util::urlDecode("z%C3%BCrich"));
|
||||||
EXPECT("!@$%^*()" == util::urlDecode("!%40%24%25%5E*()"));
|
EXPECT("!@$%^*()" == util::urlDecode("!%40%24%25%5E*()"));
|
||||||
EXPECT("Løkken" == util::urlDecode("L%C3%B8kken"));
|
EXPECT("Løkken" == util::urlDecode("L%C3%B8kken"));
|
||||||
EXPECT("á é" == util::urlDecode("%C3%A1%20%C3%A9"));
|
EXPECT("á é" == util::urlDecode("%C3%A1%20%C3%A9"));
|
||||||
EXPECT("á é" == util::urlDecode("%C3%A1+%C3%A9"));
|
EXPECT("á é" == util::urlDecode("%C3%A1+%C3%A9"));
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("json escape") {
|
CASE("json escape") {
|
||||||
EXPECT("Hello\\\\Goodbye!" == util::jsonStringEscape("Hello\\Goodbye!"));
|
EXPECT("Hello\\\\Goodbye!" == util::jsonStringEscape("Hello\\Goodbye!"));
|
||||||
EXPECT("\\\"Hello\\\"" == util::jsonStringEscape("\"Hello\""));
|
EXPECT("\\\"Hello\\\"" == util::jsonStringEscape("\"Hello\""));
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("split") {
|
CASE("split") {
|
||||||
EXPECT(util::split("hello,again", ',').size() == (size_t)2);
|
EXPECT(util::split("hello,again", ',').size() == (size_t)2);
|
||||||
EXPECT(util::split("hello,,again", ',').size() == (size_t)3);
|
EXPECT(util::split("hello,,again", ',').size() == (size_t)3);
|
||||||
EXPECT(util::split("hello", ',').size() == (size_t)1);
|
EXPECT(util::split("hello", ',').size() == (size_t)1);
|
||||||
EXPECT(util::split("", ',').size() == (size_t)0);
|
EXPECT(util::split("", ',').size() == (size_t)0);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("editdist") {
|
CASE("editdist") {
|
||||||
EXPECT(util::editDist("hello", "mello") == (size_t)1);
|
EXPECT(util::editDist("hello", "mello") == (size_t)1);
|
||||||
EXPECT(util::editDist("mello", "hello") == (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("xabcd", "abcde") == (size_t)2);
|
||||||
EXPECT(util::editDist("abcd", "abcdes") == (size_t)2);
|
EXPECT(util::editDist("abcd", "abcdes") == (size_t)2);
|
||||||
EXPECT(util::editDist("hello", "hello") == (size_t)0);
|
EXPECT(util::editDist("hello", "hello") == (size_t)0);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("toString") {
|
CASE("toString") {
|
||||||
EXPECT(util::toString(34) == "34");
|
EXPECT(util::toString(34) == "34");
|
||||||
EXPECT(util::toString("34") == "34");
|
EXPECT(util::toString("34") == "34");
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("replace") {
|
CASE("replace") {
|
||||||
std::string a("lorem ipsum ipsum lorem");
|
std::string a("lorem ipsum ipsum lorem");
|
||||||
|
|
||||||
|
@ -380,9 +394,10 @@ CASE("replace") {
|
||||||
|
|
||||||
EXPECT(!util::replaceAll(b, "", "ee"));
|
EXPECT(!util::replaceAll(b, "", "ee"));
|
||||||
EXPECT(b == "loree aaaau aaaau loree");
|
EXPECT(b == "loree aaaau aaaau loree");
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra directed, 1 to all") {
|
CASE("Edge-based Dijkstra directed, 1 to all") {
|
||||||
DirGraph<std::string, int> g;
|
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);
|
int single = EDijkstra::shortestPath(u.first, eBC, cFunc);
|
||||||
EXPECT(single == u.second);
|
EXPECT(single == u.second);
|
||||||
}
|
}
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra undirected, edge 1 to 1") {
|
CASE("Edge-based Dijkstra undirected, edge 1 to 1") {
|
||||||
UndirGraph<std::string, int> g;
|
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);
|
cost = EDijkstra::shortestPath(eAB, b, cFunc, &resE, &res);
|
||||||
EXPECT(cost == 0);
|
EXPECT(cost == 0);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra undirected, edge 1 to n") {
|
CASE("Edge-based Dijkstra undirected, edge 1 to n") {
|
||||||
UndirGraph<std::string, int> g;
|
UndirGraph<std::string, int> g;
|
||||||
|
|
||||||
|
@ -542,9 +559,10 @@ CASE("Edge-based Dijkstra undirected, edge 1 to n") {
|
||||||
EDijkstra::EList<std::string, int> resE;
|
EDijkstra::EList<std::string, int> resE;
|
||||||
int cost = EDijkstra::shortestPath(eAB, tos, cFunc, &resE, &res);
|
int cost = EDijkstra::shortestPath(eAB, tos, cFunc, &resE, &res);
|
||||||
EXPECT(cost == 0);
|
EXPECT(cost == 0);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra undirected, 1 to n") {
|
CASE("Edge-based Dijkstra undirected, 1 to n") {
|
||||||
UndirGraph<std::string, int> g;
|
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(resE[eDC]->size() == (size_t)3);
|
||||||
EXPECT(res[eED]->size() == (size_t)3);
|
EXPECT(res[eED]->size() == (size_t)3);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra undirected") {
|
CASE("Edge-based Dijkstra undirected") {
|
||||||
UndirGraph<std::string, int> g;
|
UndirGraph<std::string, int> g;
|
||||||
|
|
||||||
|
@ -668,9 +687,10 @@ CASE("Edge-based Dijkstra undirected") {
|
||||||
|
|
||||||
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
|
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
|
||||||
EXPECT(cost == 2);
|
EXPECT(cost == 2);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Edge-based Dijkstra") {
|
CASE("Edge-based Dijkstra") {
|
||||||
DirGraph<int, int> g;
|
DirGraph<int, int> g;
|
||||||
|
|
||||||
|
@ -715,9 +735,10 @@ CASE("Edge-based Dijkstra") {
|
||||||
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
|
cost = EDijkstra::shortestPath(a, d, cFunc, &res);
|
||||||
|
|
||||||
EXPECT(cost == 2);
|
EXPECT(cost == 2);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("Dijkstra") {
|
CASE("Dijkstra") {
|
||||||
DirGraph<int, int> g;
|
DirGraph<int, int> g;
|
||||||
|
|
||||||
|
@ -779,9 +800,10 @@ CASE("Dijkstra") {
|
||||||
EXPECT(costs[c] == 1);
|
EXPECT(costs[c] == 1);
|
||||||
EXPECT(costs[d] == 2);
|
EXPECT(costs[d] == 2);
|
||||||
EXPECT(costs[x] == 999);
|
EXPECT(costs[x] == 999);
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("nullable") {
|
CASE("nullable") {
|
||||||
{
|
{
|
||||||
util::Nullable<std::string> nullable;
|
util::Nullable<std::string> nullable;
|
||||||
|
@ -840,9 +862,10 @@ CASE("nullable") {
|
||||||
|
|
||||||
EXPECT_THROWS(nullable == voidnull);
|
EXPECT_THROWS(nullable == voidnull);
|
||||||
}
|
}
|
||||||
},
|
}},
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
// ___________________________________________________________________________
|
||||||
|
{
|
||||||
CASE("geometry") {
|
CASE("geometry") {
|
||||||
geo::Point<double> a(1, 2);
|
geo::Point<double> a(1, 2);
|
||||||
geo::Point<double> b(2, 3);
|
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)));
|
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) {
|
int main(int argc, char** argv) {
|
||||||
|
|
|
@ -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
|
// 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
|
// 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
|
// 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
|
#ifndef LEST_LEST_HPP_INCLUDED
|
||||||
#define LEST_LEST_H_INCLUDED
|
#define LEST_LEST_HPP_INCLUDED
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -31,14 +31,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#ifdef __clang__
|
#define lest_VERSION "1.33.1"
|
||||||
# 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"
|
|
||||||
|
|
||||||
#ifndef lest_FEATURE_AUTO_REGISTER
|
#ifndef lest_FEATURE_AUTO_REGISTER
|
||||||
# define lest_FEATURE_AUTO_REGISTER 0
|
# define lest_FEATURE_AUTO_REGISTER 0
|
||||||
|
@ -60,16 +53,71 @@
|
||||||
#define lest_FEATURE_TIME_PRECISION 0
|
#define lest_FEATURE_TIME_PRECISION 0
|
||||||
#endif
|
#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
|
#if lest_FEATURE_REGEX_SEARCH
|
||||||
# include <regex>
|
# include <regex>
|
||||||
#endif
|
#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 )
|
#if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES )
|
||||||
# define MODULE lest_MODULE
|
# define MODULE lest_MODULE
|
||||||
|
|
||||||
# if ! lest_FEATURE_AUTO_REGISTER
|
# if ! lest_FEATURE_AUTO_REGISTER
|
||||||
# define CASE lest_CASE
|
# define CASE lest_CASE
|
||||||
# define TEST lest_TEST
|
# define CASE_ON lest_CASE_ON
|
||||||
|
# define SCENARIO lest_SCENARIO
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# define SETUP lest_SETUP
|
# define SETUP lest_SETUP
|
||||||
|
@ -81,7 +129,6 @@
|
||||||
# define EXPECT_THROWS lest_EXPECT_THROWS
|
# define EXPECT_THROWS lest_EXPECT_THROWS
|
||||||
# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS
|
# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS
|
||||||
|
|
||||||
# define SCENARIO lest_SCENARIO
|
|
||||||
# define GIVEN lest_GIVEN
|
# define GIVEN lest_GIVEN
|
||||||
# define WHEN lest_WHEN
|
# define WHEN lest_WHEN
|
||||||
# define THEN lest_THEN
|
# define THEN lest_THEN
|
||||||
|
@ -89,40 +136,48 @@
|
||||||
# define AND_THEN lest_AND_THEN
|
# define AND_THEN lest_AND_THEN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define lest_SCENARIO( sketch ) lest_CASE( "Scenario: " sketch )
|
#if lest_FEATURE_AUTO_REGISTER
|
||||||
#define lest_GIVEN( context ) lest_SETUP( "Given: " context )
|
#define lest_SCENARIO( specification, sketch ) lest_CASE( specification, lest::text("Scenario: ") + sketch )
|
||||||
#define lest_WHEN( story ) lest_SECTION( " When: " story )
|
#else
|
||||||
#define lest_THEN( story ) lest_SECTION( " Then: " story )
|
#define lest_SCENARIO( sketch ) lest_CASE( lest::text("Scenario: ") + sketch )
|
||||||
#define lest_AND_WHEN( story ) lest_SECTION( " And: " story )
|
#endif
|
||||||
#define lest_AND_THEN( story ) lest_SECTION( " And: " story )
|
#define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context )
|
||||||
|
#define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story )
|
||||||
#define lest_MODULE( specification, module ) \
|
#define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story )
|
||||||
namespace { lest::add_module _( specification, module ); }
|
#define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story )
|
||||||
|
#define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story )
|
||||||
#define lest_TEST \
|
|
||||||
lest_CASE
|
|
||||||
|
|
||||||
#if lest_FEATURE_AUTO_REGISTER
|
#if lest_FEATURE_AUTO_REGISTER
|
||||||
|
|
||||||
# define lest_CASE( specification, proposition ) \
|
# 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 ) ); } \
|
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, ... ) \
|
# define lest_CASE( proposition ) \
|
||||||
proposition, [__VA_ARGS__]( lest::env & $ )
|
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 ) \
|
#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 ) \
|
#define lest_SECTION( proposition ) \
|
||||||
|
lest_SUPPRESS_WSHADOW \
|
||||||
static int lest_UNIQUE( id ) = 0; \
|
static int lest_UNIQUE( id ) = 0; \
|
||||||
if ( lest::guard $run = lest::guard( lest_UNIQUE( id ), $section, $count ) ) \
|
if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \
|
||||||
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_section( lest_env, proposition ); lest__ctx_section; ) \
|
||||||
|
lest_RESTORE_WARNINGS
|
||||||
|
|
||||||
#define lest_EXPECT( expr ) \
|
#define lest_EXPECT( expr ) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -130,8 +185,8 @@
|
||||||
{ \
|
{ \
|
||||||
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
||||||
throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
|
throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
|
||||||
else if ( $.pass ) \
|
else if ( lest_env.pass() ) \
|
||||||
lest::report( $.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, $.testing ); \
|
lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, lest_env.context() ); \
|
||||||
} \
|
} \
|
||||||
catch(...) \
|
catch(...) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -145,8 +200,8 @@
|
||||||
{ \
|
{ \
|
||||||
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
||||||
{ \
|
{ \
|
||||||
if ( $.pass ) \
|
if ( lest_env.pass() ) \
|
||||||
lest::report( $.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, $.testing ); \
|
lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, lest_env.context() ); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
|
throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
|
||||||
|
@ -162,14 +217,16 @@
|
||||||
{ \
|
{ \
|
||||||
try \
|
try \
|
||||||
{ \
|
{ \
|
||||||
|
lest_SUPPRESS_WUNUSED \
|
||||||
expr; \
|
expr; \
|
||||||
|
lest_RESTORE_WARNINGS \
|
||||||
} \
|
} \
|
||||||
catch (...) \
|
catch (...) \
|
||||||
{ \
|
{ \
|
||||||
lest::inform( lest_LOCATION, #expr ); \
|
lest::inform( lest_LOCATION, #expr ); \
|
||||||
} \
|
} \
|
||||||
if ( $.pass ) \
|
if ( lest_env.pass() ) \
|
||||||
lest::report( $.os, lest::got_none( lest_LOCATION, #expr ), $.testing ); \
|
lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \
|
||||||
} while ( lest::is_false() )
|
} while ( lest::is_false() )
|
||||||
|
|
||||||
#define lest_EXPECT_THROWS( expr ) \
|
#define lest_EXPECT_THROWS( expr ) \
|
||||||
|
@ -177,12 +234,14 @@
|
||||||
{ \
|
{ \
|
||||||
try \
|
try \
|
||||||
{ \
|
{ \
|
||||||
|
lest_SUPPRESS_WUNUSED \
|
||||||
expr; \
|
expr; \
|
||||||
|
lest_RESTORE_WARNINGS \
|
||||||
} \
|
} \
|
||||||
catch (...) \
|
catch (...) \
|
||||||
{ \
|
{ \
|
||||||
if ( $.pass ) \
|
if ( lest_env.pass() ) \
|
||||||
lest::report( $.os, lest::got{ lest_LOCATION, #expr }, $.testing ); \
|
lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr }, lest_env.context() ); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
throw lest::expected{ lest_LOCATION, #expr }; \
|
throw lest::expected{ lest_LOCATION, #expr }; \
|
||||||
|
@ -194,12 +253,14 @@
|
||||||
{ \
|
{ \
|
||||||
try \
|
try \
|
||||||
{ \
|
{ \
|
||||||
|
lest_SUPPRESS_WUNUSED \
|
||||||
expr; \
|
expr; \
|
||||||
|
lest_RESTORE_WARNINGS \
|
||||||
} \
|
} \
|
||||||
catch ( excpt & ) \
|
catch ( excpt & ) \
|
||||||
{ \
|
{ \
|
||||||
if ( $.pass ) \
|
if ( lest_env.pass() ) \
|
||||||
lest::report( $.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, $.testing ); \
|
lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, lest_env.context() ); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
catch (...) {} \
|
catch (...) {} \
|
||||||
|
@ -211,7 +272,7 @@
|
||||||
#define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line )
|
#define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line )
|
||||||
#define lest_UNIQUE3( name, line ) 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_FUNCTION lest_UNIQUE(__lest_function__ )
|
||||||
#define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ )
|
#define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ )
|
||||||
|
@ -220,6 +281,8 @@
|
||||||
|
|
||||||
namespace lest {
|
namespace lest {
|
||||||
|
|
||||||
|
const int exit_max_value = 255;
|
||||||
|
|
||||||
using text = std::string;
|
using text = std::string;
|
||||||
using texts = std::vector<text>;
|
using texts = std::vector<text>;
|
||||||
|
|
||||||
|
@ -231,8 +294,8 @@ struct test
|
||||||
std::function<void( env & )> behaviour;
|
std::function<void( env & )> behaviour;
|
||||||
|
|
||||||
#if lest_FEATURE_AUTO_REGISTER
|
#if lest_FEATURE_AUTO_REGISTER
|
||||||
test( text name, std::function<void( env & )> behaviour )
|
test( text name_, std::function<void( env & )> behaviour_ )
|
||||||
: name( name ), behaviour( behaviour ) {}
|
: name( name_), behaviour( behaviour_) {}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -266,6 +329,10 @@ struct result
|
||||||
const bool passed;
|
const bool passed;
|
||||||
const text decomposition;
|
const text decomposition;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
result( T const & passed_, text decomposition_)
|
||||||
|
: passed( !!passed_), decomposition( decomposition_) {}
|
||||||
|
|
||||||
explicit operator bool() { return ! passed; }
|
explicit operator bool() { return ! passed; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -274,15 +341,15 @@ struct location
|
||||||
const text file;
|
const text file;
|
||||||
const int line;
|
const int line;
|
||||||
|
|
||||||
location( text file, int line )
|
location( text file_, int line_)
|
||||||
: file( file ), line( line ) {}
|
: file( file_), line( line_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct comment
|
struct comment
|
||||||
{
|
{
|
||||||
const text info;
|
const text info;
|
||||||
|
|
||||||
comment( text info ) : info( info ) {}
|
comment( text info_) : info( info_) {}
|
||||||
explicit operator bool() { return ! info.empty(); }
|
explicit operator bool() { return ! info.empty(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -294,55 +361,55 @@ struct message : std::runtime_error
|
||||||
|
|
||||||
~message() throw() {} // GCC 4.6
|
~message() throw() {} // GCC 4.6
|
||||||
|
|
||||||
message( text kind, location where, text expr, text note = "" )
|
message( text kind_, location where_, text expr_, text note_ = "" )
|
||||||
: std::runtime_error( expr ), kind( kind ), where( where ), note( note ) {}
|
: std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct failure : message
|
struct failure : message
|
||||||
{
|
{
|
||||||
failure( location where, text expr, text decomposition )
|
failure( location where_, text expr_, text decomposition_)
|
||||||
: message{ "failed", where, expr + " for " + decomposition } {}
|
: message{ "failed", where_, expr_ + " for " + decomposition_ } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct success : message
|
struct success : message
|
||||||
{
|
{
|
||||||
// using message::message; // VC is lagging here
|
// using message::message; // VC is lagging here
|
||||||
|
|
||||||
success( text kind, location where, text expr, text note = "" )
|
success( text kind_, location where_, text expr_, text note_ = "" )
|
||||||
: message( kind, where, expr, note ) {}
|
: message( kind_, where_, expr_, note_ ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct passing : success
|
struct passing : success
|
||||||
{
|
{
|
||||||
passing( location where, text expr, text decomposition )
|
passing( location where_, text expr_, text decomposition_ )
|
||||||
: success( "passed", where, expr + " for " + decomposition ) {}
|
: success( "passed", where_, expr_ + " for " + decomposition_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct got_none : success
|
struct got_none : success
|
||||||
{
|
{
|
||||||
got_none( location where, text expr )
|
got_none( location where_, text expr_ )
|
||||||
: success( "passed: got no exception", where, expr ) {}
|
: success( "passed: got no exception", where_, expr_ ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct got : success
|
struct got : success
|
||||||
{
|
{
|
||||||
got( location where, text expr )
|
got( location where_, text expr_)
|
||||||
: success( "passed: got exception", where, expr ) {}
|
: success( "passed: got exception", where_, expr_) {}
|
||||||
|
|
||||||
got( location where, text expr, text excpt )
|
got( location where_, text expr_, text excpt_)
|
||||||
: success( "passed: got exception " + excpt, where, expr ) {}
|
: success( "passed: got exception " + excpt_, where_, expr_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct expected : message
|
struct expected : message
|
||||||
{
|
{
|
||||||
expected( location where, text expr, text excpt = "" )
|
expected( location where_, text expr_, text excpt_ = "" )
|
||||||
: message{ "failed: didn't get exception", where, expr, excpt } {}
|
: message{ "failed: didn't get exception", where_, expr_, excpt_ } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct unexpected : message
|
struct unexpected : message
|
||||||
{
|
{
|
||||||
unexpected( location where, text expr, text note = "" )
|
unexpected( location where_, text expr_, text note_ = "" )
|
||||||
: message{ "failed: got unexpected exception", where, expr, note } {}
|
: message{ "failed: got unexpected exception", where_, expr_, note_ } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct guard
|
struct guard
|
||||||
|
@ -350,8 +417,8 @@ struct guard
|
||||||
int & id;
|
int & id;
|
||||||
int const & section;
|
int const & section;
|
||||||
|
|
||||||
guard( int & id, int const & section, int & count )
|
guard( int & id_, int const & section_, int & count )
|
||||||
: id( id ), section( section )
|
: id( id_), section( section_)
|
||||||
{
|
{
|
||||||
if ( section == 0 )
|
if ( section == 0 )
|
||||||
id = count++ - 1;
|
id = count++ - 1;
|
||||||
|
@ -371,12 +438,12 @@ public:
|
||||||
|
|
||||||
static approx custom() { return approx( 0 ); }
|
static approx custom() { return approx( 0 ); }
|
||||||
|
|
||||||
approx operator()( double magnitude )
|
approx operator()( double new_magnitude )
|
||||||
{
|
{
|
||||||
approx approx ( magnitude );
|
approx appr( new_magnitude );
|
||||||
approx.epsilon( epsilon_ );
|
appr.epsilon( epsilon_ );
|
||||||
approx.scale ( scale_ );
|
appr.scale ( scale_ );
|
||||||
return approx;
|
return appr;
|
||||||
}
|
}
|
||||||
|
|
||||||
double magnitude() const { return magnitude_; }
|
double magnitude() const { return magnitude_; }
|
||||||
|
@ -387,13 +454,18 @@ public:
|
||||||
friend bool operator == ( double lhs, approx const & rhs )
|
friend bool operator == ( double lhs, approx const & rhs )
|
||||||
{
|
{
|
||||||
// Thanks to Richard Harris for his help refining this formula.
|
// 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 == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); }
|
||||||
friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); }
|
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 != ( 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:
|
private:
|
||||||
double epsilon_;
|
double epsilon_;
|
||||||
double scale_;
|
double scale_;
|
||||||
|
@ -447,23 +519,23 @@ template<typename T>
|
||||||
auto make_memory_string( T const & item ) -> std::string;
|
auto make_memory_string( T const & item ) -> std::string;
|
||||||
|
|
||||||
#if lest_FEATURE_LITERAL_SUFFIX
|
#if lest_FEATURE_LITERAL_SUFFIX
|
||||||
inline char const * sfx( char const * text ) { return text; }
|
inline char const * sfx( char const * txt ) { return txt; }
|
||||||
#else
|
#else
|
||||||
inline char const * sfx( char const * ) { return ""; }
|
inline char const * sfx( char const * ) { return ""; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline std::string to_string( std::nullptr_t ) { return "nullptr"; }
|
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::string const & txt ) { return "\"" + txt + "\"" ; }
|
||||||
inline std::string to_string( std::wstring const & text ) ;
|
#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 * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
|
||||||
inline std::string to_string( char * const text ) { return text ? to_string( std::string ( text ) ) : "{null string}"; }
|
inline std::string to_string( char * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
|
||||||
inline std::string to_string( wchar_t const * const text ) { return text ? to_string( std::wstring( text ) ) : "{null string}"; }
|
#if lest_FEATURE_WSTRING
|
||||||
inline std::string to_string( wchar_t * const text ) { return text ? to_string( std::wstring( text ) ) : "{null string}"; }
|
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}"; }
|
||||||
inline std::string to_string( char text ) { return "\'" + std::string( 1, text ) + "\'" ; }
|
#endif
|
||||||
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( bool flag ) { return flag ? "true" : "false"; }
|
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( 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( 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 >
|
template< typename T >
|
||||||
struct is_streamable
|
struct is_streamable
|
||||||
{
|
{
|
||||||
|
@ -526,12 +622,16 @@ template <typename T, typename R>
|
||||||
using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
|
using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
|
||||||
|
|
||||||
template< typename T, typename R >
|
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 >
|
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 >
|
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();
|
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>
|
template<typename T1, typename T2>
|
||||||
auto make_string( std::pair<T1,T2> const & pair ) -> std::string
|
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 >
|
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 );
|
return make_string( item );
|
||||||
}
|
}
|
||||||
|
@ -616,17 +731,19 @@ auto to_string( C const & cont ) -> ForContainer<C, std::string>
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if lest_FEATURE_WSTRING
|
||||||
inline
|
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 ) : '?';
|
result += chr <= 0xff ? static_cast<char>( chr ) : '?';
|
||||||
}
|
}
|
||||||
return to_string( result );
|
return to_string( result );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
auto make_value_string( T const & value ) -> std::string
|
auto make_value_string( T const & value ) -> std::string
|
||||||
|
@ -684,9 +801,9 @@ struct expression_lhs
|
||||||
{
|
{
|
||||||
const L 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 ) }; }
|
||||||
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
|
struct expression_decomposer
|
||||||
{
|
{
|
||||||
template <typename L>
|
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 );
|
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; }
|
inline text colourise( text words ) { return words; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline text pluralise( int n, text word )
|
inline text pluralise( text word, int n )
|
||||||
{
|
{
|
||||||
return n == 1 ? word : word + "s";
|
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; };
|
auto none = []( texts args ) { return args.size() == 0; };
|
||||||
|
|
||||||
#if lest_FEATURE_REGEX_SEARCH
|
#if lest_FEATURE_REGEX_SEARCH
|
||||||
auto hidden = []( text name ){ return match( { "\\[\\.\\]", "\\[hide\\]" }, name ); };
|
auto hidden = []( text arg ){ return match( { "\\[\\..*", "\\[hide\\]" }, arg ); };
|
||||||
#else
|
#else
|
||||||
auto hidden = []( text name ){ return match( { "[.]", "[hide]" }, name ); };
|
auto hidden = []( text arg ){ return match( { "[.", "[hide]" }, arg ); };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( none( include ) )
|
if ( none( include ) )
|
||||||
|
@ -864,6 +981,7 @@ struct options
|
||||||
bool pass = false;
|
bool pass = false;
|
||||||
bool lexical = false;
|
bool lexical = false;
|
||||||
bool random = false;
|
bool random = false;
|
||||||
|
bool verbose = false;
|
||||||
bool version = false;
|
bool version = false;
|
||||||
int repeat = 1;
|
int repeat = 1;
|
||||||
seed_t seed = 0;
|
seed_t seed = 0;
|
||||||
|
@ -872,24 +990,74 @@ struct options
|
||||||
struct env
|
struct env
|
||||||
{
|
{
|
||||||
std::ostream & os;
|
std::ostream & os;
|
||||||
bool pass;
|
options opt;
|
||||||
text testing;
|
text testing;
|
||||||
|
std::vector< text > ctx;
|
||||||
|
|
||||||
env( std::ostream & os, bool pass )
|
env( std::ostream & out, options option )
|
||||||
: os( os ), pass( pass ) {}
|
: os( out ), opt( option ), testing(), ctx() {}
|
||||||
|
|
||||||
env & operator()( text test )
|
env & operator()( text test )
|
||||||
{
|
{
|
||||||
testing = test; return *this;
|
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
|
struct action
|
||||||
{
|
{
|
||||||
std::ostream & os;
|
std::ostream & os;
|
||||||
|
|
||||||
|
action( std::ostream & out ) : os( out ) {}
|
||||||
|
|
||||||
action( action const & ) = delete;
|
action( action const & ) = delete;
|
||||||
action( std::ostream & os ) : os( os ) {}
|
void operator=( action const & ) = delete;
|
||||||
|
|
||||||
operator int() { return 0; }
|
operator int() { return 0; }
|
||||||
bool abort() { return false; }
|
bool abort() { return false; }
|
||||||
|
@ -898,7 +1066,7 @@ struct action
|
||||||
|
|
||||||
struct print : action
|
struct print : action
|
||||||
{
|
{
|
||||||
print( std::ostream & os ) : action( os ) {}
|
print( std::ostream & out ) : action( out ) {}
|
||||||
|
|
||||||
print & operator()( test testing )
|
print & operator()( test testing )
|
||||||
{
|
{
|
||||||
|
@ -924,7 +1092,7 @@ struct ptags : action
|
||||||
{
|
{
|
||||||
std::set<text> result;
|
std::set<text> result;
|
||||||
|
|
||||||
ptags( std::ostream & os ) : action( os ) {}
|
ptags( std::ostream & out ) : action( out ), result() {}
|
||||||
|
|
||||||
ptags & operator()( test testing )
|
ptags & operator()( test testing )
|
||||||
{
|
{
|
||||||
|
@ -944,13 +1112,13 @@ struct count : action
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
count( std::ostream & os ) : action( os ) {}
|
count( std::ostream & out ) : action( out ) {}
|
||||||
|
|
||||||
count & operator()( test ) { ++n; return *this; }
|
count & operator()( test ) { ++n; return *this; }
|
||||||
|
|
||||||
~count()
|
~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
|
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
|
struct times : action
|
||||||
{
|
{
|
||||||
env output;
|
env output;
|
||||||
options option;
|
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
|
|
||||||
timer total;
|
timer total;
|
||||||
|
|
||||||
times( std::ostream & os, options option )
|
times( std::ostream & out, options option )
|
||||||
: action( os ), output( os, option.pass ), option( option ), total()
|
: action( out ), output( out, option ), total()
|
||||||
{
|
{
|
||||||
os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION );
|
os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION );
|
||||||
}
|
}
|
||||||
|
|
||||||
operator int() { return failures; }
|
operator int() { return failures; }
|
||||||
|
|
||||||
bool abort() { return option.abort && failures > 0; }
|
bool abort() { return output.abort() && failures > 0; }
|
||||||
|
|
||||||
times & operator()( test testing )
|
times & operator()( test testing )
|
||||||
{
|
{
|
||||||
|
@ -1012,16 +1179,15 @@ struct times : action
|
||||||
struct confirm : action
|
struct confirm : action
|
||||||
{
|
{
|
||||||
env output;
|
env output;
|
||||||
options option;
|
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
|
|
||||||
confirm( std::ostream & os, options option )
|
confirm( std::ostream & out, options option )
|
||||||
: action( os ), output( os, option.pass ), option( option ) {}
|
: action( out ), output( out, option ) {}
|
||||||
|
|
||||||
operator int() { return failures; }
|
operator int() { return failures; }
|
||||||
|
|
||||||
bool abort() { return option.abort && failures > 0; }
|
bool abort() { return output.abort() && failures > 0; }
|
||||||
|
|
||||||
confirm & operator()( test testing )
|
confirm & operator()( test testing )
|
||||||
{
|
{
|
||||||
|
@ -1031,7 +1197,7 @@ struct confirm : action
|
||||||
}
|
}
|
||||||
catch( message const & e )
|
catch( message const & e )
|
||||||
{
|
{
|
||||||
++failures; report( os, e, testing.name );
|
++failures; report( os, e, output.context() );
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1040,11 +1206,11 @@ struct confirm : action
|
||||||
{
|
{
|
||||||
if ( failures > 0 )
|
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 )
|
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 )
|
inline bool is_number( text arg )
|
||||||
|
@ -1096,7 +1262,7 @@ inline bool is_number( text arg )
|
||||||
inline seed_t seed( text opt, text arg )
|
inline seed_t seed( text opt, text arg )
|
||||||
{
|
{
|
||||||
if ( is_number( arg ) )
|
if ( is_number( arg ) )
|
||||||
return lest::stoi( arg );
|
return static_cast<seed_t>( lest::stoi( arg ) );
|
||||||
|
|
||||||
if ( arg == "time" )
|
if ( arg == "time" )
|
||||||
return static_cast<seed_t>( std::chrono::high_resolution_clock::now().time_since_epoch().count() );
|
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 == "-l" || "--list-tests" == opt ) { option.list = true; continue; }
|
||||||
else if ( opt == "-t" || "--time" == opt ) { option.time = 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 == "-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 ( "--version" == opt ) { option.version = true; continue; }
|
||||||
else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; }
|
else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; }
|
||||||
else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; 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"
|
" -l, --list-tests list selected tests\n"
|
||||||
" -p, --pass also report passing tests\n"
|
" -p, --pass also report passing tests\n"
|
||||||
" -t, --time list duration of selected 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=lexical use lexical sort test order\n"
|
||||||
" --order=random use random test order\n"
|
" --order=random use random test order\n"
|
||||||
" --random-seed=n use n for random generator seed\n"
|
" --random-seed=n use n for random generator seed\n"
|
||||||
|
@ -1182,7 +1350,7 @@ inline int usage( std::ostream & os )
|
||||||
"\n"
|
"\n"
|
||||||
"Test specification:\n"
|
"Test specification:\n"
|
||||||
" \"@\", \"*\" all tests, unless excluded\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
|
#if lest_FEATURE_REGEX_SEARCH
|
||||||
" \"re\" select tests that match regular expression\n"
|
" \"re\" select tests that match regular expression\n"
|
||||||
" \"!re\" omit tests that match regular expression\n"
|
" \"!re\" omit tests that match regular expression\n"
|
||||||
|
@ -1202,7 +1370,7 @@ inline text compiler()
|
||||||
#elif defined (__GNUC__ )
|
#elif defined (__GNUC__ )
|
||||||
os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
|
os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
|
||||||
#elif defined ( _MSC_VER )
|
#elif defined ( _MSC_VER )
|
||||||
os << "MSVC " << (_MSC_VER / 100 - 6 ) << " (" << _MSC_VER << ")";
|
os << "MSVC " << (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) << " (" << _MSC_VER << ")";
|
||||||
#else
|
#else
|
||||||
os << "[compiler]";
|
os << "[compiler]";
|
||||||
#endif
|
#endif
|
||||||
|
@ -1251,7 +1419,8 @@ inline int run( tests specification, int argc, char * argv[], std::ostream & os
|
||||||
template< std::size_t N >
|
template< std::size_t N >
|
||||||
int run( test const (&specification)[N], texts arguments, std::ostream & os = std::cout )
|
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 >
|
template< std::size_t N >
|
||||||
|
@ -1268,4 +1437,10 @@ int run( test const (&specification)[N], int argc, char * argv[], std::ostream &
|
||||||
|
|
||||||
} // namespace lest
|
} // 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
|
||||||
|
|
2
src/xml
2
src/xml
|
@ -1 +1 @@
|
||||||
Subproject commit b87c8262361f72fff05ca0b1320f8a1d9160b5cd
|
Subproject commit f8e187d07f9d8045bb41883d3e1c7d0ed6f241e4
|
Loading…
Reference in a new issue