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
cd8363aa
Commit
cd8363aa
authored
Aug 10, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1518
parents
c677bf5b
faaaf3d5
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1332 additions
and
73 deletions
+1332
-73
CHANGELOG.md
CHANGELOG.md
+3
-1
libcaf_core/caf/actor_system.cpp
libcaf_core/caf/actor_system.cpp
+4
-0
libcaf_core/caf/actor_system.hpp
libcaf_core/caf/actor_system.hpp
+9
-0
libcaf_core/caf/actor_system_config.cpp
libcaf_core/caf/actor_system_config.cpp
+4
-0
libcaf_core/caf/actor_system_config.hpp
libcaf_core/caf/actor_system_config.hpp
+6
-0
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+3
-0
libcaf_core/caf/intrusive_ptr.hpp
libcaf_core/caf/intrusive_ptr.hpp
+16
-12
libcaf_core/caf/scheduled_actor.hpp
libcaf_core/caf/scheduled_actor.hpp
+5
-0
libcaf_test/CMakeLists.txt
libcaf_test/CMakeLists.txt
+2
-0
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
+324
-0
libcaf_test/caf/test/fixture/deterministic.hpp
libcaf_test/caf/test/fixture/deterministic.hpp
+443
-0
libcaf_test/caf/test/fixture/deterministic.test.cpp
libcaf_test/caf/test/fixture/deterministic.test.cpp
+346
-0
libcaf_test/caf/test/reporter.cpp
libcaf_test/caf/test/reporter.cpp
+17
-5
libcaf_test/caf/test/reporter.hpp
libcaf_test/caf/test/reporter.hpp
+7
-3
libcaf_test/caf/test/runnable.cpp
libcaf_test/caf/test/runnable.cpp
+19
-2
libcaf_test/caf/test/runnable.hpp
libcaf_test/caf/test/runnable.hpp
+115
-41
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.
CHANGELOG.md
View file @
cd8363aa
...
@@ -38,7 +38,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -38,7 +38,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
-
We renamed
`caf::flow::item_publisher`
to
`caf::flow::multicaster`
to better
-
We renamed
`caf::flow::item_publisher`
to
`caf::flow::multicaster`
to better
reflect its purpose and to avoid confusion with the new
reflect its purpose and to avoid confusion with the new
`caf::async::publisher`
.
`caf::async::publisher`
.
-
When failing to deserialize a request, the sender will receive an error of
-
When failing to deserialize a request, the sender will receive an error of
kind
`sec::malformed_message`
.
kind
`sec::malformed_message`
.
### Fixed
### Fixed
...
@@ -52,6 +52,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -52,6 +52,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
`on_complete`
on its subscriber on the first activity of the source
`on_complete`
on its subscriber on the first activity of the source
observable. Previously, the created observable would never reach its threshold
observable. Previously, the created observable would never reach its threshold
and attempt to buffer all values indefinitely.
and attempt to buffer all values indefinitely.
-
The comparison operator of
`intrusive_ptr`
no longer accidentally creates new
`intrusive_ptr`
instances when comparing to raw pointers.
## [0.19.2] - 2023-06-13
## [0.19.2] - 2023-06-13
...
...
libcaf_core/caf/actor_system.cpp
View file @
cd8363aa
...
@@ -541,4 +541,8 @@ void actor_system::release_private_thread(detail::private_thread* ptr) {
...
@@ -541,4 +541,8 @@ void actor_system::release_private_thread(detail::private_thread* ptr) {
private_threads_
.
release
(
ptr
);
private_threads_
.
release
(
ptr
);
}
}
detail
::
mailbox_factory
*
actor_system
::
mailbox_factory
()
{
return
cfg_
.
mailbox_factory
();
}
}
// namespace caf
}
// namespace caf
libcaf_core/caf/actor_system.hpp
View file @
cd8363aa
...
@@ -398,6 +398,7 @@ public:
...
@@ -398,6 +398,7 @@ public:
infer_handle_from_class_t
<
C
>
spawn
(
Ts
&&
...
xs
)
{
infer_handle_from_class_t
<
C
>
spawn
(
Ts
&&
...
xs
)
{
check_invariants
<
C
>
();
check_invariants
<
C
>
();
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_impl
<
C
,
Os
>
(
cfg
,
detail
::
spawn_fwd
<
Ts
>
(
xs
)...);
return
spawn_impl
<
C
,
Os
>
(
cfg
,
detail
::
spawn_fwd
<
Ts
>
(
xs
)...);
}
}
...
@@ -436,6 +437,7 @@ public:
...
@@ -436,6 +437,7 @@ public:
static_assert
(
spawnable
,
static_assert
(
spawnable
,
"cannot spawn function-based actor with given arguments"
);
"cannot spawn function-based actor with given arguments"
);
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_functor
<
Os
>
(
detail
::
bool_token
<
spawnable
>
{},
cfg
,
fun
,
return
spawn_functor
<
Os
>
(
detail
::
bool_token
<
spawnable
>
{},
cfg
,
fun
,
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
...
@@ -500,6 +502,7 @@ public:
...
@@ -500,6 +502,7 @@ public:
infer_handle_from_fun_t
<
F
>
infer_handle_from_fun_t
<
F
>
spawn_in_groups
(
std
::
initializer_list
<
group
>
gs
,
F
fun
,
Ts
&&
...
xs
)
{
spawn_in_groups
(
std
::
initializer_list
<
group
>
gs
,
F
fun
,
Ts
&&
...
xs
)
{
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_fun_in_groups
<
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
fun
,
return
spawn_fun_in_groups
<
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
fun
,
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
...
@@ -508,6 +511,7 @@ public:
...
@@ -508,6 +511,7 @@ public:
template
<
spawn_options
Os
=
no_spawn_options
,
class
Gs
,
class
F
,
class
...
Ts
>
template
<
spawn_options
Os
=
no_spawn_options
,
class
Gs
,
class
F
,
class
...
Ts
>
infer_handle_from_fun_t
<
F
>
spawn_in_groups
(
const
Gs
&
gs
,
F
fun
,
Ts
&&
...
xs
)
{
infer_handle_from_fun_t
<
F
>
spawn_in_groups
(
const
Gs
&
gs
,
F
fun
,
Ts
&&
...
xs
)
{
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_fun_in_groups
<
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
fun
,
return
spawn_fun_in_groups
<
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
fun
,
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
...
@@ -524,6 +528,7 @@ public:
...
@@ -524,6 +528,7 @@ public:
infer_handle_from_class_t
<
T
>
infer_handle_from_class_t
<
T
>
spawn_in_groups
(
std
::
initializer_list
<
group
>
gs
,
Ts
&&
...
xs
)
{
spawn_in_groups
(
std
::
initializer_list
<
group
>
gs
,
Ts
&&
...
xs
)
{
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_class_in_groups
<
T
,
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
return
spawn_class_in_groups
<
T
,
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
...
@@ -532,6 +537,7 @@ public:
...
@@ -532,6 +537,7 @@ public:
template
<
class
T
,
spawn_options
Os
=
no_spawn_options
,
class
Gs
,
class
...
Ts
>
template
<
class
T
,
spawn_options
Os
=
no_spawn_options
,
class
Gs
,
class
...
Ts
>
infer_handle_from_class_t
<
T
>
spawn_in_groups
(
const
Gs
&
gs
,
Ts
&&
...
xs
)
{
infer_handle_from_class_t
<
T
>
spawn_in_groups
(
const
Gs
&
gs
,
Ts
&&
...
xs
)
{
actor_config
cfg
;
actor_config
cfg
;
cfg
.
mbox_factory
=
mailbox_factory
();
return
spawn_class_in_groups
<
T
,
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
return
spawn_class_in_groups
<
T
,
Os
>
(
cfg
,
gs
.
begin
(),
gs
.
end
(),
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
...
@@ -696,6 +702,7 @@ public:
...
@@ -696,6 +702,7 @@ public:
"only scheduled actors may get spawned inactively"
);
"only scheduled actors may get spawned inactively"
);
CAF_SET_LOGGER_SYS
(
this
);
CAF_SET_LOGGER_SYS
(
this
);
actor_config
cfg
{
dummy_execution_unit
(),
nullptr
};
actor_config
cfg
{
dummy_execution_unit
(),
nullptr
};
cfg
.
mbox_factory
=
mailbox_factory
();
auto
res
=
make_actor
<
Impl
>
(
next_actor_id
(),
node
(),
this
,
cfg
,
auto
res
=
make_actor
<
Impl
>
(
next_actor_id
(),
node
(),
this
,
cfg
,
std
::
forward
<
Ts
>
(
xs
)...);
std
::
forward
<
Ts
>
(
xs
)...);
auto
ptr
=
static_cast
<
Impl
*>
(
actor_cast
<
abstract_actor
*>
(
res
));
auto
ptr
=
static_cast
<
Impl
*>
(
actor_cast
<
abstract_actor
*>
(
res
));
...
@@ -790,6 +797,8 @@ private:
...
@@ -790,6 +797,8 @@ private:
config_serv_
=
std
::
move
(
x
);
config_serv_
=
std
::
move
(
x
);
}
}
detail
::
mailbox_factory
*
mailbox_factory
();
// -- member variables -------------------------------------------------------
// -- member variables -------------------------------------------------------
/// Provides system-wide callbacks for several actor operations.
/// Provides system-wide callbacks for several actor operations.
...
...
libcaf_core/caf/actor_system_config.cpp
View file @
cd8363aa
...
@@ -478,6 +478,10 @@ actor_system_config::extract_config_file_path(string_list& args) {
...
@@ -478,6 +478,10 @@ actor_system_config::extract_config_file_path(string_list& args) {
}
}
}
}
detail
::
mailbox_factory
*
actor_system_config
::
mailbox_factory
()
{
return
nullptr
;
}
const
settings
&
content
(
const
actor_system_config
&
cfg
)
{
const
settings
&
content
(
const
actor_system_config
&
cfg
)
{
return
cfg
.
content
;
return
cfg
.
content
;
}
}
...
...
libcaf_core/caf/actor_system_config.hpp
View file @
cd8363aa
...
@@ -32,6 +32,10 @@ namespace caf {
...
@@ -32,6 +32,10 @@ namespace caf {
/// Configures an `actor_system` on startup.
/// Configures an `actor_system` on startup.
class
CAF_CORE_EXPORT
actor_system_config
{
class
CAF_CORE_EXPORT
actor_system_config
{
public:
public:
// -- friends ----------------------------------------------------------------
friend
class
actor_system
;
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
using
hook_factory
=
std
::
function
<
io
::
hook
*
(
actor_system
&
)
>
;
using
hook_factory
=
std
::
function
<
io
::
hook
*
(
actor_system
&
)
>
;
...
@@ -303,6 +307,8 @@ protected:
...
@@ -303,6 +307,8 @@ protected:
config_option_set
custom_options_
;
config_option_set
custom_options_
;
private:
private:
virtual
detail
::
mailbox_factory
*
mailbox_factory
();
void
set_remainder
(
string_list
args
);
void
set_remainder
(
string_list
args
);
mutable
std
::
vector
<
char
*>
c_args_remainder_
;
mutable
std
::
vector
<
char
*>
c_args_remainder_
;
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
cd8363aa
...
@@ -175,6 +175,9 @@ public:
...
@@ -175,6 +175,9 @@ public:
static
constexpr
bool
value
=
std
::
is_same_v
<
bool
,
result_type
>
;
static
constexpr
bool
value
=
std
::
is_same_v
<
bool
,
result_type
>
;
};
};
template
<
class
T1
,
class
T2
>
constexpr
bool
is_comparable_v
=
is_comparable
<
T1
,
T2
>::
value
;
/// Checks whether `T` behaves like a forward iterator.
/// Checks whether `T` behaves like a forward iterator.
template
<
class
T
>
template
<
class
T
>
class
is_forward_iterator
{
class
is_forward_iterator
{
...
...
libcaf_core/caf/intrusive_ptr.hpp
View file @
cd8363aa
...
@@ -231,27 +231,31 @@ bool operator!=(std::nullptr_t, const intrusive_ptr<T>& x) {
...
@@ -231,27 +231,31 @@ bool operator!=(std::nullptr_t, const intrusive_ptr<T>& x) {
// -- comparison to raw pointer ------------------------------------------------
// -- comparison to raw pointer ------------------------------------------------
/// @relates intrusive_ptr
/// @relates intrusive_ptr
template
<
class
T
>
template
<
class
T
,
class
U
>
bool
operator
==
(
const
intrusive_ptr
<
T
>&
x
,
const
T
*
y
)
{
detail
::
enable_if_t
<
detail
::
is_comparable
<
T
*
,
U
*>::
value
,
bool
>
return
x
.
get
()
==
y
;
operator
==
(
const
intrusive_ptr
<
T
>&
lhs
,
const
U
*
rhs
)
{
return
lhs
.
get
()
==
rhs
;
}
}
/// @relates intrusive_ptr
/// @relates intrusive_ptr
template
<
class
T
>
template
<
class
T
,
class
U
>
bool
operator
==
(
const
T
*
x
,
const
intrusive_ptr
<
T
>&
y
)
{
detail
::
enable_if_t
<
detail
::
is_comparable
<
T
*
,
U
*>::
value
,
bool
>
return
x
==
y
.
get
();
operator
==
(
const
T
*
lhs
,
const
intrusive_ptr
<
U
>&
rhs
)
{
return
lhs
==
rhs
.
get
();
}
}
/// @relates intrusive_ptr
/// @relates intrusive_ptr
template
<
class
T
>
template
<
class
T
,
class
U
>
bool
operator
!=
(
const
intrusive_ptr
<
T
>&
x
,
const
T
*
y
)
{
detail
::
enable_if_t
<
detail
::
is_comparable
<
T
*
,
U
*>::
value
,
bool
>
return
x
.
get
()
!=
y
;
operator
!=
(
const
intrusive_ptr
<
T
>&
lhs
,
const
U
*
rhs
)
{
return
lhs
.
get
()
!=
rhs
;
}
}
/// @relates intrusive_ptr
/// @relates intrusive_ptr
template
<
class
T
>
template
<
class
T
,
class
U
>
bool
operator
!=
(
const
T
*
x
,
const
intrusive_ptr
<
T
>&
y
)
{
detail
::
enable_if_t
<
detail
::
is_comparable
<
T
*
,
U
*>::
value
,
bool
>
return
x
!=
y
.
get
();
operator
!=
(
const
T
*
lhs
,
const
intrusive_ptr
<
U
>&
rhs
)
{
return
lhs
!=
rhs
.
get
();
}
}
// -- comparison to intrusive_pointer ------------------------------------------
// -- comparison to intrusive_pointer ------------------------------------------
...
...
libcaf_core/caf/scheduled_actor.hpp
View file @
cd8363aa
...
@@ -241,6 +241,11 @@ public:
...
@@ -241,6 +241,11 @@ public:
return
*
mailbox_
;
return
*
mailbox_
;
}
}
/// Checks whether this actor is fully initialized.
bool
initialized
()
const
noexcept
{
return
getf
(
is_initialized_flag
);
}
// -- event handlers ---------------------------------------------------------
// -- event handlers ---------------------------------------------------------
/// Sets a custom handler for unexpected messages.
/// Sets a custom handler for unexpected messages.
...
...
libcaf_test/CMakeLists.txt
View file @
cd8363aa
...
@@ -22,6 +22,8 @@ caf_add_component(
...
@@ -22,6 +22,8 @@ caf_add_component(
caf/test/block.cpp
caf/test/block.cpp
caf/test/context.cpp
caf/test/context.cpp
caf/test/factory.cpp
caf/test/factory.cpp
caf/test/fixture/deterministic.cpp
caf/test/fixture/deterministic.test.cpp
caf/test/fixture/flow.cpp
caf/test/fixture/flow.cpp
caf/test/fixture/flow.test.cpp
caf/test/fixture/flow.test.cpp
caf/test/given.cpp
caf/test/given.cpp
...
...
libcaf_test/caf/test/context.cpp
View file @
cd8363aa
...
@@ -15,13 +15,13 @@ void context::on_enter(block* ptr) {
...
@@ -15,13 +15,13 @@ void context::on_enter(block* ptr) {
call_stack
.
push_back
(
ptr
);
call_stack
.
push_back
(
ptr
);
unwind_stack
.
clear
();
unwind_stack
.
clear
();
path
.
push_back
(
ptr
);
path
.
push_back
(
ptr
);
reporter
::
instance
->
begin_step
(
ptr
);
reporter
::
instance
().
begin_step
(
ptr
);
}
}
void
context
::
on_leave
(
block
*
ptr
)
{
void
context
::
on_leave
(
block
*
ptr
)
{
call_stack
.
pop_back
();
call_stack
.
pop_back
();
unwind_stack
.
push_back
(
ptr
);
unwind_stack
.
push_back
(
ptr
);
reporter
::
instance
->
end_step
(
ptr
);
reporter
::
instance
().
end_step
(
ptr
);
}
}
bool
context
::
activated
(
block
*
ptr
)
const
noexcept
{
bool
context
::
activated
(
block
*
ptr
)
const
noexcept
{
...
...
libcaf_test/caf/test/fixture/deterministic.cpp
0 → 100644
View file @
cd8363aa
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/test/fixture/deterministic.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/detail/mailbox_factory.hpp"
#include "caf/detail/source_location.hpp"
#include "caf/detail/sync_request_bouncer.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/scheduled_actor.hpp"
namespace
caf
::
test
::
fixture
{
// -- mailbox ------------------------------------------------------------------
class
deterministic
::
mailbox_impl
:
public
ref_counted
,
public
abstract_mailbox
{
public:
mailbox_impl
(
deterministic
*
fix
,
scheduled_actor
*
owner
)
:
fix_
(
fix
),
owner_
(
owner
)
{
}
intrusive
::
inbox_result
push_back
(
mailbox_element_ptr
ptr
)
override
{
if
(
closed_
)
{
detail
::
sync_request_bouncer
bouncer
{
close_reason_
};
bouncer
(
*
ptr
);
return
intrusive
::
inbox_result
::
queue_closed
;
}
using
event_t
=
deterministic
::
scheduling_event
;
auto
unblocked
=
fix_
->
mail_count
(
owner_
)
==
0
;
auto
event
=
std
::
make_unique
<
event_t
>
(
owner_
,
std
::
move
(
ptr
));
fix_
->
events_
.
push_back
(
std
::
move
(
event
));
return
unblocked
?
intrusive
::
inbox_result
::
unblocked_reader
:
intrusive
::
inbox_result
::
success
;
}
void
push_front
(
mailbox_element_ptr
ptr
)
override
{
using
event_t
=
deterministic
::
scheduling_event
;
auto
event
=
std
::
make_unique
<
event_t
>
(
owner_
,
std
::
move
(
ptr
));
fix_
->
events_
.
emplace_front
(
std
::
move
(
event
));
}
mailbox_element_ptr
pop_front
()
override
{
return
fix_
->
pop_msg_impl
(
owner_
);
}
bool
closed
()
const
noexcept
override
{
return
closed_
;
}
bool
blocked
()
const
noexcept
override
{
return
blocked_
;
}
bool
try_block
()
override
{
blocked_
=
true
;
return
true
;
}
bool
try_unblock
()
override
{
if
(
!
blocked_
)
return
false
;
blocked_
=
false
;
return
true
;
}
size_t
close
(
const
error
&
reason
)
override
{
closed_
=
true
;
close_reason_
=
reason
;
auto
result
=
size_t
{
0
};
auto
envelope
=
fix_
->
pop_msg_impl
(
owner_
);
while
(
envelope
!=
nullptr
)
{
detail
::
sync_request_bouncer
bouncer
{
reason
};
++
result
;
envelope
=
fix_
->
pop_msg_impl
(
owner_
);
}
return
result
;
}
size_t
size
()
override
{
return
fix_
->
mail_count
(
owner_
);
}
void
ref_mailbox
()
noexcept
override
{
ref
();
}
void
deref_mailbox
()
noexcept
override
{
deref
();
}
mailbox_element
*
peek
(
message_id
)
override
{
// Note: this function only exists for backwards compatibility with the old
// unit testing framework. It is not used by the new test runner and thus
// not implemented.
CAF_RAISE_ERROR
(
std
::
logic_error
,
"peek not supported by this mailbox"
);
}
private:
bool
blocked_
=
false
;
bool
closed_
=
false
;
error
close_reason_
;
deterministic
*
fix_
;
scheduled_actor
*
owner_
;
};
class
deterministic
::
mailbox_factory_impl
:
public
detail
::
mailbox_factory
{
public:
explicit
mailbox_factory_impl
(
deterministic
*
fix
)
:
fix_
(
fix
)
{
// nop
}
abstract_mailbox
*
make
(
scheduled_actor
*
owner
)
override
{
return
new
deterministic
::
mailbox_impl
(
fix_
,
owner
);
}
abstract_mailbox
*
make
(
blocking_actor
*
)
override
{
return
nullptr
;
}
private:
deterministic
*
fix_
;
};
// -- scheduler ----------------------------------------------------------------
class
deterministic
::
scheduler_impl
:
public
scheduler
::
abstract_coordinator
{
public:
using
super
=
caf
::
scheduler
::
abstract_coordinator
;
scheduler_impl
(
actor_system
&
sys
,
deterministic
*
fix
)
:
super
(
sys
),
fix_
(
fix
)
{
// nop
}
bool
detaches_utility_actors
()
const
override
{
return
false
;
}
detail
::
test_actor_clock
&
clock
()
noexcept
override
{
return
clock_
;
}
protected:
void
start
()
override
{
// nop
}
void
stop
()
override
{
fix_
->
drop_events
();
}
void
enqueue
(
resumable
*
ptr
)
override
{
using
event_t
=
deterministic
::
scheduling_event
;
using
subtype_t
=
resumable
::
subtype_t
;
switch
(
ptr
->
subtype
())
{
case
subtype_t
:
:
scheduled_actor
:
case
subtype_t
:
:
io_actor
:
{
// Actors put their messages into events_ directly. However, we do run
// them right away if they aren't initialized yet.
auto
dptr
=
static_cast
<
scheduled_actor
*>
(
ptr
);
if
(
!
dptr
->
initialized
())
dptr
->
resume
(
system_
.
dummy_execution_unit
(),
0
);
break
;
}
default:
fix_
->
events_
.
push_back
(
std
::
make_unique
<
event_t
>
(
ptr
,
nullptr
));
}
// Before calling this function, CAF *always* bumps the reference count.
// Hence, we need to release one reference count here.
intrusive_ptr_release
(
ptr
);
}
private:
/// The fixture this scheduler belongs to.
deterministic
*
fix_
;
/// Allows users to fake time at will.
detail
::
test_actor_clock
clock_
;
};
// -- config -------------------------------------------------------------------
deterministic
::
config
::
config
(
deterministic
*
fix
)
{
factory_
=
std
::
make_unique
<
mailbox_factory_impl
>
(
fix
);
module_factories
.
push_back
([
fix
](
actor_system
&
sys
)
->
actor_system
::
module
*
{
return
new
scheduler_impl
(
sys
,
fix
);
});
}
deterministic
::
config
::~
config
()
{
// nop
}
detail
::
mailbox_factory
*
deterministic
::
config
::
mailbox_factory
()
{
return
factory_
.
get
();
}
// -- abstract_message_predicate -----------------------------------------------
deterministic
::
abstract_message_predicate
::~
abstract_message_predicate
()
{
// nop
}
// -- fixture ------------------------------------------------------------------
deterministic
::
deterministic
()
:
cfg
(
this
),
sys
(
cfg
)
{
// nop
}
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.
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_
);
}
}
bool
deterministic
::
prepone_event_impl
(
const
strong_actor_ptr
&
receiver
)
{
actor_predicate
any_sender
{
std
::
ignore
};
message_predicate
any_payload
{
std
::
ignore
};
return
prepone_event_impl
(
receiver
,
any_sender
,
any_payload
);
}
bool
deterministic
::
prepone_event_impl
(
const
strong_actor_ptr
&
receiver
,
actor_predicate
&
sender_pred
,
abstract_message_predicate
&
payload_pred
)
{
if
(
events_
.
empty
()
||
!
receiver
)
return
false
;
auto
first
=
events_
.
begin
();
auto
last
=
events_
.
end
();
auto
i
=
std
::
find_if
(
first
,
last
,
[
&
](
const
auto
&
event
)
{
auto
self
=
actor_cast
<
abstract_actor
*>
(
receiver
);
return
event
->
target
==
static_cast
<
scheduled_actor
*>
(
self
)
&&
sender_pred
(
event
->
item
->
sender
)
&&
payload_pred
(
event
->
item
->
payload
);
});
if
(
i
==
last
)
return
false
;
if
(
i
!=
first
)
{
auto
ptr
=
std
::
move
(
*
i
);
events_
.
erase
(
i
);
events_
.
insert
(
events_
.
begin
(),
std
::
move
(
ptr
));
}
return
true
;
}
deterministic
::
scheduling_event
*
deterministic
::
find_event_impl
(
const
strong_actor_ptr
&
receiver
)
{
if
(
events_
.
empty
()
||
!
receiver
)
return
nullptr
;
auto
last
=
events_
.
end
();
auto
i
=
std
::
find_if
(
events_
.
begin
(),
last
,
[
&
](
const
auto
&
event
)
{
auto
raw_ptr
=
actor_cast
<
abstract_actor
*>
(
receiver
);
return
event
->
target
==
static_cast
<
scheduled_actor
*>
(
raw_ptr
);
});
if
(
i
!=
last
)
return
i
->
get
();
return
nullptr
;
}
mailbox_element_ptr
deterministic
::
pop_msg_impl
(
scheduled_actor
*
receiver
)
{
auto
pred
=
[
&
](
const
auto
&
event
)
{
return
event
->
target
==
receiver
;
};
auto
first
=
events_
.
begin
();
auto
last
=
events_
.
end
();
auto
i
=
std
::
find_if
(
first
,
last
,
pred
);
if
(
i
==
last
)
return
nullptr
;
auto
result
=
std
::
move
((
*
i
)
->
item
);
events_
.
erase
(
i
);
return
result
;
}
size_t
deterministic
::
mail_count
(
scheduled_actor
*
receiver
)
{
if
(
receiver
==
nullptr
)
return
0
;
auto
pred
=
[
&
](
const
auto
&
event
)
{
return
event
->
target
==
receiver
;
};
return
std
::
count_if
(
events_
.
begin
(),
events_
.
end
(),
pred
);
}
size_t
deterministic
::
mail_count
(
const
strong_actor_ptr
&
receiver
)
{
auto
raw_ptr
=
actor_cast
<
abstract_actor
*>
(
receiver
);
return
mail_count
(
dynamic_cast
<
scheduled_actor
*>
(
raw_ptr
));
}
bool
deterministic
::
dispatch_message
()
{
if
(
events_
.
empty
())
return
false
;
if
(
events_
.
front
()
->
item
==
nullptr
)
{
// Regular resumable.
auto
ev
=
std
::
move
(
events_
.
front
());
events_
.
pop_front
();
ev
->
target
->
resume
(
sys
.
dummy_execution_unit
(),
0
);
return
true
;
}
// Actor: we simply resume the next actor and it will pick up its message.
auto
next
=
events_
.
front
()
->
target
;
next
->
resume
(
sys
.
dummy_execution_unit
(),
1
);
return
true
;
}
size_t
deterministic
::
dispatch_messages
()
{
size_t
result
=
0
;
while
(
dispatch_message
())
++
result
;
return
result
;
}
}
// namespace caf::test
libcaf_test/caf/test/fixture/deterministic.hpp
0 → 100644
View file @
cd8363aa
This diff is collapsed.
Click to expand it.
libcaf_test/caf/test/fixture/deterministic.test.cpp
0 → 100644
View file @
cd8363aa
This diff is collapsed.
Click to expand it.
libcaf_test/caf/test/reporter.cpp
View file @
cd8363aa
...
@@ -22,8 +22,6 @@ reporter::~reporter() {
...
@@ -22,8 +22,6 @@ reporter::~reporter() {
// nop
// nop
}
}
reporter
*
reporter
::
instance
;
namespace
{
namespace
{
/// Implements a mini-DSL for colored output:
/// Implements a mini-DSL for colored output:
...
@@ -334,8 +332,8 @@ public:
...
@@ -334,8 +332,8 @@ public:
set_live
();
set_live
();
format_to
(
colored
(),
format_to
(
colored
(),
"{0:{1}}$R(error): check failed
\n
"
"{0:{1}}$R(error): check failed
\n
"
"{0:{1}} loc: $C({
3}):$Y({4
})$0
\n
"
"{0:{1}} loc: $C({
2}):$Y({3
})$0
\n
"
"{0:{1}} check: {
5
}
\n
"
,
"{0:{1}} check: {
4
}
\n
"
,
' '
,
indent_
,
location
.
file_name
(),
location
.
line
(),
arg
);
' '
,
indent_
,
location
.
file_name
(),
location
.
line
(),
arg
);
}
}
...
@@ -388,8 +386,10 @@ public:
...
@@ -388,8 +386,10 @@ public:
' '
,
indent_
,
location
.
file_name
(),
location
.
line
(),
msg
);
' '
,
indent_
,
location
.
file_name
(),
location
.
line
(),
msg
);
}
}
void
verbosity
(
unsigned
level
)
override
{
unsigned
verbosity
(
unsigned
level
)
override
{
auto
result
=
level_
;
level_
=
level
;
level_
=
level
;
return
result
;
}
}
void
no_colors
(
bool
new_value
)
override
{
void
no_colors
(
bool
new_value
)
override
{
...
@@ -470,8 +470,20 @@ private:
...
@@ -470,8 +470,20 @@ private:
context_ptr
current_ctx_
;
context_ptr
current_ctx_
;
};
};
reporter
*
global_instance
;
}
// namespace
}
// 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
()
{
std
::
unique_ptr
<
reporter
>
reporter
::
make_default
()
{
return
std
::
make_unique
<
default_reporter
>
();
return
std
::
make_unique
<
default_reporter
>
();
}
}
...
...
libcaf_test/caf/test/reporter.hpp
View file @
cd8363aa
...
@@ -75,7 +75,8 @@ public:
...
@@ -75,7 +75,8 @@ public:
info
(
std
::
string_view
msg
,
const
detail
::
source_location
&
location
)
info
(
std
::
string_view
msg
,
const
detail
::
source_location
&
location
)
=
0
;
=
0
;
virtual
void
verbosity
(
unsigned
level
)
=
0
;
/// Sets the verbosity level of the reporter and returns the previous value.
virtual
unsigned
verbosity
(
unsigned
level
)
=
0
;
/// Sets whether the reporter disables colored output even when writing to a
/// Sets whether the reporter disables colored output even when writing to a
/// TTY.
/// TTY.
...
@@ -93,8 +94,11 @@ public:
...
@@ -93,8 +94,11 @@ public:
/// Returns statistics for the entire run.
/// Returns statistics for the entire run.
virtual
stats
total_stats
()
=
0
;
virtual
stats
total_stats
()
=
0
;
/// Stores a pointer to the currently active reporter.
/// Returns the registered reporter instance.
static
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.
/// Creates a default reporter that writes to the standard output.
static
std
::
unique_ptr
<
reporter
>
make_default
();
static
std
::
unique_ptr
<
reporter
>
make_default
();
...
...
libcaf_test/caf/test/runnable.cpp
View file @
cd8363aa
...
@@ -10,13 +10,23 @@
...
@@ -10,13 +10,23 @@
#include "caf/test/scope.hpp"
#include "caf/test/scope.hpp"
#include "caf/test/test.hpp"
#include "caf/test/test.hpp"
#include "caf/detail/scope_guard.hpp"
namespace
caf
::
test
{
namespace
caf
::
test
{
namespace
{
thread_local
runnable
*
current_runnable
;
}
// namespace
runnable
::~
runnable
()
{
runnable
::~
runnable
()
{
// nop
// nop
}
}
void
runnable
::
run
()
{
void
runnable
::
run
()
{
current_runnable
=
this
;
auto
guard
=
detail
::
make_scope_guard
([]
{
current_runnable
=
nullptr
;
});
switch
(
root_type_
)
{
switch
(
root_type_
)
{
case
block_type
:
:
scenario
:
case
block_type
:
:
scenario
:
if
(
auto
guard
=
ctx_
->
get
<
scenario
>
(
0
,
description_
,
loc_
)
->
commit
())
{
if
(
auto
guard
=
ctx_
->
get
<
scenario
>
(
0
,
description_
,
loc_
)
->
commit
())
{
...
@@ -41,13 +51,20 @@ void runnable::run() {
...
@@ -41,13 +51,20 @@ void runnable::run() {
bool
runnable
::
check
(
bool
value
,
const
detail
::
source_location
&
location
)
{
bool
runnable
::
check
(
bool
value
,
const
detail
::
source_location
&
location
)
{
if
(
value
)
{
if
(
value
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
}
else
{
}
else
{
reporter
::
instance
->
fail
(
"should be true"
,
location
);
reporter
::
instance
().
fail
(
"should be true"
,
location
);
}
}
return
value
;
return
value
;
}
}
runnable
&
runnable
::
current
()
{
auto
ptr
=
current_runnable
;
if
(
!
ptr
)
CAF_RAISE_ERROR
(
std
::
logic_error
,
"no current runnable"
);
return
*
ptr
;
}
block
&
runnable
::
current_block
()
{
block
&
runnable
::
current_block
()
{
if
(
ctx_
->
call_stack
.
empty
())
if
(
ctx_
->
call_stack
.
empty
())
CAF_RAISE_ERROR
(
std
::
logic_error
,
"no current block"
);
CAF_RAISE_ERROR
(
std
::
logic_error
,
"no current block"
);
...
...
libcaf_test/caf/test/runnable.hpp
View file @
cd8363aa
...
@@ -12,8 +12,10 @@
...
@@ -12,8 +12,10 @@
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/detail/format.hpp"
#include "caf/detail/format.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/detail/source_location.hpp"
#include "caf/detail/source_location.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/raise_error.hpp"
#include <string_view>
#include <string_view>
...
@@ -42,14 +44,26 @@ public:
...
@@ -42,14 +44,26 @@ public:
/// Runs the next branch of the test.
/// Runs the next branch of the test.
void
run
();
void
run
();
/// Generates a message with the INFO severity level.
template
<
class
...
Ts
>
[[
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
);
}
else
{
reporter
::
instance
().
fail
(
fwl
.
value
,
fwl
.
location
);
}
CAF_RAISE_ERROR
(
std
::
logic_error
,
"requirement failed: abort test"
);
}
/// Generates a message with the INFO severity level.
/// Generates a message with the INFO severity level.
template
<
class
...
Ts
>
template
<
class
...
Ts
>
void
info
(
detail
::
format_string_with_location
fwl
,
Ts
&&
...
xs
)
{
void
info
(
detail
::
format_string_with_location
fwl
,
Ts
&&
...
xs
)
{
if
constexpr
(
sizeof
...(
Ts
)
>
0
)
{
if
constexpr
(
sizeof
...(
Ts
)
>
0
)
{
auto
msg
=
detail
::
format
(
fwl
.
value
,
std
::
forward
<
Ts
>
(
xs
)...);
auto
msg
=
detail
::
format
(
fwl
.
value
,
std
::
forward
<
Ts
>
(
xs
)...);
reporter
::
instance
->
info
(
msg
,
fwl
.
location
);
reporter
::
instance
().
info
(
msg
,
fwl
.
location
);
}
else
{
}
else
{
reporter
::
instance
->
info
(
fwl
.
value
,
fwl
.
location
);
reporter
::
instance
().
info
(
fwl
.
value
,
fwl
.
location
);
}
}
}
}
...
@@ -60,11 +74,11 @@ public:
...
@@ -60,11 +74,11 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
==
rhs
)
{
if
(
lhs
==
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
eq
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
eq
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
...
@@ -75,11 +89,11 @@ public:
...
@@ -75,11 +89,11 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
!=
rhs
)
{
if
(
lhs
!=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
ne
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
ne
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
...
@@ -90,11 +104,11 @@ public:
...
@@ -90,11 +104,11 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
<
rhs
)
{
if
(
lhs
<
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
lt
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
lt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
...
@@ -105,11 +119,11 @@ public:
...
@@ -105,11 +119,11 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
<=
rhs
)
{
if
(
lhs
<=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
le
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
le
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
...
@@ -120,11 +134,11 @@ public:
...
@@ -120,11 +134,11 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
>
rhs
)
{
if
(
lhs
>
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
gt
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
gt
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
...
@@ -135,58 +149,118 @@ public:
...
@@ -135,58 +149,118 @@ public:
=
detail
::
source_location
::
current
())
{
=
detail
::
source_location
::
current
())
{
assert_save_comparison
<
T0
,
T1
>
();
assert_save_comparison
<
T0
,
T1
>
();
if
(
lhs
>=
rhs
)
{
if
(
lhs
>=
rhs
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
true
;
return
true
;
}
}
reporter
::
instance
->
fail
(
binary_predicate
::
ge
,
stringify
(
lhs
),
reporter
::
instance
().
fail
(
binary_predicate
::
ge
,
stringify
(
lhs
),
stringify
(
rhs
),
location
);
stringify
(
rhs
),
location
);
return
false
;
return
false
;
}
}
/// Checks whether `value` is `true`.
bool
check
(
bool
value
,
const
detail
::
source_location
&
location
bool
check
(
bool
value
,
const
detail
::
source_location
&
location
=
detail
::
source_location
::
current
());
=
detail
::
source_location
::
current
());
/// Returns the `runnable` instance that is currently running.
static
runnable
&
current
();
block
&
current_block
();
block
&
current_block
();
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
lvl_guard
=
detail
::
make_scope_guard
([
&
]
{
rep
.
verbosity
(
lvl
);
});
expr
();
}
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
});
}
else
{
reporter
::
instance
().
fail
(
"nested check should fail"
,
location
);
rep
.
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
}
}
#ifdef CAF_ENABLE_EXCEPTIONS
#ifdef CAF_ENABLE_EXCEPTIONS
template
<
class
Exception
=
void
,
class
CodeBlock
>
void
check_throws
(
CodeBlock
&&
fn
,
const
detail
::
source_location
&
location
/// Checks whether `expr()` throws an exception of type `Exception`.
=
detail
::
source_location
::
current
())
{
template
<
class
Exception
=
void
,
class
Expr
>
void
check_throws
(
Expr
&&
expr
,
const
detail
::
source_location
&
location
=
detail
::
source_location
::
current
())
{
if
constexpr
(
std
::
is_same_v
<
Exception
,
void
>
)
{
if
constexpr
(
std
::
is_same_v
<
Exception
,
void
>
)
{
try
{
try
{
fn
();
expr
();
}
catch
(...)
{
}
catch
(...)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
;
return
;
}
}
reporter
::
instance
->
fail
(
"throws"
,
location
);
reporter
::
instance
().
fail
(
"throws"
,
location
);
}
else
{
}
else
{
try
{
try
{
fn
();
expr
();
}
catch
(
const
Exception
&
)
{
}
catch
(
const
Exception
&
)
{
reporter
::
instance
->
pass
(
location
);
reporter
::
instance
().
pass
(
location
);
return
;
return
;
}
catch
(...)
{
}
catch
(...)
{
reporter
::
instance
->
fail
(
"throws Exception"
,
location
);
reporter
::
instance
().
fail
(
"throws Exception"
,
location
);
return
;
return
;
}
}
reporter
::
instance
->
fail
(
"throws Exception"
,
location
);
reporter
::
instance
().
fail
(
"throws Exception"
,
location
);
}
}
}
}
#endif
template
<
class
Expr
>
/// Checks whether `expr()` throws an exception of type `Exception` and
void
should_fail
(
Expr
&&
expr
,
const
caf
::
detail
::
source_location
&
location
/// increases the failure count.
=
caf
::
detail
::
source_location
::
current
())
{
template
<
class
Exception
=
void
,
class
Expr
>
auto
*
rep
=
reporter
::
instance
;
void
should_fail_with_exception
(
Expr
&&
expr
,
auto
before
=
rep
->
test_stats
();
const
caf
::
detail
::
source_location
&
location
expr
();
=
caf
::
detail
::
source_location
::
current
())
{
auto
after
=
rep
->
test_stats
();
auto
&
rep
=
reporter
::
instance
();
check_eq
(
before
.
passed
,
after
.
passed
,
location
);
auto
before
=
rep
.
test_stats
();
if
(
check_eq
(
before
.
failed
+
1
,
after
.
failed
,
location
))
auto
lvl
=
rep
.
verbosity
(
CAF_LOG_LEVEL_QUIET
);
rep
->
test_stats
({
before
.
passed
+
1
,
before
.
failed
});
auto
caught
=
false
;
if
constexpr
(
std
::
is_same_v
<
Exception
,
void
>
)
{
try
{
expr
();
}
catch
(...)
{
caught
=
true
;
}
}
else
{
try
{
expr
();
}
catch
(
const
Exception
&
)
{
caught
=
true
;
}
catch
(...)
{
// TODO: print error message
}
}
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
});
}
else
{
if
(
!
caught
)
{
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
);
}
rep
.
test_stats
({
before
.
passed
,
before
.
failed
+
1
});
}
}
}
#endif
protected:
protected:
context_ptr
ctx_
;
context_ptr
ctx_
;
std
::
string_view
description_
;
std
::
string_view
description_
;
...
...
libcaf_test/caf/test/runner.cpp
View file @
cd8363aa
...
@@ -131,7 +131,7 @@ runner::runner() : suites_(caf::test::registry::suites()) {
...
@@ -131,7 +131,7 @@ runner::runner() : suites_(caf::test::registry::suites()) {
int
runner
::
run
(
int
argc
,
char
**
argv
)
{
int
runner
::
run
(
int
argc
,
char
**
argv
)
{
auto
default_reporter
=
reporter
::
make_default
();
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
)
{
if
(
auto
[
ok
,
help_printed
]
=
parse_cli
(
argc
,
argv
);
!
ok
)
{
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
}
else
if
(
help_printed
)
{
}
else
if
(
help_printed
)
{
...
@@ -240,7 +240,7 @@ runner::parse_cli_result runner::parse_cli(int argc, char** argv) {
...
@@ -240,7 +240,7 @@ runner::parse_cli_result runner::parse_cli(int argc, char** argv) {
*
verbosity
);
*
verbosity
);
return
{
false
,
true
};
return
{
false
,
true
};
}
}
reporter
::
instance
->
verbosity
(
*
level
);
reporter
::
instance
().
verbosity
(
*
level
);
}
}
return
{
true
,
false
};
return
{
true
,
false
};
}
}
...
...
libcaf_test/caf/test/test.test.cpp
View file @
cd8363aa
...
@@ -8,8 +8,8 @@
...
@@ -8,8 +8,8 @@
using
caf
::
test
::
block_type
;
using
caf
::
test
::
block_type
;
TEST
(
"tests can contain different types of checks"
)
{
TEST
(
"tests can contain different types of checks"
)
{
auto
*
rep
=
caf
::
test
::
reporter
::
instance
;
auto
&
rep
=
caf
::
test
::
reporter
::
instance
()
;
auto
stats
=
rep
->
test_stats
();
auto
stats
=
rep
.
test_stats
();
SECTION
(
"check_ne checks for inequality"
)
{
SECTION
(
"check_ne checks for inequality"
)
{
check_ne
(
0
,
1
);
check_ne
(
0
,
1
);
should_fail
([
this
]()
{
check_ne
(
0
,
0
);
});
should_fail
([
this
]()
{
check_ne
(
0
,
0
);
});
...
@@ -38,16 +38,16 @@ TEST("tests can contain different types of checks") {
...
@@ -38,16 +38,16 @@ TEST("tests can contain different types of checks") {
should_fail
([
this
]()
{
check_lt
(
1
,
1
);
});
should_fail
([
this
]()
{
check_lt
(
1
,
1
);
});
should_fail
([
this
]()
{
check_lt
(
2
,
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"
)
{
TEST
(
"failed checks increment the failed counter"
)
{
check_eq
(
1
,
2
);
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
.
passed
,
0u
);
check_eq
(
stats
.
failed
,
1u
);
check_eq
(
stats
.
failed
,
1u
);
info
(
"reset error count to not fail the test"
);
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"
)
{
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