use oa_core::{source_project::*, view_options::*, *}; fn fixture(layer: Layer) -> (Project, Id, Id, Id, Id) { let mut p = Project::empty(); let oa = p .add_element(Kind::Activity, Layer::Oa, "Assess alarm", None) .unwrap(); let oa2 = p .add_element(Kind::Activity, Layer::Oa, "Respond", None) .unwrap(); let sa = p .add_element(Kind::Function, Layer::Sa, "Assess alarm", None) .unwrap(); let edge = p.relate(RelationKind::Interaction, "Alarm", oa, oa2); let category = p .add_element(Kind::ExchangeCategory, Layer::Oa, "Alarm data", None) .unwrap(); *p.elements.get_mut(&category).unwrap().shared_mut().unwrap() = SharedBody::ExchangeCategory { family: ExchangeFamily::Work, exchanges: vec![edge], }; let context = p .add_element(Kind::Process, Layer::Oa, "Alarm handling", None) .unwrap(); let d = p.ensure_diagram(layer); p.diagrams.get_mut(&d).unwrap().projection = ProjectionKind::Traceability; for (i, element) in [oa, oa2, sa].into_iter().enumerate() { p.place( d, element, Position { x: 300. * i as f32, y: 40., }, ); } p.diagrams.get_mut(&d).unwrap().view_options = ViewOptions { hidden_edges: vec![edge], work_categories: CategorySelection::Any(vec![category]), work_contexts: ContextSelection::Any(vec![context]), ..Default::default() }; validate_candidate(&p).unwrap(); (p, d, oa, sa, category) } #[test] fn projection_switching_preserves_complete_model_history_and_all_serializations() { for layer in [Layer::Oa, Layer::Sa] { let (baseline, diagram, _, _, _) = fixture(layer); for projection in [ ProjectionKind::Overview, ProjectionKind::Decomposition, ProjectionKind::Allocation, ProjectionKind::FunctionalDataflow, ProjectionKind::Capabilities, ] { let mut expected = baseline.clone(); expected.diagrams.get_mut(&diagram).unwrap().projection = projection; let mut session = Session::new(baseline.clone()); session .execute(Command::EditDiagram( diagram, expected.diagrams[&diagram].clone(), )) .unwrap(); assert_eq!(session.project(), &expected); let view = projection::project_view(session.project(), diagram); assert!( view.nodes .iter() .all(|n| expected.elements[&n.element].layer() == layer) ); assert_eq!( view, projection::project_view_with_index(&expected, diagram, &ViewIndex::new(&expected)) ); let source = language::format(&expected); assert_eq!(language::parse(&source).unwrap(), expected); assert_eq!( persistence::decode(&serde_json::to_vec(&expected).unwrap()).unwrap(), expected ); let bundle = format_bundle(&expected); assert_eq!( compile_bundle(&bundle, ProjectLimits::default()) .unwrap() .decoded .project, expected ); session.undo(); assert_eq!(session.project(), &baseline); assert!(!session.can_undo()); session.redo(); assert_eq!(session.project(), &expected); session .execute(Command::EditDiagram( diagram, baseline.diagrams[&diagram].clone(), )) .unwrap(); assert_eq!(session.project(), &baseline); assert_eq!( projection::project_view(session.project(), diagram), projection::project_view(&baseline, diagram) ); } } } #[test] fn projection_switching_does_not_admit_missing_elements_or_invalid_filter_kinds() { let (mut p, d, oa, _, category) = fixture(Layer::Sa); p.diagrams.get_mut(&d).unwrap().projection = ProjectionKind::Allocation; validate_candidate(&p).unwrap(); let valid = p.clone(); let node = p.diagrams[&d] .nodes .values() .find(|n| n.element == oa) .unwrap() .id; p.diagrams .get_mut(&d) .unwrap() .nodes .get_mut(&node) .unwrap() .element = Id::new_v4(); assert!(validate_candidate(&p).is_err()); p = valid.clone(); p.diagrams.get_mut(&d).unwrap().view_options.work_categories = CategorySelection::Any(vec![oa]); assert!(validate_candidate(&p).is_err()); p = valid; p.elements.remove(&category); assert!(validate_candidate(&p).is_err()); } #[test] fn projection_switching_keeps_typed_state_membership_strict() { let (mut p, d, _, _, _) = fixture(Layer::Sa); let system = p .add_element(Kind::System, Layer::Sa, "System", None) .unwrap(); let machine = p .add_element(Kind::StateMachine, Layer::Sa, "Modes", Some(system)) .unwrap(); p.diagrams.get_mut(&d).unwrap().projection = ProjectionKind::StateMachine { machine }; assert!( validation::validate(&p) .iter() .any(|i| i.code == "state_diagram_member") ); assert!(validate_candidate(&p).is_err()); }