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
e2bea08c
Commit
e2bea08c
authored
Jul 11, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate the new unit testing framework
parent
a1ba72cc
Changes
30
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
904 additions
and
820 deletions
+904
-820
CMakeLists.txt
CMakeLists.txt
+16
-1
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+6
-3
libcaf_core/test/core-legacy-test.cpp
libcaf_core/test/core-legacy-test.cpp
+168
-0
libcaf_core/test/core-test.cpp
libcaf_core/test/core-test.cpp
+5
-166
libcaf_core/test/hash/fnv.cpp
libcaf_core/test/hash/fnv.cpp
+38
-30
libcaf_io/CMakeLists.txt
libcaf_io/CMakeLists.txt
+5
-2
libcaf_io/caf/io/network/receive_buffer.hpp
libcaf_io/caf/io/network/receive_buffer.hpp
+1
-0
libcaf_io/test/io-legacy-test.cpp
libcaf_io/test/io-legacy-test.cpp
+13
-0
libcaf_io/test/io-test.cpp
libcaf_io/test/io-test.cpp
+6
-11
libcaf_io/test/io/network/receive_buffer.cpp
libcaf_io/test/io/network/receive_buffer.cpp
+179
-0
libcaf_io/test/io/receive_buffer.cpp
libcaf_io/test/io/receive_buffer.cpp
+0
-164
libcaf_net/CMakeLists.txt
libcaf_net/CMakeLists.txt
+110
-107
libcaf_net/test/detail/rfc6455.cpp
libcaf_net/test/detail/rfc6455.cpp
+120
-124
libcaf_net/test/net-legacy-test.cpp
libcaf_net/test/net-legacy-test.cpp
+202
-0
libcaf_net/test/net-test.cpp
libcaf_net/test/net-test.cpp
+5
-199
libcaf_test/caf/test/and_given.hpp
libcaf_test/caf/test/and_given.hpp
+2
-1
libcaf_test/caf/test/and_then.hpp
libcaf_test/caf/test/and_then.hpp
+2
-1
libcaf_test/caf/test/and_when.hpp
libcaf_test/caf/test/and_when.hpp
+2
-1
libcaf_test/caf/test/factory.hpp
libcaf_test/caf/test/factory.hpp
+2
-1
libcaf_test/caf/test/given.hpp
libcaf_test/caf/test/given.hpp
+2
-1
libcaf_test/caf/test/registry.hpp
libcaf_test/caf/test/registry.hpp
+2
-1
libcaf_test/caf/test/runnable.hpp
libcaf_test/caf/test/runnable.hpp
+2
-1
libcaf_test/caf/test/runner.hpp
libcaf_test/caf/test/runner.hpp
+2
-1
libcaf_test/caf/test/scenario.hpp
libcaf_test/caf/test/scenario.hpp
+2
-1
libcaf_test/caf/test/section.hpp
libcaf_test/caf/test/section.hpp
+2
-1
libcaf_test/caf/test/test.hpp
libcaf_test/caf/test/test.hpp
+2
-1
libcaf_test/caf/test/then.hpp
libcaf_test/caf/test/then.hpp
+2
-1
libcaf_test/caf/test/unit_test.hpp
libcaf_test/caf/test/unit_test.hpp
+2
-0
libcaf_test/caf/test/unit_test_impl.hpp
libcaf_test/caf/test/unit_test_impl.hpp
+2
-0
libcaf_test/caf/test/when.hpp
libcaf_test/caf/test/when.hpp
+2
-1
No files found.
CMakeLists.txt
View file @
e2bea08c
...
...
@@ -319,7 +319,8 @@ endfunction()
# ...
# )
function
(
caf_add_component name
)
set
(
varargs DEPENDENCIES HEADERS SOURCES TEST_SOURCES TEST_SUITES ENUM_TYPES
)
set
(
varargs DEPENDENCIES HEADERS SOURCES TEST_SOURCES TEST_SUITES ENUM_TYPES
LEGACY_TEST_SOURCES LEGACY_TEST_SUITES
)
cmake_parse_arguments
(
CAF_ADD_COMPONENT
""
""
"
${
varargs
}
"
${
ARGN
}
)
if
(
NOT CAF_ADD_COMPONENT_HEADERS
)
message
(
FATAL_ERROR
"Cannot add CAF component without at least one header."
)
...
...
@@ -365,6 +366,20 @@ function(caf_add_component name)
caf_add_test_suites
(
${
tst_bin_target
}
${
CAF_ADD_COMPONENT_TEST_SUITES
}
)
endif
()
endif
()
if
(
CAF_ENABLE_TESTING AND CAF_ADD_COMPONENT_LEGACY_TEST_SOURCES
)
set
(
tst_bin_target
"caf-
${
name
}
-legacy-test"
)
list
(
APPEND targets
${
tst_bin_target
}
)
add_executable
(
${
tst_bin_target
}
${
CAF_ADD_COMPONENT_LEGACY_TEST_SOURCES
}
$<TARGET_OBJECTS:
${
obj_lib_target
}
>
)
target_link_libraries
(
${
tst_bin_target
}
PRIVATE libcaf_test
${
CAF_ADD_COMPONENT_DEPENDENCIES
}
)
target_include_directories
(
${
tst_bin_target
}
PRIVATE
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/test"
)
if
(
CAF_ADD_COMPONENT_LEGACY_TEST_SUITES
)
caf_add_test_suites
(
${
tst_bin_target
}
${
CAF_ADD_COMPONENT_LEGACY_TEST_SUITES
}
)
endif
()
endif
()
target_link_libraries
(
${
pub_lib_target
}
${
CAF_ADD_COMPONENT_DEPENDENCIES
}
)
if
(
CAF_ADD_COMPONENT_ENUM_TYPES
)
foreach
(
enum_name
${
CAF_ADD_COMPONENT_ENUM_TYPES
}
)
...
...
libcaf_core/CMakeLists.txt
View file @
e2bea08c
...
...
@@ -218,8 +218,12 @@ caf_add_component(
src/uuid.cpp
TEST_SOURCES
test/core-test.cpp
test/nasty.cpp
TEST_SUITES
hash.fnv
LEGACY_TEST_SOURCES
test/core-legacy-test.cpp
test/nasty.cpp
LEGACY_TEST_SUITES
action
actor_clock
actor_factory
...
...
@@ -308,7 +312,6 @@ caf_add_component(
flow.single
function_view
handles
hash.fnv
hash.sha1
intrusive.drr_cached_queue
intrusive.drr_queue
...
...
@@ -391,5 +394,5 @@ if(NOT CAF_USE_STD_FORMAT)
endif
()
if
(
CAF_ENABLE_TESTING AND CAF_ENABLE_EXCEPTIONS
)
caf_add_test_suites
(
caf-core-test custom_exception_handler
)
caf_add_test_suites
(
caf-core-
legacy-
test custom_exception_handler
)
endif
()
libcaf_core/test/core-legacy-test.cpp
0 → 100644
View file @
e2bea08c
#define CAF_TEST_NO_MAIN
#include "caf/test/unit_test_impl.hpp"
#include "core-test.hpp"
#include <atomic>
namespace
{
/// A trivial disposable with an atomic flag.
class
trivial_impl
:
public
caf
::
ref_counted
,
public
caf
::
disposable
::
impl
{
public:
trivial_impl
()
:
flag_
(
false
)
{
// nop
}
void
dispose
()
override
{
flag_
=
true
;
}
bool
disposed
()
const
noexcept
override
{
return
flag_
.
load
();
}
void
ref_disposable
()
const
noexcept
override
{
ref
();
}
void
deref_disposable
()
const
noexcept
override
{
deref
();
}
friend
void
intrusive_ptr_add_ref
(
const
trivial_impl
*
ptr
)
noexcept
{
ptr
->
ref
();
}
friend
void
intrusive_ptr_release
(
const
trivial_impl
*
ptr
)
noexcept
{
ptr
->
deref
();
}
private:
std
::
atomic
<
bool
>
flag_
;
};
}
// namespace
namespace
caf
::
flow
{
std
::
string
to_string
(
observer_state
x
)
{
switch
(
x
)
{
default:
return
"???"
;
case
observer_state
:
:
idle
:
return
"caf::flow::observer_state::idle"
;
case
observer_state
:
:
subscribed
:
return
"caf::flow::observer_state::subscribed"
;
case
observer_state
:
:
completed
:
return
"caf::flow::observer_state::completed"
;
case
observer_state
:
:
aborted
:
return
"caf::flow::observer_state::aborted"
;
}
}
bool
from_string
(
std
::
string_view
in
,
observer_state
&
out
)
{
if
(
in
==
"caf::flow::observer_state::idle"
)
{
out
=
observer_state
::
idle
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::subscribed"
)
{
out
=
observer_state
::
subscribed
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::completed"
)
{
out
=
observer_state
::
completed
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::aborted"
)
{
out
=
observer_state
::
aborted
;
return
true
;
}
return
false
;
}
bool
from_integer
(
std
::
underlying_type_t
<
observer_state
>
in
,
observer_state
&
out
)
{
auto
result
=
static_cast
<
observer_state
>
(
in
);
switch
(
result
)
{
default:
return
false
;
case
observer_state
:
:
idle
:
case
observer_state
:
:
subscribed
:
case
observer_state
:
:
completed
:
case
observer_state
:
:
aborted
:
out
=
result
;
return
true
;
}
}
disposable
make_trivial_disposable
()
{
return
disposable
{
make_counted
<
trivial_impl
>
()};
}
void
passive_subscription_impl
::
request
(
size_t
n
)
{
demand
+=
n
;
}
void
passive_subscription_impl
::
dispose
()
{
disposed_flag
=
true
;
}
bool
passive_subscription_impl
::
disposed
()
const
noexcept
{
return
disposed_flag
;
}
}
// namespace caf::flow
std
::
string
to_string
(
level
lvl
)
{
switch
(
lvl
)
{
case
level
:
:
all
:
return
"all"
;
case
level
:
:
trace
:
return
"trace"
;
case
level
:
:
debug
:
return
"debug"
;
case
level
:
:
warning
:
return
"warning"
;
case
level
:
:
error
:
return
"error"
;
default:
return
"???"
;
}
}
bool
from_string
(
std
::
string_view
str
,
level
&
lvl
)
{
auto
set
=
[
&
](
level
value
)
{
lvl
=
value
;
return
true
;
};
if
(
str
==
"all"
)
return
set
(
level
::
all
);
else
if
(
str
==
"trace"
)
return
set
(
level
::
trace
);
else
if
(
str
==
"debug"
)
return
set
(
level
::
debug
);
else
if
(
str
==
"warning"
)
return
set
(
level
::
warning
);
else
if
(
str
==
"error"
)
return
set
(
level
::
error
);
else
return
false
;
}
bool
from_integer
(
uint8_t
val
,
level
&
lvl
)
{
if
(
val
<
5
)
{
lvl
=
static_cast
<
level
>
(
val
);
return
true
;
}
else
{
return
false
;
}
}
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
caf
;
init_global_meta_objects
<
id_block
::
core_test
>
();
core
::
init_global_meta_objects
();
return
test
::
main
(
argc
,
argv
);
}
libcaf_core/test/core-test.cpp
View file @
e2bea08c
#define CAF_TEST_NO_MAIN
// 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/
unit_test_impl
.hpp"
#include "caf/test/
caf_test_main
.hpp"
#include "core-test.hpp"
#include <atomic>
namespace
{
/// A trivial disposable with an atomic flag.
class
trivial_impl
:
public
caf
::
ref_counted
,
public
caf
::
disposable
::
impl
{
public:
trivial_impl
()
:
flag_
(
false
)
{
// nop
}
void
dispose
()
override
{
flag_
=
true
;
}
bool
disposed
()
const
noexcept
override
{
return
flag_
.
load
();
}
void
ref_disposable
()
const
noexcept
override
{
ref
();
}
void
deref_disposable
()
const
noexcept
override
{
deref
();
}
friend
void
intrusive_ptr_add_ref
(
const
trivial_impl
*
ptr
)
noexcept
{
ptr
->
ref
();
}
friend
void
intrusive_ptr_release
(
const
trivial_impl
*
ptr
)
noexcept
{
ptr
->
deref
();
}
private:
std
::
atomic
<
bool
>
flag_
;
};
}
// namespace
namespace
caf
::
flow
{
std
::
string
to_string
(
observer_state
x
)
{
switch
(
x
)
{
default:
return
"???"
;
case
observer_state
:
:
idle
:
return
"caf::flow::observer_state::idle"
;
case
observer_state
:
:
subscribed
:
return
"caf::flow::observer_state::subscribed"
;
case
observer_state
:
:
completed
:
return
"caf::flow::observer_state::completed"
;
case
observer_state
:
:
aborted
:
return
"caf::flow::observer_state::aborted"
;
}
}
bool
from_string
(
std
::
string_view
in
,
observer_state
&
out
)
{
if
(
in
==
"caf::flow::observer_state::idle"
)
{
out
=
observer_state
::
idle
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::subscribed"
)
{
out
=
observer_state
::
subscribed
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::completed"
)
{
out
=
observer_state
::
completed
;
return
true
;
}
if
(
in
==
"caf::flow::observer_state::aborted"
)
{
out
=
observer_state
::
aborted
;
return
true
;
}
return
false
;
}
bool
from_integer
(
std
::
underlying_type_t
<
observer_state
>
in
,
observer_state
&
out
)
{
auto
result
=
static_cast
<
observer_state
>
(
in
);
switch
(
result
)
{
default:
return
false
;
case
observer_state
:
:
idle
:
case
observer_state
:
:
subscribed
:
case
observer_state
:
:
completed
:
case
observer_state
:
:
aborted
:
out
=
result
;
return
true
;
}
}
disposable
make_trivial_disposable
()
{
return
disposable
{
make_counted
<
trivial_impl
>
()};
}
void
passive_subscription_impl
::
request
(
size_t
n
)
{
demand
+=
n
;
}
void
passive_subscription_impl
::
dispose
()
{
disposed_flag
=
true
;
}
bool
passive_subscription_impl
::
disposed
()
const
noexcept
{
return
disposed_flag
;
}
}
// namespace caf::flow
std
::
string
to_string
(
level
lvl
)
{
switch
(
lvl
)
{
case
level
:
:
all
:
return
"all"
;
case
level
:
:
trace
:
return
"trace"
;
case
level
:
:
debug
:
return
"debug"
;
case
level
:
:
warning
:
return
"warning"
;
case
level
:
:
error
:
return
"error"
;
default:
return
"???"
;
}
}
bool
from_string
(
std
::
string_view
str
,
level
&
lvl
)
{
auto
set
=
[
&
](
level
value
)
{
lvl
=
value
;
return
true
;
};
if
(
str
==
"all"
)
return
set
(
level
::
all
);
else
if
(
str
==
"trace"
)
return
set
(
level
::
trace
);
else
if
(
str
==
"debug"
)
return
set
(
level
::
debug
);
else
if
(
str
==
"warning"
)
return
set
(
level
::
warning
);
else
if
(
str
==
"error"
)
return
set
(
level
::
error
);
else
return
false
;
}
bool
from_integer
(
uint8_t
val
,
level
&
lvl
)
{
if
(
val
<
5
)
{
lvl
=
static_cast
<
level
>
(
val
);
return
true
;
}
else
{
return
false
;
}
}
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
caf
;
init_global_meta_objects
<
id_block
::
core_test
>
();
core
::
init_global_meta_objects
();
return
test
::
main
(
argc
,
argv
);
}
CAF_TEST_MAIN
()
libcaf_core/test/hash/fnv.cpp
View file @
e2bea08c
...
...
@@ -2,49 +2,57 @@
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE hash.fnv
#include "caf/hash/fnv.hpp"
#include "c
ore-
test.hpp"
#include "c
af/test/
test.hpp"
#include <string>
using
namespace
caf
;
using
namespace
std
::
string_literals
;
using
namespace
std
::
literals
;
template
<
class
...
Ts
>
auto
fnv32_hash
(
Ts
&&
...
xs
)
{
return
hash
::
fnv
<
uint32_t
>::
compute
(
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
auto
fnv64_hash
(
Ts
&&
...
xs
)
{
return
hash
::
fnv
<
uint64_t
>::
compute
(
std
::
forward
<
Ts
>
(
xs
)...);
}
SUITE
(
"hash.fnv"
)
{
CAF_TEST
(
FNV
hashes
build
incrementally
)
{
hash
::
fnv
<
uint32_t
>
f
;
CHECK_EQ
(
f
.
result
,
0x811C9DC5u
);
TEST
(
"hash::fnv can build hashe values incrementally"
)
{
caf
::
hash
::
fnv
<
uint32_t
>
f
;
check_eq
(
f
.
result
,
0x811C9DC5u
);
f
.
value
(
'a'
);
CHECK_EQ
(
f
.
result
,
0xE40C292Cu
);
check_eq
(
f
.
result
,
0xE40C292Cu
);
f
.
value
(
'b'
);
CHECK_EQ
(
f
.
result
,
0x4D2505CAu
);
check_eq
(
f
.
result
,
0x4D2505CAu
);
f
.
value
(
'c'
);
CHECK_EQ
(
f
.
result
,
0x1A47E90Bu
);
check_eq
(
f
.
result
,
0x1A47E90Bu
);
f
.
value
(
'd'
);
CHECK_EQ
(
f
.
result
,
0xCE3479BDu
);
check_eq
(
f
.
result
,
0xCE3479BDu
);
}
CAF_TEST
(
FNV
supports
uint32
hashing
)
{
CHECK_EQ
(
fnv32_hash
(),
0x811C9DC5u
);
CHECK_EQ
(
fnv32_hash
(
"abcd"
s
),
0xCE3479BDu
);
CHECK_EQ
(
fnv32_hash
(
"C++ Actor Framework"
s
),
0x2FF91FE5u
);
TEST
(
"fnv::compute generates a hash value in one step"
)
{
SECTION
(
"32-bit"
)
{
using
hash_type
=
caf
::
hash
::
fnv
<
uint32_t
>
;
check_eq
(
hash_type
::
compute
(),
0x811C9DC5u
);
check_eq
(
hash_type
::
compute
(
"abcd"
s
),
0xCE3479BDu
);
check_eq
(
hash_type
::
compute
(
"C++ Actor Framework"
s
),
0x2FF91FE5u
);
}
SECTION
(
"64-bit"
)
{
using
hash_type
=
caf
::
hash
::
fnv
<
uint64_t
>
;
check_eq
(
hash_type
::
compute
(),
0xCBF29CE484222325ull
);
check_eq
(
hash_type
::
compute
(
"abcd"
s
),
0xFC179F83EE0724DDull
);
check_eq
(
hash_type
::
compute
(
"C++ Actor Framework"
s
),
0xA229A760C3AF69C5ull
);
}
}
CAF_TEST
(
FNV
supports
uint64
hashing
)
{
CHECK_EQ
(
fnv64_hash
(),
0xCBF29CE484222325ull
);
CHECK_EQ
(
fnv64_hash
(
"abcd"
s
),
0xFC179F83EE0724DDull
);
CHECK_EQ
(
fnv64_hash
(
"C++ Actor Framework"
s
),
0xA229A760C3AF69C5ull
);
struct
foo
{
std
::
string
bar
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
foo
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"bar"
,
x
.
bar
));
}
TEST
(
"fnv::compute can create hash values for types with inspect overloads"
)
{
using
hash_type
=
caf
::
hash
::
fnv
<
uint32_t
>
;
check_eq
(
hash_type
::
compute
(
foo
{
"abcd"
}),
0xCE3479BDu
);
check_eq
(
hash_type
::
compute
(
foo
{
"C++ Actor Framework"
}),
0x2FF91FE5u
);
}
}
// SUITE("hash.fnv")
libcaf_io/CMakeLists.txt
View file @
e2bea08c
...
...
@@ -61,6 +61,10 @@ caf_add_component(
TEST_SOURCES
test/io-test.cpp
TEST_SUITES
io.network.receive_buffer
LEGACY_TEST_SOURCES
test/io-legacy-test.cpp
LEGACY_TEST_SUITES
detail.prometheus_broker
io.basp.message_queue
io.basp_broker
...
...
@@ -69,7 +73,6 @@ caf_add_component(
io.monitor
io.network.default_multiplexer
io.network.ip_endpoint
io.receive_buffer
io.remote_actor
io.remote_group
io.remote_spawn
...
...
@@ -77,5 +80,5 @@ caf_add_component(
io.worker
)
if
(
CAF_ENABLE_TESTING AND UNIX
)
caf_add_test_suites
(
caf-io-test io.middleman
)
caf_add_test_suites
(
caf-io-
legacy-
test io.middleman
)
endif
()
libcaf_io/caf/io/network/receive_buffer.hpp
View file @
e2bea08c
...
...
@@ -4,6 +4,7 @@
#pragma once
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <limits>
...
...
libcaf_io/test/io-legacy-test.cpp
0 → 100644
View file @
e2bea08c
#define CAF_TEST_NO_MAIN
#include "caf/test/unit_test_impl.hpp"
#include "io-test.hpp"
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
caf
;
init_global_meta_objects
<
id_block
::
io_test
>
();
io
::
middleman
::
init_global_meta_objects
();
core
::
init_global_meta_objects
();
return
test
::
main
(
argc
,
argv
);
}
libcaf_io/test/io-test.cpp
View file @
e2bea08c
#define CAF_TEST_NO_MAIN
// 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/unit_test_impl.hpp"
#include "caf/io/middleman.hpp"
#include "caf/test/caf_test_main.hpp"
#include "io-test.hpp"
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
caf
;
init_global_meta_objects
<
id_block
::
io_test
>
();
io
::
middleman
::
init_global_meta_objects
();
core
::
init_global_meta_objects
();
return
test
::
main
(
argc
,
argv
);
}
CAF_TEST_MAIN
(
caf
::
io
::
middleman
)
libcaf_io/test/io/network/receive_buffer.cpp
0 → 100644
View file @
e2bea08c
// 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/io/network/receive_buffer.hpp"
#include "caf/test/test.hpp"
#include <algorithm>
#include <string_view>
using
namespace
std
::
literals
;
using
caf
::
io
::
network
::
receive_buffer
;
SUITE
(
"io.network.receive_buffer"
)
{
TEST
(
"construction"
)
{
SECTION
(
"default-constructed buffers are empty"
)
{
receive_buffer
uut
;
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
0u
);
check
(
uut
.
data
()
==
nullptr
);
check
(
uut
.
empty
());
}
SECTION
(
"constructing with a size > 0 allocates memory"
)
{
receive_buffer
uut
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
}
SECTION
(
"move-constructing from a buffer transfers ownership"
)
{
receive_buffer
src
(
1024
);
receive_buffer
uut
{
std
::
move
(
src
)};
check_eq
(
uut
.
size
(),
1024u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
}
}
TEST
(
"reserve allocates memory if necessary"
)
{
SECTION
(
"reserve(0) is a no-op"
)
{
receive_buffer
uut
;
uut
.
reserve
(
0
);
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
0u
);
check
(
uut
.
data
()
==
nullptr
);
check
(
uut
.
empty
());
}
SECTION
(
"reserve(n) allocates memory if n > capacity"
)
{
receive_buffer
uut
;
uut
.
reserve
(
1024
);
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
uut
.
begin
()
==
uut
.
end
());
check
(
uut
.
empty
());
}
SECTION
(
"reserve(n) is a no-op if n <= capacity"
)
{
receive_buffer
uut
;
uut
.
reserve
(
1024
);
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
uut
.
begin
()
==
uut
.
end
());
check
(
uut
.
empty
());
auto
data
=
uut
.
data
();
uut
.
reserve
(
512
);
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
==
data
);
}
}
TEST
(
"resize adds or removes elements if necessary"
)
{
SECTION
(
"resize(0) is a no-op"
)
{
receive_buffer
uut
;
uut
.
resize
(
0
);
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
0u
);
check
(
uut
.
empty
());
}
SECTION
(
"resize(n) is a no-op if n == size"
)
{
receive_buffer
uut
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
uut
.
resize
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
}
SECTION
(
"resize(n) adds elements if n > size"
)
{
receive_buffer
uut
;
uut
.
resize
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
}
SECTION
(
"resize(n) removes elements if n < size"
)
{
receive_buffer
uut
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
uut
.
resize
(
512
);
check_eq
(
uut
.
size
(),
512u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
}
}
TEST
(
"clear removes all elements"
)
{
receive_buffer
uut
(
1024
);
check_eq
(
uut
.
size
(),
1024u
);
uut
.
clear
();
check_eq
(
uut
.
size
(),
0u
);
check_eq
(
uut
.
capacity
(),
1024u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
uut
.
empty
());
}
TEST
(
"push_back appends elements"
)
{
receive_buffer
uut
;
uut
.
push_back
(
'h'
);
uut
.
push_back
(
'e'
);
uut
.
push_back
(
'l'
);
uut
.
push_back
(
'l'
);
uut
.
push_back
(
'o'
);
check_eq
(
uut
.
size
(),
5u
);
check_eq
(
uut
.
capacity
(),
8u
);
check
(
uut
.
data
()
!=
nullptr
);
check
(
!
uut
.
empty
());
check_eq
(
std
::
string_view
(
uut
.
data
(),
uut
.
size
()),
"hello"
);
}
TEST
(
"insert adds elements at the given position"
)
{
receive_buffer
uut
;
uut
.
insert
(
uut
.
begin
(),
'o'
);
uut
.
insert
(
uut
.
begin
(),
'l'
);
uut
.
insert
(
uut
.
begin
(),
'l'
);
uut
.
insert
(
uut
.
begin
(),
'e'
);
uut
.
insert
(
uut
.
begin
(),
'h'
);
check_eq
(
std
::
string_view
(
uut
.
data
(),
uut
.
size
()),
"hello"
);
auto
world
=
"world"
sv
;
uut
.
insert
(
uut
.
end
(),
world
.
begin
(),
world
.
end
());
uut
.
insert
(
uut
.
begin
()
+
5
,
' '
);
check_eq
(
std
::
string_view
(
uut
.
data
(),
uut
.
size
()),
"hello world"
);
}
TEST
(
"shrink_to_fit reduces capacity to size"
)
{
auto
str
=
"hello world"
sv
;
receive_buffer
uut
;
uut
.
reserve
(
512
);
check_eq
(
uut
.
capacity
(),
512u
);
uut
.
insert
(
uut
.
end
(),
str
.
begin
(),
str
.
end
());
uut
.
shrink_to_fit
();
check_eq
(
uut
.
capacity
(),
str
.
size
());
}
TEST
(
"swap exchanges the content of two buffers"
)
{
auto
str1
=
"hello"
sv
;
auto
str2
=
"world"
sv
;
receive_buffer
buf1
;
receive_buffer
buf2
;
buf1
.
insert
(
buf1
.
end
(),
str1
.
begin
(),
str1
.
end
());
buf2
.
insert
(
buf2
.
end
(),
str2
.
begin
(),
str2
.
end
());
auto
*
buf1_data
=
buf1
.
data
();
auto
*
buf2_data
=
buf2
.
data
();
check_eq
(
std
::
string_view
(
buf1
.
data
(),
buf1
.
size
()),
"hello"
);
check_eq
(
std
::
string_view
(
buf2
.
data
(),
buf2
.
size
()),
"world"
);
buf1
.
swap
(
buf2
);
check_eq
(
std
::
string_view
(
buf1
.
data
(),
buf1
.
size
()),
"world"
);
check_eq
(
std
::
string_view
(
buf2
.
data
(),
buf2
.
size
()),
"hello"
);
check
(
buf1
.
data
()
==
buf2_data
);
check
(
buf2
.
data
()
==
buf1_data
);
}
}
// SUITE("io.network.receive_buffer")
libcaf_io/test/io/receive_buffer.cpp
deleted
100644 → 0
View file @
a1ba72cc
// 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/config.hpp"
#define CAF_SUITE io_receive_buffer
#include "io-test.hpp"
#include <algorithm>
#include "caf/io/network/receive_buffer.hpp"
using
namespace
caf
;
using
caf
::
io
::
network
::
receive_buffer
;
namespace
{
struct
fixture
{
receive_buffer
a
;
receive_buffer
b
;
std
::
vector
<
char
>
vec
;
fixture
()
:
b
(
1024ul
),
vec
{
'h'
,
'a'
,
'l'
,
'l'
,
'o'
}
{
// nop
}
std
::
string
as_string
(
const
receive_buffer
&
xs
)
{
std
::
string
result
;
for
(
auto
&
x
:
xs
)
result
+=
static_cast
<
char
>
(
x
);
return
result
;
}
};
}
// namespace
BEGIN_FIXTURE_SCOPE
(
fixture
)
CAF_TEST
(
constructors
)
{
CHECK_EQ
(
a
.
size
(),
0ul
);
CHECK_EQ
(
a
.
capacity
(),
0ul
);
CHECK
(
a
.
data
()
==
nullptr
);
CHECK
(
a
.
empty
());
CHECK_EQ
(
b
.
size
(),
1024ul
);
CHECK_EQ
(
b
.
capacity
(),
1024ul
);
CHECK
(
b
.
data
()
!=
nullptr
);
CHECK
(
!
b
.
empty
());
receive_buffer
other
{
std
::
move
(
b
)};
CHECK_EQ
(
other
.
size
(),
1024ul
);
CHECK_EQ
(
other
.
capacity
(),
1024ul
);
CHECK
(
other
.
data
()
!=
nullptr
);
CHECK
(
!
other
.
empty
());
}
CAF_TEST
(
reserve
)
{
a
.
reserve
(
0
);
CHECK_EQ
(
a
.
size
(),
0ul
);
CHECK_EQ
(
a
.
capacity
(),
0ul
);
CHECK
(
a
.
data
()
==
nullptr
);
CHECK
(
a
.
empty
());
a
.
reserve
(
1024
);
CHECK_EQ
(
a
.
size
(),
0ul
);
CHECK_EQ
(
a
.
capacity
(),
1024ul
);
CHECK
(
a
.
data
()
!=
nullptr
);
CHECK
(
a
.
begin
()
==
a
.
end
());
CHECK
(
a
.
empty
());
a
.
reserve
(
512
);
CHECK_EQ
(
a
.
size
(),
0ul
);
CHECK_EQ
(
a
.
capacity
(),
1024ul
);
CHECK
(
a
.
data
()
!=
nullptr
);
CHECK
(
a
.
begin
()
==
a
.
end
());
CHECK
(
a
.
empty
());
}
CAF_TEST
(
resize
)
{
a
.
resize
(
512
);
CHECK_EQ
(
a
.
size
(),
512ul
);
CHECK_EQ
(
a
.
capacity
(),
512ul
);
CHECK
(
a
.
data
()
!=
nullptr
);
CHECK
(
!
a
.
empty
());
b
.
resize
(
512
);
CHECK_EQ
(
b
.
size
(),
512ul
);
CHECK_EQ
(
b
.
capacity
(),
1024ul
);
CHECK
(
b
.
data
()
!=
nullptr
);
CHECK
(
!
b
.
empty
());
a
.
resize
(
1024
);
std
::
fill
(
a
.
begin
(),
a
.
end
(),
'a'
);
auto
cnt
=
0
;
CHECK
(
std
::
all_of
(
a
.
begin
(),
a
.
end
(),
[
&
](
char
c
)
{
++
cnt
;
return
c
==
'a'
;
}));
CHECK_EQ
(
cnt
,
1024
);
a
.
resize
(
10
);
cnt
=
0
;
CHECK
(
std
::
all_of
(
a
.
begin
(),
a
.
end
(),
[
&
](
char
c
)
{
++
cnt
;
return
c
==
'a'
;
}));
CHECK_EQ
(
cnt
,
10
);
a
.
resize
(
1024
);
cnt
=
0
;
CHECK
(
std
::
all_of
(
a
.
begin
(),
a
.
end
(),
[
&
](
char
c
)
{
++
cnt
;
return
c
==
'a'
;
}));
CHECK_EQ
(
cnt
,
1024
);
}
CAF_TEST
(
push_back
)
{
for
(
auto
c
:
vec
)
a
.
push_back
(
c
);
CHECK_EQ
(
vec
.
size
(),
a
.
size
());
CHECK_EQ
(
a
.
capacity
(),
8ul
);
CHECK
(
a
.
data
()
!=
nullptr
);
CHECK
(
!
a
.
empty
());
CHECK
(
std
::
equal
(
vec
.
begin
(),
vec
.
end
(),
a
.
begin
()));
}
CAF_TEST
(
insert
)
{
for
(
auto
c
:
vec
)
a
.
insert
(
a
.
end
(),
c
);
CHECK_EQ
(
as_string
(
a
),
"hallo"
);
a
.
insert
(
a
.
begin
(),
'!'
);
CHECK_EQ
(
as_string
(
a
),
"!hallo"
);
a
.
insert
(
a
.
begin
()
+
4
,
'-'
);
CHECK_EQ
(
as_string
(
a
),
"!hal-lo"
);
std
::
string
foo
=
"foo:"
;
a
.
insert
(
a
.
begin
()
+
1
,
foo
.
begin
(),
foo
.
end
());
CHECK_EQ
(
as_string
(
a
),
"!foo:hal-lo"
);
std
::
string
bar
=
":bar"
;
a
.
insert
(
a
.
end
(),
bar
.
begin
(),
bar
.
end
());
CHECK_EQ
(
as_string
(
a
),
"!foo:hal-lo:bar"
);
}
CAF_TEST
(
shrink_to_fit
)
{
a
.
shrink_to_fit
();
CHECK_EQ
(
a
.
size
(),
0ul
);
CHECK_EQ
(
a
.
capacity
(),
0ul
);
CHECK
(
a
.
data
()
==
nullptr
);
CHECK
(
a
.
empty
());
}
CAF_TEST
(
swap
)
{
for
(
auto
c
:
vec
)
a
.
push_back
(
c
);
std
::
swap
(
a
,
b
);
CHECK_EQ
(
a
.
size
(),
1024ul
);
CHECK_EQ
(
a
.
capacity
(),
1024ul
);
CHECK
(
a
.
data
()
!=
nullptr
);
CHECK_EQ
(
b
.
size
(),
vec
.
size
());
CHECK_EQ
(
std
::
distance
(
b
.
begin
(),
b
.
end
()),
static_cast
<
receive_buffer
::
difference_type
>
(
vec
.
size
()));
CHECK_EQ
(
b
.
capacity
(),
8ul
);
CHECK
(
b
.
data
()
!=
nullptr
);
CHECK_EQ
(
*
(
b
.
data
()
+
0
),
'h'
);
CHECK_EQ
(
*
(
b
.
data
()
+
1
),
'a'
);
CHECK_EQ
(
*
(
b
.
data
()
+
2
),
'l'
);
CHECK_EQ
(
*
(
b
.
data
()
+
3
),
'l'
);
CHECK_EQ
(
*
(
b
.
data
()
+
4
),
'o'
);
}
END_FIXTURE_SCOPE
()
libcaf_net/CMakeLists.txt
View file @
e2bea08c
...
...
@@ -94,11 +94,14 @@ caf_add_component(
src/net/web_socket/server.cpp
src/net/web_socket/upper_layer.cpp
TEST_SOURCES
${
CMAKE_CURRENT_BINARY_DIR
}
/test/pem.cpp
test/net-test.cpp
TEST_SUITES
detail.convert_ip_endpoint
detail.rfc6455
LEGACY_TEST_SOURCES
${
CMAKE_CURRENT_BINARY_DIR
}
/test/pem.cpp
test/net-legacy-test.cpp
LEGACY_TEST_SUITES
detail.convert_ip_endpoint
net.accept_socket
net.actor_shell
net.datagram_socket
...
...
libcaf_net/test/detail/rfc6455.cpp
View file @
e2bea08c
This diff is collapsed.
Click to expand it.
libcaf_net/test/net-legacy-test.cpp
0 → 100644
View file @
e2bea08c
#include "net-test.hpp"
#include "caf/error.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/ssl/startup.hpp"
#include "caf/net/this_host.hpp"
#include "caf/raise_error.hpp"
#define CAF_TEST_NO_MAIN
#include "caf/test/unit_test_impl.hpp"
using
namespace
caf
;
// -- mock_stream_transport ----------------------------------------------------
net
::
multiplexer
&
mock_stream_transport
::
mpx
()
noexcept
{
return
*
mpx_
;
}
bool
mock_stream_transport
::
can_send_more
()
const
noexcept
{
return
true
;
}
bool
mock_stream_transport
::
is_reading
()
const
noexcept
{
return
max_read_size
>
0
;
}
void
mock_stream_transport
::
write_later
()
{
// nop
}
void
mock_stream_transport
::
shutdown
()
{
// nop
}
void
mock_stream_transport
::
switch_protocol
(
upper_layer_ptr
new_up
)
{
next
.
swap
(
new_up
);
}
bool
mock_stream_transport
::
switching_protocol
()
const
noexcept
{
return
next
!=
nullptr
;
}
void
mock_stream_transport
::
configure_read
(
net
::
receive_policy
policy
)
{
min_read_size
=
policy
.
min_size
;
max_read_size
=
policy
.
max_size
;
}
void
mock_stream_transport
::
begin_output
()
{
// nop
}
byte_buffer
&
mock_stream_transport
::
output_buffer
()
{
return
output
;
}
bool
mock_stream_transport
::
end_output
()
{
return
true
;
}
ptrdiff_t
mock_stream_transport
::
handle_input
()
{
ptrdiff_t
result
=
0
;
auto
switch_to_next_protocol
=
[
this
]
{
assert
(
next
);
// Switch to the new protocol and initialize it.
configure_read
(
net
::
receive_policy
::
stop
());
up
.
reset
(
next
.
release
());
if
(
auto
err
=
up
->
start
(
this
))
{
up
.
reset
();
return
false
;
}
return
true
;
};
// Loop until we have drained the buffer as much as we can.
while
(
max_read_size
>
0
&&
input
.
size
()
>=
min_read_size
)
{
auto
n
=
std
::
min
(
input
.
size
(),
size_t
{
max_read_size
});
auto
bytes
=
make_span
(
input
.
data
(),
n
);
auto
delta
=
bytes
.
subspan
(
delta_offset
);
auto
consumed
=
up
->
consume
(
bytes
,
delta
);
if
(
consumed
<
0
)
{
// Negative values indicate that the application encountered an
// unrecoverable error.
return
result
;
}
else
if
(
static_cast
<
size_t
>
(
consumed
)
>
n
)
{
// Must not happen. An application cannot handle more data then we pass
// to it.
up
->
abort
(
make_error
(
sec
::
logic_error
,
"consumed > buffer.size"
));
return
result
;
}
else
if
(
consumed
==
0
)
{
if
(
next
)
{
// When switching protocol, the new layer has never seen the data, so we
// might just re-invoke the same data again.
if
(
!
switch_to_next_protocol
())
return
-
1
;
}
else
{
// See whether the next iteration would change what we pass to the
// application (max_read_size_ may have changed). Otherwise, we'll try
// again later.
delta_offset
=
static_cast
<
ptrdiff_t
>
(
n
);
if
(
n
==
std
::
min
(
input
.
size
(),
size_t
{
max_read_size
}))
{
return
result
;
}
// else: "Fall through".
}
}
else
{
if
(
next
&&
!
switch_to_next_protocol
())
return
-
1
;
// Shove the unread bytes to the beginning of the buffer and continue
// to the next loop iteration.
result
+=
consumed
;
auto
del
=
static_cast
<
size_t
>
(
consumed
);
delta_offset
=
static_cast
<
ptrdiff_t
>
(
n
-
del
);
input
.
erase
(
input
.
begin
(),
input
.
begin
()
+
del
);
}
}
return
result
;
}
// -- mock_web_socket_app ------------------------------------------------------
mock_web_socket_app
::
mock_web_socket_app
(
bool
request_messages_on_start
)
:
request_messages_on_start
(
request_messages_on_start
)
{
// nop
}
caf
::
error
mock_web_socket_app
::
start
(
caf
::
net
::
web_socket
::
lower_layer
*
ll
)
{
down
=
ll
;
if
(
request_messages_on_start
)
down
->
request_messages
();
return
caf
::
none
;
}
void
mock_web_socket_app
::
prepare_send
()
{
// nop
}
bool
mock_web_socket_app
::
done_sending
()
{
return
true
;
}
caf
::
error
mock_web_socket_app
::
accept
(
const
caf
::
net
::
http
::
request_header
&
hdr
)
{
// Store the request information in cfg to evaluate them later.
auto
&
ws
=
cfg
[
"web-socket"
].
as_dictionary
();
put
(
ws
,
"method"
,
to_rfc_string
(
hdr
.
method
()));
put
(
ws
,
"path"
,
std
::
string
{
hdr
.
path
()});
put
(
ws
,
"query"
,
hdr
.
query
());
put
(
ws
,
"fragment"
,
hdr
.
fragment
());
put
(
ws
,
"http-version"
,
hdr
.
version
());
if
(
hdr
.
num_fields
()
>
0
)
{
auto
&
fields
=
ws
[
"fields"
].
as_dictionary
();
hdr
.
for_each_field
([
&
fields
](
auto
key
,
auto
val
)
{
put
(
fields
,
std
::
string
{
key
},
std
::
string
{
val
});
});
}
return
caf
::
none
;
}
void
mock_web_socket_app
::
abort
(
const
caf
::
error
&
reason
)
{
abort_reason
=
reason
;
}
ptrdiff_t
mock_web_socket_app
::
consume_text
(
std
::
string_view
text
)
{
text_input
.
insert
(
text_input
.
end
(),
text
.
begin
(),
text
.
end
());
return
static_cast
<
ptrdiff_t
>
(
text
.
size
());
}
ptrdiff_t
mock_web_socket_app
::
consume_binary
(
caf
::
byte_span
bytes
)
{
binary_input
.
insert
(
binary_input
.
end
(),
bytes
.
begin
(),
bytes
.
end
());
return
static_cast
<
ptrdiff_t
>
(
bytes
.
size
());
}
// -- barrier ------------------------------------------------------------------
void
barrier
::
arrive_and_wait
()
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mx_
};
auto
new_count
=
++
count_
;
if
(
new_count
==
num_threads_
)
{
cv_
.
notify_all
();
}
else
if
(
new_count
>
num_threads_
)
{
count_
=
1
;
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
else
{
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
}
// -- main --------------------------------------------------------------------
int
main
(
int
argc
,
char
**
argv
)
{
net
::
this_host
::
startup
();
net
::
ssl
::
startup
();
using
namespace
caf
;
net
::
middleman
::
init_global_meta_objects
();
core
::
init_global_meta_objects
();
auto
result
=
test
::
main
(
argc
,
argv
);
net
::
ssl
::
cleanup
();
net
::
this_host
::
cleanup
();
return
result
;
}
libcaf_net/test/net-test.cpp
View file @
e2bea08c
#include "net-test.hpp"
// 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/error.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/ssl/startup.hpp"
#include "caf/net/this_host.hpp"
#include "caf/raise_error.hpp"
#include "caf/test/caf_test_main.hpp"
#define CAF_TEST_NO_MAIN
#include "caf/test/unit_test_impl.hpp"
using
namespace
caf
;
// -- mock_stream_transport ----------------------------------------------------
net
::
multiplexer
&
mock_stream_transport
::
mpx
()
noexcept
{
return
*
mpx_
;
}
bool
mock_stream_transport
::
can_send_more
()
const
noexcept
{
return
true
;
}
bool
mock_stream_transport
::
is_reading
()
const
noexcept
{
return
max_read_size
>
0
;
}
void
mock_stream_transport
::
write_later
()
{
// nop
}
void
mock_stream_transport
::
shutdown
()
{
// nop
}
void
mock_stream_transport
::
switch_protocol
(
upper_layer_ptr
new_up
)
{
next
.
swap
(
new_up
);
}
bool
mock_stream_transport
::
switching_protocol
()
const
noexcept
{
return
next
!=
nullptr
;
}
void
mock_stream_transport
::
configure_read
(
net
::
receive_policy
policy
)
{
min_read_size
=
policy
.
min_size
;
max_read_size
=
policy
.
max_size
;
}
void
mock_stream_transport
::
begin_output
()
{
// nop
}
byte_buffer
&
mock_stream_transport
::
output_buffer
()
{
return
output
;
}
bool
mock_stream_transport
::
end_output
()
{
return
true
;
}
ptrdiff_t
mock_stream_transport
::
handle_input
()
{
ptrdiff_t
result
=
0
;
auto
switch_to_next_protocol
=
[
this
]
{
assert
(
next
);
// Switch to the new protocol and initialize it.
configure_read
(
net
::
receive_policy
::
stop
());
up
.
reset
(
next
.
release
());
if
(
auto
err
=
up
->
start
(
this
))
{
up
.
reset
();
return
false
;
}
return
true
;
};
// Loop until we have drained the buffer as much as we can.
while
(
max_read_size
>
0
&&
input
.
size
()
>=
min_read_size
)
{
auto
n
=
std
::
min
(
input
.
size
(),
size_t
{
max_read_size
});
auto
bytes
=
make_span
(
input
.
data
(),
n
);
auto
delta
=
bytes
.
subspan
(
delta_offset
);
auto
consumed
=
up
->
consume
(
bytes
,
delta
);
if
(
consumed
<
0
)
{
// Negative values indicate that the application encountered an
// unrecoverable error.
return
result
;
}
else
if
(
static_cast
<
size_t
>
(
consumed
)
>
n
)
{
// Must not happen. An application cannot handle more data then we pass
// to it.
up
->
abort
(
make_error
(
sec
::
logic_error
,
"consumed > buffer.size"
));
return
result
;
}
else
if
(
consumed
==
0
)
{
if
(
next
)
{
// When switching protocol, the new layer has never seen the data, so we
// might just re-invoke the same data again.
if
(
!
switch_to_next_protocol
())
return
-
1
;
}
else
{
// See whether the next iteration would change what we pass to the
// application (max_read_size_ may have changed). Otherwise, we'll try
// again later.
delta_offset
=
static_cast
<
ptrdiff_t
>
(
n
);
if
(
n
==
std
::
min
(
input
.
size
(),
size_t
{
max_read_size
}))
{
return
result
;
}
// else: "Fall through".
}
}
else
{
if
(
next
&&
!
switch_to_next_protocol
())
return
-
1
;
// Shove the unread bytes to the beginning of the buffer and continue
// to the next loop iteration.
result
+=
consumed
;
auto
del
=
static_cast
<
size_t
>
(
consumed
);
delta_offset
=
static_cast
<
ptrdiff_t
>
(
n
-
del
);
input
.
erase
(
input
.
begin
(),
input
.
begin
()
+
del
);
}
}
return
result
;
}
// -- mock_web_socket_app ------------------------------------------------------
mock_web_socket_app
::
mock_web_socket_app
(
bool
request_messages_on_start
)
:
request_messages_on_start
(
request_messages_on_start
)
{
// nop
}
caf
::
error
mock_web_socket_app
::
start
(
caf
::
net
::
web_socket
::
lower_layer
*
ll
)
{
down
=
ll
;
if
(
request_messages_on_start
)
down
->
request_messages
();
return
caf
::
none
;
}
void
mock_web_socket_app
::
prepare_send
()
{
// nop
}
bool
mock_web_socket_app
::
done_sending
()
{
return
true
;
}
caf
::
error
mock_web_socket_app
::
accept
(
const
caf
::
net
::
http
::
request_header
&
hdr
)
{
// Store the request information in cfg to evaluate them later.
auto
&
ws
=
cfg
[
"web-socket"
].
as_dictionary
();
put
(
ws
,
"method"
,
to_rfc_string
(
hdr
.
method
()));
put
(
ws
,
"path"
,
std
::
string
{
hdr
.
path
()});
put
(
ws
,
"query"
,
hdr
.
query
());
put
(
ws
,
"fragment"
,
hdr
.
fragment
());
put
(
ws
,
"http-version"
,
hdr
.
version
());
if
(
hdr
.
num_fields
()
>
0
)
{
auto
&
fields
=
ws
[
"fields"
].
as_dictionary
();
hdr
.
for_each_field
([
&
fields
](
auto
key
,
auto
val
)
{
put
(
fields
,
std
::
string
{
key
},
std
::
string
{
val
});
});
}
return
caf
::
none
;
}
void
mock_web_socket_app
::
abort
(
const
caf
::
error
&
reason
)
{
abort_reason
=
reason
;
}
ptrdiff_t
mock_web_socket_app
::
consume_text
(
std
::
string_view
text
)
{
text_input
.
insert
(
text_input
.
end
(),
text
.
begin
(),
text
.
end
());
return
static_cast
<
ptrdiff_t
>
(
text
.
size
());
}
ptrdiff_t
mock_web_socket_app
::
consume_binary
(
caf
::
byte_span
bytes
)
{
binary_input
.
insert
(
binary_input
.
end
(),
bytes
.
begin
(),
bytes
.
end
());
return
static_cast
<
ptrdiff_t
>
(
bytes
.
size
());
}
// -- barrier ------------------------------------------------------------------
void
barrier
::
arrive_and_wait
()
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mx_
};
auto
new_count
=
++
count_
;
if
(
new_count
==
num_threads_
)
{
cv_
.
notify_all
();
}
else
if
(
new_count
>
num_threads_
)
{
count_
=
1
;
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
else
{
cv_
.
wait
(
guard
,
[
this
]
{
return
count_
.
load
()
==
num_threads_
;
});
}
}
// -- main --------------------------------------------------------------------
int
main
(
int
argc
,
char
**
argv
)
{
net
::
this_host
::
startup
();
net
::
ssl
::
startup
();
using
namespace
caf
;
net
::
middleman
::
init_global_meta_objects
();
core
::
init_global_meta_objects
();
auto
result
=
test
::
main
(
argc
,
argv
);
net
::
ssl
::
cleanup
();
net
::
this_host
::
cleanup
();
return
result
;
}
CAF_TEST_MAIN
(
caf
::
net
::
middleman
)
libcaf_test/caf/test/and_given.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
namespace
caf
::
test
{
/// Represents an `AND_GIVEN` block.
class
and_given
:
public
block
{
class
CAF_TEST_EXPORT
and_given
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/and_then.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
namespace
caf
::
test
{
/// Represents an `AND_THEN` block.
class
and_then
:
public
block
{
class
CAF_TEST_EXPORT
and_then
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/and_when.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
namespace
caf
::
test
{
/// Represents an `AND_WHEN` block.
class
and_when
:
public
block
{
class
CAF_TEST_EXPORT
and_when
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/factory.hpp
View file @
e2bea08c
...
...
@@ -4,6 +4,7 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block_type.hpp"
#include "caf/test/fwd.hpp"
...
...
@@ -13,7 +14,7 @@
namespace
caf
::
test
{
/// A factory for creating runnable test definitions.
class
factory
{
class
CAF_TEST_EXPORT
factory
{
public:
friend
class
registry
;
...
...
libcaf_test/caf/test/given.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
namespace
caf
::
test
{
/// Represents a `GIVEN` block.
class
given
:
public
block
{
class
CAF_TEST_EXPORT
given
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/registry.hpp
View file @
e2bea08c
...
...
@@ -4,6 +4,7 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block_type.hpp"
#include "caf/test/factory.hpp"
#include "caf/test/fwd.hpp"
...
...
@@ -16,7 +17,7 @@
namespace
caf
::
test
{
/// A registry for our factories.
class
registry
{
class
CAF_TEST_EXPORT
registry
{
public:
/// Maps test names to factories. Elements are sorted by the order of their
/// registration.
...
...
libcaf_test/caf/test/runnable.hpp
View file @
e2bea08c
...
...
@@ -8,6 +8,7 @@
#include "caf/deep_to_string.hpp"
#include "caf/detail/format.hpp"
#include "caf/detail/source_location.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/test/binary_predicate.hpp"
#include "caf/test/block_type.hpp"
#include "caf/test/fwd.hpp"
...
...
@@ -18,7 +19,7 @@
namespace
caf
::
test
{
/// A runnable definition of a test case or scenario.
class
runnable
{
class
CAF_TEST_EXPORT
runnable
{
public:
/// Creates a new runnable.
/// @param ctx The test context.
...
...
libcaf_test/caf/test/runner.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/registry.hpp"
namespace
caf
::
test
{
/// Implements the main loop for running tests.
class
runner
{
class
CAF_TEST_EXPORT
runner
{
public:
/// Bundles the result of a command line parsing operation.
struct
parse_cli_result
{
...
...
libcaf_test/caf/test/scenario.hpp
View file @
e2bea08c
...
...
@@ -5,6 +5,7 @@
#pragma once
#include "caf/detail/pp.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/test/and_given.hpp"
#include "caf/test/and_then.hpp"
#include "caf/test/and_when.hpp"
...
...
@@ -21,7 +22,7 @@
namespace
caf
::
test
{
class
scenario
:
public
block
{
class
CAF_TEST_EXPORT
scenario
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/section.hpp
View file @
e2bea08c
...
...
@@ -4,11 +4,12 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
namespace
caf
::
test
{
class
section
:
public
block
{
class
CAF_TEST_EXPORT
section
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/test.hpp
View file @
e2bea08c
...
...
@@ -5,6 +5,7 @@
#pragma once
#include "caf/detail/pp.hpp"
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
#include "caf/test/context.hpp"
#include "caf/test/factory.hpp"
...
...
@@ -17,7 +18,7 @@
namespace
caf
::
test
{
/// Represents a `TEST` block.
class
test
:
public
block
{
class
CAF_TEST_EXPORT
test
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/then.hpp
View file @
e2bea08c
...
...
@@ -4,13 +4,14 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
#include "caf/test/block_type.hpp"
namespace
caf
::
test
{
/// Represents a `THEN` block.
class
then
:
public
block
{
class
CAF_TEST_EXPORT
then
:
public
block
{
public:
using
block
::
block
;
...
...
libcaf_test/caf/test/unit_test.hpp
View file @
e2bea08c
...
...
@@ -26,6 +26,7 @@
#include "caf/detail/type_traits.hpp"
namespace
caf
::
test
{
inline
namespace
legacy
{
#ifdef CAF_ENABLE_EXCEPTIONS
...
...
@@ -493,6 +494,7 @@ void require_bin(bool result, const char* file, size_t line, const char* expr,
const
std
::
string
&
lhs
,
const
std
::
string
&
rhs
);
}
// namespace detail
}
// namespace legacy
}
// namespace caf::test
// on the global namespace so that it can hidden via namespace-scoping
...
...
libcaf_test/caf/test/unit_test_impl.hpp
View file @
e2bea08c
...
...
@@ -28,6 +28,7 @@
#include "caf/test/unit_test.hpp"
namespace
caf
::
test
{
inline
namespace
legacy
{
#ifdef CAF_ENABLE_EXCEPTIONS
...
...
@@ -657,6 +658,7 @@ int main(int argc, char** argv) {
return
result
?
0
:
1
;
}
}
// namespace legacy
}
// namespace caf::test
#ifndef CAF_TEST_NO_MAIN
...
...
libcaf_test/caf/test/when.hpp
View file @
e2bea08c
...
...
@@ -4,12 +4,13 @@
#pragma once
#include "caf/detail/test_export.hpp"
#include "caf/test/block.hpp"
#include "caf/test/block_type.hpp"
namespace
caf
::
test
{
class
when
:
public
block
{
class
CAF_TEST_EXPORT
when
:
public
block
{
public:
using
block
::
block
;
...
...
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