use sheets_diff::core::diff::Diff;
use sheets_diff::core::error::{SheetsDiffError, WorkbookSide};
use sheets_diff::core::unified_format::unified_diff;
const OLD_FIXTURE: &str = "tests/fixtures/file1.xlsx";
const NEW_FIXTURE: &str = "tests/fixtures/file2.xlsx";
#[test]
fn golden_fixture_output_is_stable() {
const EXPECT: &str = r#"--- tests/fixtures/file1.xlsx (sheet names)
+++ tests/fixtures/file2.xlsx (sheet names)
- Sheet1_2
+ Sheetzz
--- tests/fixtures/file1.xlsx [Sheet1]
+++ tests/fixtures/file2.xlsx [Sheet1]
@@ A1(1,1) value @@
- 1
@@ B2(2,2) value @@
- 2
+ 今日は世界
@@ B4(4,2) value @@
+ a
@@ C6(6,3) value @@
+ hej
@@ D10(10,4) value @@
- 2
+ 8
@@ D10(10,4) formula @@
- 1+1
+ 2*4
@@ D12(12,4) value @@
+ a123
@@ D12(12,4) formula @@
+ "a"&123
@@ W55(55,23) value @@
+ っs
"#;
let diff = Diff::new(OLD_FIXTURE, NEW_FIXTURE);
let output = unified_diff(&diff).format();
assert_eq!(format!("{output}"), EXPECT);
}
#[test]
fn try_new_succeeds_on_valid_fixtures() {
let diff = Diff::try_new(OLD_FIXTURE, NEW_FIXTURE);
assert!(diff.is_ok(), "expected Ok, got: {diff:?}");
}
#[test]
fn try_new_missing_old_returns_open_workbook_old() {
let result = Diff::try_new("missing-old.xlsx", NEW_FIXTURE);
assert!(
matches!(
result,
Err(SheetsDiffError::OpenWorkbook {
side: WorkbookSide::Old,
..
})
),
"unexpected result: {result:?}"
);
}
#[test]
fn try_new_missing_new_returns_open_workbook_new() {
let result = Diff::try_new(OLD_FIXTURE, "missing-new.xlsx");
assert!(
matches!(
result,
Err(SheetsDiffError::OpenWorkbook {
side: WorkbookSide::New,
..
})
),
"unexpected result: {result:?}"
);
}
#[test]
fn try_new_non_xlsx_file_returns_error_not_panic() {
let result = Diff::try_new("tests/fixtures/non-xlsx.txt", NEW_FIXTURE);
assert!(
result.is_err(),
"expected Err for non-xlsx input, got Ok"
);
}
#[test]
#[should_panic]
fn diff_new_panics_on_missing_files() {
let _ = Diff::new("no-such-old.xlsx", "no-such-new.xlsx");
}
#[test]
fn error_display_is_human_readable() {
let result = Diff::try_new("tests/fixtures/non-xlsx.txt", NEW_FIXTURE);
let err = result.unwrap_err();
let msg = err.to_string();
assert!(!msg.is_empty(), "error Display must not be empty");
let _ = std::error::Error::source(&err);
}
#[test]
fn try_from_named_readers_succeeds_on_fixture_bytes() {
use std::io::Cursor;
let old_bytes = std::fs::read(OLD_FIXTURE).expect("read old fixture");
let new_bytes = std::fs::read(NEW_FIXTURE).expect("read new fixture");
let diff = Diff::try_from_named_readers(
"old.xlsx",
Cursor::new(old_bytes),
"new.xlsx",
Cursor::new(new_bytes),
)
.expect("reader diff should succeed");
assert_eq!(diff.old_filepath, "old.xlsx");
assert_eq!(diff.new_filepath, "new.xlsx");
}
#[test]
fn reader_output_matches_path_output() {
use std::io::Cursor;
let path_diff = Diff::try_new(OLD_FIXTURE, NEW_FIXTURE).unwrap();
let old_bytes = std::fs::read(OLD_FIXTURE).expect("read old fixture");
let new_bytes = std::fs::read(NEW_FIXTURE).expect("read new fixture");
let reader_diff = Diff::try_from_named_readers(
OLD_FIXTURE,
Cursor::new(old_bytes),
NEW_FIXTURE,
Cursor::new(new_bytes),
)
.unwrap();
assert_eq!(
path_diff.cell_diffs.len(),
reader_diff.cell_diffs.len(),
"cell_diffs length mismatch"
);
assert_eq!(
path_diff.sheet_diff.len(),
reader_diff.sheet_diff.len(),
"sheet_diff length mismatch"
);
}
#[test]
fn reader_constructor_returns_open_reader_error_for_non_xlsx() {
use std::io::Cursor;
let junk = Cursor::new(b"not an xlsx".to_vec());
let new_bytes = std::fs::read(NEW_FIXTURE).expect("read new fixture");
let result = Diff::try_from_named_readers("junk", junk, "new.xlsx", Cursor::new(new_bytes));
assert!(
matches!(
result,
Err(SheetsDiffError::OpenReader {
side: WorkbookSide::Old,
..
})
),
"unexpected result: {result:?}"
);
}
#[test]
fn diff_clone_helper_compiles_and_equals() {
let mut d = Diff::try_new(OLD_FIXTURE, NEW_FIXTURE).unwrap();
let cloned = d.diff();
assert_eq!(d.old_filepath, cloned.old_filepath);
assert_eq!(d.new_filepath, cloned.new_filepath);
}