#[cfg(test)]
mod workbook_tests {
use crate::{test_functions::xml_to_vec, XlsxError};
use crate::{xmlwriter, CalculationMode, Table, Workbook};
use pretty_assertions::assert_eq;
#[test]
fn test_assemble() {
let mut workbook = Workbook::default();
workbook.add_worksheet();
workbook.assemble_xml_file();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let got = xml_to_vec(got);
let expected = xml_to_vec(
r#"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<fileVersion appName="xl" lastEdited="4" lowestEdited="4" rupBuild="4505"/>
<workbookPr defaultThemeVersion="124226"/>
<bookViews>
<workbookView xWindow="240" yWindow="15" windowWidth="16095" windowHeight="9660"/>
</bookViews>
<sheets>
<sheet name="Sheet1" sheetId="1" r:id="rId1"/>
</sheets>
<calcPr calcId="124519" fullCalcOnLoad="1"/>
</workbook>
"#,
);
assert_eq!(expected, got);
}
#[test]
fn test_define_name() {
let mut workbook = Workbook::default();
let names = vec![
".foo", "foo bar", "Foo,", "Foo/", "Foo[", "Foo]", "Foo'", "Foo\"bar", "Foo:", "Foo*", "Sheet1!Foo!Bar", "", "Sheet1!", "!Foo", "'A!B'Sales", "'A!B", "'!", "!", ];
for name in names {
let result = workbook.define_name(name, "");
assert!(
matches!(result, Err(XlsxError::NameError(_, _))),
"for name '{name}'"
);
}
}
#[test]
fn test_define_name_with_quoted_sheet_name() {
let mut workbook = Workbook::default();
let _ = workbook.add_worksheet().set_name("Sheet 1").unwrap();
let _ = workbook.add_worksheet().set_name("A!B").unwrap();
let _ = workbook.add_worksheet().set_name("It's").unwrap();
workbook.define_name("'Sheet 1'!Sales", "=1").unwrap();
workbook.define_name("'A!B'!Sales", "=2").unwrap();
workbook.define_name("'It''s'!Sales", "=3").unwrap();
let result = workbook.save_to_buffer();
assert!(result.is_ok());
}
#[test]
fn duplicate_worksheets() {
let mut workbook = Workbook::default();
let _ = workbook.add_worksheet().set_name("Foo").unwrap();
let _ = workbook.add_worksheet().set_name("Foo").unwrap();
let result = workbook.save_to_buffer();
assert!(matches!(result, Err(XlsxError::SheetnameReused(_))));
}
#[test]
fn duplicate_worksheets_case_insensitive() {
let mut workbook = Workbook::default();
let _ = workbook.add_worksheet().set_name("Foo").unwrap();
let _ = workbook.add_worksheet().set_name("foo").unwrap();
let result = workbook.save_to_buffer();
assert!(matches!(result, Err(XlsxError::SheetnameReused(_))));
}
#[test]
fn test_duplicate_table_names() {
let mut workbook = Workbook::default();
let worksheet = workbook.add_worksheet();
let mut table = Table::new().set_name("Foo");
worksheet.add_table(0, 0, 9, 9, &table).unwrap();
table = table.set_name("foo");
worksheet.add_table(10, 10, 19, 19, &table).unwrap();
let result = workbook.prepare_names();
assert!(matches!(result, Err(XlsxError::NameReused(_))));
}
#[test]
fn test_duplicate_defined_names() {
let mut workbook = Workbook::default();
workbook.define_name("Foo", "=Sheet1!$A$1").unwrap();
workbook.define_name("foo", "=Sheet1!$B$1").unwrap();
let result = workbook.prepare_names();
assert!(matches!(result, Err(XlsxError::NameReused(_))));
}
#[test]
fn test_duplicate_local_defined_names() {
let mut workbook = Workbook::default();
workbook.define_name("Sheet1!Foo", "=Sheet1!$A$1").unwrap();
workbook.define_name("Sheet1!foo", "=Sheet1!$B$1").unwrap();
let result = workbook.prepare_names();
assert!(matches!(result, Err(XlsxError::NameReused(_))));
}
#[test]
fn test_non_duplicate_defined_names() {
let mut workbook = Workbook::default();
workbook.define_name("Foo", "=Sheet1!$A$1").unwrap();
workbook.define_name("Sheet1!Foo", "=Sheet1!$B$1").unwrap();
workbook.define_name("Sheet2!Foo", "=Sheet2!$A$1").unwrap();
let result = workbook.prepare_names();
assert!(result.is_ok());
}
#[test]
fn test_duplicate_table_and_defined_name() {
let mut workbook = Workbook::default();
workbook.define_name("Foo", "=Sheet1!$A$1").unwrap();
let worksheet = workbook.add_worksheet();
let table = Table::new().set_name("foo");
worksheet.add_table(0, 0, 9, 9, &table).unwrap();
let result = workbook.prepare_names();
assert!(matches!(result, Err(XlsxError::NameReused(_))));
}
#[test]
fn test_table_name_and_local_defined_name() {
let mut workbook = Workbook::default();
workbook.define_name("Sheet1!Foo", "=Sheet1!$A$1").unwrap();
let worksheet = workbook.add_worksheet();
let table = Table::new().set_name("Foo");
worksheet.add_table(0, 0, 9, 9, &table).unwrap();
let result = workbook.prepare_names();
assert!(matches!(result, Err(XlsxError::NameReused(_))));
}
#[test]
fn non_xml_theme() {
let mut workbook = Workbook::default();
let theme_file = "tests/input/themes/empty.xml";
let result = workbook.use_custom_theme(theme_file);
assert!(matches!(result, Err(XlsxError::ThemeError(_))));
}
#[test]
fn image_gradient_fills_in_theme() {
let mut workbook = Workbook::default();
let theme_file = "tests/input/themes/civic.xml";
let result = workbook.use_custom_theme(theme_file);
assert!(matches!(result, Err(XlsxError::ThemeError(_))));
}
#[test]
fn no_theme_file_in_zip() {
let mut workbook = Workbook::default();
let theme_file = "tests/input/themes/no_theme.zip";
let result = workbook.use_custom_theme(theme_file);
assert!(matches!(result, Err(XlsxError::ThemeError(_))));
}
#[test]
#[cfg(feature = "constant_memory")]
fn test_tempfile_error() -> Result<(), XlsxError> {
let tempdir = tempfile::tempdir()?;
let tempdir_path = tempdir.path().to_path_buf();
let mut workbook = Workbook::new();
workbook.set_tempdir(&tempdir_path)?;
tempdir.close()?;
let result = workbook.add_worksheet_with_constant_memory();
assert!(matches!(result, Err(XlsxError::TempFileError(..))));
let result = workbook.add_worksheet_with_low_memory();
assert!(matches!(result, Err(XlsxError::TempFileError(..))));
let result = workbook.new_worksheet_with_constant_memory();
assert!(matches!(result, Err(XlsxError::TempFileError(..))));
let result = workbook.new_worksheet_with_low_memory();
assert!(matches!(result, Err(XlsxError::TempFileError(..))));
assert!(workbook.worksheets.is_empty());
let worksheet = workbook.add_worksheet();
assert_eq!("Sheet1", worksheet.name());
workbook.save_to_buffer()?;
let result = workbook.set_tempdir(&tempdir_path);
assert!(matches!(result, Err(XlsxError::TempFileError(..))));
let Err(error) = result else { unreachable!() };
let XlsxError::TempFileError(dir, io_error) = &error else {
unreachable!()
};
assert_eq!(&tempdir_path, dir);
assert_eq!(std::io::ErrorKind::NotFound, io_error.kind());
let source = std::error::Error::source(&error)
.and_then(|source| source.downcast_ref::<std::io::Error>());
assert_eq!(
Some(std::io::ErrorKind::NotFound),
source.map(std::io::Error::kind)
);
Ok(())
}
#[test]
fn test_zip_compression_level() -> Result<(), XlsxError> {
use crate::Image;
let create_workbook = |level: Option<u8>| -> Result<Workbook, XlsxError> {
let mut workbook = Workbook::new();
if let Some(level) = level {
workbook.set_zip_compression_level(level);
}
let worksheet = workbook.add_worksheet();
for row in 0..1000 {
worksheet.write(row, 0, "Hello")?;
worksheet.write(row, 1, row)?;
}
let image = Image::new("tests/input/images/red.png")?;
worksheet.insert_image(0, 3, &image)?;
Ok(workbook)
};
let mut workbook = create_workbook(Some(0))?;
assert_eq!(None, workbook.zip_compression_level);
let default_size = workbook.save_to_buffer()?.len();
let workbook = create_workbook(Some(10))?;
assert_eq!(None, workbook.zip_compression_level);
let mut workbook = create_workbook(Some(6))?;
assert_eq!(default_size, workbook.save_to_buffer()?.len());
let mut workbook = create_workbook(Some(1))?;
assert_eq!(Some(1), workbook.zip_compression_level);
let fast_size = workbook.save_to_buffer()?.len();
let mut workbook = create_workbook(Some(9))?;
assert_eq!(Some(9), workbook.zip_compression_level);
let best_size = workbook.save_to_buffer()?.len();
assert!(best_size < fast_size);
Ok(())
}
#[test]
fn test_write_calc_pr() {
let mut workbook = Workbook::default();
workbook.write_calc_pr();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected = r#"<calcPr calcId="124519" fullCalcOnLoad="1"/>"#;
assert_eq!(expected, got);
}
#[test]
fn test_write_calc_pr_auto() {
let mut workbook = Workbook::default();
workbook.set_calculation_mode(CalculationMode::Automatic);
workbook.write_calc_pr();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected = r#"<calcPr calcId="124519" fullCalcOnLoad="1"/>"#;
assert_eq!(expected, got);
}
#[test]
fn test_write_calc_pr_manual() {
let mut workbook = Workbook::default();
workbook.set_calculation_mode(CalculationMode::Manual);
workbook.write_calc_pr();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected = r#"<calcPr calcId="124519" calcMode="manual" calcOnSave="0"/>"#;
assert_eq!(expected, got);
}
#[test]
fn test_write_calc_pr_auto_except_tables() {
let mut workbook = Workbook::default();
workbook.set_calculation_mode(CalculationMode::Partial);
workbook.write_calc_pr();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected = r#"<calcPr calcId="124519" calcMode="autoNoTable" fullCalcOnLoad="1"/>"#;
assert_eq!(expected, got);
}
#[test]
fn test_write_workbook_view_tab_ratio() {
let mut workbook = Workbook::default();
workbook.set_tab_ratio(50);
workbook.first_sheet = 1;
workbook.active_tab = 2;
workbook.write_workbook_view();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected = r#"<workbookView xWindow="240" yWindow="15" windowWidth="16095" windowHeight="9660" tabRatio="500" firstSheet="1" activeTab="2"/>"#;
assert_eq!(expected, got);
}
#[test]
fn test_write_workbook_view_tab_ratio_out_of_range() {
let mut workbook = Workbook::default();
workbook.set_tab_ratio(101);
workbook.write_workbook_view();
let got = xmlwriter::cursor_to_str(&workbook.writer);
let expected =
r#"<workbookView xWindow="240" yWindow="15" windowWidth="16095" windowHeight="9660"/>"#;
assert_eq!(expected, got);
}
}