use std::sync::Mutex;
use async_trait::async_trait;
use crate::error::{GoveeError, Result};
use crate::types::{BackendType, Color, Device, DeviceId, DeviceState};
use super::GoveeBackend;
pub(crate) struct MockBackend {
devices: Vec<Device>,
state: Option<DeviceState>,
backend_type: BackendType,
injected_error: Mutex<Option<InjectedError>>,
}
enum InjectedError {
Persistent(fn() -> GoveeError),
}
impl MockBackend {
pub(crate) fn new() -> Self {
Self {
devices: Vec::new(),
state: None,
backend_type: BackendType::Cloud,
injected_error: Mutex::new(None),
}
}
pub(crate) fn with_devices(mut self, devices: Vec<Device>) -> Self {
self.devices = devices;
self
}
pub(crate) fn with_state(mut self, state: DeviceState) -> Self {
self.state = Some(state);
self
}
pub(crate) fn with_backend_type(mut self, backend_type: BackendType) -> Self {
self.backend_type = backend_type;
self
}
pub(crate) fn with_error(self, error_fn: fn() -> GoveeError) -> Self {
*self.injected_error.lock().unwrap() = Some(InjectedError::Persistent(error_fn));
self
}
fn check_error(&self) -> Result<()> {
let guard = self.injected_error.lock().unwrap();
match &*guard {
Some(InjectedError::Persistent(f)) => Err(f()),
None => Ok(()),
}
}
}
#[async_trait]
impl GoveeBackend for MockBackend {
async fn list_devices(&self) -> Result<Vec<Device>> {
Ok(self.devices.clone())
}
async fn get_state(&self, id: &DeviceId) -> Result<DeviceState> {
self.check_error()?;
self.state
.clone()
.ok_or_else(|| GoveeError::DeviceNotFound(id.to_string()))
}
async fn set_power(&self, _id: &DeviceId, _on: bool) -> Result<()> {
self.check_error()?;
Ok(())
}
async fn set_brightness(&self, _id: &DeviceId, _value: u8) -> Result<()> {
self.check_error()?;
Ok(())
}
async fn set_color(&self, _id: &DeviceId, _color: Color) -> Result<()> {
self.check_error()?;
Ok(())
}
async fn set_color_temp(&self, _id: &DeviceId, _kelvin: u32) -> Result<()> {
self.check_error()?;
Ok(())
}
fn backend_type(&self) -> BackendType {
self.backend_type
}
}