使用自定义原子测试类型化角色时的分段错误
Segmentation Faults when testing typed actors with custom atoms
我正在尝试对我的演员使用测试宏,但我遇到了很多分段错误。我相信我已经将问题缩小到我对自定义原子的使用。为了演示这个问题,我修改了 here 中的 'simple actor test' 以使加法器成为强类型。
#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(int, int)>;
calculator_type::behavior_type adder() {
return {
[=](int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
效果很好。然后我更进一步添加了一个名为“add_numbers”
的自定义原子
#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(calc_msgs, first_custom_type_id)
CAF_ADD_ATOM(calc_msgs, add_numbers)
CAF_END_TYPE_ID_BLOCK(calc_msgs)
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(add_numbers, int, int)>;
calculator_type::behavior_type adder() {
return {
[=](add_numbers, int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, add_numbers_v, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
这可以正常编译,但会在运行时产生分段错误。我怀疑这与我没有将 calc_msgs
传递给任何东西有关。我怎么做?还是有其他事情发生?
ID 块添加了编译时元数据。但是你还需要通过
初始化一些运行时间的状态
init_global_meta_objects<caf::id_block::calc_msgs>();
理想情况下,在调用 任何 其他 CAF 函数之前初始化此状态。特别是在初始化演员系统之前。 CAF 本身为其测试套件使用自定义 main
函数来执行此操作(参见 core-test.cpp)。在您的情况下,它看起来有点像这样:
int main(int argc, char** argv) {
using namespace caf;
init_global_meta_objects<id_block::calc_msgs>();
core::init_global_meta_objects();
return test::main(argc, argv);
}
这可能意味着您需要将类型 ID 块放入头文件中。不过,这对单元测试来说并没有什么特别之处。如果您 运行 一个普通的 CAF 应用程序,您还需要初始化全局元对象。 CAF_MAIN
可以为您完成,只要您将类型 ID 块传递给它,或者您需要手动调用函数。 CAF 手册在此处更详细地介绍了这一点:https://actor-framework.readthedocs.io/en/0.18.5/ConfiguringActorApplications.html#configuring-actor-applications.
如果这是您目前唯一的测试,您可以在包含 caf/test/unit_test_impl.hpp
之前定义 CAF_TEST_NO_MAIN
,然后添加自定义 main
函数。不过,一旦您拥有多个测试套件,将 main
移动到它自己的文件中是有意义的。
我正在尝试对我的演员使用测试宏,但我遇到了很多分段错误。我相信我已经将问题缩小到我对自定义原子的使用。为了演示这个问题,我修改了 here 中的 'simple actor test' 以使加法器成为强类型。
#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(int, int)>;
calculator_type::behavior_type adder() {
return {
[=](int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
效果很好。然后我更进一步添加了一个名为“add_numbers”
的自定义原子#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(calc_msgs, first_custom_type_id)
CAF_ADD_ATOM(calc_msgs, add_numbers)
CAF_END_TYPE_ID_BLOCK(calc_msgs)
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(add_numbers, int, int)>;
calculator_type::behavior_type adder() {
return {
[=](add_numbers, int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, add_numbers_v, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
这可以正常编译,但会在运行时产生分段错误。我怀疑这与我没有将 calc_msgs
传递给任何东西有关。我怎么做?还是有其他事情发生?
ID 块添加了编译时元数据。但是你还需要通过
初始化一些运行时间的状态init_global_meta_objects<caf::id_block::calc_msgs>();
理想情况下,在调用 任何 其他 CAF 函数之前初始化此状态。特别是在初始化演员系统之前。 CAF 本身为其测试套件使用自定义 main
函数来执行此操作(参见 core-test.cpp)。在您的情况下,它看起来有点像这样:
int main(int argc, char** argv) {
using namespace caf;
init_global_meta_objects<id_block::calc_msgs>();
core::init_global_meta_objects();
return test::main(argc, argv);
}
这可能意味着您需要将类型 ID 块放入头文件中。不过,这对单元测试来说并没有什么特别之处。如果您 运行 一个普通的 CAF 应用程序,您还需要初始化全局元对象。 CAF_MAIN
可以为您完成,只要您将类型 ID 块传递给它,或者您需要手动调用函数。 CAF 手册在此处更详细地介绍了这一点:https://actor-framework.readthedocs.io/en/0.18.5/ConfiguringActorApplications.html#configuring-actor-applications.
如果这是您目前唯一的测试,您可以在包含 caf/test/unit_test_impl.hpp
之前定义 CAF_TEST_NO_MAIN
,然后添加自定义 main
函数。不过,一旦您拥有多个测试套件,将 main
移动到它自己的文件中是有意义的。