Files
Alicho/tests/common/mock_objects.cpp
2025-10-28 10:27:49 +08:00

249 lines
8.3 KiB
C++

// ================================================================================================
// Audio Backend - 测试模拟对象实现
// ================================================================================================
#include "mock_objects.h"
#include <random>
#include <chrono>
#include <cmath>
namespace audio_backend {
namespace test {
//===================================================================================================
// ResourceLimiter 实现
//===================================================================================================
struct ResourceLimiter::Impl {
size_t memory_limit = std::numeric_limits<size_t>::max();
float cpu_limit = 100.0f;
size_t io_limit = std::numeric_limits<size_t>::max();
size_t network_limit = std::numeric_limits<size_t>::max();
ResourceUsage current_usage;
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
};
ResourceLimiter::ResourceLimiter() : pimpl_(std::make_unique<Impl>()) {}
ResourceLimiter::~ResourceLimiter() = default;
void ResourceLimiter::set_memory_limit(size_t bytes) {
pimpl_->memory_limit = bytes;
}
void ResourceLimiter::set_cpu_limit(float percentage) {
pimpl_->cpu_limit = std::clamp(percentage, 0.0f, 100.0f);
}
void ResourceLimiter::set_io_limit(size_t bytes_per_sec) {
pimpl_->io_limit = bytes_per_sec;
}
void ResourceLimiter::set_network_limit(size_t bytes_per_sec) {
pimpl_->network_limit = bytes_per_sec;
}
void ResourceLimiter::reset_limits() {
pimpl_->memory_limit = std::numeric_limits<size_t>::max();
pimpl_->cpu_limit = 100.0f;
pimpl_->io_limit = std::numeric_limits<size_t>::max();
pimpl_->network_limit = std::numeric_limits<size_t>::max();
}
ResourceUsage ResourceLimiter::get_current_usage() const {
// 模拟随机资源使用
std::uniform_real_distribution<float> cpu_dist(0.0f, pimpl_->cpu_limit * 1.2f);
std::uniform_int_distribution<size_t> memory_dist(0, pimpl_->memory_limit);
std::uniform_int_distribution<size_t> io_dist(0, pimpl_->io_limit);
std::uniform_int_distribution<size_t> network_dist(0, pimpl_->network_limit);
ResourceUsage usage;
usage.memory_usage_bytes = memory_dist(pimpl_->rng);
usage.cpu_usage_percent = cpu_dist(pimpl_->rng);
usage.io_bytes_per_sec = io_dist(pimpl_->rng);
usage.network_bytes_per_sec = network_dist(pimpl_->rng);
return usage;
}
bool ResourceLimiter::is_limit_reached(ResourceType type) const {
auto usage = get_current_usage();
switch (type) {
case ResourceType::Memory:
return usage.memory_usage_bytes >= pimpl_->memory_limit;
case ResourceType::CPU:
return usage.cpu_usage_percent >= pimpl_->cpu_limit;
case ResourceType::IO:
return usage.io_bytes_per_sec >= pimpl_->io_limit;
case ResourceType::Network:
return usage.network_bytes_per_sec >= pimpl_->network_limit;
default:
return false;
}
}
//===================================================================================================
// ErrorInjector 实现
//===================================================================================================
struct ErrorInjector::Impl {
std::map<std::string, std::map<std::string, ErrorCallback>> registered_errors;
float error_probability = 0.0f;
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
};
ErrorInjector::ErrorInjector() : pimpl_(std::make_unique<Impl>()) {}
ErrorInjector::~ErrorInjector() = default;
void ErrorInjector::register_error(const std::string& component, const std::string& operation, ErrorCallback callback) {
pimpl_->registered_errors[component][operation] = std::move(callback);
}
bool ErrorInjector::inject_error(const std::string& component, const std::string& operation) {
auto comp_it = pimpl_->registered_errors.find(component);
if (comp_it != pimpl_->registered_errors.end()) {
auto op_it = comp_it->second.find(operation);
if (op_it != comp_it->second.end()) {
op_it->second();
return true;
}
}
return false;
}
bool ErrorInjector::inject_random_error() {
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
if (dist(pimpl_->rng) < pimpl_->error_probability) {
// 随机选择一个错误注入
if (pimpl_->registered_errors.empty()) {
return false;
}
std::vector<std::pair<std::string, std::string>> error_keys;
for (const auto& comp : pimpl_->registered_errors) {
for (const auto& op : comp.second) {
error_keys.emplace_back(comp.first, op.first);
}
}
if (error_keys.empty()) {
return false;
}
std::uniform_int_distribution<size_t> key_dist(0, error_keys.size() - 1);
auto selected = error_keys[key_dist(pimpl_->rng)];
return inject_error(selected.first, selected.second);
}
return false;
}
void ErrorInjector::set_error_probability(float probability) {
pimpl_->error_probability = std::clamp(probability, 0.0f, 1.0f);
}
void ErrorInjector::reset() {
pimpl_->registered_errors.clear();
pimpl_->error_probability = 0.0f;
}
//===================================================================================================
// MockAudioGenerator 实现
//===================================================================================================
struct MockAudioGenerator::Impl {
int sample_rate;
int channels;
SignalType type = SignalType::Sine;
float frequency = 440.0f;
float amplitude = 0.5f;
float phase = 0.0f;
float phase_increment = 0.0f;
std::mt19937 rng{static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count())};
Impl(int sr, int ch) : sample_rate(sr), channels(ch) {
update_phase_increment();
}
void update_phase_increment() {
phase_increment = 2.0f * M_PI * frequency / static_cast<float>(sample_rate);
}
float generate_sample() {
float sample = 0.0f;
switch (type) {
case SignalType::Sine:
sample = amplitude * std::sin(phase);
break;
case SignalType::Square:
sample = amplitude * (std::sin(phase) >= 0.0f ? 1.0f : -1.0f);
break;
case SignalType::Triangle:
sample = amplitude * (2.0f / M_PI) * std::asin(std::sin(phase));
break;
case SignalType::Sawtooth: {
float normalized_phase = std::fmod(phase, 2.0f * M_PI) / (2.0f * M_PI);
sample = amplitude * (2.0f * normalized_phase - 1.0f);
break;
}
case SignalType::Noise: {
std::uniform_real_distribution<float> dist(-amplitude, amplitude);
sample = dist(rng);
break;
}
case SignalType::Silence:
default:
sample = 0.0f;
break;
}
// 更新相位
phase += phase_increment;
if (phase > 2.0f * M_PI) {
phase -= 2.0f * M_PI;
}
return sample;
}
};
MockAudioGenerator::MockAudioGenerator(int sample_rate, int channels)
: pimpl_(std::make_unique<Impl>(sample_rate, channels)) {}
MockAudioGenerator::~MockAudioGenerator() = default;
void MockAudioGenerator::set_signal_type(SignalType type) {
pimpl_->type = type;
}
void MockAudioGenerator::set_frequency(float frequency_hz) {
pimpl_->frequency = frequency_hz;
pimpl_->update_phase_increment();
}
void MockAudioGenerator::set_amplitude(float amplitude) {
pimpl_->amplitude = amplitude;
}
void MockAudioGenerator::set_phase(float phase_radians) {
pimpl_->phase = phase_radians;
}
void MockAudioGenerator::generate(float* buffer, size_t frames) {
for (size_t i = 0; i < frames; ++i) {
float sample = pimpl_->generate_sample();
for (int ch = 0; ch < pimpl_->channels; ++ch) {
buffer[i * pimpl_->channels + ch] = sample;
}
}
}
void MockAudioGenerator::reset() {
pimpl_->phase = 0.0f;
}
} // namespace test
} // namespace audio_backend