//! 摘要与格式化辅助的测试。 //! Tests for summary & formatting helpers. use focus_json::JsonValue; use focus_tui::format::{ caret_position, display_width, format_duration, format_tokens, summarize_tool, truncate, truncate_lines, wrap_text, }; fn obj(pairs: &[(&str, JsonValue)]) -> JsonValue { let mut o = JsonValue::obj(); for (k, v) in pairs { o.insert(*k, v.clone()).ok(); } o } #[test] fn tool_summaries_show_concrete_content() { // read → 路径 + 行范围。 // read → path + line range. let args = obj(&[ ("path", "src/main.rs".into()), ("startLine", 10u64.into()), ("endLine", 20u64.into()), ]); assert_eq!( summarize_tool("read", &args), "read src/main.rs lines 10-20" ); // write → 路径 + 字节数。 // write → path + byte count. let args = obj(&[("path", "a.txt".into()), ("content", "hello world".into())]); assert_eq!(summarize_tool("write", &args), "write a.txt (11 bytes)"); // edit → 路径 + 编辑数。 // edit → path + edit count. let edits = JsonValue::Arr(vec![JsonValue::obj(), JsonValue::obj()]); let args = obj(&[("path", "b.rs".into()), ("edits", edits)]); assert_eq!(summarize_tool("edit", &args), "edit b.rs (2 edits)"); // shell → 命令(截断)。 // shell → the command (truncated). let args = obj(&[("command", "cargo test --workspace".into())]); assert_eq!( summarize_tool("shell", &args), "shell: cargo test --workspace" ); // 未知工具 → 紧凑 JSON。 // Unknown tool → compact JSON. let args = obj(&[("x", 1u64.into())]); assert_eq!(summarize_tool("weird", &args), "weird {\"x\":1}"); } #[test] fn durations() { assert_eq!(format_duration(0), "0ms"); assert_eq!(format_duration(450), "450ms"); assert_eq!(format_duration(12_300), "12.3s"); assert_eq!(format_duration(125_000), "2m 05s"); } #[test] fn token_formatting() { assert_eq!(format_tokens(0), "0"); assert_eq!(format_tokens(999), "999"); assert_eq!(format_tokens(12_345), "12,345"); assert_eq!(format_tokens(1_000_000), "1,000,000"); } #[test] fn truncation() { assert_eq!(truncate("hello", 10), "hello"); assert_eq!(truncate("hello world", 5), "hello…"); let multi = "a\nb\nc\nd\ne\nf\ng"; let out = truncate_lines(multi, 4, 100); assert!(out.contains("truncated"), "got: {}", out); assert!(out.contains('a')); assert!(out.contains('g')); } #[test] fn wrapping_and_width() { assert_eq!(display_width("abc"), 3); assert_eq!(display_width("中文"), 4); let wrapped = wrap_text("aaaaaa", 3); assert_eq!(wrapped, vec!["aaa".to_string(), "aaa".to_string()]); // 保留显式换行。 // Preserve explicit newlines. let wrapped = wrap_text("ab\ncd", 10); assert_eq!(wrapped, vec!["ab".to_string(), "cd".to_string()]); } #[test] fn caret_positioning() { // 单行:caret 在末尾。 // Single line: caret at the end. let (row, col, total) = caret_position("hello", 5, 10); assert_eq!((row, col, total), (0, 5, 1)); // 换行后:caret 在第二行开头。 // After a newline: caret at the start of line 2. let (row, col, total) = caret_position("ab\ncd", 3, 10); assert_eq!((row, col, total), (1, 0, 2)); // 超宽行会折行。 // Over-wide lines wrap. let (row, col, total) = caret_position("aaaaaa", 6, 3); assert_eq!((row, col, total), (1, 3, 2)); }