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
6eff7c2b
Commit
6eff7c2b
authored
Mar 13, 2015
by
Dominik Charousset
Committed by
Marian Triebe
Apr 22, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor unit testing framework, fix CMake setup
parent
58c573fe
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
690 additions
and
647 deletions
+690
-647
CMakeLists.txt
CMakeLists.txt
+65
-10
libcaf_core/test/atom.cpp
libcaf_core/test/atom.cpp
+70
-65
libcaf_core/test/extract.cpp
libcaf_core/test/extract.cpp
+79
-0
libcaf_test/CMakeLists.txt
libcaf_test/CMakeLists.txt
+0
-72
libcaf_test/caf/test/unit_test.hpp
libcaf_test/caf/test/unit_test.hpp
+215
-126
libcaf_test/caf/test/unit_test_impl.hpp
libcaf_test/caf/test/unit_test_impl.hpp
+261
-105
libcaf_test/src/caf-test.cpp
libcaf_test/src/caf-test.cpp
+0
-0
libcaf_test/test.cpp
libcaf_test/test.cpp
+0
-89
libcaf_test/test/ping_pong.cpp
libcaf_test/test/ping_pong.cpp
+0
-143
libcaf_test/test/ping_pong.hpp
libcaf_test/test/ping_pong.hpp
+0
-37
No files found.
CMakeLists.txt
View file @
6eff7c2b
...
...
@@ -279,13 +279,31 @@ add_custom_target(uninstall
# path to caf core & io headers
set
(
LIBCAF_INCLUDE_DIRS
<<<<<<< HEAD
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/libcaf_core"
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/libcaf_io"
)
=======
"
${
CMAKE_SOURCE_DIR
}
/libcaf_test"
"
${
CMAKE_SOURCE_DIR
}
/libcaf_core"
"
${
CMAKE_SOURCE_DIR
}
/libcaf_io"
)
>>>>>>> Refactor unit testing framework, fix CMake setup
# path to caf opencl headers
if
(
EXISTS
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/libcaf_opencl/CMakeLists.txt"
)
set
(
LIBCAF_INCLUDE_DIRS
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/libcaf_opencl/"
"
${
LIBCAF_INCLUDE_DIRS
}
"
)
endif
()
# enable tests if not disabled
if
(
NOT CAF_NO_UNIT_TESTS
)
enable_testing
()
macro
(
add_unit_tests globstr
)
file
(
GLOB_RECURSE tests
"
${
globstr
}
"
)
set
(
CAF_ALL_UNIT_TESTS
${
CAF_ALL_UNIT_TESTS
}
${
tests
}
)
endmacro
()
else
()
macro
(
add_unit_tests globstr
)
# do nothing (unit tests disabled)
endmacro
()
endif
()
# all projects need the headers of the core components
include_directories
(
"
${
LIBCAF_INCLUDE_DIRS
}
"
)
...
...
@@ -294,8 +312,14 @@ include_directories("${LIBCAF_INCLUDE_DIRS}")
# add subprojects #
################################################################################
# build libcaf_test if not being told otherwise
if
(
NOT CAF_NO_UNIT_TESTS
)
#message(STATUS "Enter subdirectory libcaf_test")
#add_subdirectory(libcaf_test)
endif
()
# core library
add_subdirectory
(
libcaf_core
)
add_unit_tests
(
"libcaf_core/test/*.cpp"
)
# set core lib for sub directories
if
(
NOT CAF_BUILD_STATIC_ONLY
)
set
(
LIBCAF_CORE_LIBRARY libcaf_core_shared
)
...
...
@@ -326,15 +350,6 @@ add_dependencies(libcaf_io libcaf_core)
set
(
LIBCAF_LIBRARIES
"
${
LIBCAF_CORE_LIBRARY
}
"
"
${
LIBCAF_IO_LIBRARY
}
"
"
${
LIBCAF_OPENCL_LIBRARY
}
"
)
# add unit tests if not being told otherwise
if
(
NOT CAF_NO_UNIT_TESTS
)
enable_testing
()
add_subdirectory
(
libcaf_test
)
add_dependencies
(
all_unit_tests libcaf_io
)
if
(
NOT CAF_NO_OPENCL AND EXISTS
"
${
CMAKE_SOURCE_DIR
}
/libcaf_opencl/CMakeLists.txt"
)
add_subdirectory
(
libcaf_opencl/unit_testing
)
endif
()
endif
()
# build examples if not being told otherwise
if
(
NOT CAF_NO_EXAMPLES
)
add_subdirectory
(
examples
)
...
...
@@ -342,7 +357,6 @@ if(NOT CAF_NO_EXAMPLES)
if
(
NOT CAF_NO_OPENCL
AND EXISTS
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/libcaf_opencl/CMakeLists.txt"
)
add_subdirectory
(
libcaf_opencl/examples
)
add_dependencies
(
opencl_examples libcaf_opencl
)
endif
()
endif
()
# build RIAC if not being told otherwise
...
...
@@ -404,6 +418,47 @@ else()
endif
()
################################################################################
# unit tests setup #
################################################################################
if
(
NOT CAF_NO_UNIT_TESTS
)
add_executable
(
caf-test
libcaf_test/src/caf-test.cpp
libcaf_test/caf/test/unit_test.hpp
libcaf_test/caf/test/unit_test_impl.hpp
${
CAF_ALL_UNIT_TESTS
}
)
target_link_libraries
(
caf-test
${
LD_FLAGS
}
${
LIBCAF_LIBRARIES
}
${
PTHREAD_LIBRARIES
}
)
add_custom_target
(
all_unit_tests
)
add_dependencies
(
caf-test all_unit_tests
)
# enumerate all test suites.
foreach
(
test
${
CAF_ALL_UNIT_TESTS
}
)
file
(
STRINGS
${
test
}
contents
)
foreach
(
line
${
contents
}
)
if
(
"
${
line
}
"
MATCHES
"CAF_SUITE (.*)"
)
string
(
REGEX REPLACE
".* CAF_SUITE (.*)"
"
\\
1"
suite
${
line
}
)
list
(
APPEND suites
${
suite
}
)
endif
()
endforeach
()
endforeach
()
list
(
REMOVE_DUPLICATES suites
)
# creates one CMake test per test suite.
macro
(
make_test suite
)
string
(
REPLACE
" "
"_"
test_name
${
suite
}
)
set
(
caf_test
${
EXECUTABLE_OUTPUT_PATH
}
/caf-test
)
add_test
(
${
test_name
}
${
caf_test
}
-n -v 5 -s
"
${
suite
}
"
${
ARGN
}
)
endmacro
()
list
(
LENGTH suites num_suites
)
message
(
STATUS
"Found
${
num_suites
}
test suites"
)
foreach
(
suite
${
suites
}
)
make_test
(
"
${
suite
}
"
)
endforeach
()
endif
()
################################################################################
# LateX setup #
################################################################################
...
...
unit_testing/test_
atom.cpp
→
libcaf_core/test/
atom.cpp
View file @
6eff7c2b
#include <string>
#include <typeinfo>
#include <iostream>
#include "test.hpp"
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#
include "caf/all.hpp"
#include "caf/
scoped_actor
.hpp"
#
define CAF_SUITE atom
#include "caf/
test/unit_test
.hpp"
namespace
caf
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
const
atom_value
&
a
)
{
return
(
out
<<
to_string
(
a
));
}
}
// namespace caf
#include <string>
using
std
::
cout
;
using
std
::
endl
;
using
std
::
string
;
#include "caf/all.hpp"
using
namespace
caf
;
namespace
{
constexpr
auto
s_foo
=
atom
(
"FooBar"
);
using
abc_atom
=
atom_constant
<
atom
(
"abc"
)
>
;
}
using
testee
=
typed_actor
<
replies_to
<
abc_atom
>::
with
<
int
>>
;
testee
::
behavior_type
testee_impl
(
testee
::
pointer
self
)
{
return
{
[
=
](
abc_atom
)
{
CAF_CHECKPOINT
();
self
->
quit
();
return
42
;
}
};
}
void
test_typed_atom_interface
()
{
CAF_CHECKPOINT
();
scoped_actor
self
;
auto
tst
=
spawn_typed
(
testee_impl
);
self
->
sync_send
(
tst
,
abc_atom
::
value
).
await
(
[](
int
i
)
{
CAF_CHECK_EQUAL
(
i
,
42
);
},
CAF_UNEXPECTED_MSG_CB_REF
(
self
)
);
}
}
// namespace <anonymous>
template
<
atom_value
AtomValue
,
class
...
Types
>
void
foo
()
{
CAF_PRINT
(
"foo("
<<
static_cast
<
uint64_t
>
(
AtomValue
)
<<
" = "
<<
to_string
(
AtomValue
)
<<
")"
);
CAF_TEST
(
basics
)
{
// check if there are leading bits that distinguish "zzz" and "000 "
CAF_CHECK
(
atom
(
"zzz"
)
!=
atom
(
"000 "
));
// check if there are leading bits that distinguish "abc" and " abc"
CAF_CHECK
(
atom
(
"abc"
)
!=
atom
(
" abc"
));
// 'illegal' characters are mapped to whitespaces
CAF_CHECK_EQUAL
(
atom
(
" "
),
atom
(
"@!?"
));
// check to_string impl.
CAF_CHECK_EQUAL
(
to_string
(
s_foo
),
"FooBar"
);
}
struct
send_to_self
{
...
...
@@ -65,16 +55,7 @@ struct send_to_self {
blocking_actor
*
m_self
;
};
int
main
()
{
CAF_TEST
(
test_atom
);
// check if there are leading bits that distinguish "zzz" and "000 "
CAF_CHECK_NOT_EQUAL
(
atom
(
"zzz"
),
atom
(
"000 "
));
// check if there are leading bits that distinguish "abc" and " abc"
CAF_CHECK_NOT_EQUAL
(
atom
(
"abc"
),
atom
(
" abc"
));
// 'illegal' characters are mapped to whitespaces
CAF_CHECK_EQUAL
(
atom
(
" "
),
atom
(
"@!?"
));
// check to_string impl.
CAF_CHECK_EQUAL
(
to_string
(
s_foo
),
"FooBar"
);
CAF_TEST
(
receive_atoms
)
{
scoped_actor
self
;
send_to_self
f
{
self
.
get
()};
f
(
atom
(
"foo"
),
static_cast
<
uint32_t
>
(
42
));
...
...
@@ -83,21 +64,18 @@ int main() {
f
(
atom
(
"a"
),
atom
(
"b"
),
atom
(
"c"
),
23.
f
);
bool
matched_pattern
[
3
]
=
{
false
,
false
,
false
};
int
i
=
0
;
CAF_
CHECKPOINT
(
);
CAF_
TEST_VERBOSE
(
"start receive loop"
);
for
(
i
=
0
;
i
<
3
;
++
i
)
{
self
->
receive
(
on
(
atom
(
"foo"
),
arg_match
)
>>
[
&
](
uint32_t
value
)
{
CAF_CHECKPOINT
();
matched_pattern
[
0
]
=
true
;
CAF_CHECK_EQUAL
(
value
,
42
);
},
on
(
atom
(
":Attach"
),
atom
(
":Baz"
),
arg_match
)
>>
[
&
](
const
string
&
str
)
{
CAF_CHECKPOINT
();
on
(
atom
(
":Attach"
),
atom
(
":Baz"
),
arg_match
)
>>
[
&
](
const
std
::
string
&
str
)
{
matched_pattern
[
1
]
=
true
;
CAF_CHECK_EQUAL
(
str
,
"cstring"
);
},
on
(
atom
(
"a"
),
atom
(
"b"
),
atom
(
"c"
),
arg_match
)
>>
[
&
](
float
value
)
{
CAF_CHECKPOINT
();
matched_pattern
[
2
]
=
true
;
CAF_CHECK_EQUAL
(
value
,
23.
f
);
});
...
...
@@ -105,8 +83,12 @@ int main() {
CAF_CHECK
(
matched_pattern
[
0
]
&&
matched_pattern
[
1
]
&&
matched_pattern
[
2
]);
self
->
receive
(
// "erase" message { atom("b"), atom("a"), atom("c"), 23.f }
others
>>
CAF_CHECKPOINT_CB
(),
after
(
std
::
chrono
::
seconds
(
0
))
>>
CAF_UNEXPECTED_TOUT_CB
()
others
>>
[]
{
CAF_TEST_VERBOSE
(
"drain mailbox"
);
},
after
(
std
::
chrono
::
seconds
(
0
))
>>
[]
{
CAF_TEST_ERROR
(
"mailbox empty"
);
}
);
atom_value
x
=
atom
(
"abc"
);
atom_value
y
=
abc_atom
::
value
;
...
...
@@ -114,10 +96,33 @@ int main() {
auto
msg
=
make_message
(
abc_atom
());
self
->
send
(
self
,
msg
);
self
->
receive
(
on
(
atom
(
"abc"
))
>>
CAF_CHECKPOINT_CB
(),
others
>>
CAF_UNEXPECTED_MSG_CB_REF
(
self
)
on
(
atom
(
"abc"
))
>>
[]
{
CAF_TEST_VERBOSE
(
"received 'abc'"
);
},
others
>>
[]
{
CAF_TEST_ERROR
(
"unexpected message"
);
}
);
}
using
testee
=
typed_actor
<
replies_to
<
abc_atom
>::
with
<
int
>>
;
testee
::
behavior_type
testee_impl
(
testee
::
pointer
self
)
{
return
{
[
=
](
abc_atom
)
{
CAF_TEST_VERBOSE
(
"received abc_atom"
);
self
->
quit
();
return
42
;
}
};
}
CAF_TEST
(
sync_send_atom_constants
)
{
scoped_actor
self
;
auto
tst
=
spawn_typed
(
testee_impl
);
self
->
sync_send
(
tst
,
abc_atom
::
value
).
await
(
[](
int
i
)
{
CAF_CHECK_EQUAL
(
i
,
42
);
}
);
test_typed_atom_interface
();
shutdown
();
return
CAF_TEST_RESULT
();
}
libcaf_
test/test/example
.cpp
→
libcaf_
core/test/extract
.cpp
View file @
6eff7c2b
...
...
@@ -17,19 +17,63 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE "example"
#define CAF_SUITE extract
#include "caf/test/unit_test.hpp"
CAF_TEST
(
"foo"
)
{
CAF_CHECK
(
true
);
CAF_CHECK
(
!
false
);
#include <string>
#include <vector>
#include "caf/all.hpp"
using
namespace
caf
;
using
std
::
string
;
CAF_TEST
(
simple_ints
)
{
auto
msg
=
make_message
(
1
,
2
,
3
);
auto
one
=
on
(
1
)
>>
[]
{
};
auto
two
=
on
(
2
)
>>
[]
{
};
auto
three
=
on
(
3
)
>>
[]
{
};
auto
skip_two
=
[](
int
i
)
->
optional
<
skip_message_t
>
{
if
(
i
==
2
)
{
return
skip_message
();
}
return
none
;
};
CAF_CHECK_EQUAL
(
msg
.
extract
(
one
),
make_message
(
2
,
3
));
CAF_CHECK_EQUAL
(
msg
.
extract
(
two
),
make_message
(
1
,
3
));
CAF_CHECK_EQUAL
(
msg
.
extract
(
three
),
make_message
(
1
,
2
));
CAF_CHECK_EQUAL
(
msg
.
extract
(
skip_two
),
make_message
(
2
));
}
CAF_TEST
(
type_sequences
)
{
auto
_64
=
uint64_t
{
64
};
auto
msg
=
make_message
(
1.0
,
2.
f
,
"str"
,
42
,
_64
);
auto
df
=
[](
double
,
float
)
{
};
auto
fs
=
[](
float
,
const
string
&
)
{
};
auto
iu
=
[](
int
,
uint64_t
)
{
};
CAF_CHECK_EQUAL
(
msg
.
extract
(
df
),
make_message
(
"str"
,
42
,
_64
));
CAF_CHECK_EQUAL
(
msg
.
extract
(
fs
),
make_message
(
1.0
,
42
,
_64
));
CAF_CHECK_EQUAL
(
msg
.
extract
(
iu
),
make_message
(
1.0
,
2.
f
,
"str"
));
}
CAF_TEST
(
"bar"
)
{
auto
i
=
42
;
i
*=
2
;
CAF_REQUIRE
(
i
==
84
);
CAF_TEST
(
cli_args
)
{
std
::
vector
<
string
>
args
{
"-n"
,
"-v"
,
"5"
,
"--out-file=/dev/null"
};
int
verbosity
=
0
;
string
output_file
;
string
input_file
;
auto
res
=
message_builder
(
args
.
begin
(),
args
.
end
()).
extract_opts
({
{
"no-colors,n"
,
"disable colors"
},
{
"out-file,o"
,
"redirect output"
,
output_file
},
{
"in-file,i"
,
"read from file"
,
input_file
},
{
"verbosity,v"
,
"1-5"
,
verbosity
}
});
CAF_CHECK_EQUAL
(
res
.
remainder
.
size
(),
0
);
CAF_CHECK_EQUAL
(
to_string
(
res
.
remainder
),
to_string
(
message
{}));
CAF_CHECK_EQUAL
(
res
.
opts
.
count
(
"no-colors"
),
1
);
CAF_CHECK_EQUAL
(
res
.
opts
.
count
(
"verbosity"
),
1
);
CAF_CHECK_EQUAL
(
res
.
opts
.
count
(
"out-file"
),
1
);
CAF_CHECK_EQUAL
(
res
.
opts
.
count
(
"in-file"
),
0
);
CAF_CHECK_EQUAL
(
output_file
,
"/dev/null"
);
CAF_CHECK_EQUAL
(
input_file
,
""
);
}
libcaf_test/CMakeLists.txt
deleted
100644 → 0
View file @
58c573fe
cmake_minimum_required
(
VERSION 2.8
)
project
(
caf_test C CXX
)
file
(
GLOB LIBCAF_TEST_HDRS
"caf/test/*.hpp"
)
file
(
GLOB_RECURSE LIBCAF_TEST_SRCS src/unit_test.cpp
)
# build shared library if not compiling static only
if
(
NOT CAF_BUILD_STATIC_ONLY
)
add_library
(
libcaf_test SHARED
${
LIBCAF_TEST_SRCS
}
${
LIBCAF_TEST_HDRS
}
)
target_link_libraries
(
libcaf_test
${
LD_FLAGS
}
)
set
(
LIBRARY_SOVERSION
${
CAF_VERSION_MAJOR
}
)
set_target_properties
(
libcaf_test
PROPERTIES
SOVERSION
${
LIBRARY_SOVERSION
}
VERSION
${
CAF_VERSION
}
OUTPUT_NAME caf_test
)
if
(
NOT WIN32
)
install
(
TARGETS libcaf_test LIBRARY DESTINATION lib
)
endif
()
endif
()
# build static library only if --build-static or --build-static-only was set
if
(
CAF_BUILD_STATIC_ONLY OR CAF_BUILD_STATIC
)
add_library
(
libcaf_testStatic STATIC
${
LIBCAF_TEST_HDRS
}
${
LIBCAF_TEST_SRCS
}
)
set_target_properties
(
libcaf_testStatic
PROPERTIES OUTPUT_NAME caf_test_static
)
if
(
NOT WIN32
)
install
(
TARGETS libcaf_testStatic ARCHIVE DESTINATION lib
)
endif
()
endif
()
link_directories
(
${
LD_DIRS
}
)
include_directories
(
${
CMAKE_CURRENT_SOURCE_DIR
}
)
# install includes
if
(
NOT WIN32
)
install
(
DIRECTORY caf/ DESTINATION include/caf FILES_MATCHING PATTERN
"*.hpp"
)
endif
()
# The single unit test binary containing all tests.
file
(
GLOB_RECURSE tests test.cpp test/*.cpp
)
add_executable
(
caf-test
${
tests
}
)
target_link_libraries
(
caf-test
libcaf_test
${
LD_FLAGS
}
${
LIBCAF_CORE_LIBRARY
}
${
PTHREAD_LIBRARIES
}
)
add_custom_target
(
all_unit_tests
)
add_dependencies
(
caf-test all_unit_tests
)
# Enumerate all test suites.
foreach
(
test
${
tests
}
)
file
(
STRINGS
${
test
}
contents
)
foreach
(
line
${
contents
}
)
if
(
"
${
line
}
"
MATCHES
"CAF_SUITE(.*)"
)
string
(
REGEX REPLACE
".*
\"
(.*)
\"
.*"
"
\\
1"
suite
${
line
}
)
list
(
APPEND suites
${
suite
}
)
endif
()
endforeach
()
endforeach
()
list
(
REMOVE_DUPLICATES suites
)
# Creates one CMake test per test suite.
macro
(
make_test suite
)
string
(
REPLACE
" "
"_"
test_name
${
suite
}
)
set
(
caf_test
${
EXECUTABLE_OUTPUT_PATH
}
/caf-test
)
add_test
(
${
test_name
}
${
caf_test
}
-n -v 3 -s
"
${
suite
}
"
${
ARGN
}
)
endmacro
()
foreach
(
suite
${
suites
}
)
make_test
(
"
${
suite
}
"
)
endforeach
()
libcaf_test/caf/test/unit_test.hpp
View file @
6eff7c2b
...
...
@@ -21,13 +21,15 @@
#define CAF_TEST_UNIT_TEST_HPP
#include <map>
#include <regex>
#include <cmath>
#include <mutex>
#include <vector>
#include <string>
#include <memory>
#include <fstream>
#include <iostream>
#include <mutex>
#include <regex>
#include <sstream>
#include <iostream>
namespace
caf
{
namespace
test
{
...
...
@@ -41,35 +43,43 @@ class test {
virtual
~
test
();
size_t
__
expected_failures
()
const
;
size_t
expected_failures
()
const
;
void
__
pass
(
std
::
string
msg
);
void
pass
(
std
::
string
msg
);
void
__
fail
(
std
::
string
msg
,
bool
expected
);
void
fail
(
std
::
string
msg
,
bool
expected
);
const
std
::
vector
<
std
::
pair
<
bool
,
std
::
string
>>&
__trac
e
()
const
;
const
std
::
string
&
nam
e
()
const
;
const
std
::
string
&
__name
()
const
;
inline
size_t
good
()
{
return
m_good
;
}
virtual
void
__run
()
=
0
;
inline
size_t
bad
()
{
return
m_bad
;
}
virtual
void
run
()
=
0
;
private:
size_t
m_expected_failures
=
0
;
std
::
vector
<
std
::
pair
<
bool
,
std
::
string
>>
m_trace
;
size_t
m_expected_failures
;
std
::
string
m_name
;
size_t
m_good
;
size_t
m_bad
;
};
namespace
detail
{
// Thrown when a required check fails.
struct
require_error
:
std
::
logic_error
{
require_error
(
const
std
::
string
&
msg
)
:
std
::
logic_error
(
msg
)
{
}
// thrown when a required check fails
class
require_error
:
std
::
logic_error
{
public:
require_error
(
const
std
::
string
&
msg
);
require_error
(
const
require_error
&
)
=
default
;
require_error
(
require_error
&&
)
=
default
;
~
require_error
()
noexcept
;
};
//
C
onstructs spacing given a line number.
//
c
onstructs spacing given a line number.
const
char
*
fill
(
size_t
line
);
}
// namespace detail
...
...
@@ -87,19 +97,37 @@ class logger {
massive
=
4
};
class
message
{
/**
* Output stream for logging purposes.
*/
class
stream
{
public:
message
(
logger
&
l
,
level
lvl
);
stream
(
logger
&
l
,
level
lvl
);
stream
(
stream
&&
);
template
<
class
T
>
message
&
operator
<<
(
const
T
&
x
)
{
m_logger
.
log
(
m_level
,
x
);
typename
std
::
enable_if
<
!
std
::
is_same
<
T
,
char
*>::
value
,
stream
&
>::
type
operator
<<
(
const
T
&
x
)
{
m_buf
<<
x
;
return
*
this
;
}
stream
&
operator
<<
(
const
char
&
c
);
stream
&
operator
<<
(
const
char
*
cstr
);
stream
&
operator
<<
(
const
std
::
string
&
str
);
private:
void
flush
();
logger
&
m_logger
;
level
m_level
;
std
::
ostringstream
m_buf
;
};
static
bool
init
(
int
lvl_cons
,
int
lvl_file
,
const
std
::
string
&
logfile
);
...
...
@@ -118,10 +146,10 @@ class logger {
}
}
message
error
();
message
info
();
message
verbose
();
message
massive
();
stream
error
();
stream
info
();
stream
verbose
();
stream
massive
();
private:
logger
();
...
...
@@ -155,8 +183,6 @@ enum color_value {
* Drives unit test execution.
*/
class
engine
{
engine
()
=
default
;
public:
/**
* Adds a test to the engine.
...
...
@@ -182,10 +208,10 @@ class engine {
int
verbosity_console
,
int
verbosity_file
,
int
max_runtime
,
const
std
::
regex
&
suites
,
const
std
::
regex
&
not_suites
,
const
std
::
regex
&
tests
,
const
std
::
regex
&
not_tests
);
const
std
::
string
&
suites
,
const
std
::
string
&
not_suites
,
const
std
::
string
&
tests
,
const
std
::
string
&
not_tests
);
/**
* Retrieves a UNIX terminal color code or an empty string based on the
...
...
@@ -201,7 +227,11 @@ class engine {
static
test
*
current_test
();
static
std
::
vector
<
std
::
string
>
available_suites
();
private:
engine
()
=
default
;
static
engine
&
instance
();
static
std
::
string
render
(
std
::
chrono
::
microseconds
t
);
...
...
@@ -267,6 +297,36 @@ showable<T> show(T const &x) {
return
showable
<
T
>
{
x
};
}
template
<
class
T
,
bool
IsFloat
=
std
::
is_floating_point
<
T
>
::
value
,
bool
IsIntegral
=
std
::
is_integral
<
T
>::
value
>
class
lhs_cmp
{
public:
template
<
class
U
>
bool
operator
()(
const
T
&
x
,
const
U
&
y
)
{
return
x
==
y
;
}
};
template
<
class
T
>
class
lhs_cmp
<
T
,
true
,
false
>
{
public:
template
<
class
U
>
bool
operator
()(
const
T
&
x
,
const
U
&
y
)
{
using
rt
=
decltype
(
x
-
y
);
return
std
::
fabs
(
x
-
y
)
<=
std
::
numeric_limits
<
rt
>::
epsilon
();
}
};
template
<
class
T
>
class
lhs_cmp
<
T
,
false
,
true
>
{
public:
template
<
class
U
>
bool
operator
()(
const
T
&
x
,
const
U
&
y
)
{
return
x
==
static_cast
<
T
>
(
y
);
}
};
template
<
class
T
>
struct
lhs
{
public:
...
...
@@ -293,53 +353,74 @@ struct lhs {
template
<
class
U
>
using
elevated
=
typename
std
::
conditional
<
std
::
is_convertible
<
U
,
T
>::
value
,
T
,
U
>::
type
;
typename
std
::
conditional
<
std
::
is_convertible
<
U
,
T
>::
value
,
T
,
U
>::
type
;
explicit
operator
bool
()
{
m_evaluated
=
true
;
return
!!
m_value
?
pass
()
:
fail_unary
();
return
static_cast
<
bool
>
(
m_value
)
?
pass
()
:
fail_unary
();
}
// pass-or-fail
template
<
class
U
>
bool
operator
==
(
const
U
&
u
)
{
bool
pof
(
bool
res
,
const
U
&
x
)
{
m_evaluated
=
true
;
return
m_value
==
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
return
res
?
pass
()
:
fail
(
x
);
}
template
<
class
U
>
bool
operator
!=
(
const
U
&
u
)
{
m_evaluated
=
true
;
return
m_value
!=
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
bool
operator
==
(
const
U
&
x
)
{
lhs_cmp
<
T
>
cmp
;
return
pof
(
cmp
(
m_value
,
x
),
x
);
}
template
<
class
U
>
bool
operator
<
(
const
U
&
u
)
{
m_evaluated
=
true
;
return
m_value
<
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
bool
operator
!=
(
const
U
&
x
)
{
lhs_cmp
<
T
>
cmp
;
return
pof
(
!
cmp
(
m_value
,
x
),
x
);
}
template
<
class
U
>
bool
operator
<=
(
const
U
&
u
)
{
m_evaluated
=
true
;
return
m_value
<=
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
bool
operator
<
(
const
U
&
x
)
{
return
pof
(
m_value
<
static_cast
<
elevated
<
U
>>
(
x
),
x
);
}
template
<
class
U
>
bool
operator
>
(
const
U
&
u
)
{
m_evaluated
=
true
;
return
m_value
>
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
bool
operator
<=
(
const
U
&
x
)
{
return
pof
(
m_value
<=
static_cast
<
elevated
<
U
>>
(
x
),
x
);
}
template
<
class
U
>
bool
operator
>=
(
const
U
&
u
)
{
m_evaluated
=
true
;
return
m_value
>=
static_cast
<
elevated
<
U
>>
(
u
)
?
pass
()
:
fail
(
u
);
bool
operator
>
(
const
U
&
x
)
{
return
pof
(
m_value
>
static_cast
<
elevated
<
U
>>
(
x
),
x
);
}
template
<
class
U
>
bool
operator
>=
(
const
U
&
x
)
{
return
pof
(
m_value
>=
static_cast
<
elevated
<
U
>>
(
x
),
x
);
}
private:
template
<
class
V
=
T
>
auto
eval
(
int
)
->
decltype
(
!
std
::
declval
<
V
>
())
{
return
!!
m_value
;
typename
std
::
enable_if
<
std
::
is_convertible
<
V
,
bool
>::
value
&&
!
std
::
is_floating_point
<
V
>::
value
,
bool
>::
type
eval
(
int
)
{
return
static_cast
<
bool
>
(
m_value
);
}
template
<
class
V
=
T
>
typename
std
::
enable_if
<
std
::
is_floating_point
<
V
>::
value
,
bool
>::
type
eval
(
int
)
{
return
std
::
fabs
(
m_value
)
<=
std
::
numeric_limits
<
V
>::
epsilon
();
}
bool
eval
(
long
)
{
...
...
@@ -349,47 +430,44 @@ struct lhs {
bool
pass
()
{
m_passed
=
true
;
std
::
stringstream
ss
;
ss
<<
engine
::
color
(
green
)
<<
"** "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
;
m_test
->
__pass
(
ss
.
str
());
ss
<<
engine
::
color
(
green
)
<<
"** "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
;
m_test
->
pass
(
ss
.
str
());
return
true
;
}
bool
fail_unary
()
{
std
::
stringstream
ss
;
ss
<<
engine
::
color
(
red
)
<<
"!! "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
;
m_test
->
__fail
(
ss
.
str
(),
m_should_fail
);
ss
<<
engine
::
color
(
red
)
<<
"!! "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
;
m_test
->
fail
(
ss
.
str
(),
m_should_fail
);
return
false
;
}
template
<
class
U
>
bool
fail
(
const
U
&
u
)
{
std
::
stringstream
ss
;
ss
<<
engine
::
color
(
red
)
<<
"!! "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
<<
engine
::
color
(
magenta
)
<<
" ("
<<
engine
::
color
(
red
)
<<
show
(
m_value
)
<<
engine
::
color
(
magenta
)
<<
" !! "
<<
engine
::
color
(
red
)
<<
show
(
u
)
<<
engine
::
color
(
magenta
)
<<
')'
<<
engine
::
color
(
reset
);
m_test
->
__fail
(
ss
.
str
(),
m_should_fail
);
ss
<<
engine
::
color
(
red
)
<<
"!! "
<<
engine
::
color
(
blue
)
<<
m_filename
<<
engine
::
color
(
yellow
)
<<
":"
<<
engine
::
color
(
blue
)
<<
m_line
<<
fill
(
m_line
)
<<
engine
::
color
(
reset
)
<<
m_expr
<<
engine
::
color
(
magenta
)
<<
" ("
<<
engine
::
color
(
red
)
<<
show
(
m_value
)
<<
engine
::
color
(
magenta
)
<<
" !! "
<<
engine
::
color
(
red
)
<<
show
(
u
)
<<
engine
::
color
(
magenta
)
<<
')'
<<
engine
::
color
(
reset
);
m_test
->
fail
(
ss
.
str
(),
m_should_fail
);
return
false
;
}
bool
m_evaluated
=
false
;
bool
m_passed
=
false
;
test
*
m_test
;
const
char
*
m_filename
;
const
char
*
m_filename
;
size_t
m_line
;
const
char
*
m_expr
;
const
char
*
m_expr
;
bool
m_should_fail
;
const
T
&
m_value
;
};
...
...
@@ -416,67 +494,78 @@ private:
}
// namespace test
}
// namespace caf
#define CAF_TEST_ERROR(msg) \
::caf::test::logger::instance().error() << msg << '\n'
#define CAF_TEST_INFO(msg) \
::caf::test::logger::instance().info() << msg << '\n'
#define CAF_TEST_VERBOSE(msg) \
::caf::test::logger::instance().verbose() << msg << '\n'
#define CAF_TEST_PR(level, msg) \
::caf::test::logger::instance(). level () \
<< ::caf::test::engine::color(::caf::test::yellow) \
<< " -> " << ::caf::test::engine::color(::caf::test::reset) << msg << '\n'
#define CAF_TEST_ERROR(msg) \
CAF_TEST_PR(error, msg)
#define CAF_TEST_INFO(msg) \
CAF_TEST_PR(info, msg)
#define CAF_TEST_VERBOSE(msg) \
CAF_TEST_PR(verbose, msg)
#define CAF_PASTE_CONCAT(lhs, rhs) lhs ## rhs
#define CAF_PASTE(lhs, rhs) CAF_PASTE_CONCAT(lhs, rhs)
#define CAF_UNIQUE(name) CAF_PASTE(name, __LINE__)
#ifndef CAF_SUITE
#define CAF_SUITE
""
#define CAF_SUITE
unnamed
#endif
#define CAF_CHECK(...) \
do { \
(void)(::caf::test::detail::expr{ \
::caf::test::engine::current_test(), __FILE__, __LINE__, \
false, #__VA_ARGS__} ->* __VA_ARGS__); \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} while (false)
#define CAF_FAIL(...) \
do { \
(void)(::caf::test::detail::expr{ \
::caf::test::engine::current_test(), __FILE__, __LINE__, \
true, #__VA_ARGS__} ->* __VA_ARGS__); \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} while (false)
#define CAF_REQUIRE(...) \
do { \
auto CAF_UNIQUE(__result) = \
::caf::test::detail::expr{::caf::test::engine::current_test(), \
__FILE__, __LINE__, false, #__VA_ARGS__} ->* __VA_ARGS__; \
if (! CAF_UNIQUE(__result)) { \
throw ::caf::test::detail::require_error{#__VA_ARGS__}; \
} \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} while (false)
#define CAF_TEST(name) \
namespace { \
struct CAF_UNIQUE(test) : public ::caf::test::test { \
CAF_UNIQUE(test)() : test{name} { } \
void __run() final; \
}; \
::caf::test::detail::adder<CAF_UNIQUE(test)> CAF_UNIQUE(a){CAF_SUITE}; \
}
/* namespace <anonymous> */
\
void CAF_UNIQUE(test)::__run()
// Boost Test compatibility macros
#define CAF_STR(s) #s
#define CAF_XSTR(s) CAF_STR(s)
#define CAF_CHECK(...) \
{ \
static_cast<void>(::caf::test::detail::expr{ \
::caf::test::engine::current_test(), __FILE__, __LINE__, \
false, #__VA_ARGS__} ->* __VA_ARGS__); \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} static_cast<void>(0)
#define CAF_FAIL(...) \
{ \
(void)(::caf::test::detail::expr{ \
::caf::test::engine::current_test(), __FILE__, __LINE__, \
true, #__VA_ARGS__} ->* __VA_ARGS__); \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} static_cast<void>(0)
#define CAF_REQUIRE(...) \
{ \
auto CAF_UNIQUE(__result) = \
::caf::test::detail::expr{::caf::test::engine::current_test(), \
__FILE__, __LINE__, false, #__VA_ARGS__} ->* __VA_ARGS__; \
if (!CAF_UNIQUE(__result)) { \
throw ::caf::test::detail::require_error{#__VA_ARGS__}; \
} \
::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \
} static_cast<void>(0)
#define CAF_TEST(name) \
namespace { \
struct CAF_UNIQUE(test) : public ::caf::test::test { \
CAF_UNIQUE(test)() : test{CAF_XSTR(name)} { } \
void run() final; \
}; \
::caf::test::detail::adder<CAF_UNIQUE(test)> CAF_UNIQUE(a) { \
CAF_XSTR(CAF_SUITE) \
}; \
}
/* namespace <anonymous> */
\
void CAF_UNIQUE(test)::run()
// Boost Test compatibility macro
#define CAF_CHECK_EQUAL(x, y) CAF_CHECK(x == y)
#define CAF_CHECK_NE(x, y) CAF_CHECK(x != y)
#define CAF_CHECK_LT(x, y) CAF_CHECK(x < y)
#define CAF_CHECK_LE(x, y) CAF_CHECK(x <= y)
#define CAF_CHECK_GT(x, y) CAF_CHECK(x > y)
#define CAF_CHECK_GE(x, y) CAF_CHECK(x >= y)
#endif // CAF_TEST_UNIT_TEST_HPP
libcaf_test/caf/test/unit_test_impl.hpp
View file @
6eff7c2b
...
...
@@ -20,9 +20,17 @@
#ifndef CAF_TEST_UNIT_TEST_IMPL_HPP
#define CAF_TEST_UNIT_TEST_IMPL_HPP
#include <thread>
#include <cassert>
#include <cstdlib>
#include <algorithm>
#include <condition_variable>
#include <thread>
#include "caf/shutdown.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_handler.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/await_all_actors_done.hpp"
namespace
caf
{
namespace
test
{
...
...
@@ -74,7 +82,11 @@ void watchdog::stop() {
delete
s_watchdog
;
}
test
::
test
(
std
::
string
name
)
:
m_name
{
std
::
move
(
name
)}
{
test
::
test
(
std
::
string
test_name
)
:
m_expected_failures
(
0
),
m_name
(
std
::
move
(
test_name
)),
m_good
(
0
),
m_bad
(
0
)
{
// nop
}
...
...
@@ -82,32 +94,33 @@ test::~test() {
// nop
}
size_t
test
::
__
expected_failures
()
const
{
size_t
test
::
expected_failures
()
const
{
return
m_expected_failures
;
}
void
test
::
__pass
(
std
::
string
msg
)
{
m_trace
.
emplace_back
(
true
,
std
::
move
(
msg
));
void
test
::
pass
(
std
::
string
msg
)
{
++
m_good
;
::
caf
::
test
::
logger
::
instance
().
massive
()
<<
" "
<<
msg
<<
'\n'
;
}
void
test
::
__fail
(
std
::
string
msg
,
bool
expected
)
{
m_trace
.
emplace_back
(
false
,
std
::
move
(
msg
));
void
test
::
fail
(
std
::
string
msg
,
bool
expected
)
{
++
m_bad
;
::
caf
::
test
::
logger
::
instance
().
massive
()
<<
" "
<<
msg
<<
'\n'
;
if
(
expected
)
{
++
m_expected_failures
;
}
}
const
std
::
vector
<
std
::
pair
<
bool
,
std
::
string
>>&
test
::
__trace
()
const
{
return
m_trace
;
}
const
std
::
string
&
test
::
__name
()
const
{
const
std
::
string
&
test
::
name
()
const
{
return
m_name
;
}
namespace
detail
{
require_error
::
require_error
(
const
std
::
string
&
msg
)
:
std
::
logic_error
(
msg
)
{
// nop
}
require_error
::~
require_error
()
noexcept
{
// nop
}
...
...
@@ -126,18 +139,59 @@ const char* fill(size_t line) {
}
// namespace detail
logger
::
message
::
message
(
logger
&
l
,
level
lvl
)
:
m_logger
(
l
),
m_level
(
lvl
)
{
logger
::
stream
::
stream
(
logger
&
l
,
level
lvl
)
:
m_logger
(
l
),
m_level
(
lvl
)
{
// nop
}
bool
logger
::
init
(
int
lvl_cons
,
int
lvl_file
,
const
std
::
string
&
logfile
)
{
logger
::
stream
::
stream
(
stream
&&
other
)
:
m_logger
(
other
.
m_logger
)
,
m_level
(
other
.
m_level
)
{
// ostringstream does have swap since C++11... but not in GCC 4.7
m_buf
.
str
(
other
.
m_buf
.
str
());
}
logger
::
stream
&
logger
::
stream
::
operator
<<
(
const
char
&
c
)
{
m_buf
<<
c
;
if
(
c
==
'\n'
)
{
flush
();
}
return
*
this
;
}
logger
::
stream
&
logger
::
stream
::
operator
<<
(
const
char
*
cstr
)
{
if
(
*
cstr
==
'\0'
)
{
return
*
this
;
}
m_buf
<<
cstr
;
if
(
cstr
[
strlen
(
cstr
)
-
1
]
==
'\n'
)
{
flush
();
}
return
*
this
;
}
logger
::
stream
&
logger
::
stream
::
operator
<<
(
const
std
::
string
&
str
)
{
if
(
str
.
empty
())
{
return
*
this
;
}
m_buf
<<
str
;
if
(
str
.
back
()
==
'\n'
)
{
flush
();
}
return
*
this
;
}
void
logger
::
stream
::
flush
()
{
m_logger
.
log
(
m_level
,
m_buf
.
str
());
m_buf
.
str
(
""
);
}
bool
logger
::
init
(
int
lvl_cons
,
int
lvl_file
,
const
std
::
string
&
logfile
)
{
instance
().
m_level_console
=
static_cast
<
level
>
(
lvl_cons
);
instance
().
m_level_file
=
static_cast
<
level
>
(
lvl_file
);
if
(
!
logfile
.
empty
())
{
if
(
!
logfile
.
empty
())
{
instance
().
m_file
.
open
(
logfile
,
std
::
ofstream
::
out
|
std
::
ofstream
::
app
);
return
!!
instance
().
m_file
;
return
!!
instance
().
m_file
;
}
return
true
;
}
...
...
@@ -147,45 +201,51 @@ logger& logger::instance() {
return
l
;
}
logger
::
message
logger
::
error
()
{
return
message
{
*
this
,
level
::
error
};
logger
::
stream
logger
::
error
()
{
return
stream
{
*
this
,
level
::
error
};
}
logger
::
message
logger
::
info
()
{
return
message
{
*
this
,
level
::
info
};
logger
::
stream
logger
::
info
()
{
return
stream
{
*
this
,
level
::
info
};
}
logger
::
message
logger
::
verbose
()
{
return
message
{
*
this
,
level
::
verbose
};
logger
::
stream
logger
::
verbose
()
{
return
stream
{
*
this
,
level
::
verbose
};
}
logger
::
message
logger
::
massive
()
{
return
message
{
*
this
,
level
::
massive
};
logger
::
stream
logger
::
massive
()
{
return
stream
{
*
this
,
level
::
massive
};
}
logger
::
logger
()
:
m_console
(
std
::
cerr
)
{}
logger
::
logger
()
:
m_console
(
std
::
cerr
)
{
// nop
}
void
engine
::
add
(
const
char
*
name
,
std
::
unique_ptr
<
test
>
t
)
{
auto
&
suite
=
instance
().
m_suites
[
std
::
string
{
name
?
name
:
""
}];
for
(
auto
&
x
:
suite
)
if
(
x
->
__name
()
==
t
->
__
name
())
{
std
::
cout
<<
"duplicate test name: "
<<
t
->
__
name
()
<<
'\n'
;
for
(
auto
&
x
:
suite
)
{
if
(
x
->
name
()
==
t
->
name
())
{
std
::
cout
<<
"duplicate test name: "
<<
t
->
name
()
<<
'\n'
;
std
::
abort
();
}
}
suite
.
emplace_back
(
std
::
move
(
t
));
}
bool
engine
::
run
(
bool
colorize
,
const
std
::
string
&
log_file
,
int
verbosity_console
,
int
verbosity_file
,
int
,
const
std
::
regex
&
suites
,
const
std
::
regex
&
not_suites
,
const
std
::
regex
&
tests
,
const
std
::
regex
&
not_tests
)
{
if
(
!
colorize
)
{
const
std
::
string
&
log_file
,
int
verbosity_console
,
int
verbosity_file
,
int
,
// TODO: max runtime
const
std
::
string
&
suites_str
,
const
std
::
string
&
not_suites_str
,
const
std
::
string
&
tests_str
,
const
std
::
string
&
not_tests_str
)
{
if
(
not_suites_str
==
"*"
||
not_tests_str
==
"*"
)
{
// nothing to do
return
true
;
}
if
(
!
colorize
)
{
instance
().
m_reset
=
""
;
instance
().
m_black
=
""
;
instance
().
m_red
=
""
;
...
...
@@ -204,8 +264,9 @@ bool engine::run(bool colorize,
instance
().
m_bold_cyan
=
""
;
instance
().
m_bold_white
=
""
;
}
if
(
!
logger
::
init
(
verbosity_console
,
verbosity_file
,
log_file
))
if
(
!
logger
::
init
(
verbosity_console
,
verbosity_file
,
log_file
))
{
return
false
;
}
auto
&
log
=
logger
::
instance
();
std
::
chrono
::
microseconds
runtime
{
0
};
size_t
total_suites
=
0
;
...
...
@@ -215,32 +276,76 @@ bool engine::run(bool colorize,
size_t
total_bad_expected
=
0
;
auto
bar
=
'+'
+
std
::
string
(
70
,
'-'
)
+
'+'
;
auto
failed_require
=
false
;
# if !defined(__clang__) && defined(__GNUC__) \
&& __GNUC__ == 4 && __GNUC_MINOR__ < 9
// regex implementation is broken prior to 4.9
using
strvec
=
std
::
vector
<
std
::
string
>
;
auto
from_psv
=
[](
const
std
::
string
&
psv
)
->
strvec
{
// psv == pipe-separated-values
strvec
result
;
if
(
psv
!=
".*"
)
{
split
(
result
,
psv
,
"|"
,
token_compress_on
);
std
::
sort
(
result
.
begin
(),
result
.
end
());
}
return
result
;
};
auto
suites
=
from_psv
(
suites_str
);
auto
not_suites
=
from_psv
(
not_suites_str
);
auto
tests
=
from_psv
(
tests_str
);
auto
not_tests
=
from_psv
(
not_tests_str
);
auto
enabled
=
[](
const
strvec
&
whitelist
,
const
strvec
&
blacklist
,
const
std
::
string
&
x
)
{
// an empty whitelist means original input was ".*", i.e., enable all
return
!
std
::
binary_search
(
blacklist
.
begin
(),
blacklist
.
end
(),
x
)
&&
(
whitelist
.
empty
()
||
std
::
binary_search
(
whitelist
.
begin
(),
whitelist
.
end
(),
x
));
};
# else
std
::
regex
suites
{
suites_str
};
std
::
regex
tests
{
tests_str
};
std
::
regex
not_suites
;
std
::
regex
not_tests
;
// a default constructored regex matches is not equal to an "empty" regex
if
(
!
not_suites_str
.
empty
())
{
not_suites
.
assign
(
not_suites_str
);
}
if
(
!
not_tests_str
.
empty
())
{
not_tests
.
assign
(
not_tests_str
);
}
auto
enabled
=
[](
const
std
::
regex
&
whitelist
,
const
std
::
regex
&
blacklist
,
const
std
::
string
&
x
)
{
// an empty whitelist means original input was "*", i.e., enable all
return
std
::
regex_search
(
x
,
whitelist
)
&&
!
std
::
regex_search
(
x
,
blacklist
);
};
# endif
for
(
auto
&
p
:
instance
().
m_suites
)
{
if
(
!
std
::
regex_search
(
p
.
first
,
suites
)
||
std
::
regex_search
(
p
.
first
,
not_suites
))
if
(
!
enabled
(
suites
,
not_suites
,
p
.
first
))
{
continue
;
}
auto
suite_name
=
p
.
first
.
empty
()
?
"<unnamed>"
:
p
.
first
;
auto
pad
=
std
::
string
((
bar
.
size
()
-
suite_name
.
size
())
/
2
,
' '
);
bool
displayed_header
=
false
;
size_t
tests_ran
=
0
;
for
(
auto
&
t
:
p
.
second
)
{
if
(
!
std
::
regex_search
(
t
->
__name
(),
tests
)
||
std
::
regex_search
(
t
->
__name
(),
not_tests
))
if
(
!
enabled
(
tests
,
not_tests
,
t
->
name
()))
{
continue
;
}
instance
().
m_current_test
=
t
.
get
();
++
tests_ran
;
if
(
!
displayed_header
)
{
log
.
verbose
()
<<
color
(
yellow
)
<<
bar
<<
'\n'
<<
pad
<<
suite_name
<<
'\n'
<<
bar
<<
color
(
reset
)
<<
"
\n\n
"
;
if
(
!
displayed_header
)
{
log
.
verbose
()
<<
color
(
yellow
)
<<
bar
<<
'\n'
<<
pad
<<
suite_name
<<
'\n'
<<
bar
<<
color
(
reset
)
<<
"
\n\n
"
;
displayed_header
=
true
;
}
log
.
verbose
()
<<
color
(
yellow
)
<<
"- "
<<
color
(
reset
)
<<
t
->
__name
()
<<
'\n'
;
log
.
verbose
()
<<
color
(
yellow
)
<<
"- "
<<
color
(
reset
)
<<
t
->
name
()
<<
'\n'
;
auto
start
=
std
::
chrono
::
high_resolution_clock
::
now
();
watchdog
::
start
();
try
{
t
->
__
run
();
t
->
run
();
}
catch
(
const
detail
::
require_error
&
)
{
failed_require
=
true
;
}
...
...
@@ -250,77 +355,69 @@ bool engine::run(bool colorize,
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
stop
-
start
);
runtime
+=
elapsed
;
++
total_tests
;
size_t
good
=
0
;
size_t
bad
=
0
;
for
(
auto
&
trace
:
t
->
__trace
())
{
if
(
trace
.
first
)
{
++
good
;
log
.
massive
()
<<
" "
<<
trace
.
second
<<
'\n'
;
}
else
{
++
bad
;
log
.
error
()
<<
" "
<<
trace
.
second
<<
'\n'
;
}
}
size_t
good
=
t
->
good
();
size_t
bad
=
t
->
bad
();
if
(
failed_require
)
{
log
.
error
()
<<
color
(
red
)
<<
" REQUIRED"
<<
color
(
reset
)
<<
'\n'
<<
" "
<<
color
(
blue
)
<<
last_check_file
()
<<
color
(
yellow
)
<<
":"
<<
color
(
cyan
)
<<
last_check_line
()
<<
color
(
reset
)
<<
detail
::
fill
(
last_check_line
())
<<
"had last successful check"
<<
'\n'
;
log
.
error
()
<<
color
(
red
)
<<
" REQUIRED"
<<
color
(
reset
)
<<
'\n'
<<
" "
<<
color
(
blue
)
<<
last_check_file
()
<<
color
(
yellow
)
<<
":"
<<
color
(
cyan
)
<<
last_check_line
()
<<
color
(
reset
)
<<
detail
::
fill
(
last_check_line
())
<<
"had last successful check"
<<
'\n'
;
}
total_good
+=
good
;
total_bad
+=
bad
;
total_bad_expected
+=
t
->
__expected_failures
();
log
.
verbose
()
<<
color
(
yellow
)
<<
" -> "
<<
color
(
cyan
)
<<
good
+
bad
<<
color
(
reset
)
<<
" check"
<<
(
good
+
bad
>
1
?
"s "
:
" "
)
<<
"took "
<<
color
(
cyan
)
<<
render
(
elapsed
)
<<
color
(
reset
);
if
(
bad
>
0
)
log
.
verbose
()
<<
" ("
<<
color
(
green
)
<<
good
<<
color
(
reset
)
<<
'/'
<<
color
(
red
)
<<
bad
<<
color
(
reset
)
<<
")"
<<
'\n'
;
else
total_bad_expected
+=
t
->
expected_failures
();
log
.
verbose
()
<<
color
(
yellow
)
<<
" -> "
<<
color
(
cyan
)
<<
good
+
bad
<<
color
(
reset
)
<<
" check"
<<
(
good
+
bad
>
1
?
"s "
:
" "
)
<<
"took "
<<
color
(
cyan
)
<<
render
(
elapsed
)
<<
color
(
reset
);
if
(
bad
>
0
)
{
log
.
verbose
()
<<
" ("
<<
color
(
green
)
<<
good
<<
color
(
reset
)
<<
'/'
<<
color
(
red
)
<<
bad
<<
color
(
reset
)
<<
")"
<<
'\n'
;
}
else
{
log
.
verbose
()
<<
'\n'
;
if
(
failed_require
)
}
if
(
failed_require
)
{
break
;
}
}
//
We only counts suites for which have executed one or more tests.
if
(
tests_ran
>
0
)
//
only count suites which have executed one or more tests
if
(
tests_ran
>
0
)
{
++
total_suites
;
if
(
displayed_header
)
}
if
(
displayed_header
)
{
log
.
verbose
()
<<
'\n'
;
if
(
failed_require
)
}
if
(
failed_require
)
{
break
;
}
}
auto
percent_good
=
static_cast
<
unsigned
>
(
double
(
100000
*
total_good
)
static_cast
<
unsigned
>
(
double
(
100000
*
total_good
)
/
double
(
total_good
+
total_bad
))
/
1000.0
;
auto
title
=
std
::
string
{
"summary"
};
auto
pad
=
std
::
string
((
bar
.
size
()
-
title
.
size
())
/
2
,
' '
);
auto
indent
=
std
::
string
(
24
,
' '
);
log
.
info
()
<<
color
(
cyan
)
<<
bar
<<
'\n'
<<
pad
<<
title
<<
'\n'
<<
bar
<<
color
(
reset
)
<<
"
\n\n
"
<<
indent
<<
"suites: "
<<
color
(
yellow
)
<<
total_suites
<<
color
(
reset
)
<<
'\n'
<<
indent
<<
"tests: "
<<
color
(
yellow
)
<<
total_tests
<<
color
(
reset
)
<<
'\n'
<<
indent
<<
"checks: "
<<
color
(
yellow
)
<<
total_good
+
total_bad
<<
color
(
reset
);
log
.
info
()
<<
color
(
cyan
)
<<
bar
<<
'\n'
<<
pad
<<
title
<<
'\n'
<<
bar
<<
color
(
reset
)
<<
"
\n\n
"
<<
indent
<<
"suites: "
<<
color
(
yellow
)
<<
total_suites
<<
color
(
reset
)
<<
'\n'
<<
indent
<<
"tests: "
<<
color
(
yellow
)
<<
total_tests
<<
color
(
reset
)
<<
'\n'
<<
indent
<<
"checks: "
<<
color
(
yellow
)
<<
total_good
+
total_bad
<<
color
(
reset
);
if
(
total_bad
>
0
)
{
log
.
info
()
<<
" ("
<<
color
(
green
)
<<
total_good
<<
color
(
reset
)
<<
'/'
<<
color
(
red
)
<<
total_bad
<<
color
(
reset
)
<<
")"
;
if
(
total_bad_expected
)
log
.
info
()
<<
" ("
<<
color
(
green
)
<<
total_good
<<
color
(
reset
)
<<
'/'
<<
color
(
red
)
<<
total_bad
<<
color
(
reset
)
<<
")"
;
if
(
total_bad_expected
)
{
log
.
info
()
<<
' '
<<
color
(
cyan
)
<<
total_bad_expected
<<
color
(
reset
)
<<
" failures expected"
;
}
}
log
.
info
()
<<
'\n'
<<
indent
<<
"time: "
<<
color
(
yellow
)
<<
render
(
runtime
)
<<
'\n'
<<
color
(
reset
)
<<
indent
<<
"success: "
<<
(
total_bad
>
0
?
color
(
green
)
:
color
(
yellow
))
<<
percent_good
<<
"%"
<<
color
(
reset
)
<<
"
\n\n
"
<<
color
(
cyan
)
<<
bar
<<
color
(
reset
)
<<
'\n'
;
log
.
info
()
<<
'\n'
<<
indent
<<
"time: "
<<
color
(
yellow
)
<<
render
(
runtime
)
<<
'\n'
<<
color
(
reset
)
<<
indent
<<
"success: "
<<
(
total_bad
>
0
?
color
(
green
)
:
color
(
yellow
))
<<
percent_good
<<
"%"
<<
color
(
reset
)
<<
"
\n\n
"
<<
color
(
cyan
)
<<
bar
<<
color
(
reset
)
<<
'\n'
;
return
total_bad
==
total_bad_expected
;
}
...
...
@@ -396,6 +493,14 @@ test* engine::current_test() {
return
instance
().
m_current_test
;
}
std
::
vector
<
std
::
string
>
engine
::
available_suites
()
{
std
::
vector
<
std
::
string
>
result
;
for
(
auto
&
kvp
:
instance
().
m_suites
)
{
result
.
push_back
(
kvp
.
first
);
}
return
result
;
}
engine
&
engine
::
instance
()
{
static
engine
e
;
return
e
;
...
...
@@ -404,7 +509,7 @@ engine& engine::instance() {
std
::
string
engine
::
render
(
std
::
chrono
::
microseconds
t
)
{
return
t
.
count
()
>
1000000
?
(
std
::
to_string
(
t
.
count
()
/
1000000
)
+
'.'
+
std
::
to_string
((
t
.
count
()
%
1000000
)
/
10000
)
+
" s"
)
+
std
::
to_string
((
t
.
count
()
%
1000000
)
/
10000
)
+
" s"
)
:
t
.
count
()
>
1000
?
(
std
::
to_string
(
t
.
count
()
/
1000
)
+
" ms"
)
:
(
std
::
to_string
(
t
.
count
())
+
" us"
);
...
...
@@ -426,4 +531,55 @@ expr::expr(test* parent, const char* filename, size_t lineno,
}
// namespace test
}
// namespace caf
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
caf
;
// default values.
int
verbosity_console
=
3
;
int
verbosity_file
=
3
;
int
max_runtime
=
10
;
std
::
string
log_file
;
std
::
string
suites
=
".*"
;
std
::
string
not_suites
;
std
::
string
tests
=
".*"
;
std
::
string
not_tests
;
// our simple command line parser.
auto
res
=
message_builder
(
argv
+
1
,
argv
+
argc
).
extract_opts
({
{
"no-colors,n"
,
"disable coloring"
},
{
"log-file,l"
,
"set output file"
,
log_file
},
{
"console-verbosity,v"
,
"set verbosity level of console (1-5)"
,
verbosity_console
},
{
"file-verbosity,V"
,
"set verbosity level of file output (1-5)"
,
verbosity_file
},
{
"max-runtime,r"
,
"set maximum runtime in seconds"
,
max_runtime
},
{
"suites,s"
,
"define what suites to run, either * or a comma-separated list"
,
suites
},
{
"not-suites,S"
,
"exclude suites"
,
not_suites
},
{
"tests,t"
,
"set tests"
,
tests
},
{
"not-tests,T"
,
"exclude tests"
,
not_tests
},
{
"available-suites,a"
,
"print available suites"
}
});
if
(
res
.
opts
.
count
(
"help"
)
>
0
)
{
return
0
;
}
if
(
res
.
opts
.
count
(
"available-suites"
)
>
0
)
{
std
::
cout
<<
"available suites:"
<<
std
::
endl
;
for
(
auto
&
s
:
test
::
engine
::
available_suites
())
{
std
::
cout
<<
" - "
<<
s
<<
std
::
endl
;
}
return
0
;
}
if
(
!
res
.
remainder
.
empty
())
{
std
::
cerr
<<
"*** invalid command line options"
<<
std
::
endl
<<
res
.
helptext
<<
std
::
endl
;
return
1
;
}
auto
colorize
=
res
.
opts
.
count
(
"no-colors"
)
==
0
;
auto
result
=
test
::
engine
::
run
(
colorize
,
log_file
,
verbosity_console
,
verbosity_file
,
max_runtime
,
suites
,
not_suites
,
tests
,
not_tests
);
await_all_actors_done
();
shutdown
();
return
result
?
0
:
1
;
}
#endif // CAF_TEST_UNIT_TEST_IMPL_HPP
libcaf_test/src/
unit_
test.cpp
→
libcaf_test/src/
caf-
test.cpp
View file @
6eff7c2b
File moved
libcaf_test/test.cpp
deleted
100644 → 0
View file @
58c573fe
#include <cstdlib>
#include "caf/all.hpp"
#include "caf/test/unit_test.hpp"
int
main
(
int
argc
,
char
*
argv
[])
{
using
namespace
caf
;
// Default values.
auto
colorize
=
true
;
std
::
string
log_file
;
int
verbosity_console
=
3
;
int
verbosity_file
=
3
;
int
max_runtime
=
10
;
std
::
regex
suites
{
".*"
};
std
::
regex
not_suites
;
std
::
regex
tests
{
".*"
};
std
::
regex
not_tests
;
// Our simple command line parser.
message_handler
parser
{
on
(
"-n"
)
>>
[
&
]
{
colorize
=
false
;
},
on
(
"-l"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
file_name
)
{
log_file
=
file_name
;
},
on
(
"-v"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
n
)
{
verbosity_console
=
static_cast
<
int
>
(
std
::
strtol
(
n
.
c_str
(),
nullptr
,
10
));
},
on
(
"-V"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
n
)
{
verbosity_file
=
static_cast
<
int
>
(
std
::
strtol
(
n
.
c_str
(),
nullptr
,
10
));
},
on
(
"-r"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
n
)
{
max_runtime
=
static_cast
<
int
>
(
std
::
strtol
(
n
.
c_str
(),
nullptr
,
10
));
},
on
(
"-s"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
str
)
{
suites
=
str
;
},
on
(
"-S"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
str
)
{
not_suites
=
str
;
},
on
(
"-t"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
str
)
{
tests
=
str
;
},
on
(
"-T"
,
arg_match
)
>>
[
&
](
const
std
::
string
&
str
)
{
not_tests
=
str
;
},
others
()
>>
[
&
]
{
std
::
cerr
<<
"invalid command line argument"
<<
std
::
endl
;
std
::
exit
(
1
);
}
};
auto
is_opt_char
=
[](
char
c
)
{
switch
(
c
)
{
default:
return
false
;
case
'n'
:
case
'l'
:
case
'v'
:
case
'V'
:
case
'r'
:
case
's'
:
case
'S'
:
case
't'
:
case
'T'
:
return
true
;
};
};
for
(
int
i
=
1
;
i
<
argc
;
++
i
)
{
message_builder
builder
;
std
::
string
arg
{
argv
[
i
]};
if
(
arg
.
empty
()
||
arg
[
0
]
!=
'-'
)
{
std
::
cerr
<<
"invalid option: "
<<
arg
<<
std
::
endl
;
return
1
;
}
builder
.
append
(
std
::
move
(
arg
));
if
(
i
+
1
<
argc
)
{
auto
next
=
argv
[
i
+
1
];
if
(
*
next
==
'\0'
||
next
[
0
]
!=
'-'
||
!
is_opt_char
(
next
[
1
]))
{
builder
.
append
(
std
::
string
{
next
});
++
i
;
}
}
builder
.
apply
(
parser
);
}
auto
result
=
caf
::
test
::
engine
::
run
(
colorize
,
log_file
,
verbosity_console
,
verbosity_file
,
max_runtime
,
suites
,
not_suites
,
tests
,
not_tests
);
return
result
?
0
:
1
;
}
libcaf_test/test/ping_pong.cpp
deleted
100644 → 0
View file @
58c573fe
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <iostream>
#include "ping_pong.hpp"
#define CAF_SUITE "spawn"
#include "caf/all.hpp"
#include "caf/detail/logging.hpp"
#include "caf/test/unit_test.hpp"
using
std
::
cout
;
using
std
::
endl
;
using
namespace
caf
;
using
namespace
caf
;
namespace
{
size_t
s_pongs
=
0
;
behavior
ping_behavior
(
local_actor
*
self
,
size_t
num_pings
)
{
return
{
on
(
atom
(
"pong"
),
arg_match
)
>>
[
=
](
int
value
)
->
message
{
if
(
!
self
->
current_sender
())
{
CAF_TEST_ERROR
(
"current_sender() invalid!"
);
}
CAF_TEST_INFO
(
"received {'pong', "
<<
value
<<
"}"
);
// cout << to_string(self->current_message()) << endl;
if
(
++
s_pongs
>=
num_pings
)
{
CAF_TEST_INFO
(
"reached maximum, send {'EXIT', user_defined} "
<<
"to last sender and quit with normal reason"
);
self
->
send_exit
(
self
->
current_sender
(),
exit_reason
::
user_shutdown
);
self
->
quit
();
}
return
make_message
(
atom
(
"ping"
),
value
);
},
others
()
>>
[
=
]
{
self
->
quit
(
exit_reason
::
user_shutdown
);
}
};
}
behavior
pong_behavior
(
local_actor
*
self
)
{
return
{
on
(
atom
(
"ping"
),
arg_match
)
>>
[](
int
value
)
->
message
{
return
make_message
(
atom
(
"pong"
),
value
+
1
);
},
others
()
>>
[
=
]
{
self
->
quit
(
exit_reason
::
user_shutdown
);
}
};
}
}
// namespace <anonymous>
size_t
pongs
()
{
return
s_pongs
;
}
void
ping
(
blocking_actor
*
self
,
size_t
num_pings
)
{
s_pongs
=
0
;
self
->
receive_loop
(
ping_behavior
(
self
,
num_pings
));
}
void
event_based_ping
(
event_based_actor
*
self
,
size_t
num_pings
)
{
s_pongs
=
0
;
self
->
become
(
ping_behavior
(
self
,
num_pings
));
}
void
pong
(
blocking_actor
*
self
,
actor
ping_actor
)
{
self
->
send
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
self
->
receive_loop
(
pong_behavior
(
self
));
}
void
event_based_pong
(
event_based_actor
*
self
,
actor
ping_actor
)
{
CAF_LOGF_TRACE
(
"ping_actor = "
<<
to_string
(
ping_actor
));
CAF_REQUIRE
(
ping_actor
!=
invalid_actor
);
self
->
send
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
self
->
become
(
pong_behavior
(
self
));
}
CAF_TEST
(
"ping-pong"
)
{
using
namespace
caf
;
scoped_actor
self
;
self
->
trap_exit
(
true
);
auto
ping_actor
=
self
->
spawn
<
monitored
+
blocking_api
>
(
ping
,
10
);
auto
pong_actor
=
self
->
spawn
<
monitored
+
blocking_api
>
(
pong
,
ping_actor
);
self
->
link_to
(
pong_actor
);
int
i
=
0
;
int
flags
=
0
;
self
->
delayed_send
(
self
,
std
::
chrono
::
seconds
(
1
),
atom
(
"FooBar"
));
// wait for DOWN and EXIT messages of pong
self
->
receive_for
(
i
,
4
)
(
[
&
](
const
exit_msg
&
em
)
{
CAF_CHECK
(
em
.
source
==
pong_actor
);
CAF_CHECK
(
em
.
reason
==
exit_reason
::
user_shutdown
);
flags
|=
0x01
;
},
[
&
](
const
down_msg
&
dm
)
{
if
(
dm
.
source
==
pong_actor
)
{
flags
|=
0x02
;
CAF_CHECK
(
dm
.
reason
==
exit_reason
::
user_shutdown
);
}
else
if
(
dm
.
source
==
ping_actor
)
{
flags
|=
0x04
;
CAF_CHECK
(
dm
.
reason
==
exit_reason
::
normal
);
}
},
[
&
](
const
atom_value
&
val
)
{
CAF_CHECK
(
val
==
atom
(
"FooBar"
));
flags
|=
0x08
;
},
others
()
>>
[
&
]()
{
// FIXME: abort test with error message.
//CAF_FAILURE("unexpected message: " << to_string(self->current_message()));
},
after
(
std
::
chrono
::
seconds
(
5
))
>>
[
&
]()
{
// FIXME: abort test with error message.
//CAF_FAILURE("timeout in file " << __FILE__ << " in line " << __LINE__);
}
);
// wait for termination of all spawned actors
self
->
await_all_other_actors_done
();
CAF_CHECK
(
flags
==
0x0F
);
CAF_CHECK
(
pongs
()
==
10
);
}
libcaf_test/test/ping_pong.hpp
deleted
100644 → 0
View file @
58c573fe
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* 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. *
******************************************************************************/
#ifndef PING_PONG_HPP
#define PING_PONG_HPP
//#include "caf/actor.hpp"
#include <cstddef>
#include "caf/fwd.hpp"
void
ping
(
caf
::
blocking_actor
*
,
size_t
num_pings
);
void
event_based_ping
(
caf
::
event_based_actor
*
,
size_t
num_pings
);
void
pong
(
caf
::
blocking_actor
*
,
caf
::
actor
ping_actor
);
// returns the number of messages ping received
size_t
pongs
();
#endif // PING_PONG_HPP
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