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
86da3d35
Commit
86da3d35
authored
Apr 29, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve unit test for composable behaviors
parent
2fbb85b5
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
172 additions
and
65 deletions
+172
-65
libcaf_core/test/composable_behavior.cpp
libcaf_core/test/composable_behavior.cpp
+172
-65
No files found.
libcaf_core/test/composable_behavior.cpp
View file @
86da3d35
...
...
@@ -29,6 +29,8 @@ using namespace caf;
namespace
{
// -- composable behaviors using primitive data types --------------------------
using
i3_actor
=
typed_actor
<
replies_to
<
int
,
int
,
int
>::
with
<
int
>>
;
using
d_actor
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
...
...
@@ -67,109 +69,214 @@ public:
}
};
struct
foo_actor_state2
:
composed_behavior
<
i3_actor_state2
,
i3_actor_state
,
d_actor_state
>
{
// checks whether CAF resolves "diamonds" properly by inheriting
// from two behaviors that both implement i3_actor
struct
foo_actor_state2
:
composed_behavior
<
i3_actor_state2
,
i3_actor_state
,
d_actor_state
>
{
result
<
int
>
operator
()(
int
x
,
int
y
,
int
z
)
override
{
return
x
-
y
-
z
;
}
};
using
add_atom
=
atom_constant
<
atom
(
"Add"
)
>
;
using
get_name_atom
=
atom_constant
<
atom
(
"GetName"
)
>
;
// -- composable behaviors using param<T> arguments ----------------------------
std
::
atomic
<
long
>
counting_strings_created
;
std
::
atomic
<
long
>
counting_strings_moved
;
std
::
atomic
<
long
>
counting_strings_destroyed
;
// counts how many instances where created
struct
counting_string
{
public:
counting_string
()
{
++
counting_strings_created
;
}
counting_string
(
const
char
*
cstr
)
:
str_
(
cstr
)
{
++
counting_strings_created
;
}
counting_string
(
const
counting_string
&
x
)
:
str_
(
x
.
str_
)
{
++
counting_strings_created
;
}
counting_string
(
counting_string
&&
x
)
:
str_
(
std
::
move
(
x
.
str_
))
{
++
counting_strings_created
;
++
counting_strings_moved
;
}
~
counting_string
()
{
++
counting_strings_destroyed
;
}
counting_string
&
operator
=
(
const
char
*
cstr
)
{
str_
=
cstr
;
return
*
this
;
}
const
std
::
string
&
str
()
const
{
return
str_
;
}
template
<
class
Processor
>
friend
void
serialize
(
Processor
&
proc
,
counting_string
&
x
)
{
proc
&
x
.
str_
;
}
private:
std
::
string
str_
;
};
bool
operator
==
(
const
counting_string
&
x
,
const
counting_string
&
y
)
{
return
x
.
str
()
==
y
.
str
();
}
bool
operator
==
(
const
counting_string
&
x
,
const
char
*
y
)
{
return
x
.
str
()
==
y
;
}
}
// namespace <anonymous>
namespace
std
{
template
<
>
struct
hash
<
counting_string
>
{
inline
size_t
operator
()(
const
counting_string
&
ref
)
const
{
hash
<
string
>
f
;
return
f
(
ref
.
str
());
}
};
}
// namespace std
namespace
{
using
add_atom
=
atom_constant
<
atom
(
"add"
)
>
;
using
get_name_atom
=
atom_constant
<
atom
(
"getName"
)
>
;
// "base" interface
using
named_actor
=
typed_actor
<
replies_to
<
get_name_atom
>::
with
<
std
::
string
>>
;
using
named_actor
=
typed_actor
<
replies_to
<
get_name_atom
>::
with
<
counting_
string
>>
;
// a simple dictionary
using
dict
=
named_actor
::
extend
<
replies_to
<
get_atom
,
std
::
string
>::
with
<
std
::
string
>
,
replies_to
<
put_atom
,
std
::
string
,
std
::
string
>::
with
<
void
>>
;
// a simple calculator
using
calc
=
named_actor
::
extend
<
replies_to
<
add_atom
,
int
,
int
>::
with
<
int
>>
;
using
dict
=
named_actor
::
extend
<
replies_to
<
get_atom
,
counting_string
>::
with
<
counting_string
>
,
replies_to
<
put_atom
,
counting_string
,
counting_string
>::
with
<
void
>>
;
class
dict_state
:
public
composable_behavior
<
dict
>
{
public:
result
<
std
::
string
>
operator
()(
get_name_atom
)
override
{
result
<
counting_
string
>
operator
()(
get_name_atom
)
override
{
return
"dictionary"
;
}
result
<
std
::
string
>
operator
()(
get_atom
,
param
<
std
::
string
>
key
)
override
{
result
<
counting_string
>
operator
()(
get_atom
,
param
<
counting_
string
>
key
)
override
{
auto
i
=
values_
.
find
(
key
);
if
(
i
==
values_
.
end
())
return
""
;
return
i
->
second
;
}
result
<
void
>
operator
()(
put_atom
,
param
<
std
::
string
>
key
,
param
<
std
::
string
>
value
)
override
{
result
<
void
>
operator
()(
put_atom
,
param
<
counting_string
>
key
,
param
<
counting_string
>
value
)
override
{
if
(
values_
.
count
(
key
)
!=
0
)
return
unit
;
values_
.
emplace
(
key
.
move
(),
value
.
move
());
return
unit
;
}
protected:
std
::
unordered_map
<
std
::
string
,
std
::
string
>
values_
;
std
::
unordered_map
<
counting_string
,
counting_
string
>
values_
;
};
class
calc_state
:
public
composable_behavior
<
calc
>
{
public:
result
<
std
::
string
>
operator
()(
get_name_atom
)
override
{
return
"calculator"
;
}
result
<
int
>
operator
()(
add_atom
,
int
x
,
int
y
)
override
{
return
x
+
y
;
}
};
class
dict_calc_state
:
public
composed_behavior
<
dict_state
,
calc_state
>
{
public:
// composed_behavior<...> will mark this operator pure virtual, because
// of conflicting declarations in dict_state and calc_state
result
<
std
::
string
>
operator
()(
get_name_atom
)
override
{
return
"calculating dictionary"
;
}
struct
fixture
{
actor_system
system
;
};
}
// namespace <anonymous>
CAF_TEST
(
composable_behaviors
)
{
actor_system
sys
;
//auto x1 = sys.spawn<stateful_impl<foo_actor_state>>();
auto
x1
=
sys
.
spawn
<
foo_actor_state
>
();
scoped_actor
self
{
sys
};
self
->
request
(
x1
,
infinite
,
1
,
2
,
4
).
receive
(
[](
int
y
)
{
CAF_CHECK_EQUAL
(
y
,
7
);
}
);
self
->
send_exit
(
x1
,
exit_reason
::
kill
);
//auto x2 = sys.spawn<stateful_impl<composed_behavior<i3_actor_state, d_actor_state>>>();
auto
x2
=
sys
.
spawn
<
composed_behavior
<
i3_actor_state
,
d_actor_state
>>
();
self
->
request
(
x2
,
infinite
,
1
,
2
,
4
).
receive
(
[](
int
y
)
{
CAF_CHECK_EQUAL
(
y
,
7
);
CAF_TEST_FIXTURE_SCOPE
(
composable_behaviors_tests
,
fixture
)
CAF_TEST
(
composition
)
{
// test foo_foo_actor_state
auto
f1
=
make_function_view
(
system
.
spawn
<
foo_actor_state
>
());
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
// test on-the-fly composition of i3_actor_state and d_actor_state
f1
.
assign
(
system
.
spawn
<
composed_behavior
<
i3_actor_state
,
d_actor_state
>>
());
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
// test on-the-fly composition of i3_actor_state2 and d_actor_state
f1
.
assign
(
system
.
spawn
<
composed_behavior
<
i3_actor_state2
,
d_actor_state
>>
());
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
8
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
// test foo_actor_state2
f1
.
assign
(
system
.
spawn
<
foo_actor_state2
>
());
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
-
5
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
}
CAF_TEST
(
param_detaching
)
{
auto
dict
=
actor_cast
<
actor
>
(
system
.
spawn
<
dict_state
>
());
scoped_actor
self
{
system
};
// Using CAF is the key to success!
counting_string
key
=
"CAF"
;
counting_string
value
=
"success"
;
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
// wrap two strings into messages
auto
put_msg
=
make_message
(
put_atom
::
value
,
key
,
value
);
auto
get_msg
=
make_message
(
get_atom
::
value
,
key
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
5
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
// send put message to dictionary
self
->
request
(
dict
,
infinite
,
put_msg
).
receive
(
[]
{
// the handler of put_atom calls .move() on key and value,
// both causing to detach + move into the map
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
}
);
self
->
request
(
x2
,
infinite
,
1.0
).
receive
(
[](
double
y1
,
double
y2
)
{
CAF_CHECK_EQUAL
(
y1
,
1.0
);
CAF_CHECK_EQUAL
(
y1
,
y2
);
// send put message to dictionary again
self
->
request
(
dict
,
infinite
,
put_msg
).
receive
(
[]
{
// the handler checks whether key already exists -> no copies
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
}
);
self
->
send_exit
(
x2
,
exit_reason
::
kill
);
//auto x3 = sys.spawn<stateful_impl<foo_actor_state2>>();
auto
x3
=
sys
.
spawn
<
foo_actor_state2
>
();
self
->
request
(
x3
,
infinite
,
1
,
2
,
4
).
receive
(
[](
int
y
)
{
CAF_CHECK_EQUAL
(
y
,
-
5
);
// alter our initial put, this time moving it to the dictionary
put_msg
.
get_as_mutable
<
counting_string
>
(
1
)
=
"neverlord"
;
put_msg
.
get_as_mutable
<
counting_string
>
(
2
)
=
"CAF"
;
// send put message to dictionary
self
->
request
(
dict
,
infinite
,
std
::
move
(
put_msg
)).
receive
(
[]
{
// the handler of put_atom calls .move() on key and value,
// but no detaching occurs this time (unique access) -> move into the map
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
11
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
4
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
4
);
}
);
self
->
send_exit
(
x3
,
exit_reason
::
kill
);
//auto x4 = sys.spawn<stateful_impl<dict_calc_state>>();
auto
x4
=
sys
.
spawn
<
dict_calc_state
>
();
self
->
request
(
x4
,
infinite
,
add_atom
::
value
,
10
,
20
).
receive
(
[](
int
y
)
{
CAF_CHECK_EQUAL
(
y
,
30
);
// finally, check for original key
self
->
request
(
dict
,
infinite
,
std
::
move
(
get_msg
)).
receive
(
[](
const
counting_string
&
str
)
{
// we receive a copy of the value, which is copied out of the map and
// then moved into the result message;
// the string from our get_msg is destroyed
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
13
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
5
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
6
);
CAF_CHECK_EQUAL
(
str
,
"success"
);
}
);
self
->
send_exit
(
x4
,
exit_reason
::
kill
);
// temporary of our handler is destroyed
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
7
);
self
->
send_exit
(
dict
,
exit_reason
::
kill
);
self
->
await_all_other_actors_done
();
// only `key` and `value` from this scope remain
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
11
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment