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
faaaf3d5
Commit
faaaf3d5
authored
Aug 09, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add docu, fix UB, ODR violation and memory leak
parent
a65ae292
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
127 additions
and
78 deletions
+127
-78
libcaf_test/caf/test/context.cpp
libcaf_test/caf/test/context.cpp
+2
-2
libcaf_test/caf/test/fixture/deterministic.cpp
libcaf_test/caf/test/fixture/deterministic.cpp
+10
-8
libcaf_test/caf/test/fixture/deterministic.hpp
libcaf_test/caf/test/fixture/deterministic.hpp
+42
-8
libcaf_test/caf/test/reporter.cpp
libcaf_test/caf/test/reporter.cpp
+12
-2
libcaf_test/caf/test/reporter.hpp
libcaf_test/caf/test/reporter.hpp
+5
-2
libcaf_test/caf/test/runnable.cpp
libcaf_test/caf/test/runnable.cpp
+2
-2
libcaf_test/caf/test/runnable.hpp
libcaf_test/caf/test/runnable.hpp
+47
-47
libcaf_test/caf/test/runner.cpp
libcaf_test/caf/test/runner.cpp
+2
-2
libcaf_test/caf/test/test.test.cpp
libcaf_test/caf/test/test.test.cpp
+5
-5
No files found.
libcaf_test/caf/test/context.cpp
View file @
faaaf3d5
...
...
@@ -15,13 +15,13 @@ void context::on_enter(block* ptr) {
call_stack
.
push_back
(
ptr
);
unwind_stack
.
clear
();
path
.
push_back
(
ptr
);
reporter
::
instance
->
begin_step
(
ptr
);
reporter
::
instance
().
begin_step
(
ptr
);
}
void
context
::
on_leave
(
block
*
ptr
)
{
call_stack
.
pop_back
();
unwind_stack
.
push_back
(
ptr
);
reporter
::
instance
->
end_step
(
ptr
);
reporter
::
instance
().
end_step
(
ptr
);
}
bool
context
::
activated
(
block
*
ptr
)
const
noexcept
{
...
...
libcaf_test/caf/test/fixture/deterministic.cpp
View file @
faaaf3d5
...
...
@@ -151,7 +151,7 @@ protected:
}
void
stop
()
override
{
// nop
fix_
->
drop_events
();
}
void
enqueue
(
resumable
*
ptr
)
override
{
...
...
@@ -216,16 +216,18 @@ deterministic::~deterministic() {
// Note: we need clean up all remaining messages manually. This in turn may
// clean up actors as unreachable if the test did not consume all
// messages. Otherwise, the destructor of `sys` will wait for all
// actors, potentially waiting forever. However, we cannot just call
// `events_.clear()`, because that would potentially cause an actor to
// become unreachable and close its mailbox. This would call
// `pop_msg_impl` in turn, which then tries to alter the list while
// we're clearing it.
// actors, potentially waiting forever.
drop_events
();
}
void
deterministic
::
drop_events
()
{
// Note: We cannot just call `events_.clear()`, because that would potentially
// cause an actor to become unreachable and close its mailbox. This
// could call `pop_msg_impl` in turn, which then tries to alter the list
// while we're clearing it.
while
(
!
events_
.
empty
())
{
std
::
list
<
std
::
unique_ptr
<
scheduling_event
>>
tmp
;
tmp
.
splice
(
tmp
.
end
(),
events_
);
// Here, tmp will be destroyed and cleanup code of actors might send more
// messages. Hence the loop.
}
}
...
...
libcaf_test/caf/test/fixture/deterministic.hpp
View file @
faaaf3d5
...
...
@@ -204,38 +204,63 @@ public:
evaluator
&
operator
=
(
const
evaluator
&
)
=
delete
;
/// Matches the values of the message. The evaluator will match a message
/// only if all individual values match the corresponding predicate.
///
/// The template parameter pack `xs...` contains a list of match expressions
/// that all must evaluate to true for a message to match. For each match
/// expression:
///
/// - Passing a value creates a predicate that matches the value exactly.
/// - Passing a predicate (a function object taking one argument and
/// returning `bool`) will match any value for which the predicate returns
/// `true`.
/// - Passing `std::ignore` accepts any value at that position.
/// - Passing a `std::reference_wrapper<T>` will match any value and stores
/// the value in the reference wrapper.
template
<
class
...
Us
>
evaluator
&&
with
(
Us
...
xs
)
&&
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Us
));
static_assert
((
std
::
is_constructible_v
<
value_predicate
<
Ts
>
,
Us
>
&&
...));
with_
=
message_predicate
<
Ts
...
>
(
std
::
move
(
xs
)...);
return
std
::
move
(
*
this
);
}
/// Adds a predicate for the sender of the next message that matches only if
/// the sender is `src`.
evaluator
&&
from
(
const
strong_actor_ptr
&
src
)
&&
{
from_
=
value_predicate
<
strong_actor_ptr
>
{
std
::
move
(
src
)};
return
std
::
move
(
*
this
);
}
evaluator
&&
from
(
std
::
nullptr_t
)
&&
{
return
std
::
move
(
*
this
).
from
(
strong_actor_ptr
{});
}
/// Adds a predicate for the sender of the next message that matches only if
/// the sender is `src`.
evaluator
&&
from
(
const
actor
&
src
)
&&
{
from_
=
value_predicate
<
strong_actor_ptr
>
{
std
::
move
(
src
)};
return
std
::
move
(
*
this
);
}
/// Adds a predicate for the sender of the next message that matches only if
/// the sender is `src`.
template
<
class
...
Us
>
evaluator
&&
from
(
const
typed_actor
<
Us
...
>&
src
)
&&
{
from_
=
value_predicate
<
strong_actor_ptr
>
{
std
::
move
(
src
)};
return
std
::
move
(
*
this
);
}
/// Adds a predicate for the sender of the next message that matches only
/// anonymous messages, i.e., messages without a sender.
evaluator
&&
from
(
std
::
nullptr_t
)
&&
{
return
std
::
move
(
*
this
).
from
(
strong_actor_ptr
{});
}
/// Causes the evaluator to store the sender of a matched message in `src`.
evaluator
&&
from
(
std
::
reference_wrapper
<
strong_actor_ptr
>
src
)
&&
{
from_
=
value_predicate
<
strong_actor_ptr
>
{
src
};
return
std
::
move
(
*
this
);
}
/// Sets the target actor for this evaluator and evaluate the predicate.
template
<
class
T
>
bool
to
(
const
T
&
dst
)
&&
{
auto
dst_ptr
=
actor_cast
<
strong_actor_ptr
>
(
dst
);
...
...
@@ -276,7 +301,7 @@ public:
if
(
fail_on_mismatch
)
{
if
(
!
fix_
->
dispatch_message
())
ctx
.
fail
({
"failed to dispatch message"
,
loc_
});
reporter
::
instance
->
pass
(
loc_
);
reporter
::
instance
().
pass
(
loc_
);
return
true
;
}
return
fix_
->
dispatch_message
();
...
...
@@ -379,6 +404,15 @@ public:
// -- member variables -------------------------------------------------------
private:
// Note: this is put here because this member variable must be destroyed
// *after* the actor system (and thus must come before `sys` in
// the declaration order).
/// Stores all pending messages of scheduled actors.
std
::
list
<
std
::
unique_ptr
<
scheduling_event
>>
events_
;
public:
/// Configures the actor system with deterministic scheduling.
config
cfg
;
...
...
@@ -386,6 +420,9 @@ public:
actor_system
sys
;
private:
/// Removes all events from the queue.
void
drop_events
();
/// Tries find a message in `events_` that matches the given predicate and
/// moves it to the front of the queue.
bool
prepone_event_impl
(
const
strong_actor_ptr
&
receiver
);
...
...
@@ -401,9 +438,6 @@ private:
/// Removes the next message for `receiver` from the queue and returns it.
mailbox_element_ptr
pop_msg_impl
(
scheduled_actor
*
receiver
);
/// Stores all pending messages of scheduled actors.
std
::
list
<
std
::
unique_ptr
<
scheduling_event
>>
events_
;
};
}
// namespace caf::test
libcaf_test/caf/test/reporter.cpp
View file @
faaaf3d5
...
...
@@ -22,8 +22,6 @@ reporter::~reporter() {
// nop
}
reporter
*
reporter
::
instance
;
namespace
{
/// Implements a mini-DSL for colored output:
...
...
@@ -472,8 +470,20 @@ private:
context_ptr
current_ctx_
;
};
reporter
*
global_instance
;
}
// namespace
reporter
&
reporter
::
instance
()
{
if
(
global_instance
==
nullptr
)
CAF_RAISE_ERROR
(
"no reporter instance available"
);
return
*
global_instance
;
}
void
reporter
::
instance
(
reporter
*
ptr
)
{
global_instance
=
ptr
;
}
std
::
unique_ptr
<
reporter
>
reporter
::
make_default
()
{
return
std
::
make_unique
<
default_reporter
>
();
}
...
...
libcaf_test/caf/test/reporter.hpp
View file @
faaaf3d5
...
...
@@ -94,8 +94,11 @@ public:
/// Returns statistics for the entire run.
virtual
stats
total_stats
()
=
0
;
/// Stores a pointer to the currently active reporter.
static
reporter
*
instance
;
/// Returns the registered reporter instance.
static
reporter
&
instance
();
/// Sets the reporter instance for the current test run.
static
void
instance
(
reporter
*
ptr
);
/// Creates a default reporter that writes to the standard output.
static
std
::
unique_ptr
<
reporter
>
make_default
();
...
...
libcaf_test/caf/test/runnable.cpp
View file @
faaaf3d5
...
...
@@ -51,9 +51,9 @@ void runnable::run() {
bool
runnable
::
check
(
bool
value
,
const
detail
::
source_location
&
location
)
{
if
(
value
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
}
else
{
reporter
::
instance
->
fail
(
"should be true"
,
location
);
reporter
::
instance
().
fail
(
"should be true"
,
location
);
}
return
value
;
}
...
...
libcaf_test/caf/test/runnable.hpp
View file @
faaaf3d5
...
...
@@ -49,9 +49,9 @@ public:
[[
noreturn
]]
void
fail
(
detail
::
format_string_with_location
fwl
,
Ts
&&
...
xs
)
{
if
constexpr
(
sizeof
...(
Ts
)
>
0
)
{
auto
msg
=
detail
::
format
(
fwl
.
value
,
std
::
forward
<
Ts
>
(
xs
)...);
reporter
::
instance
->
fail
(
msg
,
fwl
.
location
);
reporter
::
instance
().
fail
(
msg
,
fwl
.
location
);
}
else
{
reporter
::
instance
->
fail
(
fwl
.
value
,
fwl
.
location
);
reporter
::
instance
().
fail
(
fwl
.
value
,
fwl
.
location
);
}
CAF_RAISE_ERROR
(
std
::
logic_error
,
"requirement failed: abort test"
);
}
...
...
@@ -61,9 +61,9 @@ public:
void
info
(
detail
::
format_string_with_location
fwl
,
Ts
&&
...
xs
)
{
if
constexpr
(
sizeof
...(
Ts
)
>
0
)
{
auto
msg
=
detail
::
format
(
fwl
.
value
,
std
::
forward
<
Ts
>
(
xs
)...);
reporter
::
instance
->
info
(
msg
,
fwl
.
location
);
reporter
::
instance
().
info
(
msg
,
fwl
.
location
);
}
else
{
reporter
::
instance
->
info
(
fwl
.
value
,
fwl
.
location
);
reporter
::
instance
().
info
(
fwl
.
value
,
fwl
.
location
);
}
}
...
...
@@ -74,11 +74,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
==
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
eq
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
eq
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -89,11 +89,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
!=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
ne
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
ne
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -104,11 +104,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
<
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
lt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
lt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -119,11 +119,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
<=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
le
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
le
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -134,11 +134,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
>
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
gt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
gt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -149,11 +149,11 @@ public:
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
>=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
}
reporter
::
instance
->
fail
(
binary_predicate
::
ge
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
reporter
::
instance
().
fail
(
binary_predicate
::
ge
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
return
false
;
}
...
...
@@ -169,22 +169,22 @@ public:
template
<
class
Expr
>
void
should_fail
(
Expr
&&
expr
,
const
caf
::
detail
::
source_location
&
location
=
caf
::
detail
::
source_location
::
current
())
{
auto
*
rep
=
reporter
::
instance
;
auto
lvl
=
rep
->
verbosity
(
CAF_LOG_LEVEL_QUIET
);
auto
before
=
rep
->
test_stats
();
auto
&
rep
=
reporter
::
instance
()
;
auto
lvl
=
rep
.
verbosity
(
CAF_LOG_LEVEL_QUIET
);
auto
before
=
rep
.
test_stats
();
{
auto
lvl_guard
=
detail
::
make_scope_guard
([
&
]
{
rep
->
verbosity
(
lvl
);
});
auto
lvl_guard
=
detail
::
make_scope_guard
([
&
]
{
rep
.
verbosity
(
lvl
);
});
expr
();
}
auto
after
=
rep
->
test_stats
();
auto
after
=
rep
.
test_stats
();
auto
passed_count_ok
=
before
.
passed
==
after
.
passed
;
auto
failed_count_ok
=
before
.
failed
+
1
==
after
.
failed
;
if
(
passed_count_ok
&&
failed_count_ok
)
{
reporter
::
instance
->
pass
(
location
);
rep
->
test_stats
({
before
.
passed
+
1
,
before
.
failed
});
reporter
::
instance
().
pass
(
location
);
rep
.
test_stats
({
before
.
passed
+
1
,
before
.
failed
});
}
else
{
reporter
::
instance
->
fail
(
"nested check should fail"
,
location
);
rep
->
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
reporter
::
instance
().
fail
(
"nested check should fail"
,
location
);
rep
.
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
}
}
...
...
@@ -198,21 +198,21 @@ public:
try
{
expr
();
}
catch
(...)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
;
}
reporter
::
instance
->
fail
(
"throws"
,
location
);
reporter
::
instance
().
fail
(
"throws"
,
location
);
}
else
{
try
{
expr
();
}
catch
(
const
Exception
&
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
;
}
catch
(...)
{
reporter
::
instance
->
fail
(
"throws Exception"
,
location
);
reporter
::
instance
().
fail
(
"throws Exception"
,
location
);
return
;
}
reporter
::
instance
->
fail
(
"throws Exception"
,
location
);
reporter
::
instance
().
fail
(
"throws Exception"
,
location
);
}
}
...
...
@@ -222,9 +222,9 @@ public:
void
should_fail_with_exception
(
Expr
&&
expr
,
const
caf
::
detail
::
source_location
&
location
=
caf
::
detail
::
source_location
::
current
())
{
auto
*
rep
=
reporter
::
instance
;
auto
before
=
rep
->
test_stats
();
auto
lvl
=
rep
->
verbosity
(
CAF_LOG_LEVEL_QUIET
);
auto
&
rep
=
reporter
::
instance
()
;
auto
before
=
rep
.
test_stats
();
auto
lvl
=
rep
.
verbosity
(
CAF_LOG_LEVEL_QUIET
);
auto
caught
=
false
;
if
constexpr
(
std
::
is_same_v
<
Exception
,
void
>
)
{
try
{
...
...
@@ -241,21 +241,21 @@ public:
// TODO: print error message
}
}
rep
->
verbosity
(
lvl
);
auto
after
=
rep
->
test_stats
();
rep
.
verbosity
(
lvl
);
auto
after
=
rep
.
test_stats
();
auto
passed_count_ok
=
before
.
passed
==
after
.
passed
;
auto
failed_count_ok
=
before
.
failed
+
1
==
after
.
failed
;
if
(
caught
&&
passed_count_ok
&&
failed_count_ok
)
{
reporter
::
instance
->
pass
(
location
);
rep
->
test_stats
({
before
.
passed
+
1
,
before
.
failed
});
reporter
::
instance
().
pass
(
location
);
rep
.
test_stats
({
before
.
passed
+
1
,
before
.
failed
});
}
else
{
if
(
!
caught
)
{
reporter
::
instance
->
fail
(
"nested check should throw an Exception"
,
location
);
reporter
::
instance
().
fail
(
"nested check should throw an Exception"
,
location
);
}
else
if
(
!
passed_count_ok
||
!
failed_count_ok
)
{
reporter
::
instance
->
fail
(
"nested check should fail"
,
location
);
reporter
::
instance
().
fail
(
"nested check should fail"
,
location
);
}
rep
->
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
rep
.
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
}
}
...
...
libcaf_test/caf/test/runner.cpp
View file @
faaaf3d5
...
...
@@ -131,7 +131,7 @@ runner::runner() : suites_(caf::test::registry::suites()) {
int
runner
::
run
(
int
argc
,
char
**
argv
)
{
auto
default_reporter
=
reporter
::
make_default
();
reporter
::
instance
=
default_reporter
.
get
(
);
reporter
::
instance
(
default_reporter
.
get
()
);
if
(
auto
[
ok
,
help_printed
]
=
parse_cli
(
argc
,
argv
);
!
ok
)
{
return
EXIT_FAILURE
;
}
else
if
(
help_printed
)
{
...
...
@@ -240,7 +240,7 @@ runner::parse_cli_result runner::parse_cli(int argc, char** argv) {
*
verbosity
);
return
{
false
,
true
};
}
reporter
::
instance
->
verbosity
(
*
level
);
reporter
::
instance
().
verbosity
(
*
level
);
}
return
{
true
,
false
};
}
...
...
libcaf_test/caf/test/test.test.cpp
View file @
faaaf3d5
...
...
@@ -8,8 +8,8 @@
using
caf
::
test
::
block_type
;
TEST
(
"tests can contain different types of checks"
)
{
auto
*
rep
=
caf
::
test
::
reporter
::
instance
;
auto
stats
=
rep
->
test_stats
();
auto
&
rep
=
caf
::
test
::
reporter
::
instance
()
;
auto
stats
=
rep
.
test_stats
();
SECTION
(
"check_ne checks for inequality"
)
{
check_ne
(
0
,
1
);
should_fail
([
this
]()
{
check_ne
(
0
,
0
);
});
...
...
@@ -38,16 +38,16 @@ TEST("tests can contain different types of checks") {
should_fail
([
this
]()
{
check_lt
(
1
,
1
);
});
should_fail
([
this
]()
{
check_lt
(
2
,
1
);
});
}
info
(
"this test had {} checks"
,
rep
->
test_stats
().
total
());
info
(
"this test had {} checks"
,
rep
.
test_stats
().
total
());
}
TEST
(
"failed checks increment the failed counter"
)
{
check_eq
(
1
,
2
);
auto
stats
=
caf
::
test
::
reporter
::
instance
->
test_stats
();
auto
stats
=
caf
::
test
::
reporter
::
instance
().
test_stats
();
check_eq
(
stats
.
passed
,
0u
);
check_eq
(
stats
.
failed
,
1u
);
info
(
"reset error count to not fail the test"
);
caf
::
test
::
reporter
::
instance
->
test_stats
({
2
,
0
});
caf
::
test
::
reporter
::
instance
().
test_stats
({
2
,
0
});
}
TEST
(
"each run starts with fresh local variables"
)
{
...
...
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