Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
c525c605
Unverified
Commit
c525c605
authored
Oct 15, 2019
by
Joseph Noir
Committed by
GitHub
Oct 15, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #931
Fix several issues with config values
parents
11c4eaca
760b0989
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
494 additions
and
182 deletions
+494
-182
libcaf_core/caf/actor_system_config.hpp
libcaf_core/caf/actor_system_config.hpp
+11
-4
libcaf_core/caf/config_value.hpp
libcaf_core/caf/config_value.hpp
+1
-0
libcaf_core/caf/config_value_field.hpp
libcaf_core/caf/config_value_field.hpp
+6
-9
libcaf_core/caf/config_value_object_access.hpp
libcaf_core/caf/config_value_object_access.hpp
+9
-11
libcaf_core/caf/detail/config_value_field_base.hpp
libcaf_core/caf/detail/config_value_field_base.hpp
+108
-0
libcaf_core/caf/detail/config_value_field_impl.hpp
libcaf_core/caf/detail/config_value_field_impl.hpp
+45
-91
libcaf_core/caf/detail/parse.hpp
libcaf_core/caf/detail/parse.hpp
+29
-21
libcaf_core/test/actor_system_config.cpp
libcaf_core/test/actor_system_config.cpp
+220
-40
libcaf_core/test/make_config_value_field.cpp
libcaf_core/test/make_config_value_field.cpp
+65
-6
No files found.
libcaf_core/caf/actor_system_config.hpp
View file @
c525c605
...
...
@@ -415,14 +415,14 @@ private:
const
settings
&
content
(
const
actor_system_config
&
cfg
);
/// Tries to retrieve the value associated to `name` from `cfg`.
/// @relates
config_value
/// @relates
actor_system_config
template
<
class
T
>
optional
<
T
>
get_if
(
const
actor_system_config
*
cfg
,
string_view
name
)
{
return
get_if
<
T
>
(
&
content
(
*
cfg
),
name
);
}
/// Retrieves the value associated to `name` from `cfg`.
/// @relates
config_value
/// @relates
actor_system_config
template
<
class
T
>
T
get
(
const
actor_system_config
&
cfg
,
string_view
name
)
{
return
get
<
T
>
(
content
(
cfg
),
name
);
...
...
@@ -430,7 +430,7 @@ T get(const actor_system_config& cfg, string_view name) {
/// Retrieves the value associated to `name` from `cfg` or returns
/// `default_value`.
/// @relates
config_value
/// @relates
actor_system_config
template
<
class
T
,
class
=
typename
std
::
enable_if
<
!
std
::
is_pointer
<
T
>
::
value
&&
!
std
::
is_convertible
<
T
,
string_view
>::
value
>::
type
>
...
...
@@ -440,10 +440,17 @@ T get_or(const actor_system_config& cfg, string_view name, T default_value) {
/// Retrieves the value associated to `name` from `cfg` or returns
/// `default_value`.
/// @relates
config_value
/// @relates
actor_system_config
inline
std
::
string
get_or
(
const
actor_system_config
&
cfg
,
string_view
name
,
string_view
default_value
)
{
return
get_or
(
content
(
cfg
),
name
,
default_value
);
}
/// Returns whether `xs` associates a value of type `T` to `name`.
/// @relates actor_system_config
template
<
class
T
>
bool
holds_alternative
(
const
actor_system_config
&
cfg
,
string_view
name
)
{
return
holds_alternative
<
T
>
(
content
(
cfg
),
name
);
}
}
// namespace caf
libcaf_core/caf/config_value.hpp
View file @
c525c605
...
...
@@ -259,6 +259,7 @@ CAF_DEFAULT_CONFIG_VALUE_ACCESS(bool, "boolean");
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
double
,
"real64"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
atom_value
,
"atom"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
timespan
,
"timespan"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
uri
,
"uri"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
list
,
"list"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
dictionary
,
"dictionary"
);
...
...
libcaf_core/caf/config_value_field.hpp
View file @
c525c605
...
...
@@ -33,12 +33,6 @@ public:
// -- observers --------------------------------------------------------------
/// Checks whether `x` matches the type of this field.
virtual
bool
type_check
(
const
config_value
&
x
)
const
noexcept
=
0
;
/// Returns whether this field in `object` contains valid data.
virtual
bool
valid
(
const
Object
&
object
)
const
noexcept
=
0
;
/// Returns whether this field has a default value.
virtual
bool
has_default
()
const
noexcept
=
0
;
...
...
@@ -48,11 +42,14 @@ public:
/// Returns the value of this field in `object` as config value.
virtual
config_value
get
(
const
Object
&
object
)
const
=
0
;
/// Returns whether calling `set` with `x` would succeed.
virtual
bool
valid_input
(
const
config_value
&
x
)
const
=
0
;
// -- modifiers --------------------------------------------------------------
///
Sets
this field in `object` to `x`.
/// @
pre `can_set(x)`
virtual
void
set
(
Object
&
object
,
const
config_value
&
x
)
const
=
0
;
///
Tries to set
this field in `object` to `x`.
/// @
returns `true` on success, `false` otherwise.
virtual
bool
set
(
Object
&
object
,
const
config_value
&
x
)
const
=
0
;
/// Restores the default value for this field in `object`.
/// @pre `has_default()`
...
...
libcaf_core/caf/config_value_object_access.hpp
View file @
c525c605
...
...
@@ -48,17 +48,19 @@ struct config_value_object_access {
if
(
!
dict
)
return
false
;
for
(
auto
field
:
Trait
::
fields
())
{
auto
value
=
caf
::
get_if
(
dict
,
field
->
name
());
if
(
!
value
)
{
if
(
auto
value
=
caf
::
get_if
(
dict
,
field
->
name
()))
{
if
(
dst
)
{
if
(
!
field
->
set
(
*
dst
,
*
value
))
return
false
;
}
else
{
if
(
!
field
->
valid_input
(
*
value
))
return
false
;
}
}
else
{
if
(
!
field
->
has_default
())
return
false
;
if
(
dst
)
field
->
set_default
(
*
dst
);
}
else
if
(
field
->
type_check
(
*
value
))
{
if
(
dst
)
field
->
set
(
*
dst
,
*
value
);
}
else
{
return
false
;
}
}
return
true
;
...
...
@@ -156,10 +158,6 @@ struct config_value_object_access {
ps
.
code
=
pec
::
unexpected_eof
;
return
;
}
if
(
!
fptr
->
valid
(
x
))
{
ps
.
code
=
pec
::
illegal_argument
;
return
;
}
result
[
fptr
->
name
()]
=
fptr
->
get
(
x
);
}
while
(
ps
.
consume
(
','
));
if
(
!
ps
.
consume
(
'}'
))
{
...
...
libcaf_core/caf/detail/config_value_field_base.hpp
0 → 100644
View file @
c525c605
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/dispatch_parse_cli.hpp"
#include "caf/optional.hpp"
namespace
caf
{
namespace
detail
{
template
<
class
Object
,
class
Value
>
class
config_value_field_base
:
public
config_value_field
<
Object
>
{
public:
using
super
=
config_value_field
<
Object
>
;
using
object_type
=
typename
super
::
object_type
;
using
value_type
=
Value
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
);
config_value_field_base
(
string_view
name
,
optional
<
value_type
>
default_value
,
predicate_type
predicate
)
:
name_
(
name
),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
// nop
}
config_value_field_base
(
config_value_field_base
&&
)
=
default
;
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
config_value
get
(
const
object_type
&
object
)
const
override
{
using
access
=
caf
::
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
get_value
(
object
))};
}
bool
valid_input
(
const
config_value
&
x
)
const
override
{
if
(
!
predicate_
)
return
holds_alternative
<
value_type
>
(
x
);
if
(
auto
value
=
get_if
<
value_type
>
(
&
x
))
return
predicate_
(
*
value
);
return
false
;
}
bool
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
if
(
auto
value
=
get_if
<
value_type
>
(
&
y
))
{
if
(
predicate_
&&
!
predicate_
(
*
value
))
return
false
;
set_value
(
x
,
move_if_optional
(
value
));
return
true
;
}
return
false
;
}
void
set_default
(
object_type
&
x
)
const
override
{
set_value
(
x
,
*
default_value_
);
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
const
char
*
char_blacklist
)
const
override
{
value_type
tmp
;
dispatch_parse_cli
(
ps
,
tmp
,
char_blacklist
);
if
(
ps
.
code
<=
pec
::
trailing_character
)
{
if
(
predicate_
&&
!
predicate_
(
tmp
))
ps
.
code
=
pec
::
illegal_argument
;
else
set_value
(
x
,
std
::
move
(
tmp
));
}
}
virtual
const
value_type
&
get_value
(
const
object_type
&
object
)
const
=
0
;
virtual
void
set_value
(
object_type
&
object
,
value_type
value
)
const
=
0
;
protected:
string_view
name_
;
optional
<
value_type
>
default_value_
;
predicate_type
predicate_
;
};
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/config_value_field_impl.hpp
View file @
c525c605
...
...
@@ -23,6 +23,7 @@
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/dispatch_parse_cli.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
...
...
@@ -38,157 +39,110 @@ class config_value_field_impl;
// A config value with direct access to a field via member object pointer.
template
<
class
Value
,
class
Object
>
class
config_value_field_impl
<
Value
Object
::*>
:
public
config_value_field
<
Object
>
{
:
public
config_value_field
_base
<
Object
,
Value
>
{
public:
using
super
=
config_value_field_base
<
Object
,
Value
>
;
using
member_pointer
=
Value
Object
::*
;
using
object_type
=
Object
;
using
value_type
=
Value
;
using
predicate_
pointer
=
bool
(
*
)(
const
value_type
&
);
using
predicate_
type
=
bool
(
*
)(
const
value_type
&
);
constexpr
config_value_field_impl
(
string_view
name
,
member_pointer
ptr
,
optional
<
value_type
>
default_value
=
none
,
predicate_pointer
predicate
=
nullptr
)
:
name_
(
name
),
ptr_
(
ptr
),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
predicate_type
predicate
=
nullptr
)
:
super
(
name
,
std
::
move
(
default_value
),
predicate
),
ptr_
(
ptr
)
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
bool
type_check
(
const
config_value
&
x
)
const
noexcept
override
{
return
holds_alternative
<
value_type
>
(
x
);
}
bool
valid
(
const
object_type
&
x
)
const
noexcept
override
{
return
predicate_
?
predicate_
(
x
.
*
ptr_
)
:
true
;
}
void
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
x
.
*
ptr_
=
caf
::
get
<
value_type
>
(
y
);
}
config_value
get
(
const
object_type
&
x
)
const
override
{
using
access
=
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
x
.
*
ptr_
)};
const
value_type
&
get_value
(
const
object_type
&
x
)
const
override
{
return
x
.
*
ptr_
;
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
const
char
*
char_blacklist
)
const
override
{
detail
::
dispatch_parse_cli
(
ps
,
x
.
*
ptr_
,
char_blacklist
);
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
}
void
set_default
(
object_type
&
x
)
const
override
{
x
.
*
ptr_
=
*
default_value_
;
void
set_value
(
object_type
&
x
,
value_type
y
)
const
override
{
x
.
*
ptr_
=
std
::
move
(
y
);
}
private:
string_view
name_
;
member_pointer
ptr_
;
optional
<
value_type
>
default_value_
;
predicate_pointer
predicate_
;
};
template
<
class
Get
>
struct
config_value_field_
base
{
struct
config_value_field_
trait
{
using
trait
=
get_callable_trait_t
<
Get
>
;
static_assert
(
trait
::
num_args
==
1
,
"Get must take exactly one argument (the object)"
);
using
arg
_type
=
tl_head_t
<
typename
trait
::
arg_types
>
;
using
get_argument
_type
=
tl_head_t
<
typename
trait
::
arg_types
>
;
using
value_type
=
decay_t
<
typename
trait
::
resul
t_type
>
;
using
object_type
=
decay_t
<
get_argumen
t_type
>
;
using
type
=
config_value_field
<
decay_t
<
arg_type
>>
;
};
using
get_result_type
=
typename
trait
::
result_type
;
template
<
class
Get
>
using
config_value_field_base_t
=
typename
config_value_field_base
<
Get
>::
type
;
using
value_type
=
decay_t
<
get_result_type
>
;
}
;
// A config value with access to a field via getter and setter.
template
<
class
Get
,
class
Set
>
class
config_value_field_impl
<
std
::
pair
<
Get
,
Set
>>
:
public
config_value_field_base_t
<
Get
>
{
:
public
config_value_field_base
<
typename
config_value_field_trait
<
Get
>::
object_type
,
typename
config_value_field_trait
<
Get
>::
value_type
>
{
public:
using
super
=
config_value_field_base_t
<
Get
>
;
using
trait
=
config_value_field_trait
<
Get
>
;
using
object_type
=
typename
trait
::
object_type
;
using
object_type
=
typename
super
::
objec
t_type
;
using
get_result_type
=
typename
trait
::
get_resul
t_type
;
using
get_trait
=
get_callable_trait_t
<
Get
>
;
using
value_type
=
typename
trait
::
value_type
;
using
value_type
=
decay_t
<
typename
get_trait
::
result_type
>
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
)
;
using
predicate_pointer
=
bool
(
*
)(
const
value_type
&
)
;
using
super
=
config_value_field_base
<
object_type
,
value_type
>
;
constexpr
config_value_field_impl
(
string_view
name
,
Get
getter
,
Set
setter
,
optional
<
value_type
>
default_value
=
none
,
predicate_
pointer
predicate
=
nullptr
)
:
name_
(
nam
e
),
predicate_
type
predicate
=
nullptr
)
:
super
(
name
,
std
::
move
(
default_value
),
predicat
e
),
get_
(
std
::
move
(
getter
)),
set_
(
std
::
move
(
setter
)),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
set_
(
std
::
move
(
setter
))
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
bool
type_check
(
const
config_value
&
x
)
const
noexcept
override
{
return
holds_alternative
<
value_type
>
(
x
);
}
void
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
set_
(
x
,
caf
::
get
<
value_type
>
(
y
));
}
config_value
get
(
const
object_type
&
x
)
const
override
{
using
access
=
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
get_
(
x
))};
}
bool
valid
(
const
object_type
&
x
)
const
noexcept
override
{
return
predicate_
?
predicate_
(
get_
(
x
))
:
true
;
const
value_type
&
get_value
(
const
object_type
&
x
)
const
override
{
bool_token
<
std
::
is_lvalue_reference
<
get_result_type
>::
value
>
token
;
return
get_value_impl
(
x
,
token
);
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
const
char
*
char_blacklist
)
const
override
{
value_type
tmp
;
detail
::
dispatch_parse_cli
(
ps
,
tmp
,
char_blacklist
);
if
(
ps
.
code
<=
pec
::
trailing_character
)
set_
(
x
,
std
::
move
(
tmp
));
void
set_value
(
object_type
&
x
,
value_type
y
)
const
override
{
set_
(
x
,
std
::
move
(
y
));
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
private:
template
<
class
O
>
const
value_type
&
get_value_impl
(
const
O
&
x
,
std
::
true_type
)
const
{
return
get_
(
x
);
}
void
set_default
(
object_type
&
x
)
const
override
{
set_
(
x
,
*
default_value_
);
template
<
class
O
>
const
value_type
&
get_value_impl
(
const
O
&
x
,
std
::
false_type
)
const
{
dummy_
=
get_
(
x
);
return
dummy_
;
}
private:
string_view
name_
;
Get
get_
;
Set
set_
;
optional
<
value_type
>
default_value_
;
predicate_pointer
predicate_
;
mutable
value_type
dummy_
;
};
}
// namespace detail
...
...
libcaf_core/caf/detail/parse.hpp
View file @
c525c605
...
...
@@ -107,30 +107,11 @@ void parse_element(string_parser_state& ps, std::string& x,
template
<
class
T
>
enable_if_t
<!
is_pair
<
T
>::
value
>
parse_element
(
string_parser_state
&
ps
,
T
&
x
,
const
char
*
)
{
parse
(
ps
,
x
);
}
const
char
*
);
template
<
class
First
,
class
Second
,
size_t
N
>
void
parse_element
(
string_parser_state
&
ps
,
std
::
pair
<
First
,
Second
>&
kvp
,
const
char
(
&
char_blacklist
)[
N
])
{
static_assert
(
N
>
0
,
"empty array"
);
// TODO: consider to guard the blacklist computation with
// `if constexpr (is_same_v<First, string>)` when switching to C++17.
char
key_blacklist
[
N
+
1
];
if
(
N
>
1
)
memcpy
(
key_blacklist
,
char_blacklist
,
N
-
1
);
key_blacklist
[
N
-
1
]
=
'='
;
key_blacklist
[
N
]
=
'\0'
;
parse_element
(
ps
,
kvp
.
first
,
key_blacklist
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
!
ps
.
consume
(
'='
))
{
ps
.
code
=
pec
::
unexpected_character
;
return
;
}
parse_element
(
ps
,
kvp
.
second
,
char_blacklist
);
}
const
char
(
&
char_blacklist
)[
N
]);
template
<
class
T
>
enable_if_tt
<
is_iterable
<
T
>>
parse
(
string_parser_state
&
ps
,
T
&
xs
)
{
...
...
@@ -177,6 +158,33 @@ enable_if_tt<is_iterable<T>> parse(string_parser_state& ps, T& xs) {
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
template
<
class
T
>
enable_if_t
<!
is_pair
<
T
>::
value
>
parse_element
(
string_parser_state
&
ps
,
T
&
x
,
const
char
*
)
{
parse
(
ps
,
x
);
}
template
<
class
First
,
class
Second
,
size_t
N
>
void
parse_element
(
string_parser_state
&
ps
,
std
::
pair
<
First
,
Second
>&
kvp
,
const
char
(
&
char_blacklist
)[
N
])
{
static_assert
(
N
>
0
,
"empty array"
);
// TODO: consider to guard the blacklist computation with
// `if constexpr (is_same_v<First, string>)` when switching to C++17.
char
key_blacklist
[
N
+
1
];
if
(
N
>
1
)
memcpy
(
key_blacklist
,
char_blacklist
,
N
-
1
);
key_blacklist
[
N
-
1
]
=
'='
;
key_blacklist
[
N
]
=
'\0'
;
parse_element
(
ps
,
kvp
.
first
,
key_blacklist
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
!
ps
.
consume
(
'='
))
{
ps
.
code
=
pec
::
unexpected_character
;
return
;
}
parse_element
(
ps
,
kvp
.
second
,
char_blacklist
);
}
// -- convenience functions ----------------------------------------------------
template
<
class
T
>
...
...
libcaf_core/test/actor_system_config.cpp
View file @
c525c605
...
...
@@ -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]
\n
bar=
\"
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]
\n
bar=
\"
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]
\n
bar=
\"
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]
\n
bar=
\"
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
()
libcaf_core/test/make_config_value_field.cpp
View file @
c525c605
...
...
@@ -22,6 +22,7 @@
#include "caf/test/dsl.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/config_option_set.hpp"
#include "caf/config_value_object_access.hpp"
...
...
@@ -130,15 +131,12 @@ struct fixture {
foobar
x
;
CAF_CHECK_EQUAL
(
foo_field
.
name
(),
"foo"
);
CAF_REQUIRE
(
foo_field
.
has_default
());
CAF_CHECK
(
foo_field
.
valid
(
x
));
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
0
));
foo_field
.
set_default
(
x
);
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
42
));
CAF_CHECK
(
!
foo_field
.
type_check
(
config_value
(
1.
)));
CAF_CHECK
(
foo_field
.
type_check
(
config_value
(
-
1
)));
foo_field
.
set
(
x
,
config_value
(
-
1
));
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
-
1
));
CAF_CHECK
(
!
foo_field
.
valid
(
x
));
CAF_CHECK
(
!
foo_field
.
valid_input
(
config_value
(
1.
)));
CAF_CHECK
(
!
foo_field
.
valid_input
(
config_value
(
-
1
)));
CAF_CHECK
(
!
foo_field
.
set
(
x
,
config_value
(
-
1
)));
string_view
input
=
"123"
;
string_parser_state
ps
{
input
.
begin
(),
input
.
end
()};
foo_field
.
parse_cli
(
ps
,
x
);
...
...
@@ -257,4 +255,65 @@ CAF_TEST(object access from CLI arguments - foobar_foobar) {
fbfb
({
123
,
"hello"
},
{
1
,
"world!"
}));
}
namespace
{
constexpr
const
char
*
config_text
=
R"__(
arg1 = {
foo = 42
bar = "Don't panic!"
}
arg2 = {
x = {
foo = 1
bar = "hello"
}
y = {
foo = 2
bar = "world"
}
}
)__"
;
struct
test_config
:
actor_system_config
{
test_config
()
{
opt_group
{
custom_options_
,
"global"
}
.
add
(
fb
,
"arg1,1"
,
"some foobar"
)
.
add
(
fbfb
,
"arg2,2"
,
"somme foobar-foobar"
);
}
foobar
fb
;
foobar_foobar
fbfb
;
};
}
// namespace
CAF_TEST
(
object
access
from
actor
system
config
-
file
input
)
{
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
0
,
nullptr
,
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
cfg
.
render
(
err
));
CAF_CHECK_EQUAL
(
cfg
.
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
bar
,
"Don't panic!"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
foo
,
1
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
foo
,
2
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
bar
,
"world"
);
}
CAF_TEST
(
object
access
from
actor
system
config
-
file
input
and
arguments
)
{
std
::
vector
<
std
::
string
>
args
{
"-2"
,
"{y = {bar = CAF, foo = 20}, x = {foo = 10, bar = hello}}"
,
};
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
std
::
move
(
args
),
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
cfg
.
render
(
err
));
CAF_CHECK_EQUAL
(
cfg
.
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
bar
,
"Don't panic!"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
foo
,
10
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
foo
,
20
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
bar
,
"CAF"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment