// ================================================================================================ // Audio Backend - 插件加载测试 // ================================================================================================ #include #include #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 #include #include 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 parameters_; }; // 创建模拟插件工厂 class MockPluginFactory { public: static std::unique_ptr 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(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 plugins_; }; // 插件加载测试固定装置 class PluginLoadTest : public test::PluginSandboxTest { protected: void SetUp() override { test::PluginSandboxTest::SetUp(); // 创建插件加载器 loader_ = std::make_shared(); // 创建插件宿主管理器 manager_ = std::make_unique(); // 初始化管理器 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 loader_; std::unique_ptr 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 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(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(512, 2, AudioFormat::FLOAT32); context.output_buffer = std::make_shared(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(); 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(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(); }