use super::*;
#[test]
fn lines_wrap_at_spaces_and_only_split_a_word_too_long_for_a_row() {
let pieces = |text: &str, width: usize| -> Vec<String> {
let characters: Vec<char> = text.chars().collect();
super::wrap_ranges(text, width).into_iter().map(|(from, to)| characters[from..to].iter().collect()).collect()
};
assert_eq!(pieces("the quick brown fox", 10), ["the quick ", "brown fox"]);
assert_eq!(pieces("abcdefghijkl xy", 5), ["abcde", "fghij", "kl xy"]);
assert_eq!(pieces("abcdefghijkl wxyz", 5), ["abcde", "fghij", "kl ", "wxyz"]);
assert_eq!(pieces("界界界", 4), ["界界", "界"]);
assert_eq!(pieces("界x", 1), ["界", "x"]);
assert_eq!(super::wrap_ranges("", 10), [(0, 0)]);
}
#[test]
fn hex_rows_measure_what_they_claim() {
let bytes: Vec<u8> = (0..=255u8).collect();
for (per_line, digits) in [(16, 8), (8, 4), (8, 0), (4, 0), (1, 8)] {
let full = hex_row(0, &bytes[..per_line], per_line, digits);
assert_eq!(full.chars().count(), hex_row_width(per_line, digits), "{per_line} bytes, {digits} digits: {full}");
let short = hex_row(0, &bytes[..1], per_line, digits);
assert_eq!(short.chars().count(), hex_row_width(per_line, digits) - (per_line - 1), "{short}");
}
assert_eq!(hex_row_width(HEX_BYTES_PER_LINE, HEX_OFFSET_DIGITS), crate::constants::HEX_LINE_WIDTH);
assert_eq!(hex_line(0, &bytes[..16]), hex_row(0, &bytes[..16], HEX_BYTES_PER_LINE, HEX_OFFSET_DIGITS));
}
#[test]
fn previews_binary_as_bytes_and_text_as_lines() {
let dir = std::env::temp_dir().join(format!("fm84-preview-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let binary = dir.join("binary");
std::fs::write(&binary, [0x7f, b'E', b'L', b'F', 0, 1, 2, 3]).unwrap();
let Preview::Bytes(bytes) = load_preview(&binary, 1024, 10) else {
panic!("a file with a null byte in it is a binary");
};
assert_eq!(bytes, [0x7f, b'E', b'L', b'F', 0, 1, 2, 3]);
let text = dir.join("text");
std::fs::write(&text, "one\ntwo\nthree\n").unwrap();
let Preview::Lines(lines) = load_preview(&text, 1024, 2) else {
panic!("text is still lines");
};
assert_eq!(lines, ["one", "two"]);
std::fs::remove_dir_all(&dir).unwrap();
}
fn sample(count: usize) -> Vec<String> {
let template = [
"pub fn item_{}(value: u32) -> Result<String, Error> {",
" let text = format!(\"item {} of the set\", value);",
" match value { 0 => Err(Error::Empty), _ => Ok(text) }",
"}",
];
(0..count).map(|i| template[i % template.len()].replace("{}", &i.to_string())).collect()
}
fn shape(spans: &[Vec<Span<'static>>]) -> Vec<Vec<(String, Option<Color>)>> {
spans.iter().map(|line| line.iter().map(|s| (s.content.to_string(), s.style.fg)).collect()).collect()
}
fn assert_matches_full(lines: &[String], spans: &[Vec<Span<'static>>], states: &[LineState], case: &str) {
let (expected, _) = highlight_all(lines, "rs");
assert_eq!(shape(spans), shape(&expected), "spans diverged after {case}");
assert_eq!(spans.len(), lines.len(), "span count wrong after {case}");
assert_eq!(states.len(), lines.len(), "state count wrong after {case}");
}
#[test]
fn incremental_matches_full_rehighlight() {
let mut lines = sample(200);
let (mut spans, mut states) = highlight_all(&lines, "rs");
assert_matches_full(&lines, &spans, &states, "initial load");
lines[50].push_str(" // trailing note");
highlight_from(&lines, "rs", 50, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "in-line edit");
lines.insert(10, "/* opening a block".to_string());
highlight_from(&lines, "rs", 10, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "block comment opened");
lines.insert(11, "closing it */".to_string());
highlight_from(&lines, "rs", 11, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "block comment closed");
lines.remove(11);
highlight_from(&lines, "rs", 11, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "line removed");
let last = lines.len() - 1;
lines[last].push_str("// end");
highlight_from(&lines, "rs", last, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "last-line edit");
lines.push("fn tail() {}".to_string());
highlight_from(&lines, "rs", lines.len() - 1, &mut spans, &mut states);
assert_matches_full(&lines, &spans, &states, "appended line");
}