use std::fs::File; use std::io::Read; use std::path::PathBuf; use serde_json::json; use sgclaw::compat::openxml_office_tool::OpenXmlOfficeTool; use uuid::Uuid; use zeroclaw::tools::Tool; use zip::ZipArchive; fn temp_workspace_root() -> PathBuf { let root = std::env::temp_dir().join(format!("sgclaw-openxml-office-{}", Uuid::new_v4())); std::fs::create_dir_all(&root).unwrap(); root } fn read_sheet_xml(output_path: &std::path::Path) -> String { let file = File::open(output_path).unwrap(); let mut archive = ZipArchive::new(file).unwrap(); let mut entry = archive.by_name("xl/worksheets/sheet1.xml").unwrap(); let mut xml = String::new(); entry.read_to_string(&mut xml).unwrap(); xml } #[tokio::test] async fn openxml_office_tool_renders_hotlist_xlsx_from_rows() { let workspace_root = temp_workspace_root(); let output_path = workspace_root.join("out/zhihu-hotlist.xlsx"); let tool = OpenXmlOfficeTool::new(workspace_root.clone()); let result = tool .execute(json!({ "sheet_name": "知乎热榜", "columns": ["rank", "title", "heat"], "rows": [ [1, "问题一", "344万"], [2, "问题二", "266万"] ], "output_path": output_path })) .await .unwrap(); assert!(result.success, "{result:?}"); assert!(output_path.exists()); let output_json: serde_json::Value = serde_json::from_str(&result.output).unwrap(); assert_eq!(output_json["row_count"], 2); assert_eq!(output_json["renderer"], "openxml_office"); assert_eq!(output_json["output_path"], json!(output_path.to_str().unwrap())); let xml = read_sheet_xml(&output_path); assert!(xml.contains("问题一")); assert!(xml.contains("344万")); assert!(xml.contains("问题二")); assert!(!xml.contains("{{TITLE_1}}")); } #[tokio::test] async fn openxml_office_tool_accepts_reordered_columns_when_rows_are_structured() { let workspace_root = temp_workspace_root(); let output_path = workspace_root.join("out/zhihu-hotlist-reordered.xlsx"); let tool = OpenXmlOfficeTool::new(workspace_root.clone()); let result = tool .execute(json!({ "sheet_name": "知乎热榜", "columns": ["title", "heat", "rank"], "rows": [ ["问题一", "344万", 1], ["问题二", "266万", 2] ], "output_path": output_path })) .await .unwrap(); assert!(result.success, "{result:?}"); assert!(output_path.exists()); let xml = read_sheet_xml(&output_path); assert!(xml.contains("问题一")); assert!(xml.contains("344万")); assert!(xml.contains(">1<")); } #[tokio::test] async fn openxml_office_tool_accepts_localized_hotlist_column_aliases() { let workspace_root = temp_workspace_root(); let output_path = workspace_root.join("out/zhihu-hotlist-localized.xlsx"); let tool = OpenXmlOfficeTool::new(workspace_root.clone()); let result = tool .execute(json!({ "sheet_name": "知乎热榜", "columns": ["排名", "标题", "热度"], "rows": [ [1, "问题一", "344万"], [2, "问题二", "266万"] ], "output_path": output_path })) .await .unwrap(); assert!(result.success, "{result:?}"); assert!(output_path.exists()); let xml = read_sheet_xml(&output_path); assert!(xml.contains("问题一")); assert!(xml.contains("344万")); assert!(xml.contains(">1<")); }