use verovio::{Error, Toolkit};
const SAMPLE_PAE: &str = "\
@start:clefs
@clef:G-2
@keysig:xF
@key:
@timesig:
@data:'4G/4-
@end:clefs
";
fn loaded_toolkit() -> Toolkit {
let mut tk = Toolkit::new();
tk.load_data(SAMPLE_PAE).expect("PAE fixture should load");
tk
}
#[test]
fn render_to_svg_returns_well_formed_svg() {
let mut tk = loaded_toolkit();
let svg = tk.render_to_svg(1).expect("page 1 should render");
assert!(
svg.contains("<svg"),
"expected <svg in output, got first 200 chars: {}",
&svg[..svg.len().min(200)]
);
assert!(svg.contains("</svg>"), "expected closing </svg> tag");
}
#[test]
fn render_to_svg_into_reuses_buffer() {
let mut tk = loaded_toolkit();
let mut buf = String::with_capacity(4096);
let initial_capacity = buf.capacity();
tk.render_to_svg_into(1, &mut buf).expect("render");
assert!(buf.contains("<svg"));
tk.render_to_svg_into(1, &mut buf).expect("render again");
assert!(buf.contains("<svg"));
assert!(
buf.capacity() >= initial_capacity,
"buffer capacity shrank — reuse defeated"
);
}
#[test]
fn render_to_svg_out_of_range_page_returns_render_failed() {
let mut tk = loaded_toolkit();
let res = tk.render_to_svg(999);
assert!(
matches!(res, Err(Error::RenderFailed { page: 999 })),
"got {res:?}"
);
}
#[test]
fn render_to_svg_without_loaded_data_fails() {
let mut tk = Toolkit::new();
let res = tk.render_to_svg(1);
assert!(
matches!(res, Err(Error::RenderFailed { page: 1 })),
"got {res:?}"
);
}
#[test]
fn render_to_midi_returns_base64_with_midi_header() {
let mut tk = loaded_toolkit();
let midi = tk.render_to_midi().expect("midi render");
assert!(
midi.starts_with("TVRoZA"),
"expected base64-encoded MThd header, got first 20 chars: {}",
&midi[..midi.len().min(20)]
);
}
#[test]
fn render_to_midi_into_reuses_buffer() {
let mut tk = loaded_toolkit();
let mut buf = String::with_capacity(1024);
tk.render_to_midi_into(&mut buf).expect("midi render");
let cap = buf.capacity();
tk.render_to_midi_into(&mut buf).expect("midi render again");
assert!(buf.capacity() >= cap);
}
#[test]
fn render_to_midi_without_loaded_data_fails() {
let mut tk = Toolkit::new();
let res = tk.render_to_midi();
assert!(
matches!(res, Err(Error::RenderFailed { page: 0 })),
"got {res:?}"
);
}
#[test]
fn render_to_midi_bytes_returns_standard_midi_file_header() {
let mut tk = loaded_toolkit();
let bytes = tk.render_to_midi_bytes().expect("midi bytes");
assert!(
bytes.starts_with(b"MThd"),
"expected MThd magic, got first 8 bytes: {:?}",
&bytes[..bytes.len().min(8)]
);
assert!(bytes.len() > 14, "SMF must be longer than the header");
}
#[test]
fn render_to_midi_bytes_without_loaded_data_fails() {
let mut tk = Toolkit::new();
let res = tk.render_to_midi_bytes();
assert!(
matches!(res, Err(Error::RenderFailed { page: 0 })),
"got {res:?}"
);
}
#[test]
fn render_to_timemap_without_loaded_data_returns_err() {
let mut tk = Toolkit::new();
let res = tk.render_to_timemap();
assert!(
matches!(res, Err(Error::RenderFailed { page: 0 })),
"got {res:?}"
);
}
#[test]
fn elements_at_time_without_loaded_data_returns_render_failed() {
let mut tk = Toolkit::new();
let res = tk.elements_at_time(0);
assert!(matches!(res, Err(verovio::Error::RenderFailed { page: 0 })));
}
#[test]
fn render_to_timemap_returns_json_array() {
let mut tk = loaded_toolkit();
let json = tk.render_to_timemap().expect("timemap render");
let trimmed = json.trim();
assert!(
trimmed.starts_with('[') && trimmed.ends_with(']'),
"expected JSON array, got first 200 chars: {}",
&trimmed[..trimmed.len().min(200)]
);
}
#[test]
fn redo_layout_runs_and_page_count_stays_consistent() {
let mut tk = loaded_toolkit();
let pages_before = tk.page_count();
tk.redo_layout();
let pages_after = tk.page_count();
assert_eq!(pages_before, pages_after);
}
#[test]
fn redo_layout_with_options_changes_layout() {
let mut tk = loaded_toolkit();
tk.redo_layout_with_options(r#"{"pageWidth": 1000}"#);
let svg = tk.render_to_svg(1).expect("render after redo");
assert!(svg.contains("<svg"));
}
#[test]
fn elements_at_time_at_zero_returns_json() {
let mut tk = loaded_toolkit();
let json = tk.elements_at_time(0).expect("elements_at_time");
let trimmed = json.trim();
assert!(
trimmed.starts_with('{'),
"expected JSON object, got first 200 chars: {}",
&trimmed[..trimmed.len().min(200)]
);
}
#[test]
fn elements_at_time_into_reuses_buffer() {
let mut tk = loaded_toolkit();
let mut buf = String::new();
tk.elements_at_time_into(0, &mut buf)
.expect("elements_at_time_into");
let cap = buf.capacity();
tk.elements_at_time_into(100, &mut buf)
.expect("elements_at_time_into");
assert!(buf.capacity() >= cap);
}
#[test]
fn render_svg_measure_range_empty_for_zero_or_inverted() {
const PAE: &str =
"@start:s\n@clef:G-2\n@keysig:xF\n@key:\n@timesig:4/4\n@data:'4G/4A/4B/4c/4d/4e\n@end:s\n";
let mut tk = verovio::Toolkit::from_data(PAE).expect("load");
assert_eq!(tk.render_svg_measure_range(0, 2, "\n").unwrap(), "");
assert_eq!(tk.render_svg_measure_range(3, 1, "\n").unwrap(), "");
}
#[test]
fn render_svg_measure_range_returns_svg_payload() {
const PAE: &str =
"@start:s\n@clef:G-2\n@keysig:xF\n@key:\n@timesig:4/4\n@data:'4G/4A/4B/4c/4d/4e\n@end:s\n";
let mut tk = verovio::Toolkit::from_data(PAE).expect("load");
let svg = tk.render_svg_measure_range(1, 2, "\n").unwrap();
assert!(
svg.contains("<svg"),
"expected SVG content, got {} bytes",
svg.len()
);
}
#[test]
fn render_svg_measure_range_restores_options() {
const PAE: &str =
"@start:s\n@clef:G-2\n@keysig:xF\n@key:\n@timesig:4/4\n@data:'4G/4A/4B/4c\n@end:s\n";
let mut tk = verovio::Toolkit::from_data(PAE).expect("load");
let before = tk.options();
let _ = tk.render_svg_measure_range(1, 1, "\n").unwrap();
let after = tk.options();
assert!(
!after.contains(r#""measureFrom": "1""#),
"measureFrom not restored: {after}"
);
let _ = before; }