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;
...
@@ -29,6 +29,8 @@ using namespace caf;
namespace
{
namespace
{
// -- composable behaviors using primitive data types --------------------------
using
i3_actor
=
typed_actor
<
replies_to
<
int
,
int
,
int
>::
with
<
int
>>
;
using
i3_actor
=
typed_actor
<
replies_to
<
int
,
int
,
int
>::
with
<
int
>>
;
using
d_actor
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
using
d_actor
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
...
@@ -67,109 +69,214 @@ public:
...
@@ -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
{
result
<
int
>
operator
()(
int
x
,
int
y
,
int
z
)
override
{
return
x
-
y
-
z
;
return
x
-
y
-
z
;
}
}
};
};
using
add_atom
=
atom_constant
<
atom
(
"Add"
)
>
;
// -- composable behaviors using param<T> arguments ----------------------------
using
get_name_atom
=
atom_constant
<
atom
(
"GetName"
)
>
;
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
// "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
// a simple dictionary
using
dict
=
named_actor
::
extend
<
replies_to
<
get_atom
,
std
::
string
>::
with
<
std
::
string
>
,
using
dict
=
named_actor
::
extend
<
replies_to
<
get_atom
,
counting_string
>::
with
<
counting_string
>
,
replies_to
<
put_atom
,
std
::
string
,
std
::
string
>::
with
<
void
>>
;
replies_to
<
put_atom
,
counting_string
,
counting_string
>::
with
<
void
>>
;
// a simple calculator
using
calc
=
named_actor
::
extend
<
replies_to
<
add_atom
,
int
,
int
>::
with
<
int
>>
;
class
dict_state
:
public
composable_behavior
<
dict
>
{
class
dict_state
:
public
composable_behavior
<
dict
>
{
public:
public:
result
<
std
::
string
>
operator
()(
get_name_atom
)
override
{
result
<
counting_
string
>
operator
()(
get_name_atom
)
override
{
return
"dictionary"
;
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
);
auto
i
=
values_
.
find
(
key
);
if
(
i
==
values_
.
end
())
if
(
i
==
values_
.
end
())
return
""
;
return
""
;
return
i
->
second
;
return
i
->
second
;
}
}
result
<
void
>
operator
()(
put_atom
,
param
<
std
::
string
>
key
,
result
<
void
>
operator
()(
put_atom
,
param
<
counting_string
>
key
,
param
<
std
::
string
>
value
)
override
{
param
<
counting_string
>
value
)
override
{
if
(
values_
.
count
(
key
)
!=
0
)
return
unit
;
values_
.
emplace
(
key
.
move
(),
value
.
move
());
values_
.
emplace
(
key
.
move
(),
value
.
move
());
return
unit
;
return
unit
;
}
}
protected:
protected:
std
::
unordered_map
<
std
::
string
,
std
::
string
>
values_
;
std
::
unordered_map
<
counting_string
,
counting_
string
>
values_
;
};
};
class
calc_state
:
public
composable_behavior
<
calc
>
{
struct
fixture
{
public:
actor_system
system
;
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"
;
}
};
};
}
// namespace <anonymous>
}
// namespace <anonymous>
CAF_TEST
(
composable_behaviors
)
{
CAF_TEST_FIXTURE_SCOPE
(
composable_behaviors_tests
,
fixture
)
actor_system
sys
;
//auto x1 = sys.spawn<stateful_impl<foo_actor_state>>();
CAF_TEST
(
composition
)
{
auto
x1
=
sys
.
spawn
<
foo_actor_state
>
();
// test foo_foo_actor_state
scoped_actor
self
{
sys
};
auto
f1
=
make_function_view
(
system
.
spawn
<
foo_actor_state
>
());
self
->
request
(
x1
,
infinite
,
1
,
2
,
4
).
receive
(
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
[](
int
y
)
{
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
CAF_CHECK_EQUAL
(
y
,
7
);
// 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
);
self
->
send_exit
(
x1
,
exit_reason
::
kill
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
//auto x2 = sys.spawn<stateful_impl<composed_behavior<i3_actor_state, d_actor_state>>>();
// test on-the-fly composition of i3_actor_state2 and d_actor_state
auto
x2
=
sys
.
spawn
<
composed_behavior
<
i3_actor_state
,
d_actor_state
>>
();
f1
.
assign
(
system
.
spawn
<
composed_behavior
<
i3_actor_state2
,
d_actor_state
>>
());
self
->
request
(
x2
,
infinite
,
1
,
2
,
4
).
receive
(
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
8
);
[](
int
y
)
{
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
CAF_CHECK_EQUAL
(
y
,
7
);
// 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
(
// send put message to dictionary again
[](
double
y1
,
double
y2
)
{
self
->
request
(
dict
,
infinite
,
put_msg
).
receive
(
CAF_CHECK_EQUAL
(
y1
,
1.0
);
[]
{
CAF_CHECK_EQUAL
(
y1
,
y2
);
// 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
);
// alter our initial put, this time moving it to the dictionary
//auto x3 = sys.spawn<stateful_impl<foo_actor_state2>>();
put_msg
.
get_as_mutable
<
counting_string
>
(
1
)
=
"neverlord"
;
auto
x3
=
sys
.
spawn
<
foo_actor_state2
>
();
put_msg
.
get_as_mutable
<
counting_string
>
(
2
)
=
"CAF"
;
self
->
request
(
x3
,
infinite
,
1
,
2
,
4
).
receive
(
// send put message to dictionary
[](
int
y
)
{
self
->
request
(
dict
,
infinite
,
std
::
move
(
put_msg
)).
receive
(
CAF_CHECK_EQUAL
(
y
,
-
5
);
[]
{
// 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
);
// finally, check for original key
//auto x4 = sys.spawn<stateful_impl<dict_calc_state>>();
self
->
request
(
dict
,
infinite
,
std
::
move
(
get_msg
)).
receive
(
auto
x4
=
sys
.
spawn
<
dict_calc_state
>
();
[](
const
counting_string
&
str
)
{
self
->
request
(
x4
,
infinite
,
add_atom
::
value
,
10
,
20
).
receive
(
// we receive a copy of the value, which is copied out of the map and
[](
int
y
)
{
// then moved into the result message;
CAF_CHECK_EQUAL
(
y
,
30
);
// 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