489 lines
16 KiB
C++
489 lines
16 KiB
C++
// ================================================================================================
|
||
// Audio Backend - 插件加载测试
|
||
// ================================================================================================
|
||
|
||
#include <gtest/gtest.h>
|
||
#include <gmock/gmock.h>
|
||
#include "plugin_host/core/plugin_interface.h"
|
||
#include "plugin_host/core/plugin_metadata.h"
|
||
#include "plugin_host/manager/plugin_host_manager.h"
|
||
#include "tests/common/test_fixtures.h"
|
||
#include <filesystem>
|
||
#include <thread>
|
||
#include <chrono>
|
||
|
||
using namespace audio_backend;
|
||
using namespace audio_backend::plugin_host;
|
||
using namespace std::chrono_literals;
|
||
|
||
// 创建测试插件实现
|
||
class TestPlugin : public IPlugin {
|
||
public:
|
||
TestPlugin(PluginInfo info) : info_(std::move(info)) {}
|
||
virtual ~TestPlugin() = default;
|
||
|
||
// 实现插件接口
|
||
bool initialize(const PluginInitParams& params) override {
|
||
initialized_ = true;
|
||
params_ = params;
|
||
return true;
|
||
}
|
||
|
||
bool terminate() override {
|
||
initialized_ = false;
|
||
return true;
|
||
}
|
||
|
||
bool activate() override {
|
||
active_ = true;
|
||
return true;
|
||
}
|
||
|
||
bool deactivate() override {
|
||
active_ = false;
|
||
return true;
|
||
}
|
||
|
||
PluginProcessStatus process(const ProcessContext& context) override {
|
||
last_context_ = context;
|
||
return PluginProcessStatus::Success;
|
||
}
|
||
|
||
PluginInfo get_info() const override {
|
||
return info_;
|
||
}
|
||
|
||
ParameterInfo get_parameter_info(ParameterId param_id) const override {
|
||
auto it = parameters_.find(param_id);
|
||
if (it != parameters_.end()) {
|
||
return it->second.info;
|
||
}
|
||
return ParameterInfo();
|
||
}
|
||
|
||
float get_parameter(ParameterId param_id) const override {
|
||
auto it = parameters_.find(param_id);
|
||
if (it != parameters_.end()) {
|
||
return it->second.value;
|
||
}
|
||
return 0.0f;
|
||
}
|
||
|
||
bool set_parameter(ParameterId param_id, float value) override {
|
||
auto it = parameters_.find(param_id);
|
||
if (it != parameters_.end()) {
|
||
it->second.value = value;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool handle_event(const PluginEvent& event) override {
|
||
last_event_ = event;
|
||
return true;
|
||
}
|
||
|
||
const PluginStatistics& get_statistics() const override {
|
||
return stats_;
|
||
}
|
||
|
||
void reset_statistics() override {
|
||
stats_ = PluginStatistics();
|
||
}
|
||
|
||
// 测试辅助方法
|
||
void add_parameter(ParameterId id, const ParameterInfo& info, float default_value) {
|
||
parameters_[id] = {info, default_value};
|
||
}
|
||
|
||
bool is_initialized() const { return initialized_; }
|
||
bool is_active() const { return active_; }
|
||
const PluginInitParams& get_params() const { return params_; }
|
||
const ProcessContext& get_last_context() const { return last_context_; }
|
||
const PluginEvent& get_last_event() const { return last_event_; }
|
||
|
||
private:
|
||
PluginInfo info_;
|
||
bool initialized_ = false;
|
||
bool active_ = false;
|
||
PluginInitParams params_;
|
||
ProcessContext last_context_;
|
||
PluginEvent last_event_;
|
||
PluginStatistics stats_;
|
||
|
||
struct Parameter {
|
||
ParameterInfo info;
|
||
float value;
|
||
};
|
||
|
||
std::map<ParameterId, Parameter> parameters_;
|
||
};
|
||
|
||
// 创建模拟插件工厂
|
||
class MockPluginFactory {
|
||
public:
|
||
static std::unique_ptr<IPlugin> create_test_plugin(
|
||
const std::string& id,
|
||
const std::string& name,
|
||
const std::string& version) {
|
||
|
||
PluginInfo info;
|
||
info.id = id;
|
||
info.name = name;
|
||
info.version = version;
|
||
info.vendor = "Test Vendor";
|
||
info.category = "Test";
|
||
info.description = "Test plugin for unit tests";
|
||
info.num_inputs = 2;
|
||
info.num_outputs = 2;
|
||
|
||
return std::make_unique<TestPlugin>(info);
|
||
}
|
||
};
|
||
|
||
// 创建模拟插件加载器
|
||
class MockPluginLoader : public IPluginLoader {
|
||
public:
|
||
MockPluginLoader() = default;
|
||
~MockPluginLoader() override = default;
|
||
|
||
// 实现加载器接口
|
||
PluginLoadResult load_plugin(
|
||
const std::string& plugin_path,
|
||
PluginInstanceId instance_id,
|
||
const PluginLoadConfig& config) override {
|
||
|
||
// 检查路径是否在已加载插件表中
|
||
auto it = plugins_.find(plugin_path);
|
||
if (it != plugins_.end()) {
|
||
return {PluginLoadStatus::AlreadyLoaded, nullptr,
|
||
"Plugin already loaded with instance ID " + std::to_string(it->second.instance_id)};
|
||
}
|
||
|
||
// 创建测试插件
|
||
auto plugin = MockPluginFactory::create_test_plugin(
|
||
plugin_path, // 使用路径作为ID
|
||
std::filesystem::path(plugin_path).filename().string(), // 使用文件名作为名称
|
||
"1.0.0" // 默认版本
|
||
);
|
||
|
||
if (!plugin) {
|
||
return {PluginLoadStatus::LoadError, nullptr, "Failed to create plugin"};
|
||
}
|
||
|
||
// 初始化插件
|
||
PluginInitParams params;
|
||
params.sample_rate = config.sample_rate;
|
||
params.max_block_size = config.block_size;
|
||
params.plugin_path = plugin_path;
|
||
params.host_api_version = HOST_API_VERSION;
|
||
|
||
if (!plugin->initialize(params)) {
|
||
return {PluginLoadStatus::InitError, nullptr, "Failed to initialize plugin"};
|
||
}
|
||
|
||
// 存储插件信息
|
||
plugins_[plugin_path] = {instance_id, plugin.get()};
|
||
|
||
// 返回成功结果
|
||
return {PluginLoadStatus::Success, std::move(plugin), ""};
|
||
}
|
||
|
||
bool unload_plugin(PluginInstanceId instance_id) override {
|
||
// 查找插件
|
||
for (auto it = plugins_.begin(); it != plugins_.end(); ++it) {
|
||
if (it->second.instance_id == instance_id) {
|
||
plugins_.erase(it);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 测试辅助方法
|
||
size_t get_loaded_plugin_count() const {
|
||
return plugins_.size();
|
||
}
|
||
|
||
private:
|
||
struct PluginEntry {
|
||
PluginInstanceId instance_id;
|
||
IPlugin* plugin_ptr; // 仅用于测试,不拥有对象
|
||
};
|
||
|
||
std::map<std::string, PluginEntry> plugins_;
|
||
};
|
||
|
||
// 插件加载测试固定装置
|
||
class PluginLoadTest : public test::PluginSandboxTest {
|
||
protected:
|
||
void SetUp() override {
|
||
test::PluginSandboxTest::SetUp();
|
||
|
||
// 创建插件加载器
|
||
loader_ = std::make_shared<MockPluginLoader>();
|
||
|
||
// 创建插件宿主管理器
|
||
manager_ = std::make_unique<PluginHostManager>();
|
||
|
||
// 初始化管理器
|
||
PluginHostConfig config;
|
||
config.default_sample_rate = 48000;
|
||
config.default_block_size = 512;
|
||
config.enable_sandbox = false; // 禁用沙盒进行单元测试
|
||
config.plugin_search_paths = {"./plugins", "./effects"};
|
||
config.cache_loaded_plugins = true;
|
||
|
||
ASSERT_EQ(manager_->initialize(config), common::ErrorCode::Success);
|
||
|
||
// 注册加载器
|
||
manager_->register_plugin_loader(loader_);
|
||
}
|
||
|
||
void TearDown() override {
|
||
if (manager_->is_initialized()) {
|
||
manager_->shutdown();
|
||
}
|
||
|
||
manager_.reset();
|
||
loader_.reset();
|
||
|
||
test::PluginSandboxTest::TearDown();
|
||
}
|
||
|
||
// 创建测试插件加载配置
|
||
PluginLoadConfig create_load_config() {
|
||
PluginLoadConfig config;
|
||
config.sample_rate = 48000;
|
||
config.block_size = 512;
|
||
config.enable_sandbox = false;
|
||
return config;
|
||
}
|
||
|
||
protected:
|
||
std::shared_ptr<MockPluginLoader> loader_;
|
||
std::unique_ptr<PluginHostManager> manager_;
|
||
};
|
||
|
||
// 测试插件加载
|
||
TEST_F(PluginLoadTest, LoadPlugin) {
|
||
// 创建加载配置
|
||
PluginLoadConfig config = create_load_config();
|
||
|
||
// 加载插件
|
||
PluginInstanceId instance_id = 0;
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
|
||
|
||
// 验证插件ID
|
||
EXPECT_NE(instance_id, 0);
|
||
|
||
// 验证插件已加载
|
||
EXPECT_TRUE(manager_->is_plugin_loaded(instance_id));
|
||
EXPECT_EQ(loader_->get_loaded_plugin_count(), 1);
|
||
|
||
// 获取插件信息
|
||
PluginInstanceInfo info;
|
||
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
|
||
|
||
// 验证插件信息
|
||
EXPECT_EQ(info.plugin_id, "./plugins/test_plugin.dll");
|
||
EXPECT_EQ(info.instance_id, instance_id);
|
||
EXPECT_EQ(info.state, PluginState::Initialized);
|
||
}
|
||
|
||
// 测试插件激活和停用
|
||
TEST_F(PluginLoadTest, ActivateDeactivatePlugin) {
|
||
// 加载插件
|
||
PluginInstanceId instance_id = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
|
||
|
||
// 验证初始状态
|
||
PluginInstanceInfo info;
|
||
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
|
||
EXPECT_EQ(info.state, PluginState::Initialized);
|
||
|
||
// 激活插件
|
||
ASSERT_EQ(manager_->activate_plugin(instance_id), common::ErrorCode::Success);
|
||
|
||
// 验证激活状态
|
||
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
|
||
EXPECT_EQ(info.state, PluginState::Active);
|
||
|
||
// 停用插件
|
||
ASSERT_EQ(manager_->deactivate_plugin(instance_id), common::ErrorCode::Success);
|
||
|
||
// 验证停用状态
|
||
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
|
||
EXPECT_EQ(info.state, PluginState::Initialized);
|
||
}
|
||
|
||
// 测试插件卸载
|
||
TEST_F(PluginLoadTest, UnloadPlugin) {
|
||
// 加载插件
|
||
PluginInstanceId instance_id = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
|
||
|
||
// 验证插件已加载
|
||
EXPECT_TRUE(manager_->is_plugin_loaded(instance_id));
|
||
|
||
// 卸载插件
|
||
ASSERT_EQ(manager_->unload_plugin(instance_id), common::ErrorCode::Success);
|
||
|
||
// 验证插件已卸载
|
||
EXPECT_FALSE(manager_->is_plugin_loaded(instance_id));
|
||
EXPECT_EQ(loader_->get_loaded_plugin_count(), 0);
|
||
}
|
||
|
||
// 测试加载多个插件
|
||
TEST_F(PluginLoadTest, LoadMultiplePlugins) {
|
||
// 加载第一个插件
|
||
PluginInstanceId id1 = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/plugin1.dll", id1, config), common::ErrorCode::Success);
|
||
|
||
// 加载第二个插件
|
||
PluginInstanceId id2 = 0;
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/plugin2.dll", id2, config), common::ErrorCode::Success);
|
||
|
||
// 加载第三个插件
|
||
PluginInstanceId id3 = 0;
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/plugin3.dll", id3, config), common::ErrorCode::Success);
|
||
|
||
// 验证插件已加载
|
||
EXPECT_TRUE(manager_->is_plugin_loaded(id1));
|
||
EXPECT_TRUE(manager_->is_plugin_loaded(id2));
|
||
EXPECT_TRUE(manager_->is_plugin_loaded(id3));
|
||
EXPECT_EQ(loader_->get_loaded_plugin_count(), 3);
|
||
|
||
// 验证ID不同
|
||
EXPECT_NE(id1, id2);
|
||
EXPECT_NE(id1, id3);
|
||
EXPECT_NE(id2, id3);
|
||
|
||
// 获取所有插件ID
|
||
std::vector<PluginInstanceId> ids;
|
||
ASSERT_EQ(manager_->get_all_plugin_instances(ids), common::ErrorCode::Success);
|
||
|
||
// 验证ID列表
|
||
EXPECT_EQ(ids.size(), 3);
|
||
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id1) != ids.end());
|
||
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id2) != ids.end());
|
||
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id3) != ids.end());
|
||
}
|
||
|
||
// 测试重复加载
|
||
TEST_F(PluginLoadTest, LoadDuplicatePlugin) {
|
||
// 加载插件
|
||
PluginInstanceId id1 = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", id1, config), common::ErrorCode::Success);
|
||
|
||
// 尝试再次加载同一个插件
|
||
PluginInstanceId id2 = 0;
|
||
auto result = manager_->load_plugin("./plugins/test_plugin.dll", id2, config);
|
||
|
||
// 应该返回错误
|
||
EXPECT_NE(result, common::ErrorCode::Success);
|
||
|
||
// 验证只有一个插件加载
|
||
EXPECT_EQ(loader_->get_loaded_plugin_count(), 1);
|
||
}
|
||
|
||
// 测试参数操作
|
||
TEST_F(PluginLoadTest, ParameterOperations) {
|
||
// 加载插件
|
||
PluginInstanceId instance_id = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
|
||
|
||
// 获取插件实例
|
||
auto plugin = manager_->get_plugin(instance_id);
|
||
ASSERT_NE(plugin, nullptr);
|
||
|
||
// 添加测试参数(使用TestPlugin的特定方法)
|
||
auto* test_plugin = dynamic_cast<TestPlugin*>(plugin.get());
|
||
ASSERT_NE(test_plugin, nullptr);
|
||
|
||
ParameterInfo gain_param;
|
||
gain_param.id = 1;
|
||
gain_param.name = "Gain";
|
||
gain_param.default_value = 0.5f;
|
||
gain_param.min_value = 0.0f;
|
||
gain_param.max_value = 1.0f;
|
||
|
||
test_plugin->add_parameter(1, gain_param, 0.5f);
|
||
|
||
// 获取参数信息
|
||
ParameterInfo info;
|
||
ASSERT_EQ(manager_->get_parameter_info(instance_id, 1, info), common::ErrorCode::Success);
|
||
|
||
// 验证参数信息
|
||
EXPECT_EQ(info.id, 1);
|
||
EXPECT_EQ(info.name, "Gain");
|
||
EXPECT_FLOAT_EQ(info.default_value, 0.5f);
|
||
EXPECT_FLOAT_EQ(info.min_value, 0.0f);
|
||
EXPECT_FLOAT_EQ(info.max_value, 1.0f);
|
||
|
||
// 获取参数值
|
||
float value = 0.0f;
|
||
ASSERT_EQ(manager_->get_parameter_value(instance_id, 1, value), common::ErrorCode::Success);
|
||
EXPECT_FLOAT_EQ(value, 0.5f);
|
||
|
||
// 设置参数值
|
||
ASSERT_EQ(manager_->set_parameter_value(instance_id, 1, 0.8f), common::ErrorCode::Success);
|
||
|
||
// 再次获取参数值
|
||
ASSERT_EQ(manager_->get_parameter_value(instance_id, 1, value), common::ErrorCode::Success);
|
||
EXPECT_FLOAT_EQ(value, 0.8f);
|
||
|
||
// 尝试获取不存在的参数
|
||
EXPECT_NE(manager_->get_parameter_value(instance_id, 999, value), common::ErrorCode::Success);
|
||
}
|
||
|
||
// 测试批量处理操作
|
||
TEST_F(PluginLoadTest, ProcessOperations) {
|
||
// 加载插件
|
||
PluginInstanceId instance_id = 0;
|
||
PluginLoadConfig config = create_load_config();
|
||
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
|
||
|
||
// 激活插件
|
||
ASSERT_EQ(manager_->activate_plugin(instance_id), common::ErrorCode::Success);
|
||
|
||
// 准备处理上下文
|
||
ProcessContext context;
|
||
context.input_buffer = std::make_shared<AudioBuffer>(512, 2, AudioFormat::FLOAT32);
|
||
context.output_buffer = std::make_shared<AudioBuffer>(512, 2, AudioFormat::FLOAT32);
|
||
context.time_info.sample_position = 0;
|
||
context.time_info.sample_rate = 48000;
|
||
context.time_info.tempo = 120.0;
|
||
|
||
// 填充输入缓冲区
|
||
float* input_data = context.input_buffer->interleaved_data<float>();
|
||
for (size_t i = 0; i < 512 * 2; ++i) {
|
||
input_data[i] = 0.5f;
|
||
}
|
||
|
||
// 处理音频
|
||
ASSERT_EQ(manager_->process_audio(instance_id, context), common::ErrorCode::Success);
|
||
|
||
// 验证输出缓冲区(具体处理结果取决于TestPlugin的实现)
|
||
// 在这个测试中,TestPlugin没有实际处理音频,只是记录上下文
|
||
// 所以我们验证上下文已被正确传递
|
||
|
||
auto plugin = manager_->get_plugin(instance_id);
|
||
auto* test_plugin = dynamic_cast<TestPlugin*>(plugin.get());
|
||
ASSERT_NE(test_plugin, nullptr);
|
||
|
||
const auto& last_context = test_plugin->get_last_context();
|
||
EXPECT_EQ(last_context.time_info.sample_rate, context.time_info.sample_rate);
|
||
EXPECT_EQ(last_context.time_info.tempo, context.time_info.tempo);
|
||
}
|
||
|
||
int main(int argc, char** argv) {
|
||
::testing::InitGoogleTest(&argc, argv);
|
||
return RUN_ALL_TESTS();
|
||
} |