Files
ARCADIA-Studio/crates/oa-core/tests/route_source.rs
T

199 lines
7.1 KiB
Rust

use oa_core::{language, persistence, source_project::*, *};
use serde_json::json;
const SOURCE: &str = r#"arcadia 3;
project route_example "Connection review" {
oa_activity report "Report" {}
oa_activity assess "Assess" {}
sa_function selected_assess "Selected assessment" {}
interaction signal "Signal" { source @report; target @assess; }
trace refinement "Assessment refinement" { oa @assess; sa @selected_assess; }
diagram architecture "Architecture" {
routes [
{ edge @signal; waypoints [{ x 420; y 260; }, { x 690; y 260; }];
label { fraction 0.55; offset { x 0; y -16; }; }; },
{ edge @refinement; }
];
}
diagram review "Review" { routes [{ edge @signal; }]; }
}
"#;
fn id(project: &Project, alias: &str) -> Id {
project
.identities()
.into_iter()
.find(|(_, candidate)| *candidate == alias)
.unwrap()
.0
}
#[test]
fn route_source_json_and_bundle_roundtrips_preserve_order_defaults_and_edge_aliases() {
let project = language::parse(SOURCE).unwrap();
let diagram = &project.diagrams[&id(&project, "architecture")];
assert_eq!(diagram.routes.len(), 2);
assert_eq!(diagram.routes[0].edge, id(&project, "signal"));
assert_eq!(
diagram.routes[0].waypoints[1],
Position { x: 690., y: 260. }
);
assert_eq!(diagram.routes[0].label.as_ref().unwrap().fraction, 0.55);
assert_eq!(diagram.routes[1].edge, id(&project, "refinement"));
assert!(diagram.routes[1].waypoints.is_empty());
assert!(diagram.routes[1].label.is_none());
assert!(
diagram.nodes.is_empty(),
"hidden edges can retain authored routes"
);
assert_eq!(
project.diagrams[&id(&project, "review")].routes[0].waypoints,
[]
);
let formatted = language::format(&project);
assert!(formatted.contains("edge @signal;"));
assert!(formatted.contains("edge @refinement;"));
assert!(!formatted.contains(&format!("edge \"{}\"", id(&project, "signal"))));
assert_eq!(language::parse(&formatted).unwrap(), project);
assert_eq!(
persistence::decode(&serde_json::to_vec(&project).unwrap()).unwrap(),
project
);
let compiled = compile_bundle(&format_bundle(&project), ProjectLimits::default()).unwrap();
assert_eq!(compiled.decoded.project, project);
}
#[test]
fn omitted_schema_three_routes_default_to_empty_and_v2_reader_stays_frozen() {
let project =
language::parse("arcadia 3; project p \"P\" { diagram view \"View\" {} }").unwrap();
assert!(project.diagrams.values().next().unwrap().routes.is_empty());
let mut json = serde_json::to_value(&project).unwrap();
json["diagrams"]
.as_object_mut()
.unwrap()
.values_mut()
.next()
.unwrap()
.as_object_mut()
.unwrap()
.remove("routes");
assert_eq!(
persistence::decode(&serde_json::to_vec(&json).unwrap()).unwrap(),
project
);
let v2 = include_str!("fixtures/v2-coastal-rescue.arcadia");
let migrated = language::parse(v2).unwrap();
assert!(
migrated
.diagrams
.values()
.all(|diagram| diagram.routes.is_empty())
);
assert!(
language::parse("arcadia 2; project p \"P\" { diagram view \"View\" { routes []; } }")
.is_err()
);
}
#[test]
fn invalid_route_source_has_located_errors_and_no_silent_nested_defaults() {
for route in [
"{}",
"{ edge @signal; label { offset { x 0; y 0; }; }; }",
"{ edge @signal; label { fraction 0.5; }; }",
"{ edge @signal; label { fraction 1.1; offset { x 0; y 0; }; }; }",
"{ edge @signal; waypoints [{ x 1000001; y 0; }]; }",
"{ edge @signal; waypoints [{ x 0; }]; }",
"{ edge @signal; label { fraction 0.5; offset { x 0; y 0; }; unknown true; }; }",
"{ edge @report; }",
"{ edge @absent; }",
"{ edge @signal; }, { edge @signal; }",
] {
let source = format!(
"arcadia 3; project p \"P\" {{\n oa_activity report \"Report\" {{}}\n oa_activity assess \"Assess\" {{}}\n interaction signal \"Signal\" {{ source @report; target @assess; }}\n diagram view \"View\" {{\n routes [{route}];\n }}\n}}"
);
let errors = language::parse(&source).expect_err(route);
assert!(
errors.iter().all(|error| error.line >= 5),
"{route}: {errors:?}"
);
}
}
#[test]
fn route_records_share_model_admission_for_source_json_and_bundles() {
let project = language::parse(SOURCE).unwrap();
// Project + three elements + relation + trace + two diagrams = eight,
// plus three route records = eleven. Points do not create identities.
let limits = language::ParseLimits {
max_records: 10,
..language::ParseLimits::UNLIMITED
};
assert!(limits.check_model(&project).is_err());
assert!(
language::parse_limited(&language::format(&project), limits)
.unwrap_err()
.iter()
.any(|error| error.code == "model_limit")
);
assert!(matches!(
persistence::decode_limited(&serde_json::to_vec(&project).unwrap(), limits),
Err(persistence::FileError::Limit(_))
));
let bundle = format_bundle(&project);
assert!(
compile_bundle(
&bundle,
ProjectLimits {
model: limits,
..ProjectLimits::default()
}
)
.unwrap_err()
.iter()
.any(|error| error.diagnostic.code == "model_limit")
);
let admitted = language::ParseLimits {
max_records: 11,
..limits
};
assert!(admitted.check_model(&project).is_ok());
}
#[test]
fn route_commands_json_and_one_step_undo_recover_exact_model_and_canonical_source() {
let original = language::parse(SOURCE).unwrap();
let diagram = id(&original, "architecture");
let edge = id(&original, "signal");
let before = language::format(&original);
let mut session = Session::new(original.clone());
let set_json = json!({"SetEdgeRoute": {"diagram":diagram,"route":{
"edge":edge,"waypoints":[{"x":515.5,"y":-42.0}],
"label":{"fraction":0.25,"offset":{"x":12.0,"y":-18.0}}
}}});
let set: Command = serde_json::from_value(set_json.clone()).unwrap();
assert_eq!(serde_json::to_value(&set).unwrap(), set_json);
session.execute(set).unwrap();
let updated = session.project().clone();
assert_eq!(
updated.diagrams[&id(&updated, "review")],
original.diagrams[&id(&original, "review")]
);
assert_eq!(
language::parse(&language::format(&updated)).unwrap(),
updated
);
session.undo();
assert_eq!(session.project(), &original);
assert_eq!(language::format(session.project()), before);
session.redo();
assert_eq!(session.project(), &updated);
let remove: Command =
serde_json::from_value(json!({"RemoveEdgeRoute":{"diagram":diagram,"edge":edge}})).unwrap();
session.execute(remove).unwrap();
assert_eq!(session.project().diagrams[&diagram].routes.len(), 1);
session.undo();
assert_eq!(session.project(), &updated);
}