//! Limits and hostile input.
use craft_captions::{Cue, Document, Error, Format, MAX_INPUT, TICKS_PER_SECOND, Tick, WriteOptions, parse, write};
fn doc() -> Document {
let cue = |s: i64, text: &str| Cue {
start: Tick(s * TICKS_PER_SECOND),
end: Tick((s + 2) * TICKS_PER_SECOND),
text: text.into(),
..Default::default()
};
Document { cues: vec![cue(1, "Hello there"), cue(4, "Second\nline")], ..Default::default() }
}
#[test]
fn input_over_the_size_limit_is_refused() {
let big = vec![b' '; MAX_INPUT + 1];
for format in Format::ALL {
assert_eq!(parse(&big, format), Err(Error::TooLarge(MAX_INPUT)), "{format:?}");
}
assert!(parse(big.get(..MAX_INPUT).unwrap(), Format::Srt).is_ok());
}
/// TTML is read without entity expansion: a document type with entities defines nothing.
#[test]
fn ttml_does_not_expand_entities() {
let bomb = r#"]>
"#;
assert_eq!(parse(bomb.as_bytes(), Format::Ttml), Err(Error::NotFormat("TTML")));
}
/// Every single-byte change to a written file reads or is refused; none panics.
#[test]
fn mutated_files_never_panic() {
for format in Format::ALL {
let bytes = write(&doc(), format, WriteOptions::default());
// every byte of a text file, and the header and first blocks of the (sparse) binary one
for i in 0..bytes.len().min(2048) {
for v in [0u8, 0x20, 0x3c, 0x7f, 0xff] {
let mut m = bytes.clone();
if let Some(b) = m.get_mut(i) {
*b = v;
}
let _ = parse(&m, format);
}
let _ = parse(bytes.get(..i).unwrap_or(&[]), format);
}
}
}
/// The creating program is the caller's, cut to what the header field can hold.
#[test]
fn mcc_and_stl_name_the_given_program() {
let opts = WriteOptions { program: "My\nApp \u{e9}", ..Default::default() };
let mcc = String::from_utf8(write(&doc(), Format::Mcc, opts)).unwrap();
assert!(mcc.contains("\nCreation Program=MyApp \u{e9}\n"), "{mcc}");
let stl = write(&doc(), Format::Stl, opts);
assert_eq!(stl.get(16..48), Some(&b"MyApp "[..]));
assert_eq!(parse(&stl, Format::Stl).unwrap().cues.len(), 2);
let default = String::from_utf8(write(&doc(), Format::Mcc, WriteOptions::default())).unwrap();
assert!(default.contains("Creation Program=craft-captions\n"));
}