use crate::builtins::default_registry;
use crate::diagrams::flowchart::compiler::normalize_br_tags;
use crate::format::OutputFormat;
use crate::graph::measure::{
DEFAULT_PROPORTIONAL_FONT_SIZE, DEFAULT_PROPORTIONAL_NODE_PADDING_X,
DEFAULT_PROPORTIONAL_NODE_PADDING_Y, ProportionalTextMetrics, wrap_lines,
};
use crate::payload::Diagram as Payload;
use crate::runtime::config::RenderConfig;
#[test]
fn wrap_lines_respects_br_normalized_input() {
let metrics = ProportionalTextMetrics::new(
DEFAULT_PROPORTIONAL_FONT_SIZE,
DEFAULT_PROPORTIONAL_NODE_PADDING_X,
DEFAULT_PROPORTIONAL_NODE_PADDING_Y,
);
let raw = "yes<br>some very long continuation";
let normalized = normalize_br_tags(raw);
assert_eq!(
normalized, "yes\nsome very long continuation",
"normalize_br_tags must replace <br> with a hard '\\n' break"
);
let lines = wrap_lines(&metrics, &normalized, 100.0);
assert_eq!(
lines[0], "yes",
"first segment must stand alone post-normalization, got {lines:?}"
);
assert!(
lines.len() >= 2,
"continuation segment must wrap across further lines, got {lines:?}"
);
let rest: String = lines[1..].join(" ");
assert_eq!(
rest, "some very long continuation",
"second-segment tokens round-trip in order"
);
}
#[test]
fn runtime_render_populates_wrapped_label_lines_for_long_label() {
let input =
"graph TD\n A[Start] -->|this is a deliberately long label that will wrap| B[End]\n";
let payload = default_registry()
.create("flowchart")
.expect("flowchart should be registered")
.parse(input)
.expect("fixture should parse")
.into_payload()
.expect("fixture should build a payload");
let Payload::Flowchart(mut graph) = payload else {
panic!("flowchart input should yield a flowchart payload");
};
assert!(graph.edges.iter().all(|e| e.wrapped_label_lines.is_none()));
crate::runtime::graph_family::render_graph_family(
"flowchart",
&mut graph,
OutputFormat::Svg,
&RenderConfig::default(),
)
.expect("runtime render should succeed");
let labeled = graph
.edges
.iter()
.filter(|e| e.label.is_some())
.collect::<Vec<_>>();
assert!(!labeled.is_empty(), "fixture must carry a labeled edge");
for edge in labeled {
let wrapped = edge
.wrapped_label_lines
.as_ref()
.expect("runtime wrap pass must populate wrapped_label_lines before engine solve");
assert!(
wrapped.len() >= 2,
"long label must wrap into multiple lines, got {wrapped:?}"
);
}
}
#[test]
fn wrap_lines_respects_br_case_insensitive_variants() {
let metrics = ProportionalTextMetrics::new(
DEFAULT_PROPORTIONAL_FONT_SIZE,
DEFAULT_PROPORTIONAL_NODE_PADDING_X,
DEFAULT_PROPORTIONAL_NODE_PADDING_Y,
);
for raw in ["a<br>b", "a<BR>b", "a<br/>b", "a<br />b"] {
let normalized = normalize_br_tags(raw);
let lines = wrap_lines(&metrics, &normalized, 1000.0);
assert_eq!(
lines,
vec!["a".to_string(), "b".to_string()],
"variant {raw:?} must normalize to a \\n-delimited pair"
);
}
}