use serial_test::serial;
use singleton_registry::define_registry;
use std::sync::Arc;
define_registry!(traits);
trait Logger: Send + Sync {
fn get_name(&self) -> &str;
}
trait Calculator: Send + Sync {
fn calculate(&self, a: i32, b: i32) -> i32;
}
trait Formatter: Send + Sync {
fn format(&self, value: &str) -> String;
}
struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn get_name(&self) -> &str {
"ConsoleLogger"
}
}
struct AddCalculator;
impl Calculator for AddCalculator {
fn calculate(&self, a: i32, b: i32) -> i32 {
a + b
}
}
struct UppercaseFormatter;
impl Formatter for UppercaseFormatter {
fn format(&self, value: &str) -> String {
value.to_uppercase()
}
}
#[test]
#[serial]
fn test_register_multiple_trait_objects() {
traits::register(Arc::new(ConsoleLogger) as Arc<dyn Logger>);
traits::register(Arc::new(AddCalculator) as Arc<dyn Calculator>);
traits::register(Arc::new(UppercaseFormatter) as Arc<dyn Formatter>);
let calc: Arc<Arc<dyn Calculator>> = traits::get().unwrap();
assert_eq!(calc.calculate(40, 2), 42);
let fmt: Arc<Arc<dyn Formatter>> = traits::get().unwrap();
assert_eq!(fmt.format("hello"), "HELLO");
let fmt: Arc<dyn Formatter> = traits::get_cloned().unwrap();
assert_eq!(fmt.format("hello"), "HELLO");
}
#[test]
#[serial]
fn test_dependency_injection_pattern() {
traits::register(Arc::new(AddCalculator) as Arc<dyn Calculator>);
struct Component;
impl Component {
fn process(&self) -> i32 {
let calc: Arc<Arc<dyn Calculator>> = traits::get().unwrap();
calc.calculate(20, 22)
}
}
assert_eq!(Component.process(), 42);
}
#[test]
#[serial]
fn test_polymorphism_with_concrete_and_trait_types() {
#[derive(Clone)]
struct MultiLogger {
prefix: String,
}
impl Logger for MultiLogger {
fn get_name(&self) -> &str {
&self.prefix
}
}
impl MultiLogger {
fn get_prefix(&self) -> &str {
&self.prefix
}
}
traits::register(MultiLogger {
prefix: "[CONCRETE]".to_string(),
});
let concrete = traits::get::<MultiLogger>().unwrap();
assert_eq!(concrete.get_prefix(), "[CONCRETE]"); assert_eq!(concrete.get_name(), "[CONCRETE]");
traits::register(Arc::new(MultiLogger {
prefix: "[TRAIT]".to_string(),
}) as Arc<dyn Logger>);
let trait_obj = traits::get::<Arc<dyn Logger>>().unwrap();
assert_eq!(trait_obj.get_name(), "[TRAIT]");
traits::register(Arc::new(ConsoleLogger) as Arc<dyn Logger>);
assert_eq!(
traits::get::<Arc<dyn Logger>>().unwrap().get_name(),
"ConsoleLogger"
);
traits::register(Arc::new(MultiLogger {
prefix: "[OVERRIDE]".to_string(),
}) as Arc<dyn Logger>);
assert_eq!(
traits::get::<Arc<dyn Logger>>().unwrap().get_name(),
"[OVERRIDE]"
);
assert!(traits::contains::<MultiLogger>().unwrap());
assert!(traits::contains::<Arc<dyn Logger>>().unwrap());
}