use justerm_core::{CellFlags, Engine};
#[test]
fn auto_wrap_marks_wrapline_but_hard_newline_does_not() {
let mut soft = Engine::new(3, 2);
soft.feed(b"abcd"); assert!(soft.grid().is_row_wrapped(0));
let mut hard = Engine::new(3, 2);
hard.feed(b"ab\r\nc"); assert!(!hard.grid().is_row_wrapped(0));
}
#[test]
fn grow_rows_keeps_content_adds_blank_lines() {
let mut term = Engine::new(4, 2);
term.feed(b"ab\r\ncd");
term.resize(4, 3);
assert_eq!((term.grid().cols(), term.grid().rows()), (4, 3));
assert_eq!(term.grid().cell(0, 0).c(), 'a'); assert_eq!(term.grid().cell(1, 0).c(), 'c');
assert_eq!(term.grid().cell(2, 0).c(), ' '); }
#[test]
fn shrink_rows_preserves_top_lines_in_scrollback() {
let mut term = Engine::new(4, 3);
term.feed(b"a\r\nb\r\nc");
term.resize(4, 2);
assert_eq!((term.grid().rows(), term.scrollback_len()), (2, 1));
assert_eq!(term.grid().cell(0, 0).c(), 'b'); assert_eq!(term.grid().cell(1, 0).c(), 'c');
term.scroll_up(1);
assert_eq!(term.viewport_line(0)[0].c(), 'a'); }
#[test]
fn shrink_cols_rewraps_soft_wrapped_line() {
let mut term = Engine::new(4, 4);
term.feed(b"abcdef"); assert!(term.grid().is_row_wrapped(0));
term.resize(2, 4);
assert_eq!(
(term.grid().cell(0, 0).c(), term.grid().cell(0, 1).c()),
('a', 'b')
);
assert!(term.grid().is_row_wrapped(0));
assert_eq!(
(term.grid().cell(1, 0).c(), term.grid().cell(1, 1).c()),
('c', 'd')
);
assert!(term.grid().is_row_wrapped(1));
assert_eq!(
(term.grid().cell(2, 0).c(), term.grid().cell(2, 1).c()),
('e', 'f')
);
assert!(!term.grid().cell(2, 1).flags().contains(CellFlags::WRAPLINE)); }
#[test]
fn widen_cols_merges_wrapped_segments() {
let mut term = Engine::new(2, 4);
term.feed(b"abcdef");
term.resize(6, 4);
for (col, ch) in "abcdef".chars().enumerate() {
assert_eq!(term.grid().cell(0, col).c(), ch);
}
assert!(!term.grid().cell(0, 5).flags().contains(CellFlags::WRAPLINE)); }
#[test]
fn resize_reflows_scrollback_too() {
let mut term = Engine::new(4, 2);
term.feed(b"abcdefgh"); term.feed(b"\r\nX"); assert_eq!(term.scrollback_len(), 1);
term.resize(2, 2);
let total = term.scrollback_len();
term.scroll_up(total);
let top = term.viewport_line(0);
assert_eq!(top.len(), 2, "scrollback row left at the old width");
assert_eq!((top[0].c(), top[1].c()), ('a', 'b'));
}
#[test]
fn cursor_follows_content_through_reflow() {
let mut term = Engine::new(4, 4);
term.feed(b"abcdef"); term.feed(b"\x1b[1;3H");
term.resize(2, 4);
assert_eq!((term.cursor().row, term.cursor().col), (1, 0));
}
#[test]
fn resize_to_zero_is_clamped_not_a_panic() {
let mut term = Engine::new(4, 4);
term.feed(b"hi");
term.resize(0, 0);
assert!(term.grid().cols() >= 1);
assert!(term.grid().rows() >= 1);
}
#[test]
fn reflow_keeps_wide_char_together_at_boundary() {
let mut term = Engine::new(4, 4);
term.feed("a한".as_bytes());
term.resize(2, 4);
assert_eq!(term.grid().cell(1, 0).c(), '한');
assert!(
term.grid()
.cell(1, 0)
.flags()
.contains(CellFlags::WIDE_CHAR)
);
assert!(
term.grid()
.cell(1, 1)
.flags()
.contains(CellFlags::WIDE_CHAR_SPACER)
);
}
#[test]
fn resize_while_on_alt_resizes_both_screens() {
let mut term = Engine::new(10, 5);
term.feed(b"primary");
term.feed(b"\x1b[?1049h"); term.feed(b"alt");
term.resize(20, 8); assert_eq!((term.grid().cols(), term.grid().rows()), (20, 8));
term.feed(b"\x1b[?1049l"); assert_eq!((term.grid().cols(), term.grid().rows()), (20, 8)); }
#[test]
fn primary_is_usable_after_alt_resize_roundtrip() {
let mut term = Engine::new(10, 5);
term.feed(b"line1\r\nline2");
term.feed(b"\x1b[?1049h"); term.resize(20, 8); term.feed(b"\x1b[?1049l");
assert_eq!((term.grid().cols(), term.grid().rows()), (20, 8));
assert_eq!(term.grid().cell(0, 0).c(), 'l');
term.feed(b"\r\nline3");
term.reset_damage();
term.feed(b"x");
let _ = term.damage();
for r in 0..term.grid().rows() {
let _ = term.viewport_line(r);
}
assert_eq!(term.grid().cell(0, 0).c(), 'l');
}
fn rows_after_a_feed_at_the_region_bottom(term: &mut Engine) -> Vec<String> {
term.feed(b"\x1b[2;1HA\x1b[3;1HB\x1b[4;1HC\x1b[6;1HZ");
term.feed(b"\x1b[4;1H\n"); (0..6)
.map(|r| {
(0..6)
.map(|c| term.grid().cell(r, c).c())
.collect::<String>()
.trim_end()
.to_string()
})
.collect()
}
#[test]
fn a_resize_to_the_same_geometry_keeps_the_scroll_region() {
let mut term = Engine::new(6, 6);
term.feed(b"\x1b[2;4r");
term.resize(6, 6);
let rows = rows_after_a_feed_at_the_region_bottom(&mut term);
assert_eq!(rows, ["", "B", "C", "", "", "Z"]); }
#[test]
fn a_rows_only_resize_resets_the_scroll_region() {
let mut term = Engine::new(6, 7);
term.feed(b"\x1b[2;4r");
term.resize(6, 6);
let rows = rows_after_a_feed_at_the_region_bottom(&mut term);
assert_eq!(rows, ["", "A", "B", "C", "", "Z"]); }
#[test]
fn a_cols_only_resize_resets_the_scroll_region() {
let mut term = Engine::new(7, 6);
term.feed(b"\x1b[2;4r");
term.resize(6, 6);
let rows = rows_after_a_feed_at_the_region_bottom(&mut term);
assert_eq!(rows, ["", "A", "B", "C", "", "Z"]);
}