use super::config::ContagionConfig;
use super::hook::{ContagionHook, DefaultContagionHook};
use super::state::ContagionState;
use super::system::ContagionSystem;
use super::topology::GraphTopology;
use crate::Plugin;
use std::sync::Arc;
#[derive(Plugin)]
#[plugin(name = "issun:contagion")]
pub struct ContagionPlugin {
#[plugin(skip)]
hook: Arc<dyn ContagionHook>,
#[plugin(resource)]
config: ContagionConfig,
#[plugin(resource)]
topology: GraphTopology,
#[plugin(runtime_state)]
#[allow(dead_code)]
state: ContagionState,
#[plugin(system)]
system: ContagionSystem,
}
impl ContagionPlugin {
pub fn new() -> Self {
let hook = Arc::new(DefaultContagionHook);
Self {
hook: hook.clone(),
config: ContagionConfig::default(),
topology: GraphTopology::new(),
state: ContagionState::new(),
system: ContagionSystem::new(hook),
}
}
pub fn with_config(mut self, config: ContagionConfig) -> Self {
self.config = config;
self
}
pub fn with_topology(mut self, topology: GraphTopology) -> Self {
self.topology = topology;
self
}
pub fn with_hook<H: ContagionHook + 'static>(mut self, hook: H) -> Self {
let hook = Arc::new(hook);
self.hook = hook.clone();
self.system = ContagionSystem::new(hook);
self
}
}
impl Default for ContagionPlugin {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plugin_creation() {
let _plugin = ContagionPlugin::new();
}
#[test]
fn test_with_config() {
let config = ContagionConfig::default().with_propagation_rate(0.8);
let plugin = ContagionPlugin::new().with_config(config.clone());
assert_eq!(plugin.config.global_propagation_rate, 0.8);
}
#[test]
fn test_with_topology() {
let mut topology = GraphTopology::new();
topology.add_node(super::super::ContagionNode::new(
"test",
super::super::NodeType::City,
1000,
));
let plugin = ContagionPlugin::new().with_topology(topology);
assert_eq!(plugin.topology.node_count(), 1);
}
#[test]
fn test_with_custom_hook() {
use async_trait::async_trait;
#[derive(Clone)]
struct TestHook;
#[async_trait]
impl ContagionHook for TestHook {}
let _plugin = ContagionPlugin::new().with_hook(TestHook);
}
#[test]
fn test_builder_pattern() {
let mut topology = GraphTopology::new();
topology.add_node(super::super::ContagionNode::new(
"london",
super::super::NodeType::City,
100000,
));
let config = ContagionConfig::default()
.with_propagation_rate(0.7)
.with_mutation_rate(0.15);
let plugin = ContagionPlugin::new()
.with_topology(topology)
.with_config(config);
assert_eq!(plugin.topology.node_count(), 1);
assert_eq!(plugin.config.global_propagation_rate, 0.7);
assert_eq!(plugin.config.default_mutation_rate, 0.15);
}
#[tokio::test]
async fn test_plugin_registers_resources() {
use crate::builder::GameBuilder;
let config = ContagionConfig::default().with_propagation_rate(0.8);
let mut topology = GraphTopology::new();
topology.add_node(super::super::ContagionNode::new(
"test_city",
super::super::NodeType::City,
1000,
));
let game = GameBuilder::new()
.with_plugin(
ContagionPlugin::new()
.with_config(config)
.with_topology(topology),
)
.expect("Failed to add plugin")
.build()
.await
.expect("Failed to build game");
assert!(
game.resources.contains::<ContagionConfig>(),
"ContagionConfig should be registered by Plugin derive"
);
assert!(
game.resources.contains::<GraphTopology>(),
"GraphTopology should be registered by Plugin derive"
);
assert!(
game.resources.contains::<ContagionState>(),
"ContagionState should be registered by Plugin derive"
);
}
}