use std::time::{Duration, Instant};
use excel_mcp_server::store::*;
use excel_mcp_server::tools;
use excel_mcp_server::types::inputs::*;
fn insert_rxw(store: &mut WorkbookStore) -> String {
let entry = WorkbookEntry {
id: String::new(),
data: zavora_xlsx::Workbook::new(),
read_only: false,
last_access: Instant::now(),
};
store.insert(entry).expect("insert rxw workbook")
}
fn parse_response(json: &str) -> serde_json::Value {
serde_json::from_str(json).expect("response should be valid JSON")
}
fn assert_error_structure(v: &serde_json::Value) {
assert_eq!(
v["status"].as_str(),
Some("error"),
"expected status 'error', got: {:?}",
v["status"]
);
let data = &v["data"];
assert!(
data["category"].is_string(),
"expected data.category to be a string, got: {:?}",
data["category"]
);
assert!(
data["description"].is_string(),
"expected data.description to be a string, got: {:?}",
data["description"]
);
assert!(
data["suggestion"].is_string(),
"expected data.suggestion to be a string, got: {:?}",
data["suggestion"]
);
}
#[test]
fn test_error_response_structure() {
let mut store = WorkbookStore::new();
let id = insert_rxw(&mut store);
let input = ReadCellInput {
workbook_id: id,
sheet_name: "NonExistentSheet".into(),
cell: "A1".into(),
};
let result = tools::read::read_cell(&mut store, input).unwrap();
let v = parse_response(&result);
assert_error_structure(&v);
assert_eq!(v["data"]["category"].as_str(), Some("not_found"));
}
#[test]
fn test_not_found_workbook_includes_open_ids() {
let mut store = WorkbookStore::new();
let known_id = insert_rxw(&mut store);
let input = WriteCellsInput {
workbook_id: "nonexistent-id".into(),
sheet_name: "Sheet1".into(),
cells: vec![CellWrite {
cell: "A1".into(),
value: serde_json::json!("test"),
}],
};
let result = tools::write::write_cells(&mut store, input).unwrap();
let v = parse_response(&result);
assert_error_structure(&v);
assert_eq!(v["data"]["category"].as_str(), Some("not_found"));
let suggestion = v["data"]["suggestion"].as_str().unwrap();
assert!(
suggestion.contains(&known_id),
"suggestion should contain the open workbook ID '{}', got: {}",
known_id,
suggestion
);
}
#[test]
fn test_invalid_cell_reference_error() {
let mut store = WorkbookStore::new();
let id = insert_rxw(&mut store);
let bad_ref = "ZZZZZ1";
let input = WriteCellsInput {
workbook_id: id,
sheet_name: "Sheet1".into(),
cells: vec![CellWrite {
cell: bad_ref.into(),
value: serde_json::json!("test"),
}],
};
let result = tools::write::write_cells(&mut store, input).unwrap();
let v = parse_response(&result);
assert_error_structure(&v);
assert_eq!(v["data"]["category"].as_str(), Some("parse_error"));
let description = v["data"]["description"].as_str().unwrap();
assert!(
description.contains(bad_ref),
"description should contain the bad reference '{}', got: {}",
bad_ref,
description
);
}
#[test]
fn test_capacity_exceeded_error() {
let mut store = WorkbookStore::with_config(1, Duration::from_secs(600));
let _id = insert_rxw(&mut store);
let result = tools::workbook::create_workbook(&mut store).unwrap();
let v = parse_response(&result);
assert_error_structure(&v);
assert_eq!(v["data"]["category"].as_str(), Some("capacity_exceeded"));
let description = v["data"]["description"].as_str().unwrap();
assert!(
description.to_lowercase().contains("capacity"),
"description should mention capacity, got: {}",
description
);
}