Commit 1d4dcede authored by Dominik Charousset's avatar Dominik Charousset

Remove .ini remnants completely

parent 13b5d670
...@@ -54,14 +54,6 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -54,14 +54,6 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- The `to_string` output for `error` now renders the error code enum by default. - The `to_string` output for `error` now renders the error code enum by default.
This renders the member functions `actor_system::render` and This renders the member functions `actor_system::render` and
`actor_system_config::render` obsolete. `actor_system_config::render` obsolete.
- The configuration format of CAF has come a long way since first starting to
allow user-defined configuration via `.ini` files. Rather than sticking with
the weird hybrid that evolved over the years, we are going to get rid of the
last pieces of INI syntax and go with the much cleaner, scoped syntax. CAF is
still picking up `caf-application.ini` with this release and uses the
deprecated INI parser when given any other file name that ends in `.ini`.
However, the next version of CAF is only going to recognize the new format.
The new default file name is `caf-application.conf`.
### Changed ### Changed
...@@ -148,6 +140,11 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -148,6 +140,11 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- All member functions of `scheduled_actor` for adding stream managers (such as - All member functions of `scheduled_actor` for adding stream managers (such as
`make_source`) were removed in favor their free-function equivalent, e.g., `make_source`) were removed in favor their free-function equivalent, e.g.,
`attach_stream_source` `attach_stream_source`
- The configuration format of CAF has come a long way since first starting to
allow user-defined configuration via `.ini` files. Rather than sticking with
the weird hybrid that evolved over the years, we finally get rid of the last
pieces of INI syntax and go with the much cleaner, scoped syntax. The new
default file name for configuration files is `caf-application.conf`.
### Fixed ### Fixed
......
...@@ -84,7 +84,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -84,7 +84,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/get_process_id.cpp src/detail/get_process_id.cpp
src/detail/get_root_uuid.cpp src/detail/get_root_uuid.cpp
src/detail/glob_match.cpp src/detail/glob_match.cpp
src/detail/ini_consumer.cpp
src/detail/invoke_result_visitor.cpp src/detail/invoke_result_visitor.cpp
src/detail/message_builder_element.cpp src/detail/message_builder_element.cpp
src/detail/message_data.cpp src/detail/message_data.cpp
...@@ -237,14 +236,12 @@ caf_add_test_suites(caf-core-test ...@@ -237,14 +236,12 @@ caf_add_test_suites(caf-core-test
detail.bounds_checker detail.bounds_checker
detail.config_consumer detail.config_consumer
detail.ieee_754 detail.ieee_754
detail.ini_consumer
detail.limited_vector detail.limited_vector
detail.meta_object detail.meta_object
detail.parse detail.parse
detail.parser.read_bool detail.parser.read_bool
detail.parser.read_config detail.parser.read_config
detail.parser.read_floating_point detail.parser.read_floating_point
detail.parser.read_ini
detail.parser.read_number detail.parser.read_number
detail.parser.read_number_or_timespan detail.parser.read_number_or_timespan
detail.parser.read_signed_integer detail.parser.read_signed_integer
......
...@@ -99,7 +99,7 @@ public: ...@@ -99,7 +99,7 @@ public:
/// values. /// values.
virtual settings dump_content() const; virtual settings dump_content() const;
/// Sets a config by using its INI name `config_name` to `config_value`. /// Sets a config by using its name `config_name` to `config_value`.
template <class T> template <class T>
actor_system_config& set(string_view name, T&& value) { actor_system_config& set(string_view name, T&& value) {
return set_impl(name, config_value{std::forward<T>(value)}); return set_impl(name, config_value{std::forward<T>(value)});
...@@ -113,16 +113,15 @@ public: ...@@ -113,16 +113,15 @@ public:
/// Parses `args` as tuple of strings containing CLI options and tries to open /// Parses `args` as tuple of strings containing CLI options and tries to open
/// `config_file_cstr` as config file. The parsers tries to open /// `config_file_cstr` as config file. The parsers tries to open
/// `caf-application.conf` or `caf-application.ini` (deprecated) if /// `caf-application.conf` if `config_file_cstr` is `nullptr`.
/// `config_file_cstr` is `nullptr`.
error parse(string_list args, const char* config_file_cstr = nullptr); error parse(string_list args, const char* config_file_cstr = nullptr);
/// Parses the CLI options `{argc, argv}` and `config` as configuration file. /// Parses the CLI options `{argc, argv}` and `config` as configuration file.
error parse(int argc, char** argv, std::istream& config); error parse(int argc, char** argv, std::istream& config);
/// Parses the CLI options `{argc, argv}` and tries to open `config_file_cstr` /// Parses the CLI options `{argc, argv}` and tries to open `config_file_cstr`
/// as config file. The parsers tries to open `caf-application.conf` or /// as config file. The parsers tries to open `caf-application.conf` if
/// `caf-application.ini` (deprecated) if `config_file_cstr` is `nullptr`. /// `config_file_cstr` is `nullptr`.
error parse(int argc, char** argv, const char* config_file_cstr = nullptr); error parse(int argc, char** argv, const char* config_file_cstr = nullptr);
/// Allows other nodes to spawn actors created by `fun` /// Allows other nodes to spawn actors created by `fun`
...@@ -247,7 +246,7 @@ public: ...@@ -247,7 +246,7 @@ public:
// -- parsing parameters ----------------------------------------------------- // -- parsing parameters -----------------------------------------------------
/// Configures the file path for the INI file, `caf-application.ini` per /// Configures the file path for the config file, `caf-application.conf` per
/// default. /// default.
std::string config_file_path; std::string config_file_path;
...@@ -324,10 +323,6 @@ protected: ...@@ -324,10 +323,6 @@ protected:
config_option_set custom_options_; config_option_set custom_options_;
private: private:
// TODO: deprecated. Remove with CAF 0.19.
static error parse_ini(std::istream& source, const config_option_set& opts,
settings& result);
actor_system_config& set_impl(string_view name, config_value value); actor_system_config& set_impl(string_view name, config_value value);
error extract_config_file_path(string_list& args); error extract_config_file_path(string_list& args);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <string>
#include "caf/config_option_set.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/dictionary.hpp"
#include "caf/settings.hpp"
namespace caf::detail {
class ini_consumer;
class ini_list_consumer;
class ini_map_consumer;
class CAF_CORE_EXPORT abstract_ini_consumer {
public:
// -- constructors, destructors, and assignment operators --------------------
explicit abstract_ini_consumer(abstract_ini_consumer* parent = nullptr);
abstract_ini_consumer(const abstract_ini_consumer&) = delete;
abstract_ini_consumer& operator=(const abstract_ini_consumer&) = delete;
virtual ~abstract_ini_consumer();
// -- properties -------------------------------------------------------------
virtual void value_impl(config_value&& x) = 0;
template <class T>
void value(T&& x) {
value_impl(config_value{std::forward<T>(x)});
}
abstract_ini_consumer* parent() {
return parent_;
}
ini_map_consumer begin_map();
ini_list_consumer begin_list();
protected:
// -- member variables -------------------------------------------------------
abstract_ini_consumer* parent_;
};
class CAF_CORE_EXPORT ini_map_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using map_type = config_value::dictionary;
using iterator = map_type::iterator;
// -- constructors, destructors, and assignment operators --------------------
ini_map_consumer(abstract_ini_consumer* ptr);
ini_map_consumer(ini_map_consumer&& other);
~ini_map_consumer() override;
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
map_type xs_;
iterator i_;
};
class CAF_CORE_EXPORT ini_list_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_list_consumer(abstract_ini_consumer* ptr);
ini_list_consumer(ini_list_consumer&& other);
// -- properties -------------------------------------------------------------
void end_list();
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
config_value::list xs_;
};
/// Consumes a single value from an INI parser.
class CAF_CORE_EXPORT ini_value_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
explicit ini_value_consumer(abstract_ini_consumer* parent = nullptr);
// -- properties -------------------------------------------------------------
void value_impl(config_value&& x) override;
// -- member variables -------------------------------------------------------
config_value result;
};
/// Consumes a config category.
class CAF_CORE_EXPORT ini_category_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_category_consumer(ini_consumer* parent, std::string category);
ini_category_consumer(ini_category_consumer&&);
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- properties -------------------------------------------------------------
ini_consumer* dparent();
// -- member variables -------------------------------------------------------
std::string category_;
config_value::dictionary xs_;
std::string current_key;
};
/// Consumes a series of dictionaries forming a application configuration.
class CAF_CORE_EXPORT ini_consumer : public abstract_ini_consumer {
public:
// -- friends ----------------------------------------------------------------
friend class ini_category_consumer;
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using config_map = dictionary<config_value::dictionary>;
// -- constructors, destructors, and assignment operators --------------------
ini_consumer(const config_option_set& options, settings& cfg);
// -- properties -------------------------------------------------------------
ini_category_consumer begin_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
const config_option_set& options_;
settings& cfg_;
std::string current_key_;
std::vector<error> warnings_;
};
} // namespace caf::detail
This diff is collapsed.
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "caf/detail/config_consumer.hpp" #include "caf/detail/config_consumer.hpp"
#include "caf/detail/gcd.hpp" #include "caf/detail/gcd.hpp"
#include "caf/detail/parser/read_config.hpp" #include "caf/detail/parser/read_config.hpp"
#include "caf/detail/parser/read_ini.hpp"
#include "caf/detail/parser/read_string.hpp" #include "caf/detail/parser/read_string.hpp"
#include "caf/message_builder.hpp" #include "caf/message_builder.hpp"
#include "caf/pec.hpp" #include "caf/pec.hpp"
...@@ -50,7 +49,7 @@ actor_system_config::~actor_system_config() { ...@@ -50,7 +49,7 @@ actor_system_config::~actor_system_config() {
} }
// in this config class, we have (1) hard-coded defaults that are overridden // in this config class, we have (1) hard-coded defaults that are overridden
// by (2) INI-file contents that are in turn overridden by (3) CLI arguments // by (2) config file contents that are in turn overridden by (3) CLI arguments
actor_system_config::actor_system_config() actor_system_config::actor_system_config()
: cli_helptext_printed(false), : cli_helptext_printed(false),
...@@ -61,14 +60,14 @@ actor_system_config::actor_system_config() ...@@ -61,14 +60,14 @@ actor_system_config::actor_system_config()
stream_desired_batch_complexity = defaults::stream::desired_batch_complexity; stream_desired_batch_complexity = defaults::stream::desired_batch_complexity;
stream_max_batch_delay = defaults::stream::max_batch_delay; stream_max_batch_delay = defaults::stream::max_batch_delay;
stream_credit_round_interval = defaults::stream::credit_round_interval; stream_credit_round_interval = defaults::stream::credit_round_interval;
// fill our options vector for creating INI and CLI parsers // fill our options vector for creating config file and CLI parsers
using std::string; using std::string;
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add<bool>("help,h?", "print help text to STDERR and exit") .add<bool>("help,h?", "print help text to STDERR and exit")
.add<bool>("long-help", "print long help text to STDERR and exit") .add<bool>("long-help", "print long help text to STDERR and exit")
.add<bool>("dump-config", "print configuration to STDERR and exit") .add<bool>("dump-config", "print configuration to STDERR and exit")
.add<string>(config_file_path, "config-file", .add<string>(config_file_path, "config-file",
"set config file (default: caf-application.ini)"); "set config file (default: caf-application.conf)");
opt_group{custom_options_, "stream"} opt_group{custom_options_, "stream"}
.add<timespan>(stream_desired_batch_complexity, "desired-batch-complexity", .add<timespan>(stream_desired_batch_complexity, "desired-batch-complexity",
"processing time per batch") "processing time per batch")
...@@ -211,31 +210,31 @@ settings actor_system_config::dump_content() const { ...@@ -211,31 +210,31 @@ settings actor_system_config::dump_content() const {
} }
error actor_system_config::parse(int argc, char** argv, error actor_system_config::parse(int argc, char** argv,
const char* ini_file_cstr) { const char* config_file_cstr) {
string_list args; string_list args;
if (argc > 1) if (argc > 1)
args.assign(argv + 1, argv + argc); args.assign(argv + 1, argv + argc);
return parse(std::move(args), ini_file_cstr); return parse(std::move(args), config_file_cstr);
} }
error actor_system_config::parse(int argc, char** argv, std::istream& ini) { error actor_system_config::parse(int argc, char** argv, std::istream& conf) {
string_list args; string_list args;
if (argc > 1) if (argc > 1)
args.assign(argv + 1, argv + argc); args.assign(argv + 1, argv + argc);
return parse(std::move(args), ini); return parse(std::move(args), conf);
} }
namespace { namespace {
struct config_iter { struct config_iter {
std::istream* ini; std::istream* conf;
char ch; char ch;
explicit config_iter(std::istream* istr) : ini(istr) { explicit config_iter(std::istream* istr) : conf(istr) {
ini->get(ch); conf->get(ch);
} }
config_iter() : ini(nullptr), ch('\0') { config_iter() : conf(nullptr), ch('\0') {
// nop // nop
} }
...@@ -248,7 +247,7 @@ struct config_iter { ...@@ -248,7 +247,7 @@ struct config_iter {
} }
inline config_iter& operator++() { inline config_iter& operator++() {
ini->get(ch); conf->get(ch);
return *this; return *this;
} }
}; };
...@@ -256,7 +255,7 @@ struct config_iter { ...@@ -256,7 +255,7 @@ struct config_iter {
struct config_sentinel {}; struct config_sentinel {};
bool operator!=(config_iter iter, config_sentinel) { bool operator!=(config_iter iter, config_sentinel) {
return !iter.ini->fail(); return !iter.conf->fail();
} }
struct indentation { struct indentation {
...@@ -348,18 +347,6 @@ error actor_system_config::parse(string_list args, ...@@ -348,18 +347,6 @@ error actor_system_config::parse(string_list args,
return err; return err;
if (config_file_path == "$DEFAULT") { if (config_file_path == "$DEFAULT") {
std::ifstream conf{"caf-application.conf"}; std::ifstream conf{"caf-application.conf"};
// TODO: The .ini parser is deprecated. Remove with CAF 0.19.
if (!conf.is_open()) {
conf.open("caf-application.ini");
if (conf.is_open()) {
// Consume the ini file here, because the parse() overload that takes
// an istream assumes the new config format.
if (auto err = parse_ini(conf, custom_options_, content))
return err;
std::ifstream dummy;
return parse(std::move(args), dummy);
}
}
return parse(std::move(args), conf); return parse(std::move(args), conf);
} }
std::ifstream conf{config_file_path}; std::ifstream conf{config_file_path};
...@@ -418,14 +405,6 @@ actor_system_config::parse_config_file(const char* filename, ...@@ -418,14 +405,6 @@ actor_system_config::parse_config_file(const char* filename,
std::ifstream f{filename}; std::ifstream f{filename};
if (!f.is_open()) if (!f.is_open())
return make_error(sec::cannot_open_file, filename); return make_error(sec::cannot_open_file, filename);
// TODO: The .ini parser is deprecated. Remove this block with CAF 0.19.
string_view fname{filename, strlen(filename)};
if (ends_with(fname, ".ini")) {
settings result;
if (auto err = parse_ini(f, opts, result))
return err;
return result;
}
return parse_config(f, opts); return parse_config(f, opts);
} }
...@@ -456,19 +435,6 @@ error actor_system_config::parse_config(std::istream& source, ...@@ -456,19 +435,6 @@ error actor_system_config::parse_config(std::istream& source,
return none; return none;
} }
error actor_system_config::parse_ini(std::istream& source,
const config_option_set& opts,
settings& result) {
if (!source)
return make_error(sec::runtime_error, "source stream invalid");
detail::config_consumer consumer{opts, result};
parser_state<config_iter, config_sentinel> res{config_iter{&source}};
detail::parser::read_ini(res, consumer);
if (res.i != res.e)
return make_error(res.code, res.line, res.column);
return none;
}
error actor_system_config::extract_config_file_path(string_list& args) { error actor_system_config::extract_config_file_path(string_list& args) {
auto ptr = custom_options_.qualified_name_lookup("global.config-file"); auto ptr = custom_options_.qualified_name_lookup("global.config-file");
CAF_ASSERT(ptr != nullptr); CAF_ASSERT(ptr != nullptr);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/ini_consumer.hpp"
#include "caf/pec.hpp"
namespace caf::detail {
// -- abstract_ini_consumer ----------------------------------------------------
abstract_ini_consumer::abstract_ini_consumer(abstract_ini_consumer* parent)
: parent_(parent) {
// nop
}
abstract_ini_consumer::~abstract_ini_consumer() {
// nop
}
ini_map_consumer abstract_ini_consumer::begin_map() {
return {this};
}
ini_list_consumer abstract_ini_consumer::begin_list() {
return {this};
}
// -- map_consumer -------------------------------------------------------------
ini_map_consumer::ini_map_consumer(abstract_ini_consumer* parent)
: super(parent), i_(xs_.end()) {
CAF_ASSERT(parent != nullptr);
}
ini_map_consumer::ini_map_consumer(ini_map_consumer&& other)
: super(other.parent()) {
}
ini_map_consumer::~ini_map_consumer() {
// nop
}
void ini_map_consumer::end_map() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_map_consumer::key(std::string name) {
i_ = xs_.emplace(std::move(name), config_value{}).first;
}
void ini_map_consumer::value_impl(config_value&& x) {
CAF_ASSERT(i_ != xs_.end());
i_->second = std::move(x);
}
// -- ini_list_consumer --------------------------------------------------------
ini_list_consumer::ini_list_consumer(abstract_ini_consumer* parent)
: super(parent) {
CAF_ASSERT(parent != nullptr);
}
ini_list_consumer::ini_list_consumer(ini_list_consumer&& other)
: super(other.parent()), xs_(std::move(other.xs_)) {
// nop
}
void ini_list_consumer::end_list() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_list_consumer::value_impl(config_value&& x) {
xs_.emplace_back(std::move(x));
}
// -- ini_value_consumer -------------------------------------------------------
ini_value_consumer::ini_value_consumer(abstract_ini_consumer* parent)
: super(parent) {
// nop
}
void ini_value_consumer::value_impl(config_value&& x) {
result = std::move(x);
}
// -- ini_category_consumer ----------------------------------------------------
ini_category_consumer::ini_category_consumer(ini_consumer* parent,
std::string category)
: super(parent), category_(std::move(category)) {
CAF_ASSERT(parent_ != nullptr);
}
ini_category_consumer::ini_category_consumer(ini_category_consumer&& other)
: super(other.parent()),
category_(std::move(other.category_)),
xs_(std::move(other.xs_)),
current_key(std::move(other.current_key)) {
CAF_ASSERT(parent_ != nullptr);
}
void ini_category_consumer::end_map() {
parent_->value_impl(config_value{std::move(xs_)});
}
void ini_category_consumer::key(std::string name) {
current_key = std::move(name);
}
void ini_category_consumer::value_impl(config_value&& x) {
// See whether there's an config_option associated to this category and key.
auto opt = dparent()->options_.qualified_name_lookup(category_, current_key);
if (opt == nullptr) {
// Simply store in config if no option was found.
xs_.emplace(std::move(current_key), std::move(x));
} else {
// Perform a type check to see whether this is a valid input.
if (opt->check(x) == none) {
opt->store(x);
xs_.emplace(std::move(current_key), std::move(x));
} else {
dparent()->warnings_.emplace_back(make_error(pec::type_mismatch));
}
}
}
ini_consumer* ini_category_consumer::dparent() {
// Safe, because our constructor only accepts ini_consumer parents.
return static_cast<ini_consumer*>(parent());
}
// -- ini_consumer -------------------------------------------------------------
ini_consumer::ini_consumer(const config_option_set& options, settings& cfg)
: options_(options), cfg_(cfg), current_key_("global") {
// nop
}
ini_category_consumer ini_consumer::begin_map() {
return {this, current_key_};
}
void ini_consumer::key(std::string name) {
current_key_ = std::move(name);
}
void ini_consumer::value_impl(config_value&& x) {
using dict_type = config_value::dictionary;
auto dict = get_if<dict_type>(&x);
if (dict == nullptr) {
warnings_.emplace_back(
make_error(pec::type_mismatch, "expected a dictionary at top level"));
return;
}
if (current_key_ != "global") {
auto& dst = cfg_.emplace(current_key_, dict_type{}).first->second;
if (dict != nullptr && !dict->empty()
&& holds_alternative<dict_type>(dst)) {
auto& dst_dict = get<dict_type>(dst);
// We need to "merge" values into the destination, because it can already
// contain any number of unrelated entries.
for (auto& entry : *dict)
dst_dict.insert_or_assign(entry.first, std::move(entry.second));
}
} else {
std::string prev_key;
swap(current_key_, prev_key);
for (auto& entry : *dict) {
if (holds_alternative<dict_type>(entry.second)) {
// Recurse into top-level maps.
current_key_ = std::move(entry.first);
value_impl(std::move(entry.second));
} else {
cfg_.insert_or_assign(entry.first, std::move(entry.second));
}
}
swap(prev_key, current_key_);
}
}
} // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE detail.ini_consumer
#include "caf/detail/ini_consumer.hpp"
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/read_ini.hpp"
using std::string;
using namespace caf;
// List-of-strings.
using ls = std::vector<std::string>;
namespace {
constexpr const string_view test_ini = R"(
is_server=true
port=4242
nodes=["sun", "venus", ]
[logger]
file-name = "foobar.ini" ; our file name
[scheduler] ; more settings
timing = 2us ; using microsecond resolution
)";
constexpr const string_view test_ini2 = R"(
is_server = true
logger = {
file-name = "foobar.ini"
}
port = 4242
scheduler = {
timing = 2us,
}
nodes = ["sun", "venus"]
)";
struct fixture {
config_option_set options;
settings config;
fixture() {
options.add<bool>("global", "is_server", "enables server mode")
.add<uint16_t>("global", "port", "sets local or remote port")
.add<ls>("global", "nodes", "list of remote nodes")
.add<string>("logger", "file-name", "log output file")
.add<int>("scheduler", "padding", "some integer")
.add<timespan>("scheduler", "timing", "some timespan");
}
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(ini_consumer_tests, fixture)
CAF_TEST(ini_value_consumer) {
string_view str = R"("hello world")";
detail::ini_value_consumer consumer;
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini_value(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<string>(consumer.result), "hello world");
}
CAF_TEST(ini_consumer) {
string_view str = test_ini;
detail::ini_consumer consumer{options, config};
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
CAF_CHECK_EQUAL(get<bool>(config, "is_server"), true);
CAF_CHECK_EQUAL(get<uint16_t>(config, "port"), 4242u);
CAF_CHECK_EQUAL(get<ls>(config, "nodes"), ls({"sun", "venus"}));
CAF_CHECK_EQUAL(get<string>(config, "logger.file-name"), "foobar.ini");
CAF_MESSAGE(config);
CAF_CHECK_EQUAL(get<timespan>(config, "scheduler.timing"), timespan(2000));
}
CAF_TEST(simplified syntax) {
CAF_MESSAGE("read test_ini");
{
detail::ini_consumer consumer{options, config};
string_parser_state res{test_ini.begin(), test_ini.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
settings config2;
CAF_MESSAGE("read test_ini2");
{
detail::ini_consumer consumer{options, config2};
string_parser_state res{test_ini2.begin(), test_ini2.end()};
detail::parser::read_ini(res, consumer);
CAF_CHECK_EQUAL(res.code, pec::success);
}
CAF_CHECK_EQUAL(config, config2);
}
CAF_TEST_FIXTURE_SCOPE_END()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE detail.parser.read_ini
#include "caf/detail/parser/read_ini.hpp"
#include "caf/test/dsl.hpp"
#include <string>
#include <vector>
#include "caf/config_value.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
using log_type = std::vector<std::string>;
struct test_consumer {
log_type log;
test_consumer() = default;
test_consumer(const test_consumer&) = delete;
test_consumer& operator=(const test_consumer&) = delete;
test_consumer& begin_map() {
log.emplace_back("{");
return *this;
}
void end_map() {
log.emplace_back("}");
}
test_consumer& begin_list() {
log.emplace_back("[");
return *this;
}
void end_list() {
log.emplace_back("]");
}
void key(std::string name) {
add_entry("key: ", std::move(name));
}
template <class T>
void value(T x) {
config_value cv{std::move(x)};
std::string entry = "value (";
entry += cv.type_name();
entry += "): ";
entry += to_string(cv);
log.emplace_back(std::move(entry));
}
void add_entry(const char* prefix, std::string str) {
str.insert(0, prefix);
log.emplace_back(std::move(str));
}
};
struct fixture {
expected<log_type> parse(string_view str, bool expect_success = true) {
test_consumer f;
string_parser_state res{str.begin(), str.end()};
detail::parser::read_ini(res, f);
if ((res.code == pec::success) != expect_success) {
CAF_MESSAGE("unexpected parser result state: " << res.code);
CAF_MESSAGE("input remainder: " << std::string(res.i, res.e));
}
return std::move(f.log);
}
};
template <class... Ts>
log_type make_log(Ts&&... xs) {
return log_type{std::forward<Ts>(xs)...};
}
// Tests basic functionality.
constexpr const string_view ini0 = R"(
[1group]
1value=321
[_foo]
_bar=11
[logger]
padding= 10
file-name = "foobar.ini" ; our file name
[scheduler] ; more settings
timing = 2us ; using microsecond resolution
x_ =.123
some-bool=true
some-other-bool=false
some-list=[
; here we have some list entries
123,
1..3,
23 ; twenty-three!
,2..4..2,
"abc", ; some comment and a trailing comma
]
some-map{
; here we have some list entries
entry1=123,
entry2=23 ; twenty-three! btw, comma is not mandatory
entry3= "abc" , ; some comment and a trailing comma
}
[middleman]
preconnect=[<
tcp://localhost:8080
>,<udp://remotehost?trust=false>]
)";
// clang-format off
const auto ini0_log = make_log(
"key: 1group",
"{",
"key: 1value",
"value (integer): 321",
"}",
"key: _foo",
"{",
"key: _bar",
"value (integer): 11",
"}",
"key: logger",
"{",
"key: padding",
"value (integer): 10",
"key: file-name",
"value (string): \"foobar.ini\"",
"}",
"key: scheduler",
"{",
"key: timing",
"value (timespan): 2us",
"key: x_",
"value (real): " + deep_to_string(.123),
"key: some-bool",
"value (boolean): true",
"key: some-other-bool",
"value (boolean): false",
"key: some-list",
"[",
"value (integer): 123",
"value (integer): 1",
"value (integer): 2",
"value (integer): 3",
"value (integer): 23",
"value (integer): 2",
"value (integer): 4",
"value (string): \"abc\"",
"]",
"key: some-map",
"{",
"key: entry1",
"value (integer): 123",
"key: entry2",
"value (integer): 23",
"key: entry3",
"value (string): \"abc\"",
"}",
"}",
"key: middleman",
"{",
"key: preconnect",
"[",
"value (uri): tcp://localhost:8080",
"value (uri): udp://remotehost?trust=false",
"]",
"}"
);
// clang-format on
// Tests nested parameters.
constexpr const string_view ini1 = R"(
foo {
bar = {
value1 = 1
}
value2 = 2
}
[bar.foo]
value3 = 3
)";
// clang-format off
const auto ini1_log = make_log(
"key: global",
"{",
"key: foo",
"{",
"key: bar",
"{",
"key: value1",
"value (integer): 1",
"}",
"key: value2",
"value (integer): 2",
"}",
"}",
"key: bar",
"{",
"key: foo",
"{",
"key: value3",
"value (integer): 3",
"}",
"}"
);
// clang-format on
constexpr const string_view ini2 = "#";
const auto ini2_log = make_log();
constexpr const string_view ini3 = "; foobar\n!";
const auto ini3_log = make_log();
} // namespace
CAF_TEST_FIXTURE_SCOPE(read_ini_tests, fixture)
CAF_TEST(empty inis) {
CAF_CHECK_EQUAL(parse(";foo"), make_log());
CAF_CHECK_EQUAL(parse(""), make_log());
CAF_CHECK_EQUAL(parse(" "), make_log());
CAF_CHECK_EQUAL(parse(" \n "), make_log());
CAF_CHECK_EQUAL(parse(";hello\n;world"), make_log());
}
CAF_TEST(section with valid key - value pairs) {
CAF_CHECK_EQUAL(parse("[foo]"), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [foo]"), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [ foo] "), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse(" [ foo ] "), make_log("key: foo", "{", "}"));
CAF_CHECK_EQUAL(parse("\n[a-b];foo\n;bar"), make_log("key: a-b", "{", "}"));
CAF_CHECK_EQUAL(parse(ini0), ini0_log);
CAF_CHECK_EQUAL(parse(ini1), ini1_log);
}
CAF_TEST(invalid inis) {
CAF_CHECK_EQUAL(parse(ini2), ini2_log);
CAF_CHECK_EQUAL(parse(ini3), ini3_log);
}
CAF_TEST(integer keys are legal in INI syntax) {
static constexpr string_view ini = R"__(
[foo.bar]
1 = 10
2 = 20
)__";
// clang-format off
auto log = make_log(
"key: foo",
"{",
"key: bar",
"{",
"key: 1",
"value (integer): 10",
"key: 2",
"value (integer): 20",
"}",
"}"
);
// clang-format on
CAF_CHECK_EQUAL(parse(ini), log);
}
CAF_TEST(integer keys are legal in config syntax) {
static constexpr string_view ini = R"__(
foo {
bar {
1 = 10
2 = 20
}
}
)__";
// clang-format off
auto log = make_log(
"key: global",
"{",
"key: foo",
"{",
"key: bar",
"{",
"key: 1",
"value (integer): 10",
"key: 2",
"value (integer): 20",
"}",
"}",
"}"
);
// clang-format on
CAF_CHECK_EQUAL(parse(ini), log);
}
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