Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86255574
misc.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Oct 5, 07:55
Size
16 KB
Mime Type
text/x-c++
Expires
Mon, Oct 7, 07:55 (2 d)
Engine
blob
Format
Raw Data
Handle
21385449
Attached To
rSPECMICP SpecMiCP / ReactMiCP
misc.cpp
View Options
#include "catch.hpp"
#include "specmicp_common/log.hpp"
#include "specmicp_common/timer.hpp"
#include "specmicp_common/physics/maths.hpp"
#include "specmicp_common/moving_average.hpp"
#include "specmicp_common/perfs_handler.hpp"
#include "specmicp_common/options_handler.hpp"
#include "specmicp_common/scope_guard.hpp"
#include "specmicp_common/pimpl_ptr.hpp"
#include "specmicp_common/cached_vector.hpp"
#include "specmicp_common/string_algorithms.hpp"
#include "specmicp_common/filesystem.hpp"
#include <sstream>
using namespace specmicp;
// TOC
// =======================
//
// 1 - Logger
// 2 - Timer
// 3 - Average
// 4 - Moving Average
// 5 - Performance handler
// 6 - Options handler
// 7 - Scope guard
// 8 - Pimpl pointer
// 9 - Cached Vector
// 10 - Named Cached Vector
// 11 - String algorithms
// 12 - Filesystem
// Logger
// =======================
TEST_CASE("Logger", "[io],[log]") {
SECTION("Non init logging") {
init_logger(nullptr, logger::LogLevel::Warning);
// compilation test, and runtime test of not failling nullptr
SPAM << "Spam";
DEBUG << "Debug";
INFO << "Info";
WARNING << "Warning";
ERROR << "Error";
CRITICAL << "Critical";
}
SECTION("Level test") {
std::stringstream stream_log;
init_logger(&stream_log, logger::LogLevel::Warning);
SPAM << "Spam";
REQUIRE(stream_log.str().size() == 0);
DEBUG << "Debug";
REQUIRE(stream_log.str().size() == 0);
INFO << "Info";
REQUIRE(stream_log.str().size() == 0);
WARNING << "Warning";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
ERROR << "Error";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
CRITICAL << "Critical";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
init_logger(&stream_log, logger::LogLevel::Debug);
SPAM << "Spam";
REQUIRE(stream_log.str().size() == 0);
DEBUG << "Debug";
#ifdef NDEBUG
REQUIRE(stream_log.str().size() == 0);
#else
REQUIRE(stream_log.str().size() != 0);
#endif
stream_log.str("");
INFO << "Info";
#ifdef NDEBUG
REQUIRE(stream_log.str().size() == 0);
#else
REQUIRE(stream_log.str().size() != 0);
#endif
stream_log.str("");
WARNING << "Warning";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
ERROR << "Error";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
CRITICAL << "Critical";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
}
}
// Timer
// =======================
TEST_CASE("Timer", "[time],[CPU]") {
SECTION("Timer test") {
Timer timer;
timer.stop();
CHECK(timer.elapsed_time() >= 0.0);
timer.start();
timer.stop();
CHECK(timer.elapsed_time() >= 0.0);
CHECK(timer.get_stop() >= timer.get_start());
CHECK(timer.get_ctime_start() != nullptr);
CHECK(timer.get_ctime_stop() != nullptr);
}
}
// Average
// ====================
#define test_average(method, a, b, sol) \
CHECK(average<method>(a, b) == Approx(sol).epsilon(1e-10));
#define test_average_vector(method, vector, sol) \
CHECK(average<method>(vector) == Approx(sol).epsilon(1e-10));
TEST_CASE("Average", "[average],[maths]") {
Vector test_vector(4);
test_vector << 1.0, 2.0, 3.0, 4.0;
SECTION("Arithmetic average") {
test_average(Average::arithmetic, 1.0, 1.0, 1.0);
test_average(Average::arithmetic, 2.0, 1.0, 1.5);
test_average(Average::arithmetic, -1.0, 1.0, 0.0);
test_average_vector(Average::arithmetic, test_vector, 10.0/4);
}
SECTION("Harmonic average") {
test_average(Average::harmonic, 1.0, 1.0, 1.0);
test_average(Average::harmonic, 2.0, 1.0, 2.0/(1+0.5));
test_average_vector(Average::harmonic, test_vector, 1.92);
}
SECTION("Geometric average") {
test_average(Average::geometric, 1.0, 1.0, 1.0);
test_average(Average::geometric, 1.0, 2.0, std::sqrt(2.0));
test_average_vector(Average::geometric, test_vector, std::pow(24.0, 1.0/4.0));
}
}
#undef test_average
#undef test_average_vector
// Moving Average
// =======================
TEST_CASE("Moving average", "[average],[timestep]") {
SECTION("Moving average test") {
utils::ExponentialMovingAverage moving_average(0.1, 1.0);
REQUIRE(moving_average.current_value() == 1.0);
CHECK(moving_average.add_point(1.0) == 1.0);
CHECK(moving_average.add_point(2.0) == 1.1);
REQUIRE(moving_average.add_point(3.0) == 0.9*1.1+0.3);
moving_average.reset(1.0);
REQUIRE(moving_average.current_value() == 1.0);
moving_average.set_alpha(0.2);
REQUIRE(moving_average.add_point(2.0) == Approx(0.8+0.4));
}
}
// Performance handler
// =======================
struct MockPerf
{
scalar_t residuals {-1};
index_t nb_iterations {-1};
};
class MockSolverPerf:
public PerformanceHandler<MockPerf>
{
public:
MockSolverPerf() {}
void do_stuff() {
get_perfs().residuals = 1e-6;
get_perfs().nb_iterations = 10;
}
void reset_solver() {
reset_perfs();
}
};
TEST_CASE("PerformanceHandler", "[performance],[base]") {
SECTION("Performance handler test") {
auto my_solver = MockSolverPerf();
const auto& perfs = my_solver.get_perfs();
CHECK(perfs.nb_iterations == -1);
CHECK(perfs.residuals == -1);
my_solver.do_stuff();
CHECK(perfs.nb_iterations == 10);
CHECK(perfs.residuals == 1e-6);
my_solver.reset_solver();
CHECK(perfs.nb_iterations == -1);
CHECK(perfs.residuals == -1);
}
}
// Options handler
// =======================
struct MockOptions
{
MockOptions()
{}
MockOptions(scalar_t res, index_t max_iter):
residuals(res),
max_iterations(max_iter)
{}
scalar_t residuals {1e-6};
index_t max_iterations {100};
};
class MockSolverOptions:
public OptionsHandler<MockOptions>
{
public:
MockSolverOptions() {}
MockSolverOptions(scalar_t res, index_t max_iter):
OptionsHandler(res, max_iter)
{}
};
TEST_CASE("Options handler", "[options],[base]") {
SECTION("Options handler test") {
auto my_solver_default = MockSolverOptions();
const auto& ro_options = my_solver_default.get_options();
CHECK(ro_options.max_iterations == 100);
CHECK(ro_options.residuals == 1e-6);
auto& rw_options = my_solver_default.get_options();
rw_options.max_iterations = 10;
rw_options.residuals = 1e-4;
CHECK(ro_options.max_iterations == 10);
CHECK(ro_options.residuals == 1e-4);
}
SECTION("Options handler - non default initialization") {
auto my_solver = MockSolverOptions(1e-4, 10);
const auto& ro_options = my_solver.get_options();
CHECK(ro_options.max_iterations == 10);
CHECK(ro_options.residuals == 1e-4);
}
}
// ScopeGuard
// ==========
static void will_fail(bool& hop) {
auto guard = utils::make_scope_guard([&hop]{hop=true;});
throw std::runtime_error("fail on purpose");
guard.release();
}
static void dont_fail(bool& hop) {
auto guard = utils::make_scope_guard([&hop]{hop=true;});
hop = false;
guard.release();
}
TEST_CASE("Scope guard", "[utils]") {
SECTION("Catch error") {
bool hop = false;
REQUIRE_THROWS_AS(will_fail(hop), std::runtime_error);
CHECK(hop == true);
dont_fail(hop);
CHECK(hop == false);
}
}
// pimpl_ptr
// =========
// simple Interface + Implementation to test pimpl_ptr
class MockImplementation
{
public:
MockImplementation(double a):
m_a(a)
{}
double add(double b) const {return m_a + b;}
// Compilation should failed if this one is activated
//double add(double b) {return m_a + b;}
void set(double new_a) { m_a = new_a;}
private:
double m_a;
};
class MockInterface
{
public:
MockInterface(double a):
m_impl(utils::make_pimpl<MockImplementation>(a))
{}
double add(double b) const {return m_impl->add(b);}
void set(double new_a) {return m_impl->set(new_a);}
private:
utils::pimpl_ptr<MockImplementation> m_impl;
};
TEST_CASE("pimpl_ptr", "[utils],[pointer],[const]") {
SECTION("Test mock") {
auto hop = MockImplementation(1.0);
CHECK(hop.add(2.0) == Approx(3.0));
hop.set(2.0);
CHECK(hop.add(2.0) == Approx(4.0));
}
//SECTION("compilation fail") {
// const MockInterface fail1(2.0);
// fail1.set(3.0);
//}
}
// Cached Vector
//
TEST_CASE("Cached vector", "[utils],[container],[cache]")
{
SECTION("Default") {
utils::CachedVector<std::string> cached;
cached.push_back("value0");
cached.push_back(0);
CHECK(cached.size() == 2);
CHECK(cached.size_cache() == 1);
CHECK(cached[0] == "value0");
CHECK(cached[1] == "value0");
for (auto& it: cached) {
CHECK(it == "value0");
}
cached.emplace_back("truc");
CHECK(cached[2] == "truc");
cached.emplace_back("other");
CHECK(cached[3] == "other");
cached.push_back(2);
CHECK(cached.at(4) == "other");
CHECK(cached.size() == 5);
CHECK(cached.size_cache() == 3);
auto& new_val = cached.fork(1);
new_val = "plop";
CHECK(cached[1] == "plop");
for (auto it=cached.begin_index(); it!=cached.cend_index();++it)
{
CHECK(*it < cached.size());
CHECK(*it >= 0);
}
//! it's possible, absolutely not a good idea
for (auto& value: cached) {
value = "reinit";
}
CHECK(cached[2] == "reinit");
}
SECTION("Default constructor") {
static_assert(std::is_default_constructible<std::string>::value,
"String is default constructible"
);
utils::CachedVector<std::string> cached(5);
CHECK(cached[4] == "");
}
}
// Named Cached Vector
TEST_CASE("NamedCachedVector", "[utils],[container],[cache]")
{
SECTION("Default") {
utils::NameCachedVector<std::string> cached(
5, "default_name", "default_value");
CHECK(cached.size_cache() == 1);
CHECK(cached.size() == 5);
CHECK(cached.get("default_name") == "default_value");
auto& forked = cached.fork(2, "new name");
forked = "new value";
CHECK(cached.size_cache() == 2);
CHECK(cached.size() == 5);
CHECK(cached[2] == "new value");
CHECK(cached.get("new name") == "new value");
CHECK(cached.has_value("new name"));
CHECK(not cached.has_value("not a name"));
cached.push_back_cache("another name", "another value");
CHECK(cached.get("another name") == "another value");
CHECK(cached.size_cache() == 3);
CHECK(cached.size() == 5);
for (auto& value: cached)
{
CHECK(value != "another value");
}
}
SECTION("Default constructor") {
static_assert(std::is_default_constructible<std::string>::value,
"String is default constructible"
);
utils::NameCachedVector<std::string> cached(5, "default");
CHECK(cached[4] == "");
}
}
// String Algorithms
// =================
TEST_CASE("String algorithms", "[utils],[string],[algorithms]")
{
SECTION("split") {
std::string test1 = "a";
CHECK(utils::split(test1, ',') == std::vector<std::string>({"a", }));
std::string test2 = "a,b,c";
CHECK(utils::split(test2, ',') == std::vector<std::string>({"a", "b", "c"}));
std::string test3 = "a,b,c,";
CHECK(utils::split(test3, ',') == std::vector<std::string>({"a", "b", "c"}));
}
SECTION("strip") {
CHECK(utils::strip("hop") == "hop");
CHECK(utils::strip(" hop") == "hop");
CHECK(utils::strip("hop ") == "hop");
CHECK(utils::strip(" hop ") == "hop");
CHECK(utils::strip(" hop hop ") == "hop hop");
CHECK(utils::strip(" ") == "");
}
SECTION("range_indices") {
CHECK(utils::range_indices("1") == std::vector<index_t>({1, }));
CHECK(utils::range_indices("-1:3") == std::vector<index_t>({-1, 0, 1, 2, 3}));
CHECK(utils::range_indices("1,5") == std::vector<index_t>({1, 5}));
CHECK(utils::range_indices<index_t>("1,3:5") == std::vector<index_t>({1, 3, 4, 5}));
CHECK(utils::range_indices("1,5,") == std::vector<index_t>({1, 5}));
CHECK(utils::range_indices("1, 3:5, 2") == std::vector<index_t>({1, 2, 3, 4, 5,}));
CHECK(utils::range_indices<uindex_t>("1,3:5") == std::vector<uindex_t>({1, 3, 4, 5}));
CHECK_THROWS_AS(utils::range_indices<uindex_t>("1,-3:5"), std::invalid_argument);
CHECK_THROWS_AS(utils::range_indices<uindex_t>("-2"), std::invalid_argument);
}
SECTION("parse expr") {
CHECK(utils::parse_expression<scalar_t>("2.0") == 2.0);
CHECK(utils::parse_expression<scalar_t>("-2.0") == -2.0);
CHECK(utils::parse_expression<scalar_t>("2.0 +2.0") == 4.0);
CHECK(utils::parse_expression<scalar_t>("2.0/ 2.0") == 1.0);
CHECK(utils::parse_expression<scalar_t>("3 + 2.0 / 2.0") == 4.0);
CHECK(utils::parse_expression<scalar_t>("1e-6") == 1e-6);
CHECK(utils::parse_expression<scalar_t>("2*1e-6") == 2e-6);
CHECK(utils::parse_expression<scalar_t>("1e-6-2") == 1e-6-2);
CHECK(utils::parse_expression<scalar_t>("1e-6/1e-3*1e-2") == 1e-5);
CHECK(utils::parse_expression<scalar_t>("3 + a / 2.0", {{"a", 2}}) == 4.0);
CHECK(utils::parse_expression<scalar_t>("a + b / c",
{{"a", 2,}, {"b", 3.0}, {"c", 6.0}}) == 2.5);
CHECK_THROWS(utils::parse_expression<scalar_t>("234.53as"));
CHECK_THROWS(utils::parse_expression<scalar_t>("3 + a / 2.0", {{"b", 2}}));
CHECK_THROWS(utils::parse_expression<scalar_t>("3 + a/ / 2.0", {{"a", 2}}));
CHECK_THROWS(utils::parse_expression<scalar_t>("3 + a // 2.0", {{"a", 2}}));
}
SECTION("string to bool") {
CHECK(utils::string_to_bool("True") == true);
CHECK(utils::string_to_bool(" true") == true);
CHECK(utils::string_to_bool("1") == true);
CHECK(utils::string_to_bool("yes ") == true);
CHECK(utils::string_to_bool("Yes") == true);
CHECK(utils::string_to_bool(" Y ") == true);
CHECK(utils::string_to_bool("False") == false);
CHECK(utils::string_to_bool("false ") == false);
CHECK(utils::string_to_bool(" 0 ") == false);
CHECK(utils::string_to_bool(" no ") == false);
CHECK(utils::string_to_bool(" No") == false);
CHECK(utils::string_to_bool("N ") == false);
CHECK_THROWS_AS(utils::string_to_bool("plop"), std::invalid_argument);
CHECK_THROWS_AS(utils::string_to_bool(" plop"), std::invalid_argument);
CHECK_THROWS_AS(utils::string_to_bool("Faolse"), std::invalid_argument);
}
}
// Filesystem
// ===========
TEST_CASE("filesystem", "[io],[dir],[filesystem]") {
SECTION("is directory") {
CHECK(utils::is_directory(CURRENT_DIRECTORY));
CHECK_FALSE(utils::is_directory("test_common"));
CHECK_FALSE(utils::is_directory("mouahahahah"));
}
SECTION("is directory") {
CHECK_FALSE(utils::is_file(CURRENT_DIRECTORY));
CHECK(utils::is_file("test_common"));
CHECK(utils::is_file(utils::complete_path(
CURRENT_DIRECTORY, "test_common")));
}
SECTION("Current directory") {
CHECK(utils::get_current_directory() == CURRENT_DIRECTORY);
}
SECTION("Complete path") {
CHECK(utils::complete_path("/usr/include/", "dirent.h") ==
"/usr/include/dirent.h");
CHECK(utils::complete_path("/usr/include", "dirent.h") ==
"/usr/include/dirent.h");
}
SECTION("Absolute path") {
std::string error = "";
CHECK(utils::relative_to_absolute("./test_common", error) ==
utils::complete_path(CURRENT_DIRECTORY, "test_common"));
CHECK(error == "");
CHECK(utils::relative_to_absolute("../../platypus.duck", error) == "");
CHECK(error != "");
}
SECTION("Find path") {
CHECK(utils::find_path("dirent.h", {"/usr/include"})
== "/usr/include/dirent.h");
CHECK(utils::find_path("not_found_becuase_.h", {"/usr/include"})
== "");
}
SECTION("has_env") {
CHECK(utils::has_env("USER"));
CHECK_FALSE(utils::has_env("platypus_platypus_platypys_35897037289589"));
}
SECTION("get_env") {
CHECK(utils::get_env("USER") != "");
CHECK(utils::get_env("platypus_platypus_platypys_35897037289589") == "");
}
}
Event Timeline
Log In to Comment