use crate::error::{Result, SaorsaAgentError};
use std::collections::HashMap;
pub trait WidgetFactory: Send + Sync {
fn create(&self) -> Result<String>;
fn name(&self) -> &str;
fn description(&self) -> &str;
}
#[derive(Debug, Clone)]
pub struct OverlayConfig {
pub position: (u16, u16),
pub size: (u16, u16),
pub z_index: u16,
pub closeable: bool,
}
impl OverlayConfig {
pub fn new(position: (u16, u16), size: (u16, u16), z_index: u16, closeable: bool) -> Self {
Self {
position,
size,
z_index,
closeable,
}
}
}
impl Default for OverlayConfig {
fn default() -> Self {
Self {
position: (0, 0),
size: (80, 24),
z_index: 1000,
closeable: true,
}
}
}
pub struct WidgetRegistry {
factories: HashMap<String, Box<dyn WidgetFactory>>,
}
impl WidgetRegistry {
pub fn new() -> Self {
Self {
factories: HashMap::new(),
}
}
pub fn register_widget(&mut self, factory: Box<dyn WidgetFactory>) -> Result<()> {
let name = factory.name().to_string();
if self.factories.contains_key(&name) {
return Err(SaorsaAgentError::Extension(format!(
"widget factory '{}' is already registered",
name
)));
}
self.factories.insert(name, factory);
Ok(())
}
pub fn unregister_widget(&mut self, name: &str) -> Result<()> {
self.factories.remove(name).ok_or_else(|| {
SaorsaAgentError::Extension(format!("widget factory '{}' not found", name))
})?;
Ok(())
}
pub fn create_widget(&self, name: &str) -> Result<String> {
let factory = self.factories.get(name).ok_or_else(|| {
SaorsaAgentError::Extension(format!("widget factory '{}' not found", name))
})?;
factory.create()
}
pub fn list_widgets(&self) -> Vec<&dyn WidgetFactory> {
self.factories.values().map(|b| &**b).collect()
}
}
impl Default for WidgetRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestWidgetFactory {
name: String,
}
impl TestWidgetFactory {
fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
}
impl WidgetFactory for TestWidgetFactory {
fn create(&self) -> Result<String> {
Ok(format!("TestWidget({})", self.name))
}
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
"A test widget"
}
}
#[test]
fn register_widget() {
let mut registry = WidgetRegistry::new();
let factory = Box::new(TestWidgetFactory::new("test"));
let result = registry.register_widget(factory);
assert!(result.is_ok());
assert_eq!(registry.list_widgets().len(), 1);
}
#[test]
fn duplicate_widget_fails() {
let mut registry = WidgetRegistry::new();
let factory1 = Box::new(TestWidgetFactory::new("test"));
let factory2 = Box::new(TestWidgetFactory::new("test"));
assert!(registry.register_widget(factory1).is_ok());
let result = registry.register_widget(factory2);
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("already registered"));
}
_ => unreachable!(),
}
}
#[test]
fn unregister_widget() {
let mut registry = WidgetRegistry::new();
let factory = Box::new(TestWidgetFactory::new("test"));
assert!(registry.register_widget(factory).is_ok());
assert!(registry.unregister_widget("test").is_ok());
assert_eq!(registry.list_widgets().len(), 0);
}
#[test]
fn unregister_nonexistent_fails() {
let mut registry = WidgetRegistry::new();
let result = registry.unregister_widget("nonexistent");
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("not found"));
}
_ => unreachable!(),
}
}
#[test]
fn create_widget() {
let mut registry = WidgetRegistry::new();
let factory = Box::new(TestWidgetFactory::new("test"));
assert!(registry.register_widget(factory).is_ok());
let result = registry.create_widget("test");
assert!(result.is_ok());
let widget_str = result.ok().unwrap_or_default();
assert_eq!(widget_str, "TestWidget(test)");
}
#[test]
fn create_nonexistent_fails() {
let registry = WidgetRegistry::new();
let result = registry.create_widget("nonexistent");
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("not found"));
}
_ => unreachable!(),
}
}
#[test]
fn list_widgets() {
let mut registry = WidgetRegistry::new();
let factory1 = Box::new(TestWidgetFactory::new("test1"));
let factory2 = Box::new(TestWidgetFactory::new("test2"));
assert!(registry.register_widget(factory1).is_ok());
assert!(registry.register_widget(factory2).is_ok());
let list = registry.list_widgets();
assert_eq!(list.len(), 2);
}
#[test]
fn overlay_config_default() {
let config = OverlayConfig::default();
assert_eq!(config.position, (0, 0));
assert_eq!(config.size, (80, 24));
assert_eq!(config.z_index, 1000);
assert!(config.closeable);
}
#[test]
fn overlay_config_new() {
let config = OverlayConfig::new((10, 20), (100, 50), 2000, false);
assert_eq!(config.position, (10, 20));
assert_eq!(config.size, (100, 50));
assert_eq!(config.z_index, 2000);
assert!(!config.closeable);
}
}