#include #include #include #include #include #include #ifndef XPLUGIN_NO_THREADS #include #endif #include using base_type = plugin::PluginBase; using factory_base_type = xp::xfactory_base; using plugin_registry_type = xp::xplugin_registry; void test_xplugin_impl(plugin_registry_type& registry) { CHECK_EQ(registry.size(), 3); auto factory_01 = registry["plugin_01"]; auto factory_02 = registry["plugin_02"]; auto factory_03 = registry["plugin_03"]; auto plugin_01 = factory_01->create(1, "a"); auto plugin_02 = factory_02->create(2, "b"); auto plugin_03 = factory_03->create(3, "c"); CHECK(plugin_01); CHECK(plugin_02); CHECK(plugin_03); CHECK_EQ(plugin_01->name(), "Plugin01"); CHECK_EQ(plugin_02->name(), "Plugin02"); CHECK_EQ(plugin_03->name(), "Plugin03"); CHECK_EQ(plugin_01->greet(), "hello from Plugin01"); CHECK_EQ(plugin_02->greet(), "hello from Plugin02"); CHECK_EQ(plugin_03->greet(), "hello from Plugin03"); // // iterate over plugins SUBCASE("begin_end") { std::cout << "begin" << std::endl; auto begin = registry.begin(); auto begin2 = registry.begin(); CHECK(begin == begin2); auto end = registry.end(); CHECK(begin != end); CHECK(end != begin); CHECK(begin == begin); CHECK(end == end); CHECK(begin == registry.begin()); CHECK(end == registry.end()); auto d = std::distance(begin, end); CHECK_EQ(d, 3); } SUBCASE("increment") { auto begin = registry.begin(); auto end = registry.end(); CHECK(begin != end); auto d = std::distance(begin, end); CHECK_EQ(d, 3); ++begin; CHECK(begin != end); d = std::distance(begin, end); CHECK_EQ(d, 2); ++begin; CHECK(begin != end); d = std::distance(begin, end); CHECK_EQ(d, 1); ++begin; CHECK(begin == end); d = std::distance(begin, end); CHECK_EQ(d, 0); } SUBCASE("dereference") { auto begin = registry.begin(); auto pair = *begin; CHECK_EQ(pair.first[0], 'p'); } SUBCASE("iterator-values-copy") { std::set plugin_names; for (auto p : registry) { p.second->create(1, "a")->greet(); plugin_names.insert(p.first); } CHECK_EQ(plugin_names.size(), 3); CHECK(plugin_names.count("plugin_01")); CHECK(plugin_names.count("plugin_02")); CHECK(plugin_names.count("plugin_03")); } SUBCASE("iterator-values-ref") { std::set plugin_names; for (auto &p : registry) { p.second->create(1, "a")->greet(); plugin_names.insert(p.first); } CHECK_EQ(plugin_names.size(), 3); CHECK(plugin_names.count("plugin_01")); CHECK(plugin_names.count("plugin_02")); CHECK(plugin_names.count("plugin_03")); } SUBCASE("iterator-unpack") { std::set plugin_names; for (auto [name, factory] : registry) { factory->create(1, "a")->greet(); plugin_names.insert(name); } CHECK_EQ(plugin_names.size(), 3); CHECK(plugin_names.count("plugin_01")); CHECK(plugin_names.count("plugin_02")); CHECK(plugin_names.count("plugin_03")); } } namespace { std::string get_default_extension() { #ifdef _WIN32 return ".dll"; #elif __APPLE__ return ".dylib"; #else return ".so"; #endif } } TEST_CASE("test_xplugin") { std::filesystem::path path("testplugin_a"); plugin_registry_type registry(path); test_xplugin_impl(registry); std::vector plugin_list; for (const auto &entry : std::filesystem::directory_iterator(path)) { if (entry.path().extension() == get_default_extension()) { plugin_list.push_back(entry.path()); } } plugin_registry_type registry2(std::move(plugin_list)); test_xplugin_impl(registry2); } TEST_CASE("test_xregistry_getter") { using base_type = plugin::PluginBase; using factory_base_type = xp::xfactory_base; using plugin_registry_type = xp::xplugin_registry; plugin_registry_type registry("testplugin_a"); CHECK_EQ(registry.size(), 3); auto factory_01 = registry["plugin_01"]; auto factory_02 = registry["plugin_02"]; auto factory_03 = registry["plugin_03"]; auto plugin_01 = factory_01->create(1, "a"); auto plugin_02 = factory_02->create(2, "b"); auto plugin_03 = factory_03->create(3, "c"); CHECK(plugin_01); CHECK(plugin_02); CHECK(plugin_03); CHECK_EQ(plugin_01->name(), "Plugin01"); CHECK_EQ(plugin_02->name(), "Plugin02"); CHECK_EQ(plugin_03->name(), "Plugin03"); CHECK_EQ(plugin_01->greet(), "hello from Plugin01"); CHECK_EQ(plugin_02->greet(), "hello from Plugin02"); CHECK_EQ(plugin_03->greet(), "hello from Plugin03"); } TEST_CASE("test_xregistry_open_same_lib_multiple_times") { using base_type = plugin::PluginBase; using factory_base_type = xp::xfactory_base; using plugin_registry_type = xp::xplugin_registry; std::vector registries(1000); for (auto ®istry : registries) { registry = new plugin_registry_type("testplugin_a"); } for (auto ®istry : registries) { CHECK_EQ(registry->size(), 3); auto factory_01 = registry->operator[]("plugin_01"); auto factory_02 = registry->operator[]("plugin_02"); auto factory_03 = registry->operator[]("plugin_03"); auto plugin_01 = factory_01->create(1, "a"); auto plugin_02 = factory_02->create(2, "b"); auto plugin_03 = factory_03->create(3, "c"); CHECK(plugin_01); CHECK(plugin_02); CHECK(plugin_03); CHECK_EQ(plugin_01->name(), "Plugin01"); CHECK_EQ(plugin_02->name(), "Plugin02"); CHECK_EQ(plugin_03->name(), "Plugin03"); } for (auto ®istry : registries) { delete registry; } } #ifndef XPLUGIN_NO_THREADS TEST_CASE("parallel_access") { using base_type = plugin::PluginBase; using factory_base_type = xp::xfactory_base; using plugin_registry_type = xp::xthread_save_plugin_registry; for (std::size_t i = 0; i < 1000; ++i) { plugin_registry_type registry("testplugin_a"); auto f = [&]() { auto factory_01 = registry["plugin_01"]; auto factory_02 = registry["plugin_02"]; auto factory_03 = registry["plugin_03"]; auto plugin_01 = factory_01->create(1, "a"); auto plugin_02 = factory_02->create(2, "b"); auto plugin_03 = factory_03->create(3, "c"); CHECK(plugin_01); CHECK(plugin_02); CHECK(plugin_03); CHECK_EQ(plugin_01->name(), "Plugin01"); CHECK_EQ(plugin_02->name(), "Plugin02"); CHECK_EQ(plugin_03->name(), "Plugin03"); }; std::thread thread1(f); std::thread thread2(f); thread1.join(); thread2.join(); } } #endif // XPLUGIN_NO_THREADS #ifndef XPLUGIN_NO_THREADS TEST_CASE("parallel_iterator_access") { using base_type = plugin::PluginBase; using factory_base_type = xp::xfactory_base; using plugin_registry_type = xp::xthread_save_plugin_registry; for (std::size_t i = 0; i < 1000; ++i) { plugin_registry_type registry("testplugin_a"); auto f = [®istry]() { for (auto name_factory : registry) { auto name = name_factory.first; auto factory = name_factory.second; CHECK(name[0] == 'p'); CHECK(factory); auto plugin = factory->create(1, "a"); CHECK(plugin); CHECK_EQ(plugin->name()[0], 'P'); } }; std::thread thread1(f); std::thread thread2(f); thread1.join(); thread2.join(); } } #endif // XPLUGIN_NO_THREADS