使用自定义原子测试类型化角色时的分段错误

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 移动到它自己的文件中是有意义的。