Commit 07acd352 authored by Dominik Charousset's avatar Dominik Charousset

Extend unit tests for actor_system_config

parent 01102251
......@@ -22,41 +22,64 @@
#include "caf/test/dsl.hpp"
#include <deque>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace caf;
namespace {
// TODO: switch to std::operator""s when switching to C++14
std::string operator"" _s(const char* str, size_t size) {
return std::string{str, size};
}
timespan operator"" _ms(unsigned long long x) {
return std::chrono::duration_cast<timespan>(std::chrono::milliseconds(x));
}
uri operator"" _u(const char* str, size_t size) {
return unbox(make_uri(string_view{str, size}));
}
atom_value operator"" _a(const char* str, size_t size) {
return atom_from_string(string_view{str, size});
}
using string_list = std::vector<std::string>;
struct config : actor_system_config {
config() {
opt_group{custom_options_, "?foo"}
.add<std::string>("bar,b", "some string parameter");
config_option_adder options(string_view category) {
return opt_group{custom_options_, category};
}
void clear() {
content.clear();
remainder.clear();
}
};
struct fixture {
fixture() {
ini << "[foo]\nbar=\"hello\"";
}
config cfg;
error parse(string_list args) {
opts.clear();
remainder.clear();
config cfg;
auto result = cfg.parse(std::move(args), ini);
opts = content(cfg);
remainder = cfg.remainder;
return result;
config_option_adder options(string_view category) {
return cfg.options(category);
}
std::stringstream ini;
settings opts;
std::vector<std::string> remainder;
void parse(const char* file_content, string_list args = {}) {
cfg.clear();
cfg.remainder.clear();
std::istringstream ini{file_content};
if (auto err = cfg.parse(std::move(args), ini))
CAF_FAIL("parse() failed: " << cfg.render(err));
}
};
} // namespace
......@@ -64,37 +87,194 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(actor_system_config_tests, fixture)
CAF_TEST(parsing - without CLI arguments) {
CAF_CHECK_EQUAL(parse({}), none);
CAF_CHECK(remainder.empty());
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "hello");
auto text = "[foo]\nbar=\"hello\"";
options("?foo").add<std::string>("bar,b", "some string parameter");
parse(text);
CAF_CHECK(cfg.remainder.empty());
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "hello");
}
CAF_TEST(parsing - without CLI remainder) {
CAF_TEST(parsing - without CLI cfg.remainder) {
auto text = "[foo]\nbar=\"hello\"";
options("?foo").add<std::string>("bar,b", "some string parameter");
CAF_MESSAGE("CLI long name");
CAF_CHECK_EQUAL(parse({"--foo.bar=test"}), none);
CAF_CHECK(remainder.empty());
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "test");
parse(text, {"--foo.bar=test"});
CAF_CHECK(cfg.remainder.empty());
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "test");
CAF_MESSAGE("CLI abbreviated long name");
CAF_CHECK_EQUAL(parse({"--bar=test"}), none);
CAF_CHECK(remainder.empty());
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "test");
parse(text, {"--bar=test"});
CAF_CHECK(cfg.remainder.empty());
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "test");
CAF_MESSAGE("CLI short name");
CAF_CHECK_EQUAL(parse({"-b", "test"}), none);
CAF_CHECK(remainder.empty());
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "test");
parse(text, {"-b", "test"});
CAF_CHECK(cfg.remainder.empty());
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "test");
CAF_MESSAGE("CLI short name without whitespace");
CAF_CHECK_EQUAL(parse({"-btest"}), none);
CAF_CHECK(remainder.empty());
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "test");
parse(text, {"-btest"});
CAF_CHECK(cfg.remainder.empty());
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "test");
}
CAF_TEST(parsing - with CLI cfg.remainder) {
auto text = "[foo]\nbar=\"hello\"";
options("?foo").add<std::string>("bar,b", "some string parameter");
CAF_MESSAGE("valid cfg.remainder");
parse(text, {"-b", "test", "hello", "world"});
CAF_CHECK_EQUAL(get_or(cfg, "foo.bar", ""), "test");
CAF_CHECK_EQUAL(cfg.remainder, string_list({"hello", "world"}));
CAF_MESSAGE("invalid cfg.remainder");
}
// Checks whether both a synced variable and the corresponding entry in
// content(cfg) are equal to `value`.
#define CHECK_SYNCED(var, value) \
do { \
CAF_CHECK_EQUAL(var, value); \
CAF_CHECK_EQUAL(get_if<decltype(var)>(&cfg, #var), value); \
} while (false)
// Checks whether an entry in content(cfg) is equal to `value`.
#define CHECK_TEXT_ONLY(type, var, value) \
CAF_CHECK_EQUAL(get_if<type>(&cfg, #var), value)
#define ADD(var) add(var, #var, "...")
#define VAR(type) \
auto some_##type = type{}; \
options("global").add(some_##type, "some_" #type, "...")
#define NAMED_VAR(type, name) \
auto name = type{}; \
options("global").add(name, #name, "...")
CAF_TEST(integers and integer containers options) {
// Use a wild mess of "list-like" and "map-like" containers from the STL.
using int_list = std::vector<int>;
using int_list_list = std::list<std::deque<int>>;
using int_map = std::unordered_map<std::string, int>;
using int_list_map = std::map<std::string, std::unordered_set<int>>;
using int_map_list = std::set<std::map<std::string, int>>;
auto text = R"__(
some_int = 42
yet_another_int = 123
some_int_list = [1, 2, 3]
some_int_list_list = [[1, 2, 3], [4, 5, 6]]
some_int_map = {a = 1, b = 2, c = 3}
some_int_list_map = {a = [1, 2, 3], b = [4, 5, 6]}
some_int_map_list = [{a = 1, b = 2, c = 3}, {d = 4, e = 5, f = 6}]
)__";
NAMED_VAR(int, some_other_int);
VAR(int);
VAR(int_list);
VAR(int_list_list);
VAR(int_map);
VAR(int_list_map);
VAR(int_map_list);
parse(text, {"--some_other_int=23"});
CHECK_SYNCED(some_int, 42);
CHECK_SYNCED(some_other_int, 23);
CHECK_TEXT_ONLY(int, yet_another_int, 123);
CHECK_SYNCED(some_int_list, int_list({1, 2, 3}));
CHECK_SYNCED(some_int_list_list, int_list_list({{1, 2, 3}, {4, 5, 6}}));
CHECK_SYNCED(some_int_map, int_map({{{"a", 1}, {"b", 2}, {"c", 3}}}));
CHECK_SYNCED(some_int_list_map,
int_list_map({{{"a", {1, 2, 3}}, {"b", {4, 5, 6}}}}));
CHECK_SYNCED(some_int_map_list,
int_map_list({{{"a", 1}, {"b", 2}, {"c", 3}},
{{"d", 4}, {"e", 5}, {"f", 6}}}));
}
CAF_TEST(parsing - with CLI remainder) {
CAF_MESSAGE("valid remainder");
CAF_CHECK_EQUAL(parse({"-b", "test", "hello", "world"}), none);
CAF_CHECK_EQUAL(get_or(opts, "foo.bar", ""), "test");
CAF_CHECK_EQUAL(remainder, string_list({"hello", "world"}));
CAF_MESSAGE("invalid remainder");
CAF_CHECK_NOT_EQUAL(parse({"-b", "test", "-abc"}), none);
CAF_TEST(basic and basic containers options) {
using std::map;
using std::string;
using std::vector;
using int_list = vector<int>;
using bool_list = vector<bool>;
using double_list = vector<double>;
using atom_value_list = vector<atom_value>;
using timespan_list = vector<timespan>;
using uri_list = vector<uri>;
using string_list = vector<string>;
using int_map = map<string, int>;
using bool_map = map<string, bool>;
using double_map = map<string, double>;
using atom_value_map = map<string, atom_value>;
using timespan_map = map<string, timespan>;
using uri_map = map<string, uri>;
using string_map = map<string, string>;
auto text = R"__(
some_int = 42
some_bool = true
some_double = 1e23
some_atom_value = 'atom'
some_timespan = 123ms
some_uri = <foo:bar>
some_string = "string"
some_int_list = [1, 2, 3]
some_bool_list = [false, true]
some_double_list = [1., 2., 3.]
some_atom_value_list = ['a', 'b', 'c']
some_timespan_list = [123ms, 234ms, 345ms]
some_uri_list = [<foo:a>, <foo:b>, <foo:c>]
some_string_list = ["a", "b", "c"]
some_int_map = {a = 1, b = 2, c = 3}
some_bool_map = {a = true, b = false}
some_double_map = {a = 1., b = 2., c = 3.}
some_atom_value_map = {a = '1', b = '2', c = '3'}
some_timespan_map = {a = 123ms, b = 234ms, c = 345ms}
some_uri_map = {a = <foo:a>, b = <foo:b>, c = <foo:c>}
some_string_map = {a = "1", b = "2", c = "3"}
)__";
VAR(int);
VAR(bool);
VAR(double);
VAR(atom_value);
VAR(timespan);
VAR(uri);
VAR(string);
VAR(int_list);
VAR(bool_list);
VAR(double_list);
VAR(atom_value_list);
VAR(timespan_list);
VAR(uri_list);
VAR(string_list);
VAR(int_map);
VAR(bool_map);
VAR(double_map);
VAR(atom_value_map);
VAR(timespan_map);
VAR(uri_map);
VAR(string_map);
parse(text);
CAF_MESSAGE("check primitive types");
CHECK_SYNCED(some_int, 42);
CHECK_SYNCED(some_bool, true);
CHECK_SYNCED(some_double, 1e23);
CHECK_SYNCED(some_atom_value, "atom"_a);
CHECK_SYNCED(some_timespan, 123_ms);
CHECK_SYNCED(some_uri, "foo:bar"_u);
CHECK_SYNCED(some_string, "string"_s);
CAF_MESSAGE("check list types");
CHECK_SYNCED(some_int_list, int_list({1, 2, 3}));
CHECK_SYNCED(some_bool_list, bool_list({false, true}));
CHECK_SYNCED(some_double_list, double_list({1., 2., 3.}));
CHECK_SYNCED(some_atom_value_list, atom_value_list({"a"_a, "b"_a, "c"_a}));
CHECK_SYNCED(some_timespan_list, timespan_list({123_ms, 234_ms, 345_ms}));
CHECK_SYNCED(some_uri_list, uri_list({"foo:a"_u, "foo:b"_u, "foo:c"_u}));
CHECK_SYNCED(some_string_list, string_list({"a", "b", "c"}));
CAF_MESSAGE("check dictionary types");
CHECK_SYNCED(some_int_map, int_map({{"a", 1}, {"b", 2}, {"c", 3}}));
CHECK_SYNCED(some_bool_map, bool_map({{"a", true}, {"b", false}}));
CHECK_SYNCED(some_double_map, double_map({{"a", 1.}, {"b", 2.}, {"c", 3.}}));
CHECK_SYNCED(some_atom_value_map,
atom_value_map({{"a", "1"_a}, {"b", "2"_a}, {"c", "3"_a}}));
CHECK_SYNCED(some_timespan_map,
timespan_map({{"a", 123_ms}, {"b", 234_ms}, {"c", 345_ms}}));
CHECK_SYNCED(some_uri_map,
uri_map({{"a", "foo:a"_u}, {"b", "foo:b"_u}, {"c", "foo:c"_u}}));
CHECK_SYNCED(some_string_map,
string_map({{"a", "1"}, {"b", "2"}, {"c", "3"}}));
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment