feat: add more API methods to Result and Option
This commit is contained in:
parent
b8ac4c450c
commit
e48a0430b6
181
src/ro.h
181
src/ro.h
@ -7,12 +7,20 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#define None(T) (ro::Option<T>())
|
#define None(...) ro::Option<__VA_ARGS__>()
|
||||||
#define Some(v) (ro::Option(v))
|
#define Some(...) ro::Option(__VA_ARGS__)
|
||||||
#define ERR(fmt, ...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
|
#define ERR(fmt, ...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
|
||||||
#define try_unwrap(l,...) try{l=(__VA_ARGS__).unwrap();}catch(ro::Error e){return e;}
|
#define try_unwrap(l, ...) \
|
||||||
// #define Err(e) (ro::Result(e))
|
try \
|
||||||
// #define Ok(v) (ro::Result(v))
|
{ \
|
||||||
|
l = (__VA_ARGS__).unwrap(); \
|
||||||
|
} \
|
||||||
|
catch (ro::Error e) \
|
||||||
|
{ \
|
||||||
|
return e; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ERR_INVALID_ACESS "Invalid access"
|
||||||
|
|
||||||
namespace ro
|
namespace ro
|
||||||
{
|
{
|
||||||
@ -42,13 +50,13 @@ namespace ro
|
|||||||
return std::string(l.what()) == std::string(r.what());
|
return std::string(l.what()) == std::string(r.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend inline Error operator+(const Error & l, const Error &r)
|
friend inline Error operator+(const Error &l, const Error &r)
|
||||||
{
|
{
|
||||||
return Error(std::string(l.what()) + "\n" + r.what());
|
return Error(std::string(l.what()) + "\n" + r.what());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename E>
|
template <typename T, typename E = ro::Error>
|
||||||
class Result;
|
class Result;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -56,6 +64,7 @@ namespace ro
|
|||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using type_t = T;
|
||||||
Option(T obj) : m_some(obj), m_notnull(true){};
|
Option(T obj) : m_some(obj), m_notnull(true){};
|
||||||
Option() : m_notnull(false){};
|
Option() : m_notnull(false){};
|
||||||
|
|
||||||
@ -64,6 +73,7 @@ namespace ro
|
|||||||
insert(value);
|
insert(value);
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline friend bool operator==(const Option<T> &l, const Option<T> &r)
|
inline friend bool operator==(const Option<T> &l, const Option<T> &r)
|
||||||
{
|
{
|
||||||
if (!l.m_notnull && !r.m_notnull)
|
if (!l.m_notnull && !r.m_notnull)
|
||||||
@ -111,13 +121,43 @@ namespace ro
|
|||||||
|
|
||||||
inline bool is_none() const { return !m_notnull; };
|
inline bool is_none() const { return !m_notnull; };
|
||||||
inline bool is_some() const { return m_notnull; };
|
inline bool is_some() const { return m_notnull; };
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline U match(const std::function<U(T &)> &expected, const std::function<U()> &unexpected)
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
return expected(m_some);
|
||||||
|
}
|
||||||
|
return unexpected();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline U match(const std::function<U(const T &)> &expected, const std::function<U()> &unexpected) const
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
return expected(m_some);
|
||||||
|
}
|
||||||
|
return unexpected();
|
||||||
|
}
|
||||||
|
|
||||||
inline const T &unwrap() const
|
inline const T &unwrap() const
|
||||||
{
|
{
|
||||||
if (m_notnull)
|
if (m_notnull)
|
||||||
{
|
{
|
||||||
return m_some;
|
return m_some;
|
||||||
}
|
}
|
||||||
throw Error("Object is None");
|
throw Error(ERR_INVALID_ACESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T &unwrap()
|
||||||
|
{
|
||||||
|
if (m_notnull)
|
||||||
|
{
|
||||||
|
return m_some;
|
||||||
|
}
|
||||||
|
throw Error(ERR_INVALID_ACESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T &unwrap_or(const T &alt) const
|
inline const T &unwrap_or(const T &alt) const
|
||||||
@ -138,7 +178,7 @@ namespace ro
|
|||||||
return fn();
|
return fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T &get_or_insert(const T &value)
|
inline T &get_or_insert(const T &value)
|
||||||
{
|
{
|
||||||
if (!m_notnull)
|
if (!m_notnull)
|
||||||
{
|
{
|
||||||
@ -146,7 +186,8 @@ namespace ro
|
|||||||
}
|
}
|
||||||
return m_some;
|
return m_some;
|
||||||
}
|
}
|
||||||
inline const T &insert(const T &value)
|
|
||||||
|
inline T &insert(const T &value)
|
||||||
{
|
{
|
||||||
m_some = value;
|
m_some = value;
|
||||||
m_notnull = true;
|
m_notnull = true;
|
||||||
@ -184,7 +225,7 @@ namespace ro
|
|||||||
|
|
||||||
inline bool into(T &output) const
|
inline bool into(T &output) const
|
||||||
{
|
{
|
||||||
if(is_some())
|
if (is_some())
|
||||||
{
|
{
|
||||||
output = m_some;
|
output = m_some;
|
||||||
return true;
|
return true;
|
||||||
@ -250,6 +291,62 @@ namespace ro
|
|||||||
return Option<std::tuple<T, U>>();
|
return Option<std::tuple<T, U>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename U, typename R>
|
||||||
|
inline Option<R> zip_with(const Option<U> &other, const std::function<R(const T &, const U &)> &fn)
|
||||||
|
{
|
||||||
|
if (m_notnull && other.is_some())
|
||||||
|
{
|
||||||
|
return fn(m_some, other.unwrap());
|
||||||
|
}
|
||||||
|
return Option<R>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Y, typename Z>
|
||||||
|
inline typename std::enable_if<std::is_base_of<std::tuple<Y, Z>, T>::value, std::tuple<Option<Y>, Option<Z>>>::type unzip()
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
return std::tuple<Option<Y>, Option<Z>>(Some(std::get<Y>(m_some)), Some(std::get<Z>(m_some)));
|
||||||
|
}
|
||||||
|
return std::tuple<Option<Y>, Option<Z>>(None(Y), None(Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X = T>
|
||||||
|
inline typename std::enable_if<std::is_base_of<Option<typename X::type_t>, X>::value, X>::type flatten()
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
return m_some;
|
||||||
|
}
|
||||||
|
return None(typename X::type_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X = T>
|
||||||
|
inline typename std::enable_if<std::is_base_of<Result<typename X::type_ok_t, typename X::type_err_t>, X>::value, Result<Option<typename X::type_ok_t>, typename X::type_err_t>>::type transpose()
|
||||||
|
{
|
||||||
|
if (is_none())
|
||||||
|
{
|
||||||
|
return Option<typename X::type_ok_t>();
|
||||||
|
}
|
||||||
|
if (m_some.is_ok())
|
||||||
|
{
|
||||||
|
return m_some.ok();
|
||||||
|
}
|
||||||
|
return m_some.unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Option<T> replace(const T &value)
|
||||||
|
{
|
||||||
|
|
||||||
|
Option<T> ret;
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
ret = m_some;
|
||||||
|
}
|
||||||
|
insert(value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_some;
|
T m_some;
|
||||||
bool m_notnull;
|
bool m_notnull;
|
||||||
@ -260,6 +357,8 @@ namespace ro
|
|||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using type_ok_t = T;
|
||||||
|
using type_err_t = E;
|
||||||
Result(T obj) : m_result(obj){};
|
Result(T obj) : m_result(obj){};
|
||||||
Result(E err) { m_error.insert(err); };
|
Result(E err) { m_error.insert(err); };
|
||||||
Result(){};
|
Result(){};
|
||||||
@ -329,6 +428,26 @@ namespace ro
|
|||||||
inline bool is_ok() const { return m_error.is_none(); };
|
inline bool is_ok() const { return m_error.is_none(); };
|
||||||
inline bool is_err() const { return m_error.is_some(); };
|
inline bool is_err() const { return m_error.is_some(); };
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline U match(const std::function<U(T &)> &expected, const std::function<U(E &)> &unexpected)
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return expected(m_result);
|
||||||
|
}
|
||||||
|
return unexpected(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline U match(const std::function<U(const T &)> &expected, const std::function<U(const E &)> &unexpected) const
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return expected(m_result);
|
||||||
|
}
|
||||||
|
return unexpected(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
inline Result<T, F> or_else(const std::function<Result<T, F>(const E &)> &fn)
|
inline Result<T, F> or_else(const std::function<Result<T, F>(const E &)> &fn)
|
||||||
{
|
{
|
||||||
@ -338,7 +457,6 @@ namespace ro
|
|||||||
}
|
}
|
||||||
return fn(m_error.unwrap());
|
return fn(m_error.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T &unwrap() const
|
inline const T &unwrap() const
|
||||||
{
|
{
|
||||||
if (is_ok())
|
if (is_ok())
|
||||||
@ -348,6 +466,15 @@ namespace ro
|
|||||||
throw m_error.unwrap();
|
throw m_error.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline T &unwrap()
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
throw m_error.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
inline const E &unwrap_err() const
|
inline const E &unwrap_err() const
|
||||||
{
|
{
|
||||||
if (is_err())
|
if (is_err())
|
||||||
@ -357,7 +484,7 @@ namespace ro
|
|||||||
throw m_result;
|
throw m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T &expect(const E& e) const
|
inline const T &expect(const E &e) const
|
||||||
{
|
{
|
||||||
if (is_ok())
|
if (is_ok())
|
||||||
{
|
{
|
||||||
@ -417,7 +544,7 @@ namespace ro
|
|||||||
|
|
||||||
inline bool into(T &output) const
|
inline bool into(T &output) const
|
||||||
{
|
{
|
||||||
if(is_ok())
|
if (is_ok())
|
||||||
{
|
{
|
||||||
output = m_result;
|
output = m_result;
|
||||||
return true;
|
return true;
|
||||||
@ -434,6 +561,32 @@ namespace ro
|
|||||||
return fn(m_error.unwrap());
|
return fn(m_error.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename X = T>
|
||||||
|
inline typename std::enable_if<std::is_base_of<Result<typename X::type_ok_t, typename X::type_err_t>, X>::value, X>::type flatten()
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
return m_error.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X = T>
|
||||||
|
inline typename std::enable_if<std::is_base_of<Option<typename X::type_t>, X>::value, Option<Result<typename X::type_t, E>>>::type transpose()
|
||||||
|
{
|
||||||
|
if (is_err())
|
||||||
|
{
|
||||||
|
return Result<typename X::type_t, E>(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_result.is_none())
|
||||||
|
{
|
||||||
|
return None(Result<typename X::type_t, E>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<typename X::type_t, E>(m_result.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
inline const Option<E> &err() const { return m_error; }
|
inline const Option<E> &err() const { return m_error; }
|
||||||
inline Option<T> ok() const { return is_ok() ? Option<T>(m_result) : Option<T>(); }
|
inline Option<T> ok() const { return is_ok() ? Option<T>(m_result) : Option<T>(); }
|
||||||
|
|
||||||
|
364
test/test.cpp
364
test/test.cpp
@ -4,35 +4,39 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ro;
|
using namespace ro;
|
||||||
|
|
||||||
struct Stat{
|
struct Stat
|
||||||
|
{
|
||||||
int passed;
|
int passed;
|
||||||
int total;
|
int total;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Stat g_stat = {0,0};
|
static Stat g_stat = {0, 0};
|
||||||
|
|
||||||
#define assert(v,fmt,...) if(!(v)) { \
|
#define assert(v, fmt, ...) \
|
||||||
|
if (!(v)) \
|
||||||
|
{ \
|
||||||
throw Error(ro::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \
|
throw Error(ro::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestError: public Error {
|
class TestError : public Error
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
TestError(const char *s) : Error(s){};
|
TestError(const char *s) : Error(s){};
|
||||||
};
|
};
|
||||||
|
|
||||||
void test(const char* desc, const std::function<void()>& lambda)
|
void test(const char *desc, const std::function<void()> &lambda)
|
||||||
{
|
{
|
||||||
std::cout << "Run test: " << desc << "..........";
|
std::cout << "Run test: " << desc << "..........";
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
lambda();
|
lambda();
|
||||||
std::cout << "OK" << std::endl;
|
std::cout << "OK" << std::endl;
|
||||||
g_stat.passed++;
|
g_stat.passed++;
|
||||||
}
|
}
|
||||||
catch(ro::Error e)
|
catch (ro::Error e)
|
||||||
{
|
{
|
||||||
std::cout << "FAILED" << std::endl;
|
std::cout << "FAILED" << std::endl;
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
@ -40,47 +44,63 @@ void test(const char* desc, const std::function<void()>& lambda)
|
|||||||
g_stat.total++;
|
g_stat.total++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int, Error> test_macro(const Result<int, Error> & target)
|
Result<int, Error> test_macro(const Result<int, Error> &target)
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
try_unwrap(a,target);
|
try_unwrap(a, target);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Point
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Point(int a, int b) : x(a), y(b){};
|
||||||
|
Point(){};
|
||||||
|
inline friend bool operator==(const Point &l, const Point &r)
|
||||||
|
{
|
||||||
|
return l.x == r.x && l.y == r.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char const *argv[])
|
int main(int argc, char const *argv[])
|
||||||
{
|
{
|
||||||
test("Test Option", [](){
|
test("Test Option", []()
|
||||||
|
{
|
||||||
Option<string> opt;
|
Option<string> opt;
|
||||||
assert(opt.is_none(), "Option is not empty");
|
assert(opt.is_none(), "Option is not empty");
|
||||||
assert(! opt.is_some(), "Option has some value");
|
assert(! opt.is_some(), "Option has some value");
|
||||||
string text = "This is some data";
|
string text = "This is some data";
|
||||||
opt = text;
|
opt = text;
|
||||||
assert(opt.is_some(), "Option shall has some value");
|
assert(opt.is_some(), "Option shall has some value");
|
||||||
assert(opt.unwrap() == text,"Value mistmatch");
|
assert(opt.unwrap() == text,"Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option -> Result convert", [](){
|
test("Option -> Result convert", []()
|
||||||
|
{
|
||||||
Option<string> opt;
|
Option<string> opt;
|
||||||
Result<string, Error> ret = opt.ok_or(ERR("Option is null"));
|
Result<string, Error> ret = opt.ok_or(ERR("Option is null"));
|
||||||
assert(ret.is_err(), "Object should containe error object");
|
assert(ret.is_err(), "Object should containe error object");
|
||||||
string err = ret.err().unwrap().what();
|
string err = ret.err().unwrap().what();
|
||||||
assert( err.find("Option is null") != string::npos, "Error message mistmatch");
|
assert( err.find("Option is null") != string::npos, "Error message mismatch");
|
||||||
|
|
||||||
opt = "abc";
|
opt = string("abc");
|
||||||
ret = opt.ok_or(ERR("Option is null"));
|
ret = opt.ok_or(ERR("Option is null"));
|
||||||
assert(ret.is_ok(), "Object should contain data");
|
assert(ret.is_ok(), "Object should contain data");
|
||||||
assert(ret.unwrap() == "abc", "Data mistmatch");
|
assert(ret.unwrap() == "abc", "Data mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("OPtion get_or_insert", [](){
|
test("OPtion get_or_insert", []()
|
||||||
|
{
|
||||||
auto x = None(int);
|
auto x = None(int);
|
||||||
int y = x.get_or_insert(5);
|
int & y = x.get_or_insert(5);
|
||||||
assert(y == 5, "Unexpected value");
|
assert(y == 5, "Unexpected value");
|
||||||
|
|
||||||
assert(x == 5, "Unexpected value");
|
assert(x == 5, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option map", [](){
|
test("Option map", []()
|
||||||
|
{
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return "Hello";
|
return "Hello";
|
||||||
};
|
};
|
||||||
@ -91,11 +111,10 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
opt = 2;
|
opt = 2;
|
||||||
opt1 = opt.map<string>(fn);
|
opt1 = opt.map<string>(fn);
|
||||||
assert(opt1.unwrap() == "Hello", "Value mismatch");
|
assert(opt1.unwrap() == "Hello", "Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
|
test("Option map_or", []()
|
||||||
test("Option map_or", [](){
|
{
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return ++x;
|
return ++x;
|
||||||
};
|
};
|
||||||
@ -106,20 +125,20 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
opt = 2;
|
opt = 2;
|
||||||
v = opt.map_or<int>(0, fn);
|
v = opt.map_or<int>(0, fn);
|
||||||
assert(v == 3, "Value mismatch %d",v);
|
assert(v == 3, "Value mismatch %d",v); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option filter", [](){
|
test("Option filter", []()
|
||||||
|
{
|
||||||
auto fn = [](int n) {
|
auto fn = [](int n) {
|
||||||
return n % 2 == 0;
|
return n % 2 == 0;
|
||||||
};
|
};
|
||||||
//Option<int> opt = None(int).filter(fn);
|
//Option<int> opt = None(int).filter(fn);
|
||||||
assert(None(int).filter(fn).is_none(), "Filter value shall be None");
|
assert(None(int).filter(fn).is_none(), "Filter value shall be None");
|
||||||
assert(Some(3).filter(fn).is_none(), "Filter value shall be None");
|
assert(Some(3).filter(fn).is_none(), "Filter value shall be None");
|
||||||
assert(Some(4).filter(fn).is_some(), "Filter value shall not be None");
|
assert(Some(4).filter(fn).is_some(), "Filter value shall not be None"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option OR", [](){
|
test("Option OR", []()
|
||||||
|
{
|
||||||
auto x = Some(2);
|
auto x = Some(2);
|
||||||
auto y = None(int);
|
auto y = None(int);
|
||||||
assert((x | y) == Some(2), "Unexpected value");
|
assert((x | y) == Some(2), "Unexpected value");
|
||||||
@ -134,10 +153,10 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
x = None(int);
|
x = None(int);
|
||||||
y = None(int);
|
y = None(int);
|
||||||
assert((x | y) == None(int), "Unexpected value");
|
assert((x | y) == None(int), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option AND", [](){
|
test("Option AND", []()
|
||||||
|
{
|
||||||
auto x = Some(2);
|
auto x = Some(2);
|
||||||
auto y = None(int);
|
auto y = None(int);
|
||||||
assert((x & y) == None(int), "Unexpected value");
|
assert((x & y) == None(int), "Unexpected value");
|
||||||
@ -152,10 +171,10 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
x = None(int);
|
x = None(int);
|
||||||
y = None(int);
|
y = None(int);
|
||||||
assert((x & y) == None(int), "Unexpected value");
|
assert((x & y) == None(int), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option XOR", [](){
|
test("Option XOR", []()
|
||||||
|
{
|
||||||
auto x = Some(2);
|
auto x = Some(2);
|
||||||
auto y = None(int);
|
auto y = None(int);
|
||||||
assert((x ^ y) == Some(2), "Unexpected value");
|
assert((x ^ y) == Some(2), "Unexpected value");
|
||||||
@ -170,27 +189,27 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
x = None(int);
|
x = None(int);
|
||||||
y = None(int);
|
y = None(int);
|
||||||
assert((x ^ y) == None(int), "Unexpected value");
|
assert((x ^ y) == None(int), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option or_else", [](){
|
test("Option or_else", []()
|
||||||
|
{
|
||||||
auto nobody = [](){return None(int);};
|
auto nobody = [](){return None(int);};
|
||||||
auto vikings = [](){return Some(100);};
|
auto vikings = [](){return Some(100);};
|
||||||
|
|
||||||
assert(None(int).or_else(vikings) == Some(100), "Unexpected value");
|
assert(None(int).or_else(vikings) == Some(100), "Unexpected value");
|
||||||
assert(None(int).or_else(nobody) == None(int), "Unexpected value");
|
assert(None(int).or_else(nobody) == None(int), "Unexpected value");
|
||||||
|
|
||||||
assert(Some(2).or_else(vikings) == Some(2), "Unexpected value");
|
assert(Some(2).or_else(vikings) == Some(2), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option and_then", [](){
|
test("Option and_then", []()
|
||||||
|
{
|
||||||
auto fn = [](int x){return string("Hello");};
|
auto fn = [](int x){return string("Hello");};
|
||||||
|
|
||||||
assert(Some(1).and_then<string>(fn) == Some(string("Hello")), "Unexpected value");
|
assert(Some(1).and_then<string>(fn) == Some(string("Hello")), "Unexpected value");
|
||||||
assert(None(int).and_then<string>(fn) == None(string), "Unexpected value");
|
assert(None(int).and_then<string>(fn) == None(string), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option take", [](){
|
test("Option take", []()
|
||||||
|
{
|
||||||
auto x = Some(2);
|
auto x = Some(2);
|
||||||
auto y = x.take();
|
auto y = x.take();
|
||||||
|
|
||||||
@ -200,10 +219,10 @@ int main(int argc, char const *argv[])
|
|||||||
auto z = None(int);
|
auto z = None(int);
|
||||||
y = z.take();
|
y = z.take();
|
||||||
assert(x == None(int), "Unexpected value");
|
assert(x == None(int), "Unexpected value");
|
||||||
assert(y == None(int), "Unexpected value");
|
assert(y == None(int), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option take_if", [](){
|
test("Option take_if", []()
|
||||||
|
{
|
||||||
auto fn = [](int n) {
|
auto fn = [](int n) {
|
||||||
return n % 2 == 0;
|
return n % 2 == 0;
|
||||||
};
|
};
|
||||||
@ -216,23 +235,27 @@ int main(int argc, char const *argv[])
|
|||||||
auto z = Some(3);
|
auto z = Some(3);
|
||||||
y = z.take_if(fn);
|
y = z.take_if(fn);
|
||||||
assert(z == Some(3), "Unexpected value");
|
assert(z == Some(3), "Unexpected value");
|
||||||
assert(y == None(int), "Unexpected value");
|
assert(y == None(int), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Option unwrap_or", [](){
|
test("Option unwrap_or", []()
|
||||||
|
{
|
||||||
assert(Some(2).unwrap_or(4) == 2, "Unexpected value");
|
assert(Some(2).unwrap_or(4) == 2, "Unexpected value");
|
||||||
assert(None(int).unwrap_or(4) == 4, "Unexpected value");
|
assert(None(int).unwrap_or(4) == 4, "Unexpected value");
|
||||||
|
|
||||||
assert(None(Error).unwrap_or(Error("Hello")) == Error("Hello"), "Unexpected value");
|
assert(None(Error).unwrap_or(Error("Hello")) == Error("Hello"), "Unexpected value");
|
||||||
|
|
||||||
});
|
});
|
||||||
test("Option unwrap_or_else", [](){
|
test("Option unwrap_or_else", []()
|
||||||
assert(Some(2).unwrap_or_else([](){ return 4; }) == 2, "Unexpected value");
|
{
|
||||||
assert(None(int).unwrap_or_else([](){ return 4; }) == 4, "Unexpected value");
|
assert(Some(2).unwrap_or_else([]()
|
||||||
|
{ return 4; }) == 2,
|
||||||
|
"Unexpected value");
|
||||||
|
assert(None(int).unwrap_or_else([]()
|
||||||
|
{ return 4; }) == 4,
|
||||||
|
"Unexpected value");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Option zip", [](){
|
test("Option zip", []()
|
||||||
|
{
|
||||||
auto x = Some(2);
|
auto x = Some(2);
|
||||||
auto y = Some(string("Hello"));
|
auto y = Some(string("Hello"));
|
||||||
auto z = None(int);
|
auto z = None(int);
|
||||||
@ -240,10 +263,33 @@ int main(int argc, char const *argv[])
|
|||||||
assert(x.zip(y).unwrap() == std::tuple(2, string("Hello")), "Unexpected value");
|
assert(x.zip(y).unwrap() == std::tuple(2, string("Hello")), "Unexpected value");
|
||||||
|
|
||||||
assert(x.zip(z).is_none(), "Unexpected value");
|
assert(x.zip(z).is_none(), "Unexpected value");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Option Into", [](){
|
test("Option unzip", []()
|
||||||
|
{
|
||||||
|
auto x = Some(std::tuple(2, string("Hello")));
|
||||||
|
auto y = x.unzip<int,string>();
|
||||||
|
|
||||||
|
assert(std::get<0>(y) == Some(2) , "Unexpected value");
|
||||||
|
assert(std::get<1>(y) == Some(string("Hello")), "Unexpected value");
|
||||||
|
x = None(std::tuple<int,string>);
|
||||||
|
y = x.unzip<int,string>();
|
||||||
|
assert(std::get<0>(y) == None(int) , "Unexpected value");
|
||||||
|
assert(std::get<1>(y) == None(string), "Unexpected value"); });
|
||||||
|
|
||||||
|
test("Option zip with", []()
|
||||||
|
{
|
||||||
|
|
||||||
|
auto fn = [](const int& a, const int & b) {return Point(a,b);};
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = Some(8);
|
||||||
|
auto z = x.zip_with<int,Point>(y, fn);
|
||||||
|
assert(z == Some(Point(2,8)), "Unexpected value");
|
||||||
|
z = x.zip_with<int,Point>(None(int), fn);
|
||||||
|
assert(z.is_none(), "Unexpected value"); });
|
||||||
|
|
||||||
|
test("Option Into", []()
|
||||||
|
{
|
||||||
Option<int> x = 2;
|
Option<int> x = 2;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
bool v = x.into(y);
|
bool v = x.into(y);
|
||||||
@ -254,18 +300,67 @@ int main(int argc, char const *argv[])
|
|||||||
v = x.into(y);
|
v = x.into(y);
|
||||||
y = 0;
|
y = 0;
|
||||||
assert(v == false, "Return value shall not be true");
|
assert(v == false, "Return value shall not be true");
|
||||||
assert(y == 0, "Unexpected value");
|
assert(y == 0, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Test Result", []{
|
test("Test Option match", []
|
||||||
|
{
|
||||||
|
Option<int> x = 10;
|
||||||
|
int y = x.match<int>(
|
||||||
|
[](int & x) { x += 10; return x;},
|
||||||
|
[]() {return 0; }
|
||||||
|
);
|
||||||
|
assert(x == y, "Data mismatch");
|
||||||
|
x = None(int);
|
||||||
|
y = x.match<int>(
|
||||||
|
[](int & x) { x += 10; return x;},
|
||||||
|
[]() {return 0;}
|
||||||
|
);
|
||||||
|
assert(x == None(int), "Data mismatch");
|
||||||
|
assert(y == 0, "Data mismatch"); });
|
||||||
|
|
||||||
|
test("Option flatten", []
|
||||||
|
{
|
||||||
|
Option<int> z = Some(1);
|
||||||
|
Option<Option<int>> x = Some(Some(6));
|
||||||
|
assert(x.flatten() == Some(6), "Unexpected value");
|
||||||
|
|
||||||
|
Option< Option< Option<int> > > y = Option(Option<Option<int>>(Option(10)));
|
||||||
|
|
||||||
|
assert(y.flatten() == Some(Some(10)), "Unexpected value");
|
||||||
|
assert(y.flatten().flatten() == Some(10), "Unexpected value"); });
|
||||||
|
|
||||||
|
test("Option transpose", []
|
||||||
|
{
|
||||||
|
Option<Result<int>> x = Some(Result(10));
|
||||||
|
Result<Option<int>> y = Some(10);
|
||||||
|
|
||||||
|
assert(x.transpose() == y, "Unexpected value");
|
||||||
|
|
||||||
|
x = Some(Result<int>(Error("error")));
|
||||||
|
assert(x.transpose() == Error("error"), "Unexpected value"); });
|
||||||
|
|
||||||
|
test("Replace", []
|
||||||
|
{
|
||||||
|
Option<int> x = 20;
|
||||||
|
auto y = x.replace(10);
|
||||||
|
assert(x == 10, "Unexpected value");
|
||||||
|
assert(y == 20, "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = x.replace(10);
|
||||||
|
assert(x == 10, "Unexpected value");
|
||||||
|
assert(y == None(int), "Unexpected value"); });
|
||||||
|
|
||||||
|
test("Test Result", []
|
||||||
|
{
|
||||||
Result<string, Error> ret = ERR("Error");
|
Result<string, Error> ret = ERR("Error");
|
||||||
assert(ret.is_err(), "Object should containe error object");
|
assert(ret.is_err(), "Object should containe error object");
|
||||||
ret = string("Hello");
|
ret = string("Hello");
|
||||||
assert(ret.is_ok(), "Object should contain data");
|
assert(ret.is_ok(), "Object should contain data");
|
||||||
assert(ret.unwrap() == "Hello", "Data mistmatch");
|
assert(ret.unwrap() == "Hello", "Data mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result->option convert",[](){
|
test("Result->option convert", []()
|
||||||
|
{
|
||||||
Result<string, Error> ret = ERR("Error");
|
Result<string, Error> ret = ERR("Error");
|
||||||
Option<string> opt_v = ret.ok();
|
Option<string> opt_v = ret.ok();
|
||||||
assert(opt_v.is_none(), "Value shall not be present");
|
assert(opt_v.is_none(), "Value shall not be present");
|
||||||
@ -276,10 +371,10 @@ int main(int argc, char const *argv[])
|
|||||||
opt_v = ret.ok();
|
opt_v = ret.ok();
|
||||||
assert(opt_v.is_some(), "Value shall be present");
|
assert(opt_v.is_some(), "Value shall be present");
|
||||||
opt_err = ret.err();
|
opt_err = ret.err();
|
||||||
assert(opt_err.is_none(), "Erreur shall be none");
|
assert(opt_err.is_none(), "Erreur shall be none"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result expect", [](){
|
test("Result expect", []()
|
||||||
|
{
|
||||||
try{
|
try{
|
||||||
Result<string, Error> ret = ERR("Error");
|
Result<string, Error> ret = ERR("Error");
|
||||||
auto s = ret.expect(ERR("Expect message"));
|
auto s = ret.expect(ERR("Expect message"));
|
||||||
@ -289,10 +384,10 @@ int main(int argc, char const *argv[])
|
|||||||
{
|
{
|
||||||
assert(true, "%s", e.what());
|
assert(true, "%s", e.what());
|
||||||
cout << e.what() << endl;
|
cout << e.what() << endl;
|
||||||
}
|
} });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result map", [](){
|
test("Result map", []()
|
||||||
|
{
|
||||||
auto err = ERR("Error");
|
auto err = ERR("Error");
|
||||||
auto fn = [](string data){
|
auto fn = [](string data){
|
||||||
return 1;
|
return 1;
|
||||||
@ -300,29 +395,28 @@ int main(int argc, char const *argv[])
|
|||||||
Result<string, Error> ret = err;
|
Result<string, Error> ret = err;
|
||||||
Result<int, Error> ret1 = ret.map<int>(fn);
|
Result<int, Error> ret1 = ret.map<int>(fn);
|
||||||
assert(ret1.is_err(), "mapped result shall be an error");
|
assert(ret1.is_err(), "mapped result shall be an error");
|
||||||
assert(ret1.err() == ret.err(), "Error object mistmatch");
|
assert(ret1.err() == ret.err(), "Error object mismatch");
|
||||||
|
|
||||||
ret = string("Hello");
|
ret = string("Hello");
|
||||||
ret1 = ret.map<int>(fn);
|
ret1 = ret.map<int>(fn);
|
||||||
assert(ret1.is_ok(), "mapped result shall not be an error");
|
assert(ret1.is_ok(), "mapped result shall not be an error");
|
||||||
assert(ret1.unwrap() == 1, "Value mistmatch");
|
assert(ret1.unwrap() == 1, "Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
|
test("Result map_err", []()
|
||||||
test("Result map_err", [](){
|
{
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return "Hello";
|
return "Hello";
|
||||||
};
|
};
|
||||||
Result<bool, int> ret = true;
|
Result<bool, int> ret = true;
|
||||||
Result<bool, string> ret1 = ret.map_err<string>(fn);
|
Result<bool, string> ret1 = ret.map_err<string>(fn);
|
||||||
assert(ret1.unwrap() == true, "Value mistmatch");
|
assert(ret1.unwrap() == true, "Value mismatch");
|
||||||
|
|
||||||
ret = 10;
|
ret = 10;
|
||||||
ret1 = ret.map_err<string>(fn);
|
ret1 = ret.map_err<string>(fn);
|
||||||
assert(ret1.err().unwrap() == "Hello", "Value mistmatch");
|
assert(ret1.err().unwrap() == "Hello", "Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result map_or", [](){
|
test("Result map_or", []()
|
||||||
|
{
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return ++x;
|
return ++x;
|
||||||
};
|
};
|
||||||
@ -333,10 +427,10 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
ret = 2;
|
ret = 2;
|
||||||
v = ret.map_or<int>(0, fn);
|
v = ret.map_or<int>(0, fn);
|
||||||
assert(v == 3, "Value mismatch %d",v);
|
assert(v == 3, "Value mismatch %d",v); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result AND", [](){
|
test("Result AND", []()
|
||||||
|
{
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
Result<int, Error> y = Error("Hello");
|
Result<int, Error> y = Error("Hello");
|
||||||
assert((x&y) == Error("Hello"), "Value mismatch");
|
assert((x&y) == Error("Hello"), "Value mismatch");
|
||||||
@ -351,10 +445,10 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
x = 1;
|
x = 1;
|
||||||
y = 10;
|
y = 10;
|
||||||
assert((x&y) == 10, "Value mismatch");
|
assert((x&y) == 10, "Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result OR", [](){
|
test("Result OR", []()
|
||||||
|
{
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
Result<int, Error> y = Error("Hello");
|
Result<int, Error> y = Error("Hello");
|
||||||
assert((x|y) == 2, "Value mismatch");
|
assert((x|y) == 2, "Value mismatch");
|
||||||
@ -369,20 +463,20 @@ int main(int argc, char const *argv[])
|
|||||||
|
|
||||||
x = 1;
|
x = 1;
|
||||||
y = 10;
|
y = 10;
|
||||||
assert((x|y) == 1, "Value mismatch");
|
assert((x|y) == 1, "Value mismatch"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result and_then", [](){
|
test("Result and_then", []()
|
||||||
|
{
|
||||||
auto fn = [](int x){return string("Hello");};
|
auto fn = [](int x){return string("Hello");};
|
||||||
|
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
auto test = Result<string,Error>(string("Hello"));
|
auto test = Result<string,Error>(string("Hello"));
|
||||||
assert(x.and_then<string>(fn) == string("Hello"), "Unexpected value");
|
assert(x.and_then<string>(fn) == string("Hello"), "Unexpected value");
|
||||||
x = Error("Error");
|
x = Error("Error");
|
||||||
assert(x.and_then<string>(fn) == Error("Error"), "Unexpected value");
|
assert(x.and_then<string>(fn) == Error("Error"), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result or_else", [](){
|
test("Result or_else", []()
|
||||||
|
{
|
||||||
auto sq = [](int x){return x*x;};
|
auto sq = [](int x){return x*x;};
|
||||||
auto err = [](int x){return x;};
|
auto err = [](int x){return x;};
|
||||||
Result<double, int> x(2.0);
|
Result<double, int> x(2.0);
|
||||||
@ -396,33 +490,32 @@ int main(int argc, char const *argv[])
|
|||||||
assert(ret == 9, "Unexpected value");
|
assert(ret == 9, "Unexpected value");
|
||||||
|
|
||||||
ret = x.or_else<int>(err).or_else<int>(err);
|
ret = x.or_else<int>(err).or_else<int>(err);
|
||||||
assert(ret == 3, "Unexpected value");
|
assert(ret == 3, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result unwrap_err", [](){
|
test("Result unwrap_err", []()
|
||||||
|
{
|
||||||
Result<int, Error> x = Error("Hello");
|
Result<int, Error> x = Error("Hello");
|
||||||
assert(x.unwrap_err() == Error("Hello"), "Unexpected value");
|
assert(x.unwrap_err() == Error("Hello"), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result unwrap_or", [](){
|
test("Result unwrap_or", []()
|
||||||
|
{
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
assert(x.unwrap_or(10) == 2, "Unexpected value");
|
assert(x.unwrap_or(10) == 2, "Unexpected value");
|
||||||
|
|
||||||
x = ERR("Error");
|
x = ERR("Error");
|
||||||
assert(x.unwrap_or(10) == 10, "Unexpected value");
|
assert(x.unwrap_or(10) == 10, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("Result unwrap_or_else", [](){
|
test("Result unwrap_or_else", []()
|
||||||
|
{
|
||||||
auto fn = [](const Error& x){return strlen(x.what());};
|
auto fn = [](const Error& x){return strlen(x.what());};
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
assert(x.unwrap_or_else(fn) == 2, "Unexpected value");
|
assert(x.unwrap_or_else(fn) == 2, "Unexpected value");
|
||||||
|
|
||||||
x = Error("HELLO");
|
x = Error("HELLO");
|
||||||
assert(x.unwrap_or_else(fn) == 5, "Unexpected value");
|
assert(x.unwrap_or_else(fn) == 5, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
|
test("Result Into", []()
|
||||||
test("Result Into", [](){
|
{
|
||||||
Result<int, Error> x = 2;
|
Result<int, Error> x = 2;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
bool v = x.into(y);
|
bool v = x.into(y);
|
||||||
@ -433,16 +526,59 @@ int main(int argc, char const *argv[])
|
|||||||
v = x.into(y);
|
v = x.into(y);
|
||||||
y = 0;
|
y = 0;
|
||||||
assert(v == false, "Return value shall not be true");
|
assert(v == false, "Return value shall not be true");
|
||||||
assert(y == 0, "Unexpected value");
|
assert(y == 0, "Unexpected value"); });
|
||||||
});
|
|
||||||
|
|
||||||
test("try_unwrap", [](){
|
test("try_unwrap", []()
|
||||||
|
{
|
||||||
Result<int, Error> x = test_macro(Result<int, Error>(10));
|
Result<int, Error> x = test_macro(Result<int, Error>(10));
|
||||||
assert(x == 10, "Unexpected value");
|
assert(x == 10, "Unexpected value");
|
||||||
|
|
||||||
x = test_macro(Result<int, Error>(Error("Hello")));
|
x = test_macro(Result<int, Error>(Error("Hello")));
|
||||||
assert(x.is_err(), "Unexpected value");
|
assert(x.is_err(), "Unexpected value"); });
|
||||||
});
|
|
||||||
|
test("Test Result match", []
|
||||||
|
{
|
||||||
|
Result<int> x = 10;
|
||||||
|
int y = x.match<int>(
|
||||||
|
[](int & x) { x += 10; return x;},
|
||||||
|
[](Error & e) {return 0; }
|
||||||
|
);
|
||||||
|
assert(x == y, "Data mismatch");
|
||||||
|
|
||||||
|
x = Error("error");
|
||||||
|
y = x.match<int>(
|
||||||
|
[](int & x) { x += 10; return x;},
|
||||||
|
[](Error & e) {return 0;}
|
||||||
|
);
|
||||||
|
assert(x == Error("error"), "Data mismatch");
|
||||||
|
assert(y == 0, "Data mismatch"); });
|
||||||
|
|
||||||
|
test("Result Test uwrap mut", []
|
||||||
|
{
|
||||||
|
Result<int> x = 10;
|
||||||
|
int& y = x.unwrap();
|
||||||
|
y = 50;
|
||||||
|
assert(x == 50, "Value mismatch"); });
|
||||||
|
|
||||||
|
test("Result flatten", []()
|
||||||
|
{
|
||||||
|
auto x = Result<Result<int>>(Result(20));
|
||||||
|
assert(x.flatten() == Result(20),"Value mismatch");
|
||||||
|
auto z = Result<int>(Error("error"));
|
||||||
|
x = Result<Result<int>>(Result(z));
|
||||||
|
assert(x.flatten() == Error("error"),"Value mismatch"); });
|
||||||
|
|
||||||
|
test("Result transpose", []()
|
||||||
|
{
|
||||||
|
Result<Option<int>>x = Some(5);
|
||||||
|
Option<Result<int>>y = Some(Result(5));
|
||||||
|
assert(x.transpose() == y, "Value mismatch");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
assert(x.transpose().is_none(), "Transposed value shall be none");
|
||||||
|
x = Error("Error");
|
||||||
|
y = Some(Result<int>(Error("Error")));
|
||||||
|
assert(x.transpose() == y, "Value mismatch"); });
|
||||||
|
|
||||||
cout << "REPORT: " << g_stat.passed << " tests passed / " << g_stat.total << " tests." << endl;
|
cout << "REPORT: " << g_stat.passed << " tests passed / " << g_stat.total << " tests." << endl;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user