Complete source 6 engineering workflows and preserve release validation evidence
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
//! App-level copy behavior, with separate state/architecture view identities.
|
||||
use super::*;
|
||||
|
||||
struct Fixture {
|
||||
app: App,
|
||||
architecture: Id,
|
||||
states: Id,
|
||||
machine: Id,
|
||||
region: Id,
|
||||
state: Id,
|
||||
}
|
||||
|
||||
fn fixture() -> Fixture {
|
||||
let project = language::parse(
|
||||
r#"arcadia 3; project copied_views "Copied views" {
|
||||
oa_entity crew "Crew" {}
|
||||
oa_state_machine modes "Modes" { parent @crew; }
|
||||
oa_region main "Main" { parent @modes; }
|
||||
oa_state ready "Ready" { parent @main; }
|
||||
diagram architecture "Architecture" {}
|
||||
diagram state_view "Modes view" { projection { StateMachine { machine @modes; }; }; }
|
||||
node crew_view { diagram @architecture; element @crew; }
|
||||
node main_view { diagram @state_view; element @main; }
|
||||
node ready_view { diagram @state_view; element @ready; }
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let identity = |alias| {
|
||||
project
|
||||
.identities()
|
||||
.into_iter()
|
||||
.find(|(_, candidate)| *candidate == alias)
|
||||
.unwrap()
|
||||
.0
|
||||
};
|
||||
let architecture = identity("architecture");
|
||||
let states = identity("state_view");
|
||||
let machine = identity("modes");
|
||||
let region = identity("main");
|
||||
let state = identity("ready");
|
||||
let mut app = App::with_project(project);
|
||||
// Initial view UUID order must not determine the test's workspace.
|
||||
app.page = Page::Behavior;
|
||||
app.active_diagram = Some(architecture);
|
||||
app.behavior.active_owner = Some(machine);
|
||||
app.behavior.diagram.diagram = Some(states);
|
||||
app.selected = state;
|
||||
app.refresh_draft();
|
||||
Fixture {
|
||||
app,
|
||||
architecture,
|
||||
states,
|
||||
machine,
|
||||
region,
|
||||
state,
|
||||
}
|
||||
}
|
||||
|
||||
fn send(app: &mut App, message: Message) {
|
||||
let _ = app.update(message);
|
||||
}
|
||||
|
||||
fn raw_property(app: &App) -> serde_json::Value {
|
||||
serde_json::to_value(app.draft.as_ref().unwrap().recovery_snapshot()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copying_the_current_state_view_uses_its_own_identity_and_is_one_source_undo() {
|
||||
let mut f = fixture();
|
||||
assert_eq!(f.app.state_context().unwrap().diagram, f.states);
|
||||
assert_eq!(f.app.active_diagram, Some(f.architecture));
|
||||
let before = f.app.document.snapshot();
|
||||
let revision = f.app.document.revision();
|
||||
send(&mut f.app, Message::DuplicateDiagram(f.states));
|
||||
assert_eq!(f.app.page, Page::Behavior);
|
||||
assert_eq!(f.app.behavior.active_owner, Some(f.machine));
|
||||
let copied = f.app.state_context().unwrap().diagram;
|
||||
assert_ne!(copied, f.states);
|
||||
assert_ne!(copied, f.architecture);
|
||||
assert_eq!(f.app.active_diagram, Some(copied));
|
||||
assert_eq!(f.app.selected, copied);
|
||||
assert_eq!(
|
||||
f.app.project().diagrams[&copied].projection.state_machine(),
|
||||
Some(f.machine)
|
||||
);
|
||||
assert_eq!(
|
||||
f.app.project().diagrams[&copied]
|
||||
.nodes
|
||||
.values()
|
||||
.map(|node| node.element)
|
||||
.collect::<BTreeSet<_>>(),
|
||||
BTreeSet::from([f.region, f.state])
|
||||
);
|
||||
assert_eq!(f.app.document.revision(), revision + 1);
|
||||
let accepted = f.app.document.snapshot();
|
||||
assert_eq!(
|
||||
source_project::compile_bundle(f.app.document.bundle(), LIMITS)
|
||||
.unwrap()
|
||||
.decoded
|
||||
.project,
|
||||
*f.app.project()
|
||||
);
|
||||
let mut only_original = f.app.project().clone();
|
||||
only_original.diagrams.remove(&copied);
|
||||
assert_eq!(only_original, before.decoded.project);
|
||||
send(&mut f.app, Message::Undo);
|
||||
assert_eq!(f.app.project(), &before.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &before.bundle);
|
||||
assert!(!f.app.document.can_undo());
|
||||
send(&mut f.app, Message::Redo);
|
||||
assert_eq!(f.app.project(), &accepted.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &accepted.bundle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copying_architecture_keeps_architecture_even_with_a_retained_state_view() {
|
||||
let mut f = fixture();
|
||||
f.app.page = Page::Diagram;
|
||||
f.app.active_diagram = Some(f.architecture);
|
||||
f.app.selected = f.architecture;
|
||||
f.app.refresh_draft();
|
||||
send(&mut f.app, Message::DuplicateDiagram(f.architecture));
|
||||
let copied = f.app.active_diagram.unwrap();
|
||||
assert_ne!(copied, f.architecture);
|
||||
assert_eq!(f.app.page, Page::Diagram);
|
||||
assert!(f.app.state_context().is_none());
|
||||
assert_eq!(f.app.project().diagrams[&copied].name, "Architecture copy");
|
||||
assert_eq!(
|
||||
f.app.project().diagrams[&copied].projection,
|
||||
f.app.project().diagrams[&f.architecture].projection
|
||||
);
|
||||
assert_eq!(f.app.project().diagrams[&copied].nodes.len(), 1);
|
||||
assert_eq!(f.app.selected, copied);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stale_copy_does_not_apply_an_unrelated_valid_property_draft() {
|
||||
let mut f = fixture();
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::Field("/name".into(), "Pending state rename".into()),
|
||||
);
|
||||
let raw = raw_property(&f.app);
|
||||
let before = f.app.document.snapshot();
|
||||
let revision = f.app.document.revision();
|
||||
send(&mut f.app, Message::DuplicateDiagram(Id::new_v4()));
|
||||
assert_eq!(f.app.project(), &before.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &before.bundle);
|
||||
assert_eq!(f.app.document.revision(), revision);
|
||||
assert_eq!(raw_property(&f.app), raw);
|
||||
assert_eq!(f.app.selected, f.state);
|
||||
assert!(!f.app.document.can_undo());
|
||||
assert!(f.app.status.contains("no longer exists"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_rejection_preserves_invalid_property_and_pending_behavior_drafts() {
|
||||
let mut f = fixture();
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::Field("/alias".into(), "invalid alias!".into()),
|
||||
);
|
||||
let before = f.app.document.snapshot();
|
||||
let raw = raw_property(&f.app);
|
||||
send(&mut f.app, Message::DuplicateDiagram(f.states));
|
||||
assert_eq!(f.app.project(), &before.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &before.bundle);
|
||||
assert_eq!(raw_property(&f.app), raw);
|
||||
assert!(!f.app.document.can_undo());
|
||||
|
||||
let mut f = fixture();
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::Behavior(crate::behavior::Event::States(
|
||||
crate::behavior::states::Event::Start(
|
||||
f.machine,
|
||||
crate::behavior::states::Tool::Vertex,
|
||||
f.region,
|
||||
),
|
||||
)),
|
||||
);
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::Behavior(crate::behavior::Event::States(
|
||||
crate::behavior::states::Event::Name("Unfinished nested state".into()),
|
||||
)),
|
||||
);
|
||||
assert!(f.app.behavior.has_pending());
|
||||
let raw = f.app.behavior.recovery_snapshot().unwrap();
|
||||
let before = f.app.document.snapshot();
|
||||
send(&mut f.app, Message::DuplicateDiagram(f.states));
|
||||
assert_eq!(f.app.project(), &before.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &before.bundle);
|
||||
assert_eq!(f.app.behavior.recovery_snapshot().unwrap(), raw);
|
||||
assert_eq!(f.app.state_context().unwrap().diagram, f.states);
|
||||
assert!(!f.app.document.can_undo());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_rejection_preserves_an_incomplete_source_buffer() {
|
||||
let mut f = fixture();
|
||||
let raw = "arcadia 6; project unfinished \"Unfinished source\" {".to_owned();
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::SourceEdit(text_editor::Action::SelectAll),
|
||||
);
|
||||
send(
|
||||
&mut f.app,
|
||||
Message::SourceEdit(text_editor::Action::Edit(text_editor::Edit::Paste(
|
||||
Arc::new(raw.clone()),
|
||||
))),
|
||||
);
|
||||
assert!(f.app.source_dirty());
|
||||
let before = f.app.document.snapshot();
|
||||
let source = f.app.source_workspace.bundle();
|
||||
send(&mut f.app, Message::DuplicateDiagram(f.states));
|
||||
assert_eq!(f.app.project(), &before.decoded.project);
|
||||
assert_eq!(f.app.document.bundle(), &before.bundle);
|
||||
assert_eq!(f.app.source_workspace.bundle(), source);
|
||||
assert_eq!(f.app.source_workspace.text(), raw);
|
||||
assert!(!f.app.document.can_undo());
|
||||
}
|
||||
Reference in New Issue
Block a user