use super::*;
use ratatui::text::Span;
#[test]
fn ascii_width() {
assert_eq!(display_width("hello"), 5);
}
#[test]
fn cjk_width() {
assert_eq!(display_width("日本語"), 6);
}
#[test]
fn mixed_width() {
assert_eq!(display_width("hi日本"), 6); }
#[test]
fn empty_width() {
assert_eq!(display_width(""), 0);
}
#[test]
fn truncate_ascii_no_op() {
assert_eq!(truncate_to_width("hello", 10), "hello");
assert_eq!(truncate_to_width("hello", 5), "hello");
}
#[test]
fn truncate_ascii() {
assert_eq!(truncate_to_width("hello world", 8), "hello w…");
}
#[test]
fn truncate_cjk() {
assert_eq!(truncate_to_width("日本語テスト", 7), "日本語…");
}
#[test]
fn truncate_cjk_boundary() {
assert_eq!(truncate_to_width("日本語テスト", 6), "日本…");
}
#[test]
fn truncate_edge_min() {
assert_eq!(truncate_to_width("hello", 1), "…");
}
#[test]
fn truncate_zero_width() {
assert_eq!(truncate_to_width("hello", 0), "");
}
#[test]
fn truncate_empty() {
assert_eq!(truncate_to_width("", 5), "");
}
#[test]
fn exceeds_ascii() {
assert!(!exceeds_width("hello", 10));
assert!(exceeds_width("hello world", 8));
}
#[test]
fn exceeds_cjk() {
assert!(exceeds_width("日本語", 5)); assert!(!exceeds_width("日本語", 6));
}
#[test]
fn scroll_fits() {
let (r, m) = scroll_display("hello", 10, 0);
assert_eq!(r, "hello");
assert_eq!(m, 0);
}
#[test]
fn scroll_start_ascii() {
let (r, m) = scroll_display("hello world", 8, 0);
assert_eq!(r, "hello w…");
assert_eq!(m, 4); }
#[test]
fn scroll_end_ascii() {
let (r, _) = scroll_display("hello world", 8, 100);
assert_eq!(r, "…o world");
}
#[test]
fn scroll_middle_ascii() {
let (r, _) = scroll_display("hello world", 8, 2);
assert_eq!(r, "…llo wo…");
}
#[test]
fn scroll_cjk_start() {
let (r, m) = scroll_display("日本語テスト", 7, 0);
assert_eq!(r, "日本語…");
assert_eq!(m, 6); }
#[test]
fn scroll_cjk_end() {
let (r, _) = scroll_display("日本語テスト", 7, 100);
assert_eq!(r, "…テスト");
}
#[test]
fn pad_ascii() {
assert_eq!(pad_to_width("hi", 5), "hi ");
}
#[test]
fn pad_exact() {
assert_eq!(pad_to_width("hello", 5), "hello");
}
#[test]
fn pad_cjk() {
assert_eq!(pad_to_width("日本", 6), "日本 ");
}
#[test]
fn pad_truncate() {
assert_eq!(pad_to_width("hello world", 5), "hello");
}
#[test]
fn pad_truncate_cjk_boundary() {
assert_eq!(pad_to_width("日本語", 5), "日本 ");
}
#[test]
fn take_columns_basic() {
let (s, c) = take_columns("hello", 3);
assert_eq!(s, "hel");
assert_eq!(c, 3);
}
#[test]
fn take_columns_cjk_boundary() {
let (s, c) = take_columns("日本語", 3);
assert_eq!(s, "日");
assert_eq!(c, 2);
}
#[test]
fn skip_columns_basic() {
let (s, actual) = skip_columns("hello world", 6);
assert_eq!(s, "world");
assert_eq!(actual, 6);
}
#[test]
fn skip_columns_cjk() {
let (s, actual) = skip_columns("日本語テスト", 4);
assert_eq!(s, "語テスト");
assert_eq!(actual, 4);
}
#[test]
fn skip_columns_cjk_odd_boundary() {
let (s, actual) = skip_columns("日本語テスト", 3);
assert_eq!(s, "語テスト");
assert_eq!(actual, 4);
}
#[test]
fn scroll_cjk_middle_odd_pos() {
let (r, _) = scroll_display("日本語テスト", 8, 3);
assert_eq!(r, "…\u{0020}語テ\u{0020}…");
assert_eq!(display_width(&r), 8);
}
#[test]
fn scroll_cjk_end_odd_boundary() {
let (r, _) = scroll_display("日本語テスト", 8, 100);
assert_eq!(display_width(&r), 8);
assert!(r.starts_with('…'));
}
#[test]
fn emoji_display_width() {
assert_eq!(display_width("🎉"), 2);
}
#[test]
fn truncate_emoji() {
assert_eq!(truncate_to_width("🎉🎊🎁", 3), "🎉…");
}
#[test]
fn scroll_zero_width() {
let (r, m) = scroll_display("hello world", 0, 0);
assert_eq!(r, "");
assert_eq!(m, 0);
let (r2, m2) = scroll_display("hello world", 0, 5);
assert_eq!(r2, "");
assert_eq!(m2, 0);
}
#[test]
fn scroll_width_one() {
let (r, m) = scroll_display("hello world", 1, 0);
assert_eq!(r, "…");
assert_eq!(display_width(&r), 1);
assert_eq!(m, 11);
let (r2, _) = scroll_display("hello world", 1, 5);
assert_eq!(r2, "…");
assert_eq!(display_width(&r2), 1);
}
#[test]
fn scroll_width_two_cjk() {
let (r, _) = scroll_display("日本語", 2, 0);
assert_eq!(r, " …");
assert_eq!(display_width(&r), 2);
let (r2, _) = scroll_display("日本語", 2, 1);
assert_eq!(r2, "……");
assert_eq!(display_width(&r2), 2);
let (r3, _) = scroll_display("日本語", 2, 100);
assert_eq!(r3, "… ");
assert_eq!(display_width(&r3), 2);
}
#[test]
fn scroll_start_cjk_boundary_padding() {
let (r, _) = scroll_display("日本語テスト", 5, 0);
assert_eq!(r, "日本…");
let (r2, _) = scroll_display("日本語テスト", 4, 0);
assert_eq!(display_width(&r2), 4);
assert_eq!(r2, "日 …");
}
fn wrap_spans(
spans: &[Span<'static>],
max_width: usize,
continuation_indent: usize,
) -> Vec<Vec<Span<'static>>> {
wrap_spans_with_ranges(spans, max_width, continuation_indent)
.into_iter()
.map(|line| line.spans)
.collect()
}
fn wrap_plain(text: &str, max_width: usize, indent: usize) -> Vec<String> {
let spans = vec![Span::raw(text.to_string())];
wrap_spans(&spans, max_width, indent)
.into_iter()
.map(|line| line.iter().map(|s| s.content.as_ref()).collect())
.collect()
}
#[test]
fn wrap_no_op_when_fits() {
assert_eq!(wrap_plain("hello world", 20, 0), vec!["hello world"]);
}
#[test]
fn wrap_at_word_boundary() {
assert_eq!(
wrap_plain("hello world foo", 12, 0),
vec!["hello world", "foo"]
);
}
#[test]
fn wrap_continuation_indent() {
assert_eq!(
wrap_plain("hello world foo", 12, 2),
vec!["hello world", " foo"]
);
}
#[test]
fn wrap_long_word_char_break() {
assert_eq!(wrap_plain("abcdefghij", 5, 0), vec!["abcde", "fghij"]);
}
#[test]
fn wrap_cjk_break() {
let result = wrap_plain("日本語テスト", 8, 0);
assert_eq!(result.len(), 2);
assert_eq!(result[0], "日本語テ");
assert_eq!(result[1], "スト");
}
#[test]
fn wrap_preserves_styles() {
use ratatui::style::Style;
let bold = Style::new().bold();
let spans = vec![
Span::raw("hello ".to_string()),
Span::styled("world foo".to_string(), bold),
];
let lines = wrap_spans(&spans, 10, 0);
assert_eq!(lines.len(), 2);
let line1_text: String = lines[0].iter().map(|s| s.content.as_ref()).collect();
let line2_text: String = lines[1].iter().map(|s| s.content.as_ref()).collect();
assert_eq!(line1_text, "hello");
assert_eq!(line2_text, "world foo");
let styled_span = lines[1]
.iter()
.find(|s| s.content.as_ref().contains("world"));
assert!(styled_span.is_some());
assert!(
styled_span
.unwrap()
.style
.add_modifier
.contains(ratatui::style::Modifier::BOLD)
);
}
#[test]
fn wrap_zero_width_no_panic() {
let result = wrap_plain("hello", 0, 0);
assert_eq!(result, vec!["hello"]);
}
#[test]
fn wrap_empty_input() {
let spans: Vec<Span<'static>> = vec![];
let result = wrap_spans(&spans, 10, 0);
assert_eq!(result.len(), 1);
assert!(result[0].is_empty());
}
#[test]
fn wrap_multiple_spaces_collapsed() {
let result = wrap_plain("aaa bbb", 4, 0);
assert_eq!(result, vec!["aaa", "bbb"]);
}
#[test]
fn wrap_spans_line_width_zero_fallback() {
let spans = vec![Span::raw("abc")];
let result = wrap_spans(&spans, 2, 3); assert_eq!(result.len(), 2); let text: String = result
.iter()
.map(|line| line.iter().map(|s| s.content.as_ref()).collect::<String>())
.collect::<Vec<_>>()
.join("|");
assert_eq!(text, "ab|c");
}