1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
//! Tests for Abscissa's component functionality
#![cfg(feature = "default")]
mod example_app;
use self::example_app::{ExampleApp, ExampleConfig};
use abscissa_core::{component, Component, FrameworkError, FrameworkErrorKind::ComponentError};
/// ID for `FoobarComponent` (example component #1)
const FOOBAR_COMPONENT_ID: component::Id = component::Id::new("component::FoobarComponent");
/// ID for `BazComponent` (example component #2)
const BAZ_COMPONENT_ID: component::Id = component::Id::new("component::BazComponent");
/// ID for `QuuxComponent` (example component #3)
const QUUX_COMPONENT_ID: component::Id = component::Id::new("component::QuuxComponent");
/// Example component #1
#[derive(Component, Debug, Default)]
pub struct FoobarComponent {
/// Component state
pub state: Option<String>,
}
impl FoobarComponent {
/// Set the state string to a particular value
pub fn set_state(&mut self, state_str: &str) {
self.state = Some(state_str.to_owned());
}
}
/// Example component #2
#[derive(Component, Debug, Default)]
pub struct BazComponent {}
/// Example component #3
#[derive(Component, Debug, Default)]
#[component(inject = "init_foobar(component::FoobarComponent)")]
#[component(inject = "init_baz(component::BazComponent)")]
pub struct QuuxComponent {
/// State of Foo at the time we were initialized?
pub foobar_state: Option<String>,
/// Did we get a callback that `Baz` has been initialized?
pub baz_initialized: bool,
}
impl QuuxComponent {
/// Callback run after `FoobarComponent` has been initialized
pub fn init_foobar(&mut self, foobar: &mut FoobarComponent) -> Result<(), FrameworkError> {
self.foobar_state = foobar.state.clone();
foobar.state = Some("hijacked!".to_owned());
Ok(())
}
/// Callback run after `BazComponent` has been initialized
pub fn init_baz(&mut self, _baz: &BazComponent) -> Result<(), FrameworkError> {
self.baz_initialized = true;
Ok(())
}
}
fn init_components() -> Vec<Box<dyn Component<ExampleApp>>> {
let mut foobar = FoobarComponent::default();
foobar.set_state("original foobar state");
let component1 = Box::new(foobar);
let component2 = Box::<BazComponent>::default();
let component3 = Box::<QuuxComponent>::default();
let components: Vec<Box<dyn Component<ExampleApp>>> = vec![component1, component2, component3];
// Ensure component IDs are as expected
assert_eq!(components[0].id(), FOOBAR_COMPONENT_ID);
assert_eq!(components[1].id(), BAZ_COMPONENT_ID);
assert_eq!(components[2].id(), QUUX_COMPONENT_ID);
components
}
#[test]
fn component_registration() {
let mut registry = component::Registry::default();
assert!(registry.is_empty());
let components = init_components();
registry.register(components).unwrap();
assert_eq!(registry.len(), 3);
// Fetch components and make sure they got registered correctly
let foobar_comp = registry.get_by_id(FOOBAR_COMPONENT_ID).unwrap();
assert_eq!(foobar_comp.id(), FOOBAR_COMPONENT_ID);
let baz_comp = registry.get_by_id(BAZ_COMPONENT_ID).unwrap();
assert_eq!(baz_comp.id(), BAZ_COMPONENT_ID);
let quux_comp = registry.get_by_id(QUUX_COMPONENT_ID).unwrap();
assert_eq!(quux_comp.id(), QUUX_COMPONENT_ID);
}
#[test]
fn duplicate_component_registration() {
let foobar1 = Box::<FoobarComponent>::default();
let foobar2 = Box::<FoobarComponent>::default();
let components: Vec<Box<dyn Component<ExampleApp>>> = vec![foobar1, foobar2];
let mut registry = component::Registry::default();
assert!(registry.is_empty());
let err = registry.register(components).err().unwrap();
assert_eq!(*err.kind(), ComponentError);
assert_eq!(registry.len(), 1);
let foobar = registry.get_by_id(FOOBAR_COMPONENT_ID).unwrap();
assert_eq!(foobar.id(), FOOBAR_COMPONENT_ID);
}
#[test]
fn get_downcast_ref() {
let mut registry = component::Registry::default();
let component = Box::<FoobarComponent>::default() as Box<dyn Component<ExampleApp>>;
registry.register(vec![component]).unwrap();
{
let foo_mut = registry.get_downcast_mut::<FoobarComponent>().unwrap();
foo_mut.set_state("mutated!");
}
{
let foo_comp = registry.get_downcast_ref::<FoobarComponent>().unwrap();
assert_eq!(foo_comp.state.as_ref().unwrap(), "mutated!");
}
}
#[test]
fn dependency_injection() {
let mut registry = component::Registry::default();
let mut components = init_components();
// Start component up in reverse order to make sure sorting works
components.reverse();
registry.register(components).unwrap();
registry.after_config(&ExampleConfig::default()).unwrap();
let foobar_comp = registry.get_downcast_ref::<FoobarComponent>().unwrap();
assert_eq!(foobar_comp.state.as_ref().unwrap(), "hijacked!");
let quux_comp = registry.get_downcast_ref::<QuuxComponent>().unwrap();
assert_eq!(
quux_comp.foobar_state.as_ref().unwrap(),
"original foobar state"
);
}
|