Extra2D/tests/test_plugin_loader.cpp

414 lines
12 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include <plugin/plugin_loader.h>
#include <plugin/iplugin.h>
#include <algorithm>
using namespace extra2d;
// ============================================================================
// 测试用插件类
// ============================================================================
class TestPlugin : public IPlugin {
public:
TestPlugin(const char* name, const char* version = "1.0.0",
const std::vector<std::string>& deps = {})
: name_(name), version_(version), dependencies_(deps) {
info_.name = name;
info_.version = version;
info_.dependencies = deps;
}
const PluginInfo& getInfo() const override { return info_; }
bool load() override {
loadCalled = true;
return loadResult;
}
void unload() override {
unloadCalled = true;
}
std::vector<std::string> getDependencies() const override {
return dependencies_;
}
std::string name_;
std::string version_;
std::vector<std::string> dependencies_;
PluginInfo info_;
bool loadCalled = false;
bool unloadCalled = false;
bool loadResult = true;
};
// ============================================================================
// PluginLoader 基础测试
// ============================================================================
TEST(PluginLoader, BasicOperations) {
PluginLoader loader;
TestPlugin plugin1("Plugin1");
TestPlugin plugin2("Plugin2", "2.0.0");
// 注册插件
loader.registerPlugin(&plugin1);
EXPECT_EQ(1, loader.getPluginCount());
EXPECT_TRUE(loader.hasPlugin("Plugin1"));
loader.registerPlugin(&plugin2);
EXPECT_EQ(2, loader.getPluginCount());
EXPECT_TRUE(loader.hasPlugin("Plugin2"));
// 获取插件
EXPECT_EQ(&plugin1, loader.getPlugin("Plugin1"));
EXPECT_EQ(&plugin2, loader.getPlugin("Plugin2"));
EXPECT_EQ(nullptr, loader.getPlugin("NonExistent"));
// 卸载插件
loader.unloadPlugin("Plugin1");
EXPECT_EQ(1, loader.getPluginCount());
EXPECT_FALSE(loader.hasPlugin("Plugin1"));
EXPECT_TRUE(loader.hasPlugin("Plugin2"));
}
TEST(PluginLoader, DuplicateRegistration) {
PluginLoader loader;
TestPlugin plugin1("SameName", "1.0.0");
TestPlugin plugin2("SameName", "2.0.0");
loader.registerPlugin(&plugin1);
EXPECT_EQ(1, loader.getPluginCount());
// 重复注册同名插件,后注册的应覆盖
loader.registerPlugin(&plugin2);
EXPECT_EQ(1, loader.getPluginCount());
IPlugin* retrieved = loader.getPlugin("SameName");
EXPECT_NE(nullptr, retrieved);
EXPECT_EQ("2.0.0", retrieved->getInfo().version);
}
TEST(PluginLoader, GetAllPlugins) {
PluginLoader loader;
TestPlugin plugin1("Plugin1");
TestPlugin plugin2("Plugin2");
TestPlugin plugin3("Plugin3");
loader.registerPlugin(&plugin1);
loader.registerPlugin(&plugin2);
loader.registerPlugin(&plugin3);
auto allPlugins = loader.getAllPlugins();
EXPECT_EQ(3, allPlugins.size());
}
// ============================================================================
// 加载和卸载测试
// ============================================================================
TEST(PluginLoader, LoadUnload) {
PluginLoader loader;
TestPlugin plugin1("Plugin1");
TestPlugin plugin2("Plugin2");
loader.registerPlugin(&plugin1);
loader.registerPlugin(&plugin2);
// 加载所有插件
EXPECT_TRUE(loader.initAll());
EXPECT_TRUE(plugin1.loadCalled);
EXPECT_TRUE(plugin2.loadCalled);
// 卸载所有插件
loader.shutdownAll();
EXPECT_TRUE(plugin1.unloadCalled);
EXPECT_TRUE(plugin2.unloadCalled);
}
TEST(PluginLoader, LoadFailure) {
PluginLoader loader;
TestPlugin plugin1("Plugin1");
TestPlugin plugin2("Plugin2");
plugin2.loadResult = false; // 模拟加载失败
loader.registerPlugin(&plugin1);
loader.registerPlugin(&plugin2);
// 加载应失败
EXPECT_FALSE(loader.initAll());
EXPECT_TRUE(plugin1.loadCalled);
EXPECT_TRUE(plugin2.loadCalled);
}
// ============================================================================
// 依赖关系测试
// ============================================================================
TEST(PluginLoader, Dependencies) {
PluginLoader loader;
// PluginC 依赖 PluginBPluginB 依赖 PluginA
TestPlugin pluginA("PluginA");
TestPlugin pluginB("PluginB", "1.0.0", {"PluginA"});
TestPlugin pluginC("PluginC", "1.0.0", {"PluginB"});
loader.registerPlugin(&pluginC);
loader.registerPlugin(&pluginB);
loader.registerPlugin(&pluginA);
// 所有插件都应能加载(依赖会自动解析)
EXPECT_TRUE(loader.initAll());
EXPECT_TRUE(pluginA.loadCalled);
EXPECT_TRUE(pluginB.loadCalled);
EXPECT_TRUE(pluginC.loadCalled);
loader.shutdownAll();
}
TEST(PluginLoader, MissingDependency) {
PluginLoader loader;
// PluginB 依赖不存在的 PluginA
TestPlugin pluginB("PluginB", "1.0.0", {"PluginA"});
loader.registerPlugin(&pluginB);
// 加载应失败(依赖未满足)
EXPECT_FALSE(loader.initAll());
EXPECT_FALSE(pluginB.loadCalled);
}
TEST(PluginLoader, CircularDependency) {
PluginLoader loader;
// A 依赖 BB 依赖 A循环依赖
TestPlugin pluginA("PluginA", "1.0.0", {"PluginB"});
TestPlugin pluginB("PluginB", "1.0.0", {"PluginA"});
loader.registerPlugin(&pluginA);
loader.registerPlugin(&pluginB);
// 循环依赖应能处理(目前实现可能不检测循环,但至少不应崩溃)
// 注意:根据实现不同,这可能成功或失败
loader.initAll();
loader.shutdownAll();
}
TEST(PluginLoader, DependencyLoadOrder) {
PluginLoader loader;
std::vector<std::string> loadOrder;
std::vector<std::string> unloadOrder;
class OrderTrackingPlugin : public IPlugin {
public:
OrderTrackingPlugin(const char* name,
const std::vector<std::string>& deps,
std::vector<std::string>& loadVec,
std::vector<std::string>& unloadVec)
: name_(name), loadOrder_(loadVec), unloadOrder_(unloadVec) {
info_.name = name;
info_.dependencies = deps;
}
const PluginInfo& getInfo() const override { return info_; }
bool load() override {
loadOrder_.push_back(name_);
return true;
}
void unload() override {
unloadOrder_.push_back(name_);
}
std::string name_;
PluginInfo info_;
std::vector<std::string>& loadOrder_;
std::vector<std::string>& unloadOrder_;
};
// C 依赖 BB 依赖 A
OrderTrackingPlugin pluginC("PluginC", {"PluginB"}, loadOrder, unloadOrder);
OrderTrackingPlugin pluginA("PluginA", {}, loadOrder, unloadOrder);
OrderTrackingPlugin pluginB("PluginB", {"PluginA"}, loadOrder, unloadOrder);
loader.registerPlugin(&pluginC);
loader.registerPlugin(&pluginA);
loader.registerPlugin(&pluginB);
loader.initAll();
// 加载顺序应满足依赖关系
EXPECT_EQ(3, loadOrder.size());
// A 必须在 B 之前加载
auto aPos = std::find(loadOrder.begin(), loadOrder.end(), "PluginA");
auto bPos = std::find(loadOrder.begin(), loadOrder.end(), "PluginB");
auto cPos = std::find(loadOrder.begin(), loadOrder.end(), "PluginC");
EXPECT_TRUE(aPos < bPos);
EXPECT_TRUE(bPos < cPos);
loader.shutdownAll();
// 卸载顺序应与加载顺序相反
EXPECT_EQ(3, unloadOrder.size());
}
// ============================================================================
// 空加载器测试
// ============================================================================
TEST(PluginLoader, EmptyLoader) {
PluginLoader loader;
EXPECT_EQ(0, loader.getPluginCount());
EXPECT_FALSE(loader.hasPlugin("AnyPlugin"));
EXPECT_EQ(nullptr, loader.getPlugin("AnyPlugin"));
auto allPlugins = loader.getAllPlugins();
EXPECT_EQ(0, allPlugins.size());
// 空加载器的初始化和关闭不应崩溃
EXPECT_TRUE(loader.initAll());
loader.shutdownAll();
}
TEST(PluginLoader, UnloadNonExistent) {
PluginLoader loader;
// 卸载不存在的插件不应崩溃
EXPECT_NO_THROW(loader.unloadPlugin("NonExistent"));
}
// ============================================================================
// 搜索路径测试
// ============================================================================
TEST(PluginLoader, SearchPaths) {
PluginLoader loader;
// 添加搜索路径
loader.addSearchPath("/usr/lib/extra2d/plugins");
loader.addSearchPath("/home/user/.extra2d/plugins");
loader.addSearchPath("./plugins");
// 搜索路径功能主要用于动态库加载,这里只验证不崩溃
EXPECT_NO_THROW(loader.loadPluginsFromDirectory("./non_existent_dir"));
}
// ============================================================================
// 插件信息测试
// ============================================================================
TEST(PluginLoader, PluginInfo) {
PluginLoader loader;
TestPlugin plugin("TestPlugin", "1.2.3");
plugin.info_.author = "Test Author";
plugin.info_.description = "Test Description";
plugin.info_.dependencies = {"Dep1", "Dep2"};
loader.registerPlugin(&plugin);
IPlugin* retrieved = loader.getPlugin("TestPlugin");
EXPECT_NE(nullptr, retrieved);
const PluginInfo& info = retrieved->getInfo();
EXPECT_EQ("TestPlugin", info.name);
EXPECT_EQ("1.2.3", info.version);
EXPECT_EQ("Test Author", info.author);
EXPECT_EQ("Test Description", info.description);
EXPECT_EQ(2, info.dependencies.size());
EXPECT_EQ("Dep1", info.dependencies[0]);
EXPECT_EQ("Dep2", info.dependencies[1]);
}
// ============================================================================
// 插件生命周期测试
// ============================================================================
TEST(PluginLoader, PluginLifecycle) {
PluginLoader loader;
enum class State { Created, Loaded, Running, Unloaded };
class LifecyclePlugin : public IPlugin {
public:
LifecyclePlugin(const char* name, State& state)
: name_(name), state_(state) {
state_ = State::Created;
info_.name = name;
}
const PluginInfo& getInfo() const override { return info_; }
bool load() override {
state_ = State::Loaded;
return true;
}
void unload() override {
state_ = State::Unloaded;
}
std::string name_;
State& state_;
PluginInfo info_;
};
State state = State::Created;
LifecyclePlugin plugin("Lifecycle", state);
EXPECT_EQ(State::Created, state);
loader.registerPlugin(&plugin);
loader.initAll();
EXPECT_EQ(State::Loaded, state);
loader.shutdownAll();
EXPECT_EQ(State::Unloaded, state);
}
// ============================================================================
// 复杂依赖测试
// ============================================================================
TEST(PluginLoader, ComplexDependencies) {
PluginLoader loader;
// 创建复杂的依赖图:
// A -> B -> D
// A -> C -> D
// E (独立)
TestPlugin pluginA("A", "1.0.0", {});
TestPlugin pluginB("B", "1.0.0", {"A"});
TestPlugin pluginC("C", "1.0.0", {"A"});
TestPlugin pluginD("D", "1.0.0", {"B", "C"});
TestPlugin pluginE("E", "1.0.0", {});
// 乱序注册
loader.registerPlugin(&pluginD);
loader.registerPlugin(&pluginB);
loader.registerPlugin(&pluginE);
loader.registerPlugin(&pluginC);
loader.registerPlugin(&pluginA);
// 所有插件都应能加载
EXPECT_TRUE(loader.initAll());
EXPECT_TRUE(pluginA.loadCalled);
EXPECT_TRUE(pluginB.loadCalled);
EXPECT_TRUE(pluginC.loadCalled);
EXPECT_TRUE(pluginD.loadCalled);
EXPECT_TRUE(pluginE.loadCalled);
loader.shutdownAll();
}