FIX: small diverse fixes (#35)

This commit is contained in:
Nicolás Hatcher Andrés
2024-04-14 21:50:14 +02:00
committed by GitHub
parent b3b7dea930
commit 49ef846ebd
25 changed files with 246 additions and 2749 deletions

View File

@@ -308,9 +308,9 @@ impl Lexer {
return self.consume_range(None); return self.consume_range(None);
} }
let name_upper = name.to_ascii_uppercase(); let name_upper = name.to_ascii_uppercase();
if name_upper == self.language.booleans.true_value { if name_upper == self.language.booleans.r#true {
return TokenType::Boolean(true); return TokenType::Boolean(true);
} else if name_upper == self.language.booleans.false_value { } else if name_upper == self.language.booleans.r#false {
return TokenType::Boolean(false); return TokenType::Boolean(false);
} }
if self.mode == LexerMode::A1 { if self.mode == LexerMode::A1 {
@@ -660,8 +660,8 @@ impl Lexer {
fn consume_error(&mut self) -> TokenType { fn consume_error(&mut self) -> TokenType {
let errors = &self.language.errors; let errors = &self.language.errors;
let rest_of_formula: String = self.chars[self.position - 1..self.len].iter().collect(); let rest_of_formula: String = self.chars[self.position - 1..self.len].iter().collect();
if rest_of_formula.starts_with(&errors.ref_value) { if rest_of_formula.starts_with(&errors.r#ref) {
self.position += errors.ref_value.chars().count() - 1; self.position += errors.r#ref.chars().count() - 1;
return TokenType::Error(Error::REF); return TokenType::Error(Error::REF);
} else if rest_of_formula.starts_with(&errors.name) { } else if rest_of_formula.starts_with(&errors.name) {
self.position += errors.name.chars().count() - 1; self.position += errors.name.chars().count() - 1;

View File

@@ -6,11 +6,11 @@ use crate::{
token::TokenType, token::TokenType,
}, },
language::get_language, language::get_language,
locale::get_locale_fix, locale::get_locale,
}; };
fn new_language_lexer(formula: &str, locale: &str, language: &str) -> Lexer { fn new_language_lexer(formula: &str, locale: &str, language: &str) -> Lexer {
let locale = get_locale_fix(locale).unwrap(); let locale = get_locale(locale).unwrap();
let language = get_language(language).unwrap(); let language = get_language(language).unwrap();
Lexer::new(formula, LexerMode::A1, locale, language) Lexer::new(formula, LexerMode::A1, locale, language)
} }

View File

@@ -120,7 +120,7 @@ impl Error {
pub fn to_localized_error_string(&self, language: &Language) -> String { pub fn to_localized_error_string(&self, language: &Language) -> String {
match self { match self {
Error::NULL => language.errors.null.to_string(), Error::NULL => language.errors.null.to_string(),
Error::REF => language.errors.ref_value.to_string(), Error::REF => language.errors.r#ref.to_string(),
Error::NAME => language.errors.name.to_string(), Error::NAME => language.errors.name.to_string(),
Error::VALUE => language.errors.value.to_string(), Error::VALUE => language.errors.value.to_string(),
Error::DIV => language.errors.div.to_string(), Error::DIV => language.errors.div.to_string(),
@@ -137,7 +137,7 @@ impl Error {
pub fn get_error_by_name(name: &str, language: &Language) -> Option<Error> { pub fn get_error_by_name(name: &str, language: &Language) -> Option<Error> {
let errors = &language.errors; let errors = &language.errors;
if name == errors.ref_value { if name == errors.r#ref {
return Some(Error::REF); return Some(Error::REF);
} else if name == errors.name { } else if name == errors.name {
return Some(Error::NAME); return Some(Error::NAME);

View File

@@ -5,16 +5,13 @@ use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct Booleans { pub struct Booleans {
#[serde(rename = "true")] pub r#true: String,
pub true_value: String, pub r#false: String,
#[serde(rename = "false")]
pub false_value: String,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct Errors { pub struct Errors {
#[serde(rename = "ref")] pub r#ref: String,
pub ref_value: String,
pub name: String, pub name: String,
pub value: String, pub value: String,
pub div: String, pub div: String,

View File

@@ -80,14 +80,8 @@ static LOCALES: Lazy<HashMap<String, Locale>> = Lazy::new(|| {
serde_json::from_str(include_str!("locales.json")).expect("Failed parsing locale") serde_json::from_str(include_str!("locales.json")).expect("Failed parsing locale")
}); });
pub fn get_locale(_id: &str) -> Result<&Locale, String> { pub fn get_locale(id: &str) -> Result<&Locale, String> {
// TODO: pass the locale once we implement locales in Rust // TODO: pass the locale once we implement locales in Rust
let locale = LOCALES.get("en").ok_or("Invalid locale")?;
Ok(locale)
}
// TODO: Remove this function one we implement locales properly
pub fn get_locale_fix(id: &str) -> Result<&Locale, String> {
let locale = LOCALES.get(id).ok_or("Invalid locale")?; let locale = LOCALES.get(id).ok_or("Invalid locale")?;
Ok(locale) Ok(locale)
} }

View File

@@ -798,7 +798,7 @@ impl Model {
None None
} }
/// Returns a model from a String representation of a workbook /// Returns a model from an internal binary representation of a workbook
/// ///
/// # Examples /// # Examples
/// ///
@@ -816,9 +816,12 @@ impl Model {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
///
/// See also:
/// * [Model::to_bytes]
pub fn from_bytes(s: &[u8]) -> Result<Model, String> { pub fn from_bytes(s: &[u8]) -> Result<Model, String> {
let workbook: Workbook = let workbook: Workbook =
bitcode::decode(s).map_err(|_| "Error parsing workbook".to_string())?; bitcode::decode(s).map_err(|e| format!("Error parsing workbook: {e}"))?;
Model::from_workbook(workbook) Model::from_workbook(workbook)
} }
@@ -1760,7 +1763,10 @@ impl Model {
.get_style(self.get_cell_style_index(sheet, row, column)) .get_style(self.get_cell_style_index(sheet, row, column))
} }
/// Returns a JSON string of the workbook /// Returns an internal binary representation of the workbook
///
/// See also:
/// * [Model::from_bytes]
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
bitcode::encode(&self.workbook) bitcode::encode(&self.workbook)
} }

View File

@@ -53,4 +53,5 @@ mod test_frozen_rows_and_columns;
mod test_get_cell_content; mod test_get_cell_content;
mod test_percentage; mod test_percentage;
mod test_today; mod test_today;
mod test_types;
mod user_model; mod user_model;

View File

@@ -0,0 +1,24 @@
#![allow(clippy::unwrap_used)]
use crate::types::{Alignment, HorizontalAlignment, VerticalAlignment};
#[test]
fn alignment_default() {
let alignment = Alignment::default();
assert_eq!(
alignment,
Alignment {
horizontal: HorizontalAlignment::General,
vertical: VerticalAlignment::Bottom,
wrap_text: false
}
);
let s = serde_json::to_string(&alignment).unwrap();
// defaults stringifies as an empty object
assert_eq!(s, "{}");
let a: Alignment = serde_json::from_str("{}").unwrap();
assert_eq!(a, alignment)
}

View File

@@ -25,7 +25,7 @@ fn send_queue() {
#[test] #[test]
fn apply_external_diffs_wrong_str() { fn apply_external_diffs_wrong_str() {
let mut model1 = UserModel::from_model(new_empty_model()); let mut model1 = UserModel::from_model(new_empty_model());
assert!(model1.apply_external_diffs("invalid").is_err()); assert!(model1.apply_external_diffs("invalid".as_bytes()).is_err());
} }
#[test] #[test]
@@ -155,5 +155,7 @@ fn new_sheet() {
#[test] #[test]
fn wrong_diffs_handled() { fn wrong_diffs_handled() {
let mut model = UserModel::from_model(new_empty_model()); let mut model = UserModel::from_model(new_empty_model());
assert!(model.apply_external_diffs("Hello world").is_err()); assert!(model
.apply_external_diffs("Hello world".as_bytes())
.is_err());
} }

View File

@@ -144,13 +144,18 @@ fn basic_fill() {
let style = model.get_cell_style(0, 1, 1).unwrap(); let style = model.get_cell_style(0, 1, 1).unwrap();
assert_eq!(style.fill.bg_color, None); assert_eq!(style.fill.bg_color, None);
assert_eq!(style.fill.fg_color, None);
// bg_color // bg_color
model model
.update_range_style(&range, "fill.bg_color", "#F2F2F2") .update_range_style(&range, "fill.bg_color", "#F2F2F2")
.unwrap(); .unwrap();
model
.update_range_style(&range, "fill.fg_color", "#F3F4F5")
.unwrap();
let style = model.get_cell_style(0, 1, 1).unwrap(); let style = model.get_cell_style(0, 1, 1).unwrap();
assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned())); assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned()));
assert_eq!(style.fill.fg_color, Some("#F3F4F5".to_owned()));
let send_queue = model.flush_send_queue(); let send_queue = model.flush_send_queue();
@@ -159,6 +164,7 @@ fn basic_fill() {
let style = model2.get_cell_style(0, 1, 1).unwrap(); let style = model2.get_cell_style(0, 1, 1).unwrap();
assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned())); assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned()));
assert_eq!(style.fill.fg_color, Some("#F3F4F5".to_owned()));
} }
#[test] #[test]
@@ -171,9 +177,15 @@ fn fill_errors() {
width: 1, width: 1,
height: 1, height: 1,
}; };
assert!(model assert_eq!(
.update_range_style(&range, "fill.bg_color", "#FFF") model.update_range_style(&range, "fill.bg_color", "#FFF"),
.is_err()); Err("Invalid color: '#FFF'.".to_string())
);
assert_eq!(
model.update_range_style(&range, "fill.fg_color", "#FFF"),
Err("Invalid color: '#FFF'.".to_string())
);
} }
#[test] #[test]

View File

@@ -25,6 +25,6 @@ fn errors() {
let model_bytes = "Early in the morning, late in the century, Cricklewood Broadway.".as_bytes(); let model_bytes = "Early in the morning, late in the century, Cricklewood Broadway.".as_bytes();
assert_eq!( assert_eq!(
&UserModel::from_bytes(model_bytes).unwrap_err(), &UserModel::from_bytes(model_bytes).unwrap_err(),
"Error parsing workbook" "Error parsing workbook: invalid packing"
); );
} }

View File

@@ -4,37 +4,15 @@ use std::{collections::HashMap, fmt::Display};
use crate::expressions::token::Error; use crate::expressions::token::Error;
// Useful for `#[serde(default = "default_as_true")]`
fn default_as_true() -> bool {
true
}
fn default_as_false() -> bool { fn default_as_false() -> bool {
false false
} }
// Useful for `#[serde(skip_serializing_if = "is_true")]`
fn is_true(b: &bool) -> bool {
*b
}
fn is_false(b: &bool) -> bool { fn is_false(b: &bool) -> bool {
!*b !*b
} }
fn is_zero(num: &i32) -> bool { #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
*num == 0
}
fn is_default_alignment(o: &Option<Alignment>) -> bool {
o.is_none() || *o == Some(Alignment::default())
}
fn hashmap_is_empty(h: &HashMap<String, Table>) -> bool {
h.values().len() == 0
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Metadata { pub struct Metadata {
pub application: String, pub application: String,
pub app_version: String, pub app_version: String,
@@ -44,14 +22,13 @@ pub struct Metadata {
pub last_modified: String, //"2020-11-20T16:24:35" pub last_modified: String, //"2020-11-20T16:24:35"
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct WorkbookSettings { pub struct WorkbookSettings {
pub tz: String, pub tz: String,
pub locale: String, pub locale: String,
} }
/// An internal representation of an IronCalc Workbook /// An internal representation of an IronCalc Workbook
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[serde(deny_unknown_fields)]
pub struct Workbook { pub struct Workbook {
pub shared_strings: Vec<String>, pub shared_strings: Vec<String>,
pub defined_names: Vec<DefinedName>, pub defined_names: Vec<DefinedName>,
@@ -60,17 +37,14 @@ pub struct Workbook {
pub name: String, pub name: String,
pub settings: WorkbookSettings, pub settings: WorkbookSettings,
pub metadata: Metadata, pub metadata: Metadata,
#[serde(default)]
#[serde(skip_serializing_if = "hashmap_is_empty")]
pub tables: HashMap<String, Table>, pub tables: HashMap<String, Table>,
} }
/// A defined name. The `sheet_id` is the sheet index in case the name is local /// A defined name. The `sheet_id` is the sheet index in case the name is local
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct DefinedName { pub struct DefinedName {
pub name: String, pub name: String,
pub formula: String, pub formula: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub sheet_id: Option<u32>, pub sheet_id: Option<u32>,
} }
@@ -80,8 +54,7 @@ pub struct DefinedName {
/// * state: /// * state:
/// 18.18.68 ST_SheetState (Sheet Visibility Types) /// 18.18.68 ST_SheetState (Sheet Visibility Types)
/// hidden, veryHidden, visible /// hidden, veryHidden, visible
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[serde(rename_all = "lowercase")]
pub enum SheetState { pub enum SheetState {
Visible, Visible,
Hidden, Hidden,
@@ -99,7 +72,7 @@ impl Display for SheetState {
} }
/// Internal representation of a worksheet Excel object /// Internal representation of a worksheet Excel object
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Worksheet { pub struct Worksheet {
pub dimension: String, pub dimension: String,
pub cols: Vec<Col>, pub cols: Vec<Col>,
@@ -109,15 +82,10 @@ pub struct Worksheet {
pub shared_formulas: Vec<String>, pub shared_formulas: Vec<String>,
pub sheet_id: u32, pub sheet_id: u32,
pub state: SheetState, pub state: SheetState,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>, pub color: Option<String>,
pub merge_cells: Vec<String>, pub merge_cells: Vec<String>,
pub comments: Vec<Comment>, pub comments: Vec<Comment>,
#[serde(default)]
#[serde(skip_serializing_if = "is_zero")]
pub frozen_rows: i32, pub frozen_rows: i32,
#[serde(default)]
#[serde(skip_serializing_if = "is_zero")]
pub frozen_columns: i32, pub frozen_columns: i32,
} }
@@ -126,7 +94,7 @@ pub struct Worksheet {
pub type SheetData = HashMap<i32, HashMap<i32, Cell>>; pub type SheetData = HashMap<i32, HashMap<i32, Cell>>;
// ECMA-376-1:2016 section 18.3.1.73 // ECMA-376-1:2016 section 18.3.1.73
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Row { pub struct Row {
/// Row index /// Row index
pub r: i32, pub r: i32,
@@ -134,23 +102,19 @@ pub struct Row {
pub custom_format: bool, pub custom_format: bool,
pub custom_height: bool, pub custom_height: bool,
pub s: i32, pub s: i32,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub hidden: bool, pub hidden: bool,
} }
// ECMA-376-1:2016 section 18.3.1.13 // ECMA-376-1:2016 section 18.3.1.13
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Col { pub struct Col {
// Column definitions are defined on ranges, unlike rows which store unique, per-row entries. // Column definitions are defined on ranges, unlike rows which store unique, per-row entries.
/// First column affected by this record. Settings apply to column in \[min, max\] range. /// First column affected by this record. Settings apply to column in \[min, max\] range.
pub min: i32, pub min: i32,
/// Last column affected by this record. Settings apply to column in \[min, max\] range. /// Last column affected by this record. Settings apply to column in \[min, max\] range.
pub max: i32, pub max: i32,
pub width: f64, pub width: f64,
pub custom_width: bool, pub custom_width: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<i32>, pub style: Option<i32>,
} }
@@ -165,32 +129,55 @@ pub enum CellType {
CompoundData = 128, CompoundData = 128,
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, Clone, PartialEq)] #[derive(Encode, Decode, Debug, Clone, PartialEq)]
#[serde(tag = "t", deny_unknown_fields)]
pub enum Cell { pub enum Cell {
#[serde(rename = "empty")] EmptyCell {
EmptyCell { s: i32 }, s: i32,
#[serde(rename = "b")] },
BooleanCell { v: bool, s: i32 },
#[serde(rename = "n")] BooleanCell {
NumberCell { v: f64, s: i32 }, v: bool,
s: i32,
},
NumberCell {
v: f64,
s: i32,
},
// Maybe we should not have this type. In Excel this is just a string // Maybe we should not have this type. In Excel this is just a string
#[serde(rename = "e")] ErrorCell {
ErrorCell { ei: Error, s: i32 }, ei: Error,
s: i32,
},
// Always a shared string // Always a shared string
#[serde(rename = "s")] SharedString {
SharedString { si: i32, s: i32 }, si: i32,
s: i32,
},
// Non evaluated Formula // Non evaluated Formula
#[serde(rename = "u")] CellFormula {
CellFormula { f: i32, s: i32 }, f: i32,
#[serde(rename = "fb")] s: i32,
CellFormulaBoolean { f: i32, v: bool, s: i32 }, },
#[serde(rename = "fn")]
CellFormulaNumber { f: i32, v: f64, s: i32 }, CellFormulaBoolean {
f: i32,
v: bool,
s: i32,
},
CellFormulaNumber {
f: i32,
v: f64,
s: i32,
},
// always inline string // always inline string
#[serde(rename = "str")] CellFormulaString {
CellFormulaString { f: i32, v: String, s: i32 }, f: i32,
#[serde(rename = "fe")] v: String,
s: i32,
},
CellFormulaError { CellFormulaError {
f: i32, f: i32,
ei: Error, ei: Error,
@@ -209,17 +196,16 @@ impl Default for Cell {
} }
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Comment { pub struct Comment {
pub text: String, pub text: String,
pub author_name: String, pub author_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub author_id: Option<String>, pub author_id: Option<String>,
pub cell_ref: String, pub cell_ref: String,
} }
// ECMA-376-1:2016 section 18.5.1.2 // ECMA-376-1:2016 section 18.5.1.2
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Table { pub struct Table {
pub name: String, pub name: String,
pub display_name: String, pub display_name: String,
@@ -227,34 +213,24 @@ pub struct Table {
pub reference: String, pub reference: String,
pub totals_row_count: u32, pub totals_row_count: u32,
pub header_row_count: u32, pub header_row_count: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub header_row_dxf_id: Option<u32>, pub header_row_dxf_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data_dxf_id: Option<u32>, pub data_dxf_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub totals_row_dxf_id: Option<u32>, pub totals_row_dxf_id: Option<u32>,
pub columns: Vec<TableColumn>, pub columns: Vec<TableColumn>,
pub style_info: TableStyleInfo, pub style_info: TableStyleInfo,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub has_filters: bool, pub has_filters: bool,
} }
// totals_row_label vs totals_row_function might be mutually exclusive. Use an enum? // totals_row_label vs totals_row_function might be mutually exclusive. Use an enum?
// the totals_row_function is an enum not String methinks // the totals_row_function is an enum not String methinks
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct TableColumn { pub struct TableColumn {
pub id: u32, pub id: u32,
pub name: String, pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub totals_row_label: Option<String>, pub totals_row_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub header_row_dxf_id: Option<u32>, pub header_row_dxf_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data_dxf_id: Option<u32>, pub data_dxf_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub totals_row_dxf_id: Option<u32>, pub totals_row_dxf_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub totals_row_function: Option<String>, pub totals_row_function: Option<String>,
} }
@@ -272,25 +248,16 @@ impl Default for TableColumn {
} }
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Default)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
pub struct TableStyleInfo { pub struct TableStyleInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>, pub name: Option<String>,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub show_first_column: bool, pub show_first_column: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub show_last_column: bool, pub show_last_column: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub show_row_stripes: bool, pub show_row_stripes: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub show_column_stripes: bool, pub show_column_stripes: bool,
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Styles { pub struct Styles {
pub num_fmts: Vec<NumFmt>, pub num_fmts: Vec<NumFmt>,
pub fonts: Vec<Font>, pub fonts: Vec<Font>,
@@ -326,7 +293,7 @@ pub struct Style {
pub quote_prefix: bool, pub quote_prefix: bool,
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct NumFmt { pub struct NumFmt {
pub num_fmt_id: i32, pub num_fmt_id: i32,
pub format_code: String, pub format_code: String,
@@ -516,29 +483,17 @@ pub struct Alignment {
pub wrap_text: bool, pub wrap_text: bool,
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct CellStyleXfs { pub struct CellStyleXfs {
pub num_fmt_id: i32, pub num_fmt_id: i32,
pub font_id: i32, pub font_id: i32,
pub fill_id: i32, pub fill_id: i32,
pub border_id: i32, pub border_id: i32,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_number_format: bool, pub apply_number_format: bool,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_border: bool, pub apply_border: bool,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_alignment: bool, pub apply_alignment: bool,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_protection: bool, pub apply_protection: bool,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_font: bool, pub apply_font: bool,
#[serde(default = "default_as_true")]
#[serde(skip_serializing_if = "is_true")]
pub apply_fill: bool, pub apply_fill: bool,
} }
@@ -559,39 +514,24 @@ impl Default for CellStyleXfs {
} }
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Default)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
pub struct CellXfs { pub struct CellXfs {
pub xf_id: i32, pub xf_id: i32,
pub num_fmt_id: i32, pub num_fmt_id: i32,
pub font_id: i32, pub font_id: i32,
pub fill_id: i32, pub fill_id: i32,
pub border_id: i32, pub border_id: i32,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_number_format: bool, pub apply_number_format: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_border: bool, pub apply_border: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_alignment: bool, pub apply_alignment: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_protection: bool, pub apply_protection: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_font: bool, pub apply_font: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub apply_fill: bool, pub apply_fill: bool,
#[serde(default = "default_as_false")]
#[serde(skip_serializing_if = "is_false")]
pub quote_prefix: bool, pub quote_prefix: bool,
#[serde(skip_serializing_if = "is_default_alignment")]
pub alignment: Option<Alignment>, pub alignment: Option<Alignment>,
} }
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct CellStyles { pub struct CellStyles {
pub name: String, pub name: String,
pub xf_id: i32, pub xf_id: i32,

View File

@@ -2,7 +2,7 @@
use std::{collections::HashMap, fmt::Debug}; use std::{collections::HashMap, fmt::Debug};
use serde::{Deserialize, Serialize}; use bitcode::{Decode, Encode};
use crate::{ use crate::{
constants, constants,
@@ -18,19 +18,19 @@ use crate::{
utils::is_valid_hex_color, utils::is_valid_hex_color,
}; };
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Encode, Decode)]
struct RowData { struct RowData {
row: Option<Row>, row: Option<Row>,
data: HashMap<i32, Cell>, data: HashMap<i32, Cell>,
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Encode, Decode)]
struct ColumnData { struct ColumnData {
column: Option<Col>, column: Option<Col>,
data: HashMap<i32, Cell>, data: HashMap<i32, Cell>,
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Encode, Decode)]
enum Diff { enum Diff {
// Cell diffs // Cell diffs
SetCellValue { SetCellValue {
@@ -160,13 +160,13 @@ impl History {
} }
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Encode, Decode)]
enum DiffType { enum DiffType {
Undo, Undo,
Redo, Redo,
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Encode, Decode)]
struct QueueDiffs { struct QueueDiffs {
r#type: DiffType, r#type: DiffType,
list: DiffList, list: DiffList,
@@ -408,9 +408,9 @@ impl UserModel {
/// ///
/// See also: /// See also:
/// * [UserModel::apply_external_diffs] /// * [UserModel::apply_external_diffs]
pub fn flush_send_queue(&mut self) -> String { pub fn flush_send_queue(&mut self) -> Vec<u8> {
// This can never fail :O: // This can never fail :O:
let q = serde_json::to_string(&self.send_queue).unwrap(); let q = bitcode::encode(&self.send_queue);
self.send_queue = vec![]; self.send_queue = vec![];
q q
} }
@@ -421,8 +421,8 @@ impl UserModel {
/// ///
/// See also: /// See also:
/// * [UserModel::flush_send_queue] /// * [UserModel::flush_send_queue]
pub fn apply_external_diffs(&mut self, diff_list_str: &str) -> Result<(), String> { pub fn apply_external_diffs(&mut self, diff_list_str: &[u8]) -> Result<(), String> {
if let Ok(queue_diffs_list) = serde_json::from_str::<Vec<QueueDiffs>>(diff_list_str) { if let Ok(queue_diffs_list) = bitcode::decode::<Vec<QueueDiffs>>(diff_list_str) {
for queue_diff in queue_diffs_list { for queue_diff in queue_diffs_list {
if matches!(queue_diff.r#type, DiffType::Redo) { if matches!(queue_diff.r#type, DiffType::Redo) {
self.apply_diff_list(&queue_diff.list)?; self.apply_diff_list(&queue_diff.list)?;
@@ -845,6 +845,9 @@ impl UserModel {
"fill.bg_color" => { "fill.bg_color" => {
style.fill.bg_color = color(value)?; style.fill.bg_color = color(value)?;
} }
"fill.fg_color" => {
style.fill.fg_color = color(value)?;
}
"num_fmt" => { "num_fmt" => {
style.num_fmt = value.to_owned(); style.num_fmt = value.to_owned();
} }

View File

@@ -1,9 +1,12 @@
all: all:
wasm-pack build --target web --scope ironcalc wasm-pack build --target web --scope ironcalc --release
cp README.pkg.md pkg/README.md cp README.pkg.md pkg/README.md
tsc types.ts --target esnext --module esnext tsc types.ts --target esnext --module esnext
python fix_types.py python fix_types.py
tests:
wasm-pack build --target nodejs && node tests/test.mjs
lint: lint:
cargo check cargo check
cargo fmt -- --check cargo fmt -- --check

View File

@@ -14,9 +14,9 @@ export function getTokens(formula: string): any;
""".strip() """.strip()
get_tokens_str_types = r""" get_tokens_str_types = r"""
* @returns {TokenType[]} * @returns {MarkedToken[]}
*/ */
export function getTokens(formula: string): TokenType[]; export function getTokens(formula: string): MarkedToken[];
""".strip() """.strip()
update_style_str = r""" update_style_str = r"""

View File

@@ -71,12 +71,12 @@ impl Model {
} }
#[wasm_bindgen(js_name = "flushSendQueue")] #[wasm_bindgen(js_name = "flushSendQueue")]
pub fn flush_send_queue(&mut self) -> String { pub fn flush_send_queue(&mut self) -> Vec<u8> {
self.model.flush_send_queue() self.model.flush_send_queue()
} }
#[wasm_bindgen(js_name = "applyExternalDiffs")] #[wasm_bindgen(js_name = "applyExternalDiffs")]
pub fn apply_external_diffs(&mut self, diffs: &str) -> Result<(), JsError> { pub fn apply_external_diffs(&mut self, diffs: &[u8]) -> Result<(), JsError> {
self.model.apply_external_diffs(diffs).map_err(to_js_error) self.model.apply_external_diffs(diffs).map_err(to_js_error)
} }

View File

@@ -8,7 +8,7 @@
use std::path; use std::path;
use ironcalc::{compare::test_file, export::save_to_xlsx, import::load_model_from_xlsx}; use ironcalc::{compare::test_file, export::save_to_xlsx, import::load_from_xlsx};
fn main() { fn main() {
let args: Vec<_> = std::env::args().collect(); let args: Vec<_> = std::env::args().collect();
@@ -27,7 +27,7 @@ fn main() {
let file_path = path::Path::new(file_name); let file_path = path::Path::new(file_name);
let base_name = file_path.file_stem().unwrap().to_str().unwrap(); let base_name = file_path.file_stem().unwrap().to_str().unwrap();
let output_file_name = &format!("{base_name}.output.xlsx"); let output_file_name = &format!("{base_name}.output.xlsx");
let mut model = load_model_from_xlsx(file_name, "en", "UTC").unwrap(); let mut model = load_from_xlsx(file_name, "en", "UTC").unwrap();
model.evaluate(); model.evaluate();
println!("Saving result as: {output_file_name}. Please open with Excel and test."); println!("Saving result as: {output_file_name}. Please open with Excel and test.");
save_to_xlsx(&model, output_file_name).unwrap(); save_to_xlsx(&model, output_file_name).unwrap();

View File

@@ -8,7 +8,7 @@
use std::path; use std::path;
use ironcalc::{export::save_to_json, import::load_model_from_xlsx}; use ironcalc::{export::save_to_icalc, import::load_from_xlsx};
fn main() { fn main() {
let args: Vec<_> = std::env::args().collect(); let args: Vec<_> = std::env::args().collect();
@@ -21,6 +21,6 @@ fn main() {
let file_path = path::Path::new(file_name); let file_path = path::Path::new(file_name);
let base_name = file_path.file_stem().unwrap().to_str().unwrap(); let base_name = file_path.file_stem().unwrap().to_str().unwrap();
let output_file_name = &format!("{base_name}.ic"); let output_file_name = &format!("{base_name}.ic");
let model = load_model_from_xlsx(file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(file_name, "en", "UTC").unwrap();
save_to_json(model.workbook, output_file_name); save_to_icalc(model.workbook, output_file_name);
} }

View File

@@ -5,7 +5,7 @@ use ironcalc_base::types::*;
use ironcalc_base::{expressions::utils::number_to_column, Model}; use ironcalc_base::{expressions::utils::number_to_column, Model};
use crate::export::save_to_xlsx; use crate::export::save_to_xlsx;
use crate::import::load_model_from_xlsx; use crate::import::load_from_xlsx;
pub struct CompareError { pub struct CompareError {
message: String, message: String,
@@ -164,13 +164,13 @@ pub(crate) fn compare_models(m1: &Model, m2: &Model) -> Result<(), String> {
let mut message = "".to_string(); let mut message = "".to_string();
for diff in diffs { for diff in diffs {
message = format!( message = format!(
"{}\n.Diff: {}!{}{}, value1: {}, value2 {}\n {}", "{}\n.Diff: {}!{}{}, value1: {:?}, value2 {:?}\n {}",
message, message,
diff.sheet_name, diff.sheet_name,
number_to_column(diff.column).unwrap(), number_to_column(diff.column).unwrap(),
diff.row, diff.row,
serde_json::to_string(&diff.value1).unwrap(), &diff.value1,
serde_json::to_string(&diff.value2).unwrap(), &diff.value2,
diff.reason diff.reason
); );
} }
@@ -183,15 +183,15 @@ pub(crate) fn compare_models(m1: &Model, m2: &Model) -> Result<(), String> {
/// Tests that file in file_path produces the same results in Excel and in IronCalc. /// Tests that file in file_path produces the same results in Excel and in IronCalc.
pub fn test_file(file_path: &str) -> Result<(), String> { pub fn test_file(file_path: &str) -> Result<(), String> {
let model1 = load_model_from_xlsx(file_path, "en", "UTC").unwrap(); let model1 = load_from_xlsx(file_path, "en", "UTC").unwrap();
let mut model2 = load_model_from_xlsx(file_path, "en", "UTC").unwrap(); let mut model2 = load_from_xlsx(file_path, "en", "UTC").unwrap();
model2.evaluate(); model2.evaluate();
compare_models(&model1, &model2) compare_models(&model1, &model2)
} }
/// Tests that file in file_path can be converted to xlsx and read again /// Tests that file in file_path can be converted to xlsx and read again
pub fn test_load_and_saving(file_path: &str, temp_dir_name: &Path) -> Result<(), String> { pub fn test_load_and_saving(file_path: &str, temp_dir_name: &Path) -> Result<(), String> {
let model1 = load_model_from_xlsx(file_path, "en", "UTC").unwrap(); let model1 = load_from_xlsx(file_path, "en", "UTC").unwrap();
let base_name = Path::new(file_path).file_name().unwrap().to_str().unwrap(); let base_name = Path::new(file_path).file_name().unwrap().to_str().unwrap();
@@ -200,7 +200,7 @@ pub fn test_load_and_saving(file_path: &str, temp_dir_name: &Path) -> Result<(),
// test can save // test can save
save_to_xlsx(&model1, temp_file_path).unwrap(); save_to_xlsx(&model1, temp_file_path).unwrap();
// test can open // test can open
let mut model2 = load_model_from_xlsx(temp_file_path, "en", "UTC").unwrap(); let mut model2 = load_from_xlsx(temp_file_path, "en", "UTC").unwrap();
model2.evaluate(); model2.evaluate();
compare_models(&model1, &model2) compare_models(&model1, &model2)
} }

View File

@@ -129,9 +129,9 @@ pub fn save_xlsx_to_writer<W: Write + Seek>(model: &Model, writer: W) -> Result<
} }
/// Exports an internal representation of a workbook into an equivalent IronCalc json format /// Exports an internal representation of a workbook into an equivalent IronCalc json format
pub fn save_to_json(workbook: Workbook, output: &str) { pub fn save_to_icalc(workbook: Workbook, output: &str) {
let s = serde_json::to_string(&workbook).unwrap(); let s = bitcode::encode(&workbook);
let file_path = std::path::Path::new(output); let file_path = std::path::Path::new(output);
let mut file = fs::File::create(file_path).unwrap(); let mut file = fs::File::create(file_path).unwrap();
file.write_all(s.as_bytes()).unwrap(); file.write_all(&s).unwrap();
} }

View File

@@ -3,7 +3,9 @@ use std::fs;
use ironcalc_base::Model; use ironcalc_base::Model;
use crate::error::XlsxError; use crate::error::XlsxError;
use crate::{export::save_to_xlsx, import::load_model_from_xlsx}; use crate::export::save_to_icalc;
use crate::import::load_from_icalc;
use crate::{export::save_to_xlsx, import::load_from_xlsx};
pub fn new_empty_model() -> Model { pub fn new_empty_model() -> Model {
Model::new_empty("model", "en", "UTC").unwrap() Model::new_empty("model", "en", "UTC").unwrap()
@@ -26,11 +28,11 @@ fn test_values() {
// noop // noop
model.evaluate(); model.evaluate();
{
let temp_file_name = "temp_file_test_values.xlsx"; let temp_file_name = "temp_file_test_values.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "123.456"); assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "123.456");
assert_eq!( assert_eq!(
model.get_formatted_cell_value(0, 2, 1).unwrap(), model.get_formatted_cell_value(0, 2, 1).unwrap(),
@@ -49,6 +51,31 @@ fn test_values() {
assert_eq!(model.get_formatted_cell_value(0, 7, 1).unwrap(), "#VALUE!"); assert_eq!(model.get_formatted_cell_value(0, 7, 1).unwrap(), "#VALUE!");
fs::remove_file(temp_file_name).unwrap(); fs::remove_file(temp_file_name).unwrap();
}
{
let temp_file_name = "temp_file_test_values.ic";
save_to_icalc(model.workbook, temp_file_name);
let model = load_from_icalc(temp_file_name).unwrap();
assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "123.456");
assert_eq!(
model.get_formatted_cell_value(0, 2, 1).unwrap(),
"Hello world!"
);
assert_eq!(
model.get_formatted_cell_value(0, 3, 1).unwrap(),
"Hello world!"
);
assert_eq!(
model.get_formatted_cell_value(0, 4, 1).unwrap(),
"你好世界!"
);
assert_eq!(model.get_formatted_cell_value(0, 5, 1).unwrap(), "TRUE");
assert_eq!(model.get_formatted_cell_value(0, 6, 1).unwrap(), "FALSE");
assert_eq!(model.get_formatted_cell_value(0, 7, 1).unwrap(), "#VALUE!");
fs::remove_file(temp_file_name).unwrap();
}
} }
#[test] #[test]
@@ -67,7 +94,7 @@ fn test_formulas() {
let temp_file_name = "temp_file_test_formulas.xlsx"; let temp_file_name = "temp_file_test_formulas.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
assert_eq!(model.get_formatted_cell_value(0, 1, 2).unwrap(), "11"); assert_eq!(model.get_formatted_cell_value(0, 1, 2).unwrap(), "11");
assert_eq!(model.get_formatted_cell_value(0, 2, 2).unwrap(), "13"); assert_eq!(model.get_formatted_cell_value(0, 2, 2).unwrap(), "13");
assert_eq!(model.get_formatted_cell_value(0, 3, 2).unwrap(), "15"); assert_eq!(model.get_formatted_cell_value(0, 3, 2).unwrap(), "15");
@@ -89,7 +116,7 @@ fn test_sheets() {
let temp_file_name = "temp_file_test_sheets.xlsx"; let temp_file_name = "temp_file_test_sheets.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
assert_eq!( assert_eq!(
model.workbook.get_worksheet_names(), model.workbook.get_worksheet_names(),
vec!["Sheet1", "With space", "Tango & Cash", "你好世界"] vec!["Sheet1", "With space", "Tango & Cash", "你好世界"]
@@ -118,7 +145,7 @@ fn test_named_styles() {
let temp_file_name = "temp_file_test_named_styles.xlsx"; let temp_file_name = "temp_file_test_named_styles.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
assert!(model assert!(model
.workbook .workbook
.styles .styles

View File

@@ -106,7 +106,7 @@ fn load_xlsx_from_reader<R: Read + std::io::Seek>(
// Public methods // Public methods
/// Imports a file from disk into an internal representation /// Imports a file from disk into an internal representation
pub fn load_from_excel(file_name: &str, locale: &str, tz: &str) -> Result<Workbook, XlsxError> { fn load_from_excel(file_name: &str, locale: &str, tz: &str) -> Result<Workbook, XlsxError> {
let file_path = std::path::Path::new(file_name); let file_path = std::path::Path::new(file_name);
let file = fs::File::open(file_path)?; let file = fs::File::open(file_path)?;
let reader = BufReader::new(file); let reader = BufReader::new(file);
@@ -118,7 +118,14 @@ pub fn load_from_excel(file_name: &str, locale: &str, tz: &str) -> Result<Workbo
load_xlsx_from_reader(name, reader, locale, tz) load_xlsx_from_reader(name, reader, locale, tz)
} }
pub fn load_model_from_xlsx(file_name: &str, locale: &str, tz: &str) -> Result<Model, XlsxError> { pub fn load_from_xlsx(file_name: &str, locale: &str, tz: &str) -> Result<Model, XlsxError> {
let workbook = load_from_excel(file_name, locale, tz)?; let workbook = load_from_excel(file_name, locale, tz)?;
Model::from_workbook(workbook).map_err(XlsxError::Workbook) Model::from_workbook(workbook).map_err(XlsxError::Workbook)
} }
pub fn load_from_icalc(file_name: &str) -> Result<Model, XlsxError> {
let contents = fs::read(file_name)
.map_err(|e| XlsxError::IO(format!("Could not extract workbook name: {}", e)))?;
let workbook: Workbook = bitcode::decode(&contents).unwrap();
Model::from_workbook(workbook).map_err(XlsxError::Workbook)
}

BIN
xlsx/tests/example.ic Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -3,33 +3,32 @@ use uuid::Uuid;
use ironcalc::compare::{test_file, test_load_and_saving}; use ironcalc::compare::{test_file, test_load_and_saving};
use ironcalc::export::save_to_xlsx; use ironcalc::export::save_to_xlsx;
use ironcalc::import::{load_from_excel, load_model_from_xlsx}; use ironcalc::import::{load_from_icalc, load_from_xlsx};
use ironcalc_base::types::{HorizontalAlignment, VerticalAlignment, Workbook}; use ironcalc_base::types::{HorizontalAlignment, VerticalAlignment};
use ironcalc_base::Model; use ironcalc_base::Model;
// This is a functional test. // This is a functional test.
// We check that the output of example.xlsx is what we expect. // We check that the output of example.xlsx is what we expect.
#[test] #[test]
fn test_example() { fn test_example() {
let model = load_from_excel("tests/example.xlsx", "en", "UTC").unwrap(); let model = load_from_xlsx("tests/example.xlsx", "en", "UTC").unwrap();
assert_eq!(model.worksheets[0].frozen_rows, 0); let workbook = model.workbook;
assert_eq!(model.worksheets[0].frozen_columns, 0); assert_eq!(workbook.worksheets[0].frozen_rows, 0);
let contents = assert_eq!(workbook.worksheets[0].frozen_columns, 0);
fs::read_to_string("tests/example.json").expect("Something went wrong reading the file"); let model2 = load_from_icalc("tests/example.ic").unwrap();
let model2: Workbook = serde_json::from_str(&contents).unwrap(); let s = bitcode::encode(&model2.workbook);
let s = serde_json::to_string(&model).unwrap(); assert_eq!(workbook, model2.workbook, "{:?}", s);
assert_eq!(model, model2, "{s}");
} }
#[test] #[test]
fn test_save_to_xlsx() { fn test_save_to_xlsx() {
let mut model = load_model_from_xlsx("tests/example.xlsx", "en", "UTC").unwrap(); let mut model = load_from_xlsx("tests/example.xlsx", "en", "UTC").unwrap();
model.evaluate(); model.evaluate();
let temp_file_name = "temp_file_example.xlsx"; let temp_file_name = "temp_file_example.xlsx";
// test can safe // test can safe
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
// test can open // test can open
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
let metadata = &model.workbook.metadata; let metadata = &model.workbook.metadata;
assert_eq!(metadata.application, "IronCalc Sheets"); assert_eq!(metadata.application, "IronCalc Sheets");
// FIXME: This will need to be updated once we fix versioning // FIXME: This will need to be updated once we fix versioning
@@ -41,7 +40,9 @@ fn test_save_to_xlsx() {
#[test] #[test]
fn test_freeze() { fn test_freeze() {
// freeze has 3 frozen columns and 2 frozen rows // freeze has 3 frozen columns and 2 frozen rows
let model = load_from_excel("tests/freeze.xlsx", "en", "UTC").unwrap(); let model = load_from_xlsx("tests/freeze.xlsx", "en", "UTC")
.unwrap()
.workbook;
assert_eq!(model.worksheets[0].frozen_rows, 2); assert_eq!(model.worksheets[0].frozen_rows, 2);
assert_eq!(model.worksheets[0].frozen_columns, 3); assert_eq!(model.worksheets[0].frozen_columns, 3);
} }
@@ -49,7 +50,9 @@ fn test_freeze() {
#[test] #[test]
fn test_split() { fn test_split() {
// We test that a workbook with split panes do not produce frozen rows and columns // We test that a workbook with split panes do not produce frozen rows and columns
let model = load_from_excel("tests/split.xlsx", "en", "UTC").unwrap(); let model = load_from_xlsx("tests/split.xlsx", "en", "UTC")
.unwrap()
.workbook;
assert_eq!(model.worksheets[0].frozen_rows, 0); assert_eq!(model.worksheets[0].frozen_rows, 0);
assert_eq!(model.worksheets[0].frozen_columns, 0); assert_eq!(model.worksheets[0].frozen_columns, 0);
} }
@@ -145,14 +148,14 @@ fn test_model_has_correct_styles(model: &Model) {
#[test] #[test]
fn test_simple_text() { fn test_simple_text() {
let model = load_model_from_xlsx("tests/basic_text.xlsx", "en", "UTC").unwrap(); let model = load_from_xlsx("tests/basic_text.xlsx", "en", "UTC").unwrap();
test_model_has_correct_styles(&model); test_model_has_correct_styles(&model);
let temp_file_name = "temp_file_test_named_styles.xlsx"; let temp_file_name = "temp_file_test_named_styles.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap(); save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_model_from_xlsx(temp_file_name, "en", "UTC").unwrap(); let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
fs::remove_file(temp_file_name).unwrap(); fs::remove_file(temp_file_name).unwrap();
test_model_has_correct_styles(&model); test_model_has_correct_styles(&model);
} }
@@ -160,7 +163,9 @@ fn test_simple_text() {
#[test] #[test]
fn test_defined_names_casing() { fn test_defined_names_casing() {
let test_file_path = "tests/calc_tests/defined_names_for_unit_test.xlsx"; let test_file_path = "tests/calc_tests/defined_names_for_unit_test.xlsx";
let loaded_workbook = load_from_excel(test_file_path, "en", "UTC").unwrap(); let loaded_workbook = load_from_xlsx(test_file_path, "en", "UTC")
.unwrap()
.workbook;
let mut model = Model::from_bytes(&bitcode::encode(&loaded_workbook)).unwrap(); let mut model = Model::from_bytes(&bitcode::encode(&loaded_workbook)).unwrap();
let (row, column) = (2, 13); // B13 let (row, column) = (2, 13); // B13