Error Handling of public Set functions (#88)

What are we trying to achieve ?

++ Currently all the major public set functions is panic prone and does not handle and return error. This PR tries to address to all those functions.

What major errors that could happen in these functions ?

++ All the functions which are being made as error safe is being tested against invalid sheet, row and column values, which could given by user

What are the list of functions whose return type has been altered ?

**base/src/model.rs**
1. update_cell_with_text
2. update_cell_with_bool
3. update_cell_with_number
4. set_user_input
5. get_cell_style_index
6. get_style_for_cell
7. set_cell_with_string

++> New functions being added

1. set_cell_with_boolean
2. set_cell_with_number

**base/src/styles.rs**

1. get_style_with_quote_prefix
3. get_style_with_format
4. get_style_without_quote_prefix
5. get_style

**base/src/worksheet.rs**

1. update_cell
2. set_cell_style
3. set_cell_with_formula
4. set_cell_with_number
6. set_cell_with_string
8. set_cell_with_boolean
9. set_cell_with_error
10. cell_clear_contents
11. cell_clear_contents_with_style

++> Above is the comprehensive list of all functions being ( most are public, some are private ) altered for better error handling. As a side effect of changing function signature, there are many changes being done to other functions ( mostly adding "?" to enable to error propagation further )
This commit is contained in:
Varun Hegde
2024-09-14 21:07:31 +05:30
committed by GitHub
parent 83a4431417
commit 2b03b3e3b9
26 changed files with 1087 additions and 362 deletions

View File

@@ -3,15 +3,15 @@ use ironcalc_base::{types::CellType, Model};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut model = Model::new_empty("formulas-and-errors", "en", "UTC")?;
// A1
model.set_user_input(0, 1, 1, "1".to_string());
model.set_user_input(0, 1, 1, "1".to_string())?;
// A2
model.set_user_input(0, 2, 1, "2".to_string());
model.set_user_input(0, 2, 1, "2".to_string())?;
// A3
model.set_user_input(0, 3, 1, "3".to_string());
model.set_user_input(0, 3, 1, "3".to_string())?;
// B1
model.set_user_input(0, 1, 2, "=SUM(A1:A3)".to_string());
model.set_user_input(0, 1, 2, "=SUM(A1:A3)".to_string())?;
// B2
model.set_user_input(0, 2, 2, "=B1/0".to_string());
model.set_user_input(0, 2, 2, "=B1/0".to_string())?;
// Evaluate
model.evaluate();

View File

@@ -3,11 +3,11 @@ use ironcalc_base::{cell::CellValue, Model};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut model = Model::new_empty("hello-world", "en", "UTC")?;
// A1
model.set_user_input(0, 1, 1, "Hello".to_string());
model.set_user_input(0, 1, 1, "Hello".to_string())?;
// B1
model.set_user_input(0, 1, 2, "world!".to_string());
model.set_user_input(0, 1, 2, "world!".to_string())?;
// C1
model.set_user_input(0, 1, 3, "=CONCAT(A1, \" \", B1".to_string());
model.set_user_input(0, 1, 3, "=CONCAT(A1, \" \", B1".to_string())?;
// evaluates
model.evaluate();

View File

@@ -79,12 +79,11 @@ impl Model {
let formula_or_value = self
.get_cell_formula(sheet, source_row, source_column)?
.unwrap_or_else(|| source_cell.get_text(&self.workbook.shared_strings, &self.language));
self.set_user_input(sheet, target_row, target_column, formula_or_value);
self.set_user_input(sheet, target_row, target_column, formula_or_value)?;
self.workbook
.worksheet_mut(sheet)?
.set_cell_style(target_row, target_column, style);
self.cell_clear_all(sheet, source_row, source_column)?;
Ok(())
.set_cell_style(target_row, target_column, style)?;
self.cell_clear_all(sheet, source_row, source_column)
}
/// Inserts one or more new columns into the model at the specified index.

View File

@@ -7,19 +7,15 @@ use crate::{
calc_result::{CalcResult, Range},
cell::CellValue,
constants::{self, LAST_COLUMN, LAST_ROW},
expressions::token::{Error, OpCompare, OpProduct, OpSum, OpUnary},
expressions::{
parser::move_formula::{move_formula, MoveContext},
token::get_error_by_name,
types::*,
utils::{self, is_valid_row},
},
expressions::{
parser::{
move_formula::{move_formula, MoveContext},
stringify::{to_rc_format, to_string},
Node, Parser,
},
utils::is_valid_column_number,
token::{get_error_by_name, Error, OpCompare, OpProduct, OpSum, OpUnary},
types::*,
utils::{self, is_valid_column_number, is_valid_row},
},
formatter::{
format::{format_number, parse_formatted_number},
@@ -1204,10 +1200,10 @@ impl Model {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut model = Model::new_empty("model", "en", "UTC")?;
/// let (sheet, row, column) = (0, 1, 1);
/// model.set_user_input(sheet, row, column, "Hello!".to_string());
/// model.set_user_input(sheet, row, column, "Hello!".to_string())?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "Hello!".to_string());
///
/// model.update_cell_with_text(sheet, row, column, "Goodbye!");
/// model.update_cell_with_text(sheet, row, column, "Goodbye!")?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "Goodbye!".to_string());
/// # Ok(())
/// # }
@@ -1218,23 +1214,30 @@ impl Model {
/// * [Model::update_cell_with_number()]
/// * [Model::update_cell_with_bool()]
/// * [Model::update_cell_with_formula()]
pub fn update_cell_with_text(&mut self, sheet: u32, row: i32, column: i32, value: &str) {
let style_index = self.get_cell_style_index(sheet, row, column);
pub fn update_cell_with_text(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: &str,
) -> Result<(), String> {
let style_index = self.get_cell_style_index(sheet, row, column)?;
let new_style_index;
if common::value_needs_quoting(value, &self.language) {
new_style_index = self
.workbook
.styles
.get_style_with_quote_prefix(style_index);
.get_style_with_quote_prefix(style_index)?;
} else if self.workbook.styles.style_is_quote_prefix(style_index) {
new_style_index = self
.workbook
.styles
.get_style_without_quote_prefix(style_index);
.get_style_without_quote_prefix(style_index)?;
} else {
new_style_index = style_index;
}
self.set_cell_with_string(sheet, row, column, value, new_style_index);
self.set_cell_with_string(sheet, row, column, value, new_style_index)
}
/// Updates the value of a cell with a boolean value
@@ -1247,10 +1250,10 @@ impl Model {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut model = Model::new_empty("model", "en", "UTC")?;
/// let (sheet, row, column) = (0, 1, 1);
/// model.set_user_input(sheet, row, column, "TRUE".to_string());
/// model.set_user_input(sheet, row, column, "TRUE".to_string())?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "TRUE".to_string());
///
/// model.update_cell_with_bool(sheet, row, column, false);
/// model.update_cell_with_bool(sheet, row, column, false)?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "FALSE".to_string());
/// # Ok(())
/// # }
@@ -1261,17 +1264,22 @@ impl Model {
/// * [Model::update_cell_with_number()]
/// * [Model::update_cell_with_text()]
/// * [Model::update_cell_with_formula()]
pub fn update_cell_with_bool(&mut self, sheet: u32, row: i32, column: i32, value: bool) {
let style_index = self.get_cell_style_index(sheet, row, column);
pub fn update_cell_with_bool(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: bool,
) -> Result<(), String> {
let style_index = self.get_cell_style_index(sheet, row, column)?;
let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
self.workbook
.styles
.get_style_without_quote_prefix(style_index)
.get_style_without_quote_prefix(style_index)?
} else {
style_index
};
let worksheet = &mut self.workbook.worksheets[sheet as usize];
worksheet.set_cell_with_boolean(row, column, value, new_style_index);
self.set_cell_with_boolean(sheet, row, column, value, new_style_index)
}
/// Updates the value of a cell with a number
@@ -1284,10 +1292,10 @@ impl Model {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut model = Model::new_empty("model", "en", "UTC")?;
/// let (sheet, row, column) = (0, 1, 1);
/// model.set_user_input(sheet, row, column, "42".to_string());
/// model.set_user_input(sheet, row, column, "42".to_string())?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "42".to_string());
///
/// model.update_cell_with_number(sheet, row, column, 23.0);
/// model.update_cell_with_number(sheet, row, column, 23.0)?;
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "23".to_string());
/// # Ok(())
/// # }
@@ -1298,17 +1306,22 @@ impl Model {
/// * [Model::update_cell_with_text()]
/// * [Model::update_cell_with_bool()]
/// * [Model::update_cell_with_formula()]
pub fn update_cell_with_number(&mut self, sheet: u32, row: i32, column: i32, value: f64) {
let style_index = self.get_cell_style_index(sheet, row, column);
pub fn update_cell_with_number(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: f64,
) -> Result<(), String> {
let style_index = self.get_cell_style_index(sheet, row, column)?;
let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
self.workbook
.styles
.get_style_without_quote_prefix(style_index)
.get_style_without_quote_prefix(style_index)?
} else {
style_index
};
let worksheet = &mut self.workbook.worksheets[sheet as usize];
worksheet.set_cell_with_number(row, column, value, new_style_index);
self.set_cell_with_number(sheet, row, column, value, new_style_index)
}
/// Updates the formula of given cell
@@ -1322,11 +1335,11 @@ impl Model {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut model = Model::new_empty("model", "en", "UTC")?;
/// let (sheet, row, column) = (0, 1, 1);
/// model.set_user_input(sheet, row, column, "=A2*2".to_string());
/// model.set_user_input(sheet, row, column, "=A2*2".to_string())?;
/// model.evaluate();
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "=A2*2".to_string());
///
/// model.update_cell_with_formula(sheet, row, column, "=A3*2".to_string());
/// model.update_cell_with_formula(sheet, row, column, "=A3*2".to_string())?;
/// model.evaluate();
/// assert_eq!(model.get_cell_content(sheet, row, column)?, "=A3*2".to_string());
/// # Ok(())
@@ -1345,12 +1358,12 @@ impl Model {
column: i32,
formula: String,
) -> Result<(), String> {
let mut style_index = self.get_cell_style_index(sheet, row, column);
let mut style_index = self.get_cell_style_index(sheet, row, column)?;
if self.workbook.styles.style_is_quote_prefix(style_index) {
style_index = self
.workbook
.styles
.get_style_without_quote_prefix(style_index);
.get_style_without_quote_prefix(style_index)?;
}
let formula = formula
.strip_prefix('=')
@@ -1390,31 +1403,36 @@ impl Model {
/// * [Model::update_cell_with_number()]
/// * [Model::update_cell_with_bool()]
/// * [Model::update_cell_with_text()]
pub fn set_user_input(&mut self, sheet: u32, row: i32, column: i32, value: String) {
pub fn set_user_input(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: String,
) -> Result<(), String> {
// If value starts with "'" then we force the style to be quote_prefix
let style_index = self.get_cell_style_index(sheet, row, column);
let style_index = self.get_cell_style_index(sheet, row, column)?;
if let Some(new_value) = value.strip_prefix('\'') {
// First check if it needs quoting
let new_style = if common::value_needs_quoting(new_value, &self.language) {
self.workbook
.styles
.get_style_with_quote_prefix(style_index)
.get_style_with_quote_prefix(style_index)?
} else {
style_index
};
self.set_cell_with_string(sheet, row, column, new_value, new_style);
self.set_cell_with_string(sheet, row, column, new_value, new_style)?;
} else {
let mut new_style_index = style_index;
if self.workbook.styles.style_is_quote_prefix(style_index) {
new_style_index = self
.workbook
.styles
.get_style_without_quote_prefix(style_index);
.get_style_without_quote_prefix(style_index)?;
}
if let Some(formula) = value.strip_prefix('=') {
let formula_index = self
.set_cell_with_formula(sheet, row, column, formula, new_style_index)
.expect("could not set the cell formula");
let formula_index =
self.set_cell_with_formula(sheet, row, column, formula, new_style_index)?;
// Update the style if needed
let cell = CellReferenceIndex { sheet, row, column };
let parsed_formula = &self.parsed_formulas[sheet as usize][formula_index as usize];
@@ -1422,15 +1440,11 @@ impl Model {
let new_style_index = self
.workbook
.styles
.get_style_with_format(new_style_index, &units.get_num_fmt());
let style = self.workbook.styles.get_style(new_style_index);
self.set_cell_style(sheet, row, column, &style)
.expect("Failed setting the style");
.get_style_with_format(new_style_index, &units.get_num_fmt())?;
let style = self.workbook.styles.get_style(new_style_index)?;
self.set_cell_style(sheet, row, column, &style)?
}
} else {
let worksheets = &mut self.workbook.worksheets;
let worksheet = &mut worksheets[sheet as usize];
// The list of currencies is '$', '€' and the local currency
let mut currencies = vec!["$", ""];
let currency = &self.locale.currency.symbol;
@@ -1443,35 +1457,39 @@ impl Model {
// Should not apply the format in the following cases:
// - we assign a date to already date-formatted cell
let should_apply_format = !(is_likely_date_number_format(
&self.workbook.styles.get_style(new_style_index).num_fmt,
&self.workbook.styles.get_style(new_style_index)?.num_fmt,
) && is_likely_date_number_format(&num_fmt));
if should_apply_format {
new_style_index = self
.workbook
.styles
.get_style_with_format(new_style_index, &num_fmt);
.get_style_with_format(new_style_index, &num_fmt)?;
}
}
worksheet.set_cell_with_number(row, column, v, new_style_index);
return;
let worksheet = self.workbook.worksheet_mut(sheet)?;
worksheet.set_cell_with_number(row, column, v, new_style_index)?;
return Ok(());
}
// We try to parse as boolean
if let Ok(v) = value.to_lowercase().parse::<bool>() {
worksheet.set_cell_with_boolean(row, column, v, new_style_index);
return;
let worksheet = self.workbook.worksheet_mut(sheet)?;
worksheet.set_cell_with_boolean(row, column, v, new_style_index)?;
return Ok(());
}
// Check is it is error value
let upper = value.to_uppercase();
let worksheet = self.workbook.worksheet_mut(sheet)?;
match get_error_by_name(&upper, &self.language) {
Some(error) => {
worksheet.set_cell_with_error(row, column, error, new_style_index);
worksheet.set_cell_with_error(row, column, error, new_style_index)?;
}
None => {
self.set_cell_with_string(sheet, row, column, &value, new_style_index);
self.set_cell_with_string(sheet, row, column, &value, new_style_index)?;
}
}
}
}
Ok(())
}
fn set_cell_with_formula(
@@ -1512,24 +1530,66 @@ impl Model {
self.parsed_formulas[sheet as usize].push(parsed_formula);
formula_index = (shared_formulas.len() as i32) - 1;
}
worksheet.set_cell_with_formula(row, column, formula_index, style);
worksheet.set_cell_with_formula(row, column, formula_index, style)?;
Ok(formula_index)
}
fn set_cell_with_string(&mut self, sheet: u32, row: i32, column: i32, value: &str, style: i32) {
let worksheets = &mut self.workbook.worksheets;
let worksheet = &mut worksheets[sheet as usize];
fn set_cell_with_string(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: &str,
style: i32,
) -> Result<(), String> {
match self.shared_strings.get(value) {
Some(string_index) => {
worksheet.set_cell_with_string(row, column, *string_index as i32, style);
self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
row,
column,
*string_index as i32,
style,
)?;
}
None => {
let string_index = self.workbook.shared_strings.len();
self.workbook.shared_strings.push(value.to_string());
self.shared_strings.insert(value.to_string(), string_index);
worksheet.set_cell_with_string(row, column, string_index as i32, style);
self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
row,
column,
string_index as i32,
style,
)?;
}
}
Ok(())
}
fn set_cell_with_boolean(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: bool,
style: i32,
) -> Result<(), String> {
self.workbook
.worksheet_mut(sheet)?
.set_cell_with_boolean(row, column, value, style)
}
fn set_cell_with_number(
&mut self,
sheet: u32,
row: i32,
column: i32,
value: f64,
style: i32,
) -> Result<(), String> {
self.workbook
.worksheet_mut(sheet)?
.set_cell_with_number(row, column, value, style)
}
/// Gets the Excel Value (Bool, Number, String) of a cell
@@ -1596,7 +1656,7 @@ impl Model {
) -> Result<String, String> {
match self.workbook.worksheet(sheet_index)?.cell(row, column) {
Some(cell) => {
let format = self.get_style_for_cell(sheet_index, row, column).num_fmt;
let format = self.get_style_for_cell(sheet_index, row, column)?.num_fmt;
let formatted_value =
cell.formatted_value(&self.workbook.shared_strings, &self.language, |value| {
format_number(value, &format, &self.locale).text
@@ -1699,7 +1759,7 @@ impl Model {
pub fn cell_clear_contents(&mut self, sheet: u32, row: i32, column: i32) -> Result<(), String> {
self.workbook
.worksheet_mut(sheet)?
.cell_clear_contents(row, column);
.cell_clear_contents(row, column)?;
Ok(())
}
@@ -1734,43 +1794,40 @@ impl Model {
}
/// Returns the style index for cell (`sheet`, `row`, `column`)
pub fn get_cell_style_index(&self, sheet: u32, row: i32, column: i32) -> i32 {
pub fn get_cell_style_index(&self, sheet: u32, row: i32, column: i32) -> Result<i32, String> {
// First check the cell, then row, the column
let cell = self
.workbook
.worksheet(sheet)
.expect("Invalid sheet")
.cell(row, column);
let cell = self.workbook.worksheet(sheet)?.cell(row, column);
match cell {
Some(cell) => cell.get_style(),
Some(cell) => Ok(cell.get_style()),
None => {
let rows = &self.workbook.worksheets[sheet as usize].rows;
let rows = &self.workbook.worksheet(sheet)?.rows;
for r in rows {
if r.r == row {
if r.custom_format {
return r.s;
return Ok(r.s);
}
break;
}
}
let cols = &self.workbook.worksheets[sheet as usize].cols;
let cols = &self.workbook.worksheet(sheet)?.cols;
for c in cols.iter() {
let min = c.min;
let max = c.max;
if column >= min && column <= max {
return c.style.unwrap_or(0);
return Ok(c.style.unwrap_or(0));
}
}
0
Ok(0)
}
}
}
/// Returns the style for cell (`sheet`, `row`, `column`)
pub fn get_style_for_cell(&self, sheet: u32, row: i32, column: i32) -> Style {
self.workbook
.styles
.get_style(self.get_cell_style_index(sheet, row, column))
pub fn get_style_for_cell(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
let style_index = self.get_cell_style_index(sheet, row, column)?;
let style = self.workbook.styles.get_style(style_index)?;
Ok(style)
}
/// Returns an internal binary representation of the workbook
@@ -1810,7 +1867,7 @@ impl Model {
Some(formula) => formula,
None => self.get_formatted_cell_value(sheet, row, column)?,
};
let style = self.get_style_for_cell(sheet, row, column);
let style = self.get_style_for_cell(sheet, row, column)?;
if style.font.b {
cell_markup = format!("**{cell_markup}**")
}

View File

@@ -161,26 +161,29 @@ impl Styles {
pub fn create_named_style(&mut self, style_name: &str, style: &Style) -> Result<(), String> {
let style_index = self.create_new_style(style);
self.add_named_cell_style(style_name, style_index)?;
Ok(())
self.add_named_cell_style(style_name, style_index)
}
pub(crate) fn get_style_with_quote_prefix(&mut self, index: i32) -> i32 {
let mut style = self.get_style(index);
pub(crate) fn get_style_with_quote_prefix(&mut self, index: i32) -> Result<i32, String> {
let mut style = self.get_style(index)?;
style.quote_prefix = true;
self.get_style_index_or_create(&style)
Ok(self.get_style_index_or_create(&style))
}
pub(crate) fn get_style_with_format(&mut self, index: i32, num_fmt: &str) -> i32 {
let mut style = self.get_style(index);
pub(crate) fn get_style_with_format(
&mut self,
index: i32,
num_fmt: &str,
) -> Result<i32, String> {
let mut style = self.get_style(index)?;
style.num_fmt = num_fmt.to_string();
self.get_style_index_or_create(&style)
Ok(self.get_style_index_or_create(&style))
}
pub(crate) fn get_style_without_quote_prefix(&mut self, index: i32) -> i32 {
let mut style = self.get_style(index);
pub(crate) fn get_style_without_quote_prefix(&mut self, index: i32) -> Result<i32, String> {
let mut style = self.get_style(index)?;
style.quote_prefix = false;
self.get_style_index_or_create(&style)
Ok(self.get_style_index_or_create(&style))
}
pub(crate) fn style_is_quote_prefix(&self, index: i32) -> bool {
@@ -188,9 +191,11 @@ impl Styles {
cell_xf.quote_prefix
}
pub(crate) fn get_style(&self, index: i32) -> Style {
let cell_xf = &self.cell_xfs[index as usize];
pub(crate) fn get_style(&self, index: i32) -> Result<Style, String> {
let cell_xf = &self
.cell_xfs
.get(index as usize)
.ok_or("Invalid index provided".to_string())?;
let border_id = cell_xf.border_id as usize;
let fill_id = cell_xf.fill_id as usize;
let font_id = cell_xf.font_id as usize;
@@ -198,14 +203,14 @@ impl Styles {
let quote_prefix = cell_xf.quote_prefix;
let alignment = cell_xf.alignment.clone();
Style {
Ok(Style {
alignment,
num_fmt: get_num_fmt(num_fmt_id, &self.num_fmts),
fill: self.fills[fill_id].clone(),
font: self.fonts[font_id].clone(),
border: self.borders[border_id].clone(),
quote_prefix,
}
})
}
}
@@ -221,8 +226,7 @@ impl Model {
let style_index = self.workbook.styles.get_style_index_or_create(style);
self.workbook
.worksheet_mut(sheet)?
.set_cell_style(row, column, style_index);
Ok(())
.set_cell_style(row, column, style_index)
}
pub fn copy_cell_style(
@@ -237,9 +241,7 @@ impl Model {
self.workbook
.worksheet_mut(destination_cell.0)?
.set_cell_style(destination_cell.1, destination_cell.2, source_style_index);
Ok(())
.set_cell_style(destination_cell.1, destination_cell.2, source_style_index)
}
/// Sets the style "style_name" in cell
@@ -253,8 +255,7 @@ impl Model {
let style_index = self.workbook.styles.get_style_index_by_name(style_name)?;
self.workbook
.worksheet_mut(sheet)?
.set_cell_style(row, column, style_index);
Ok(())
.set_cell_style(row, column, style_index)
}
pub fn set_sheet_style(&mut self, sheet: u32, style_name: &str) -> Result<(), String> {

View File

@@ -52,6 +52,7 @@ mod test_fn_type;
mod test_frozen_rows_and_columns;
mod test_get_cell_content;
mod test_percentage;
mod test_set_functions_error_handling;
mod test_today;
mod test_types;
mod user_model;

View File

@@ -26,7 +26,7 @@ fn test_column_width() {
assert!((worksheet.get_column_width(1).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
assert!((worksheet.get_column_width(2).unwrap() - 30.0).abs() < f64::EPSILON);
assert!((worksheet.get_column_width(3).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
assert_eq!(model.get_cell_style_index(0, 23, 2), 6);
assert_eq!(model.get_cell_style_index(0, 23, 2), Ok(6));
}
#[test]
@@ -53,7 +53,7 @@ fn test_column_width_lower_edge() {
assert!(
(worksheet.get_column_width(6).unwrap() - 10.0 * COLUMN_WIDTH_FACTOR).abs() < f64::EPSILON
);
assert_eq!(model.get_cell_style_index(0, 23, 5), 1);
assert_eq!(model.get_cell_style_index(0, 23, 5), Ok(1));
}
#[test]
@@ -80,5 +80,5 @@ fn test_column_width_higher_edge() {
);
assert!((worksheet.get_column_width(16).unwrap() - 30.0).abs() < f64::EPSILON);
assert!((worksheet.get_column_width(17).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
assert_eq!(model.get_cell_style_index(0, 23, 16), 1);
assert_eq!(model.get_cell_style_index(0, 23, 16), Ok(1));
}

View File

@@ -17,7 +17,9 @@ fn test_empty_model() {
#[test]
fn test_model_simple_evaluation() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "= 1 + 3".to_string());
model
.set_user_input(0, 1, 1, "= 1 + 3".to_string())
.unwrap();
model.evaluate();
let result = model._get_text_at(0, 1, 1);
assert_eq!(result, *"4");
@@ -43,7 +45,7 @@ fn test_model_simple_evaluation_order() {
#[test]
fn test_model_invalid_formula() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "= 1 +".to_string());
model.set_user_input(0, 1, 1, "= 1 +".to_string()).unwrap();
model.evaluate();
let result = model._get_text_at(0, 1, 1);
assert_eq!(result, *"#ERROR!");
@@ -54,8 +56,10 @@ fn test_model_invalid_formula() {
#[test]
fn test_model_dependencies() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "23".to_string()); // A1
model.set_user_input(0, 1, 2, "= A1* 2-4".to_string()); // B1
model.set_user_input(0, 1, 1, "23".to_string()).unwrap(); // A1
model
.set_user_input(0, 1, 2, "= A1* 2-4".to_string())
.unwrap(); // B1
model.evaluate();
let result = model._get_text_at(0, 1, 1);
assert_eq!(result, *"23");
@@ -65,7 +69,9 @@ fn test_model_dependencies() {
let result = model._get_formula("B1");
assert_eq!(result, *"=A1*2-4");
model.set_user_input(0, 2, 1, "=SUM(A1, B1)".to_string()); // A2
model
.set_user_input(0, 2, 1, "=SUM(A1, B1)".to_string())
.unwrap(); // A2
model.evaluate();
let result = model._get_text_at(0, 2, 1);
assert_eq!(result, *"65");
@@ -74,8 +80,10 @@ fn test_model_dependencies() {
#[test]
fn test_model_strings() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "Hello World".to_string());
model.set_user_input(0, 1, 2, "=A1".to_string());
model
.set_user_input(0, 1, 1, "Hello World".to_string())
.unwrap();
model.set_user_input(0, 1, 2, "=A1".to_string()).unwrap();
model.evaluate();
let result = model._get_text_at(0, 1, 1);
assert_eq!(result, *"Hello World");
@@ -152,21 +160,35 @@ fn test_to_excel_precision_str() {
#[test]
fn test_booleans() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "true".to_string());
model.set_user_input(0, 2, 1, "TRUE".to_string());
model.set_user_input(0, 3, 1, "True".to_string());
model.set_user_input(0, 4, 1, "false".to_string());
model.set_user_input(0, 5, 1, "FALSE".to_string());
model.set_user_input(0, 6, 1, "False".to_string());
model.set_user_input(0, 1, 1, "true".to_string()).unwrap();
model.set_user_input(0, 2, 1, "TRUE".to_string()).unwrap();
model.set_user_input(0, 3, 1, "True".to_string()).unwrap();
model.set_user_input(0, 4, 1, "false".to_string()).unwrap();
model.set_user_input(0, 5, 1, "FALSE".to_string()).unwrap();
model.set_user_input(0, 6, 1, "False".to_string()).unwrap();
model.set_user_input(0, 1, 2, "=ISLOGICAL(A1)".to_string());
model.set_user_input(0, 2, 2, "=ISLOGICAL(A2)".to_string());
model.set_user_input(0, 3, 2, "=ISLOGICAL(A3)".to_string());
model.set_user_input(0, 4, 2, "=ISLOGICAL(A4)".to_string());
model.set_user_input(0, 5, 2, "=ISLOGICAL(A5)".to_string());
model.set_user_input(0, 6, 2, "=ISLOGICAL(A6)".to_string());
model
.set_user_input(0, 1, 2, "=ISLOGICAL(A1)".to_string())
.unwrap();
model
.set_user_input(0, 2, 2, "=ISLOGICAL(A2)".to_string())
.unwrap();
model
.set_user_input(0, 3, 2, "=ISLOGICAL(A3)".to_string())
.unwrap();
model
.set_user_input(0, 4, 2, "=ISLOGICAL(A4)".to_string())
.unwrap();
model
.set_user_input(0, 5, 2, "=ISLOGICAL(A5)".to_string())
.unwrap();
model
.set_user_input(0, 6, 2, "=ISLOGICAL(A6)".to_string())
.unwrap();
model.set_user_input(0, 1, 5, "=IF(false, True, FALSe)".to_string());
model
.set_user_input(0, 1, 5, "=IF(false, True, FALSe)".to_string())
.unwrap();
model.evaluate();
@@ -191,19 +213,19 @@ fn test_booleans() {
#[test]
fn test_set_cell_style() {
let mut model = new_empty_model();
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(!style.font.b);
style.font.b = true;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(style.font.b);
style.font.b = false;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let style = model.get_style_for_cell(0, 1, 1);
let style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(!style.font.b);
}
@@ -211,21 +233,21 @@ fn test_set_cell_style() {
fn test_copy_cell_style() {
let mut model = new_empty_model();
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
style.font.b = true;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let mut style = model.get_style_for_cell(0, 1, 2);
let mut style = model.get_style_for_cell(0, 1, 2).unwrap();
style.font.i = true;
assert!(model.set_cell_style(0, 1, 2, &style).is_ok());
assert!(model.copy_cell_style((0, 1, 1), (0, 1, 2)).is_ok());
let style = model.get_style_for_cell(0, 1, 1);
let style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(style.font.b);
assert!(!style.font.i);
let style = model.get_style_for_cell(0, 1, 2);
let style = model.get_style_for_cell(0, 1, 2).unwrap();
assert!(style.font.b);
assert!(!style.font.i);
}
@@ -234,15 +256,15 @@ fn test_copy_cell_style() {
fn test_get_cell_style_index() {
let mut model = new_empty_model();
let mut style = model.get_style_for_cell(0, 1, 1);
let style_index = model.get_cell_style_index(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
let style_index = model.get_cell_style_index(0, 1, 1).unwrap();
assert_eq!(style_index, 0);
assert!(!style.font.b);
style.font.b = true;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let style_index = model.get_cell_style_index(0, 1, 1);
let style_index = model.get_cell_style_index(0, 1, 1).unwrap();
assert_eq!(style_index, 1);
}
@@ -250,29 +272,29 @@ fn test_get_cell_style_index() {
fn test_model_set_cells_with_values_styles() {
let mut model = new_empty_model();
// Inputs
model.set_user_input(0, 1, 1, "21".to_string()); // A1
model.set_user_input(0, 2, 1, "2".to_string()); // A2
model.set_user_input(0, 1, 1, "21".to_string()).unwrap(); // A1
model.set_user_input(0, 2, 1, "2".to_string()).unwrap(); // A2
let style_index = model.get_cell_style_index(0, 1, 1);
let style_index = model.get_cell_style_index(0, 1, 1).unwrap();
assert_eq!(style_index, 0);
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
style.font.b = true;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
assert!(model.set_cell_style(0, 2, 1, &style).is_ok());
let style_index = model.get_cell_style_index(0, 1, 1);
let style_index = model.get_cell_style_index(0, 1, 1).unwrap();
assert_eq!(style_index, 1);
let style_index = model.get_cell_style_index(0, 2, 1);
let style_index = model.get_cell_style_index(0, 2, 1).unwrap();
assert_eq!(style_index, 1);
model.update_cell_with_number(0, 1, 2, 1.0);
model.update_cell_with_number(0, 2, 1, 2.0);
model.update_cell_with_number(0, 1, 2, 1.0).unwrap();
model.update_cell_with_number(0, 2, 1, 2.0).unwrap();
model.evaluate();
// Styles are not modified
let style_index = model.get_cell_style_index(0, 1, 1);
let style_index = model.get_cell_style_index(0, 1, 1).unwrap();
assert_eq!(style_index, 1);
let style_index = model.get_cell_style_index(0, 2, 1);
let style_index = model.get_cell_style_index(0, 2, 1).unwrap();
assert_eq!(style_index, 1);
}
@@ -280,20 +302,20 @@ fn test_model_set_cells_with_values_styles() {
fn test_style_fmt_id() {
let mut model = new_empty_model();
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
style.num_fmt = "#.##".to_string();
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let style = model.get_style_for_cell(0, 1, 1);
let style = model.get_style_for_cell(0, 1, 1).unwrap();
assert_eq!(style.num_fmt, "#.##");
let mut style = model.get_style_for_cell(0, 10, 1);
let mut style = model.get_style_for_cell(0, 10, 1).unwrap();
style.num_fmt = "$$#,##0.0000".to_string();
assert!(model.set_cell_style(0, 10, 1, &style).is_ok());
let style = model.get_style_for_cell(0, 10, 1);
let style = model.get_style_for_cell(0, 10, 1).unwrap();
assert_eq!(style.num_fmt, "$$#,##0.0000");
// Make sure old style is not touched
let style = model.get_style_for_cell(0, 1, 1);
let style = model.get_style_for_cell(0, 1, 1).unwrap();
assert_eq!(style.num_fmt, "#.##");
}
@@ -357,9 +379,13 @@ fn set_input_autocomplete() {
let mut model = new_empty_model();
model._set("A1", "1");
model._set("A2", "2");
model.set_user_input(0, 3, 1, "=SUM(A1:A2".to_string());
model
.set_user_input(0, 3, 1, "=SUM(A1:A2".to_string())
.unwrap();
// This will fail anyway
model.set_user_input(0, 4, 1, "=SUM(A1*".to_string());
model
.set_user_input(0, 4, 1, "=SUM(A1*".to_string())
.unwrap();
model.evaluate();
assert_eq!(model._get_formula("A3"), "=SUM(A1:A2)");
@@ -405,7 +431,7 @@ fn test_get_formatted_cell_value() {
model._set("A5", "123.456");
// change A5 format
let mut style = model.get_style_for_cell(0, 5, 1);
let mut style = model.get_style_for_cell(0, 5, 1).unwrap();
style.num_fmt = "$#,##0.00".to_string();
model.set_cell_style(0, 5, 1, &style).unwrap();

View File

@@ -5,8 +5,12 @@ use crate::test::util::new_empty_model;
#[test]
fn test_formulas() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "$100.348".to_string());
model.set_user_input(0, 1, 2, "=ISNUMBER(A1)".to_string());
model
.set_user_input(0, 1, 1, "$100.348".to_string())
.unwrap();
model
.set_user_input(0, 1, 2, "=ISNUMBER(A1)".to_string())
.unwrap();
model.evaluate();

View File

@@ -3,7 +3,7 @@ use crate::test::util::new_empty_model;
#[test]
fn test_metadata_new_model() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "5.5".to_string());
model.set_user_input(0, 1, 1, "5.5".to_string()).unwrap();
model.evaluate();
let metadata = &model.workbook.metadata;
assert_eq!(metadata.application, "IronCalc Sheets");

View File

@@ -14,7 +14,9 @@ fn test_is_empty_cell_non_existing_sheet() {
fn test_is_empty_cell() {
let mut model = new_empty_model();
assert!(model.is_empty_cell(0, 3, 1).unwrap());
model.set_user_input(0, 3, 1, "Hello World".to_string());
model
.set_user_input(0, 3, 1, "Hello World".to_string())
.unwrap();
assert!(!model.is_empty_cell(0, 3, 1).unwrap());
model.cell_clear_contents(0, 3, 1).unwrap();
assert!(model.is_empty_cell(0, 3, 1).unwrap());

View File

@@ -57,12 +57,12 @@ fn test_quote_prefix_enter() {
model._set("A2", "=ISTEXT(A1)");
model.evaluate();
// We introduce a value with a "quote prefix" index
model.set_user_input(0, 1, 3, "'=A1".to_string());
model.set_user_input(0, 1, 3, "'=A1".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("C1"), *"=A1");
// But if we enter with a quote_prefix but without the "'" it won't be quote_prefix
model.set_user_input(0, 1, 4, "=A1".to_string());
model.set_user_input(0, 1, 4, "=A1".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("D1"), *"123");
}
@@ -75,7 +75,7 @@ fn test_quote_prefix_reenter() {
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
// We introduce a value with a "quote prefix" index
model.set_user_input(0, 1, 1, "123".to_string());
model.set_user_input(0, 1, 1, "123".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("A2"), *"FALSE");
}
@@ -83,7 +83,7 @@ fn test_quote_prefix_reenter() {
#[test]
fn test_update_cell_quote() {
let mut model = new_empty_model();
model.update_cell_with_text(0, 1, 1, "= 1 + 3");
model.update_cell_with_text(0, 1, 1, "= 1 + 3").unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), *"= 1 + 3");
assert!(!model._has_formula("A1"));
@@ -92,12 +92,12 @@ fn test_update_cell_quote() {
#[test]
fn test_update_quote_prefix_reenter() {
let mut model = new_empty_model();
model.update_cell_with_text(0, 1, 1, "123");
model.update_cell_with_text(0, 1, 1, "123").unwrap();
model._set("A2", "=ISTEXT(A1)");
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
// We reenter as a number
model.update_cell_with_number(0, 1, 1, 123.0);
model.update_cell_with_number(0, 1, 1, 123.0).unwrap();
model.evaluate();
assert_eq!(model._get_text("A2"), *"FALSE");
}
@@ -105,12 +105,12 @@ fn test_update_quote_prefix_reenter() {
#[test]
fn test_update_quote_prefix_reenter_bool() {
let mut model = new_empty_model();
model.update_cell_with_text(0, 1, 1, "TRUE");
model.update_cell_with_text(0, 1, 1, "TRUE").unwrap();
model._set("A2", "=ISTEXT(A1)");
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
// We enter a bool
model.update_cell_with_bool(0, 1, 1, true);
model.update_cell_with_bool(0, 1, 1, true).unwrap();
model.evaluate();
assert_eq!(model._get_text("A2"), *"FALSE");
}
@@ -118,29 +118,29 @@ fn test_update_quote_prefix_reenter_bool() {
#[test]
fn test_update_quote_prefix_reenter_text() {
let mut model = new_empty_model();
model.update_cell_with_text(0, 1, 1, "123");
model.update_cell_with_text(0, 1, 1, "123").unwrap();
model._set("A2", "=ISTEXT(A1)");
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
assert!(model.get_style_for_cell(0, 1, 1).unwrap().quote_prefix);
// We enter a string
model.update_cell_with_text(0, 1, 1, "Hello");
model.update_cell_with_text(0, 1, 1, "Hello").unwrap();
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
assert!(!model.get_style_for_cell(0, 1, 1).quote_prefix);
assert!(!model.get_style_for_cell(0, 1, 1).unwrap().quote_prefix);
}
#[test]
fn test_update_quote_prefix_reenter_text_2() {
let mut model = new_empty_model();
model.update_cell_with_text(0, 1, 1, "123");
model.update_cell_with_text(0, 1, 1, "123").unwrap();
model._set("A2", "=ISTEXT(A1)");
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
assert!(model.get_style_for_cell(0, 1, 1).unwrap().quote_prefix);
// We enter another number
model.update_cell_with_text(0, 1, 1, "42");
model.update_cell_with_text(0, 1, 1, "42").unwrap();
model.evaluate();
assert_eq!(model._get_text("A2"), *"TRUE");
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
assert!(model.get_style_for_cell(0, 1, 1).unwrap().quote_prefix);
}

View File

@@ -0,0 +1,449 @@
use crate::{expressions::token, test::util::new_empty_model, types::Cell};
#[test]
fn test_update_cell_with_text() {
let mut model = new_empty_model();
// Below are safe inputs
model.set_user_input(0, 1, 1, "Hello".to_string()).unwrap();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.update_cell_with_text(1, 1, 1, "new value");
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// Case2 : Invalid Row
let update_result = model.update_cell_with_text(0, 0, 1, "new value");
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Invalid Column
let update_result = model.update_cell_with_text(0, 1, 1048579, "new value");
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_update_cell_with_number() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_number(0, 1, 1, 10.0).unwrap();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.update_cell_with_number(1, 1, 1, 20.0);
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// Case2 : Invalid Row
let update_result = model.update_cell_with_number(0, 0, 1, 20.0);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Invalid Column
let update_result = model.update_cell_with_number(0, 1, 1048579, 20.0);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_update_cell_with_bool() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_bool(0, 1, 1, true).unwrap();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.update_cell_with_bool(1, 1, 1, false);
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// Case2 : Invalid Row
let update_result = model.update_cell_with_bool(0, 0, 1, false);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Invalid Column
let update_result = model.update_cell_with_bool(0, 1, 1048579, false);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_update_cell_with_formula() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_number(0, 1, 1, 10.0).unwrap();
model
.update_cell_with_formula(0, 1, 2, "=A1*2".to_string())
.unwrap();
model.evaluate();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.update_cell_with_formula(1, 1, 2, "=A1*2".to_string());
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// Case2 : Invalid Row
let update_result = model.update_cell_with_formula(0, 0, 2, "=A1*2".to_string());
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Invalid Column
let update_result = model.update_cell_with_formula(0, 1, 1048579, "=A1*2".to_string());
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_set_user_input() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_number(0, 1, 1, 10.0).unwrap();
model.evaluate();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.set_user_input(1, 1, 2, "20.0".to_string());
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// Case2 : Invalid Row
let update_result = model.set_user_input(0, 0, 2, "20.0".to_string());
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Invalid Column
let update_result = model.set_user_input(0, 1, 1048579, "20.0".to_string());
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_get_style_for_cell() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_number(0, 1, 1, 10.0).unwrap();
model.evaluate();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.get_style_for_cell(1, 1, 2);
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// ATTENTION : get_cell_style_index tries to get cell using row and col
// if we invalid row or column is given, it will return index 0.
// Case2 : Invalid Row
let update_result = model.get_style_for_cell(0, 0, 2);
assert_eq!(update_result.is_ok(), true);
// Case3 : Invalid Column
let update_result = model.get_style_for_cell(0, 1, 1048579);
assert_eq!(update_result.is_ok(), true);
}
#[test]
fn test_get_cell_style_index() {
let mut model = new_empty_model();
// Below are safe inputs
model.update_cell_with_number(0, 1, 1, 10.0).unwrap();
model.evaluate();
// Now testing all the possible error scenarios
// Case1 : Invalid sheet
let update_result = model.get_cell_style_index(1, 1, 2);
assert_eq!(update_result, Err("Invalid sheet index".to_string()));
// ATTENTION : get_cell_style_index tries to get cell using row and col
// if we invalid row or column is given, it will return index 0.
// Case2 : Invalid Row
let update_result = model.get_cell_style_index(0, 0, 2);
assert_eq!(update_result, Ok(0));
// Case3 : Invalid Column
let update_result = model.get_cell_style_index(0, 1, 1048579);
assert_eq!(update_result, Ok(0));
}
#[test]
fn test_worksheet_update_cell() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result =
model
.workbook
.worksheet_mut(0)
.unwrap()
.update_cell(0, 1, Cell::new_number(10.0, 1));
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result =
model
.workbook
.worksheet_mut(0)
.unwrap()
.update_cell(1, 1048579, Cell::new_number(10.0, 1));
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_style() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_style(0, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_style(1, 1048579, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_with_formula() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_formula(0, 1, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_formula(1, 1048579, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_with_number() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_number(0, 1, 1.0, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_number(1, 1048579, 1.0, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_with_string() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_string(0, 1, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_string(1, 1048579, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_with_boolean() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_boolean(0, 1, true, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_boolean(1, 1048579, true, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_set_cell_with_error() {
let mut model = new_empty_model();
// Now testing all the possible error scenarios
// Case1: Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_error(0, 1, token::Error::ERROR, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.set_cell_with_error(1, 1048579, token::Error::ERROR, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
}
#[test]
fn test_worksheet_cell_clear_contents() {
let mut model = new_empty_model();
model
.workbook
.worksheet_mut(0)
.unwrap()
.update_cell(1, 1, Cell::new_number(10.0, 1))
.unwrap();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents(0, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents(1, 1048579);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Valid case
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents(1, 1);
assert_eq!(update_result, Ok(()))
}
#[test]
fn test_worksheet_cell_clear_contents_with_style() {
let mut model = new_empty_model();
model
.workbook
.worksheet_mut(0)
.unwrap()
.update_cell(1, 1, Cell::new_number(10.0, 1))
.unwrap();
// Now testing all the possible error scenarios
// Case1 : Invalid Row
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents_with_style(0, 1, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case2 : Invalid Column
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents_with_style(1, 1048579, 1);
assert_eq!(update_result, Err("Incorrect row or column".to_string()));
// Case3 : Valid case
let update_result = model
.workbook
.worksheet_mut(0)
.unwrap()
.cell_clear_contents_with_style(1, 1, 1);
assert_eq!(update_result, Ok(()))
}
#[test]
fn workbook_styles_get_style_error_handling() {
let model = new_empty_model();
// case 1 : Invalid index
assert_eq!(
model.workbook.styles.get_style(15),
Err("Invalid index provided".to_string())
);
}
#[test]
fn workbook_styles_get_style_without_quote_prefix_error_handling() {
let mut model = new_empty_model();
// case 1 : Invalid index
assert_eq!(
model.workbook.styles.get_style_without_quote_prefix(15),
Err("Invalid index provided".to_string())
);
}
#[test]
fn workbook_styles_get_style_with_format_error_handling() {
let mut model = new_empty_model();
// case 1 : Invalid index
assert_eq!(
model
.workbook
.styles
.get_style_with_format(15, "dummy_num_format"),
Err("Invalid index provided".to_string())
);
}
#[test]
fn workbook_styles_get_style_with_quote_prefix_handling() {
let mut model = new_empty_model();
// case 1 : Invalid index
assert_eq!(
model.workbook.styles.get_style_with_quote_prefix(15),
Err("Invalid index provided".to_string())
);
}

View File

@@ -5,16 +5,28 @@ use crate::{cell::CellValue, test::util::new_empty_model};
#[test]
fn test_currencies() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "$100.348".to_string());
model.set_user_input(0, 1, 2, "=ISNUMBER(A1)".to_string());
model
.set_user_input(0, 1, 1, "$100.348".to_string())
.unwrap();
model
.set_user_input(0, 1, 2, "=ISNUMBER(A1)".to_string())
.unwrap();
model.set_user_input(0, 2, 1, "$ 100.348".to_string());
model.set_user_input(0, 2, 2, "=ISNUMBER(A2)".to_string());
model
.set_user_input(0, 2, 1, "$ 100.348".to_string())
.unwrap();
model
.set_user_input(0, 2, 2, "=ISNUMBER(A2)".to_string())
.unwrap();
model.set_user_input(0, 3, 1, "100$".to_string());
model.set_user_input(0, 3, 2, "=ISNUMBER(A3)".to_string());
model.set_user_input(0, 3, 1, "100$".to_string()).unwrap();
model
.set_user_input(0, 3, 2, "=ISNUMBER(A3)".to_string())
.unwrap();
model.set_user_input(0, 4, 1, "3.1415926$".to_string());
model
.set_user_input(0, 4, 1, "3.1415926$".to_string())
.unwrap();
model.evaluate();
@@ -43,9 +55,9 @@ fn test_currencies() {
#[test]
fn scientific() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "3e-4".to_string());
model.set_user_input(0, 2, 1, "5e-4$".to_string());
model.set_user_input(0, 3, 1, "6e-4%".to_string());
model.set_user_input(0, 1, 1, "3e-4".to_string()).unwrap();
model.set_user_input(0, 2, 1, "5e-4$".to_string()).unwrap();
model.set_user_input(0, 3, 1, "6e-4%".to_string()).unwrap();
model.evaluate();
@@ -61,9 +73,13 @@ fn scientific() {
#[test]
fn test_percentage() {
let mut model = new_empty_model();
model.set_user_input(0, 10, 1, "50%".to_string());
model.set_user_input(0, 10, 2, "=ISNUMBER(A10)".to_string());
model.set_user_input(0, 11, 1, "55.759%".to_string());
model.set_user_input(0, 10, 1, "50%".to_string()).unwrap();
model
.set_user_input(0, 10, 2, "=ISNUMBER(A10)".to_string())
.unwrap();
model
.set_user_input(0, 11, 1, "55.759%".to_string())
.unwrap();
model.evaluate();
@@ -81,8 +97,8 @@ fn test_percentage_ops() {
let mut model = new_empty_model();
model._set("A1", "5%");
model._set("A2", "20%");
model.set_user_input(0, 3, 1, "=A1+A2".to_string());
model.set_user_input(0, 4, 1, "=A1*A2".to_string());
model.set_user_input(0, 3, 1, "=A1+A2".to_string()).unwrap();
model.set_user_input(0, 4, 1, "=A1*A2".to_string()).unwrap();
model.evaluate();
@@ -93,11 +109,19 @@ fn test_percentage_ops() {
#[test]
fn test_numbers() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "1,000,000".to_string());
model
.set_user_input(0, 1, 1, "1,000,000".to_string())
.unwrap();
model.set_user_input(0, 20, 1, "50,123.549".to_string());
model.set_user_input(0, 21, 1, "50,12.549".to_string());
model.set_user_input(0, 22, 1, "1,234567".to_string());
model
.set_user_input(0, 20, 1, "50,123.549".to_string())
.unwrap();
model
.set_user_input(0, 21, 1, "50,12.549".to_string())
.unwrap();
model
.set_user_input(0, 22, 1, "1,234567".to_string())
.unwrap();
model.evaluate();
@@ -131,7 +155,7 @@ fn test_numbers() {
#[test]
fn test_negative_numbers() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "-100".to_string());
model.set_user_input(0, 1, 1, "-100".to_string()).unwrap();
model.evaluate();
@@ -144,15 +168,19 @@ fn test_negative_numbers() {
#[test]
fn test_negative_currencies() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "-$100".to_string());
model.set_user_input(0, 2, 1, "-$99.123".to_string());
model.set_user_input(0, 1, 1, "-$100".to_string()).unwrap();
model
.set_user_input(0, 2, 1, "-$99.123".to_string())
.unwrap();
// This is valid!
model.set_user_input(0, 3, 1, "$-345".to_string());
model.set_user_input(0, 3, 1, "$-345".to_string()).unwrap();
model.set_user_input(0, 1, 2, "-200$".to_string());
model.set_user_input(0, 2, 2, "-92.689$".to_string());
model.set_user_input(0, 1, 2, "-200$".to_string()).unwrap();
model
.set_user_input(0, 2, 2, "-92.689$".to_string())
.unwrap();
// This is valid!
model.set_user_input(0, 3, 2, "-22$".to_string());
model.set_user_input(0, 3, 2, "-22$".to_string()).unwrap();
model.evaluate();
@@ -174,8 +202,10 @@ fn test_formulas() {
let mut model = new_empty_model();
model._set("A1", "$100");
model._set("A2", "$200");
model.set_user_input(0, 3, 1, "=A1+A2".to_string());
model.set_user_input(0, 4, 1, "=SUM(A1:A3)".to_string());
model.set_user_input(0, 3, 1, "=A1+A2".to_string()).unwrap();
model
.set_user_input(0, 4, 1, "=SUM(A1:A3)".to_string())
.unwrap();
model.evaluate();
@@ -198,9 +228,9 @@ fn test_product() {
model._set("A2", "$5");
model._set("A3", "4");
model.set_user_input(0, 1, 2, "=A1*A2".to_string());
model.set_user_input(0, 2, 2, "=A1*A3".to_string());
model.set_user_input(0, 3, 2, "=A1*3".to_string());
model.set_user_input(0, 1, 2, "=A1*A2".to_string()).unwrap();
model.set_user_input(0, 2, 2, "=A1*A3".to_string()).unwrap();
model.set_user_input(0, 3, 2, "=A1*3".to_string()).unwrap();
model.evaluate();
@@ -216,10 +246,12 @@ fn test_division() {
model._set("A2", "$5");
model._set("A3", "4");
model.set_user_input(0, 1, 2, "=A1/A2".to_string());
model.set_user_input(0, 2, 2, "=A1/A3".to_string());
model.set_user_input(0, 3, 2, "=A1/2".to_string());
model.set_user_input(0, 4, 2, "=100/A2".to_string());
model.set_user_input(0, 1, 2, "=A1/A2".to_string()).unwrap();
model.set_user_input(0, 2, 2, "=A1/A3".to_string()).unwrap();
model.set_user_input(0, 3, 2, "=A1/2".to_string()).unwrap();
model
.set_user_input(0, 4, 2, "=100/A2".to_string())
.unwrap();
model.evaluate();
@@ -235,54 +267,54 @@ fn test_some_complex_examples() {
// $3.00 / 2 = $1.50
model._set("A1", "$3.00");
model._set("A2", "2");
model.set_user_input(0, 3, 1, "=A1/A2".to_string());
model.set_user_input(0, 3, 1, "=A1/A2".to_string()).unwrap();
// $3 / 2 = $1
model._set("B1", "$3");
model._set("B2", "2");
model.set_user_input(0, 3, 2, "=B1/B2".to_string());
model.set_user_input(0, 3, 2, "=B1/B2".to_string()).unwrap();
// $5.00 * 25% = 25% * $5.00 = $1.25
model._set("C1", "$5.00");
model._set("C2", "25%");
model.set_user_input(0, 3, 3, "=C1*C2".to_string());
model.set_user_input(0, 4, 3, "=C2*C1".to_string());
model.set_user_input(0, 3, 3, "=C1*C2".to_string()).unwrap();
model.set_user_input(0, 4, 3, "=C2*C1".to_string()).unwrap();
// $5 * 75% = 75% * $5 = $1
model._set("D1", "$5");
model._set("D2", "75%");
model.set_user_input(0, 3, 4, "=D1*D2".to_string());
model.set_user_input(0, 4, 4, "=D2*D1".to_string());
model.set_user_input(0, 3, 4, "=D1*D2".to_string()).unwrap();
model.set_user_input(0, 4, 4, "=D2*D1".to_string()).unwrap();
// $10 + $9.99 = $9.99 + $10 = $19.99
model._set("E1", "$10");
model._set("E2", "$9.99");
model.set_user_input(0, 3, 5, "=E1+E2".to_string());
model.set_user_input(0, 4, 5, "=E2+E1".to_string());
model.set_user_input(0, 3, 5, "=E1+E2".to_string()).unwrap();
model.set_user_input(0, 4, 5, "=E2+E1".to_string()).unwrap();
// $2 * 2 = 2 * $2 = $4
model._set("F1", "$2");
model._set("F2", "2");
model.set_user_input(0, 3, 6, "=F1*F2".to_string());
model.set_user_input(0, 4, 6, "=F2*F1".to_string());
model.set_user_input(0, 3, 6, "=F1*F2".to_string()).unwrap();
model.set_user_input(0, 4, 6, "=F2*F1".to_string()).unwrap();
// $2.50 * 2 = 2 * $2.50 = $5.00
model._set("G1", "$2.50");
model._set("G2", "2");
model.set_user_input(0, 3, 7, "=G1*G2".to_string());
model.set_user_input(0, 4, 7, "=G2*G1".to_string());
model.set_user_input(0, 3, 7, "=G1*G2".to_string()).unwrap();
model.set_user_input(0, 4, 7, "=G2*G1".to_string()).unwrap();
// $2 * 2.5 = 2.5 * $2 = $5
model._set("H1", "$2");
model._set("H2", "2.5");
model.set_user_input(0, 3, 8, "=H1*H2".to_string());
model.set_user_input(0, 4, 8, "=H2*H1".to_string());
model.set_user_input(0, 3, 8, "=H1*H2".to_string()).unwrap();
model.set_user_input(0, 4, 8, "=H2*H1".to_string()).unwrap();
// 10% * 1,000 = 1,000 * 10% = 100
model._set("I1", "10%");
model._set("I2", "1,000");
model.set_user_input(0, 3, 9, "=I1*I2".to_string());
model.set_user_input(0, 4, 9, "=I2*I1".to_string());
model.set_user_input(0, 3, 9, "=I1*I2".to_string()).unwrap();
model.set_user_input(0, 4, 9, "=I2*I1".to_string()).unwrap();
model.evaluate();
@@ -320,9 +352,15 @@ fn test_financial_functions() {
model._set("A3", "10");
model._set("A4", "$10,000");
model.set_user_input(0, 5, 1, "=PMT(A2/12,A3,A4)".to_string());
model.set_user_input(0, 6, 1, "=PMT(A2/12,A3,A4,,1)".to_string());
model.set_user_input(0, 7, 1, "=PMT(0.2, 3, -200)".to_string());
model
.set_user_input(0, 5, 1, "=PMT(A2/12,A3,A4)".to_string())
.unwrap();
model
.set_user_input(0, 6, 1, "=PMT(A2/12,A3,A4,,1)".to_string())
.unwrap();
model
.set_user_input(0, 7, 1, "=PMT(0.2, 3, -200)".to_string())
.unwrap();
model.evaluate();
@@ -339,9 +377,15 @@ fn test_sum_function() {
model._set("A1", "$100");
model._set("A2", "$300");
model.set_user_input(0, 1, 2, "=SUM(A:A)".to_string());
model.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string());
model.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string());
model
.set_user_input(0, 1, 2, "=SUM(A:A)".to_string())
.unwrap();
model
.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string())
.unwrap();
model
.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string())
.unwrap();
model.evaluate();
@@ -353,7 +397,7 @@ fn test_sum_function() {
#[test]
fn test_number() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "3".to_string());
model.set_user_input(0, 1, 1, "3".to_string()).unwrap();
model.evaluate();
@@ -367,7 +411,9 @@ fn test_number() {
#[test]
fn test_currencies_eur_prefix() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "€100.348".to_string());
model
.set_user_input(0, 1, 1, "€100.348".to_string())
.unwrap();
model.evaluate();
@@ -381,19 +427,27 @@ fn test_currencies_eur_prefix() {
#[test]
fn test_currencies_eur_suffix() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "100.348€".to_string());
model.set_user_input(0, 2, 1, "25".to_string());
model
.set_user_input(0, 1, 1, "100.348".to_string())
.unwrap();
model.set_user_input(0, 2, 1, "25€".to_string()).unwrap();
// negatives
model.set_user_input(0, 1, 2, "-123.348€".to_string());
model.set_user_input(0, 2, 2, "-42".to_string());
model
.set_user_input(0, 1, 2, "-123.348".to_string())
.unwrap();
model.set_user_input(0, 2, 2, "-42€".to_string()).unwrap();
// with a space
model.set_user_input(0, 1, 3, "101.348 €".to_string());
model.set_user_input(0, 2, 3, "26".to_string());
model
.set_user_input(0, 1, 3, "101.348".to_string())
.unwrap();
model.set_user_input(0, 2, 3, "26 €".to_string()).unwrap();
model.set_user_input(0, 1, 4, "-12.348 €".to_string());
model.set_user_input(0, 2, 4, "-45".to_string());
model
.set_user_input(0, 1, 4, "-12.348".to_string())
.unwrap();
model.set_user_input(0, 2, 4, "-45 €".to_string()).unwrap();
model.evaluate();
@@ -449,9 +503,15 @@ fn test_sum_function_eur() {
model._set("A1", "€100");
model._set("A2", "€300");
model.set_user_input(0, 1, 2, "=SUM(A:A)".to_string());
model.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string());
model.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string());
model
.set_user_input(0, 1, 2, "=SUM(A:A)".to_string())
.unwrap();
model
.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string())
.unwrap();
model
.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string())
.unwrap();
model.evaluate();
@@ -463,7 +523,9 @@ fn test_sum_function_eur() {
#[test]
fn input_dates() {
let mut model = new_empty_model();
model.set_user_input(0, 1, 1, "3/4/2025".to_string());
model
.set_user_input(0, 1, 1, "3/4/2025".to_string())
.unwrap();
model.evaluate();
@@ -474,7 +536,9 @@ fn input_dates() {
);
// further date assignments do not change the format
model.set_user_input(0, 1, 1, "08-08-2028".to_string());
model
.set_user_input(0, 1, 1, "08-08-2028".to_string())
.unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), "8/8/2028");
}

View File

@@ -14,7 +14,7 @@ fn test_sheet_markup() {
model._set("A4", "Total");
model._set("B4", "=SUM(B2:B3)");
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
style.font.b = true;
model.set_cell_style(0, 1, 1, &style).unwrap();
model.set_cell_style(0, 1, 2, &style).unwrap();

View File

@@ -138,14 +138,14 @@ fn test_insert_sheet() {
// Insert the sheet at the end and check the formula
assert!(model.insert_sheet("Bacchus", 1, None).is_ok());
model.set_user_input(1, 3, 1, "42".to_string());
model.set_user_input(1, 3, 1, "42".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), "42");
assert_eq!(model._get_text("A2"), "#REF!");
// Insert a sheet in between the other two
assert!(model.insert_sheet("Dionysus", 1, None).is_ok());
model.set_user_input(1, 3, 1, "111".to_string());
model.set_user_input(1, 3, 1, "111".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), "42");
assert_eq!(model._get_text("A2"), "111");
@@ -176,7 +176,7 @@ fn test_rename_sheet() {
let mut model = new_empty_model();
model.new_sheet();
model._set("A1", "=NewSheet!A3");
model.set_user_input(1, 3, 1, "25".to_string());
model.set_user_input(1, 3, 1, "25".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), "#REF!");
assert!(model.rename_sheet("Sheet2", "NewSheet").is_ok());
@@ -189,7 +189,7 @@ fn test_rename_sheet_by_index() {
let mut model = new_empty_model();
model.new_sheet();
model._set("A1", "=NewSheet!A1");
model.set_user_input(1, 1, 1, "25".to_string());
model.set_user_input(1, 1, 1, "25".to_string()).unwrap();
model.evaluate();
assert_eq!(model._get_text("A1"), "#REF!");
assert!(model.rename_sheet_by_index(1, "NewSheet").is_ok());

View File

@@ -7,10 +7,10 @@ use crate::types::Style;
fn test_model_set_cells_with_values_styles() {
let mut model = new_empty_model();
// Inputs
model.set_user_input(0, 1, 1, "21".to_string()); // A1
model.set_user_input(0, 2, 1, "42".to_string()); // A2
model.set_user_input(0, 1, 1, "21".to_string()).unwrap(); // A1
model.set_user_input(0, 2, 1, "42".to_string()).unwrap(); // A2
let style_base = model.get_style_for_cell(0, 1, 1);
let style_base = model.get_style_for_cell(0, 1, 1).unwrap();
let mut style = style_base.clone();
style.font.b = true;
style.num_fmt = "#,##0.00".to_string();
@@ -19,7 +19,7 @@ fn test_model_set_cells_with_values_styles() {
let mut style = style_base;
style.num_fmt = "#,##0.00".to_string();
assert!(model.set_cell_style(0, 2, 1, &style).is_ok());
let style: Style = model.get_style_for_cell(0, 2, 1);
let style: Style = model.get_style_for_cell(0, 2, 1).unwrap();
assert_eq!(style.num_fmt, "#,##0.00".to_string());
}
@@ -27,21 +27,21 @@ fn test_model_set_cells_with_values_styles() {
fn test_named_styles() {
let mut model = new_empty_model();
model._set("A1", "42");
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
style.font.b = true;
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
let bold_style_index = model.get_cell_style_index(0, 1, 1);
let bold_style_index = model.get_cell_style_index(0, 1, 1).unwrap();
let e = model
.workbook
.styles
.add_named_cell_style("bold", bold_style_index);
assert!(e.is_ok());
model._set("A2", "420");
let a2_style_index = model.get_cell_style_index(0, 2, 1);
let a2_style_index = model.get_cell_style_index(0, 2, 1).unwrap();
assert!(a2_style_index != bold_style_index);
let e = model.set_cell_style_by_name(0, 2, 1, "bold");
assert!(e.is_ok());
assert_eq!(model.get_cell_style_index(0, 2, 1), bold_style_index);
assert_eq!(model.get_cell_style_index(0, 2, 1), Ok(bold_style_index));
}
#[test]
@@ -49,7 +49,7 @@ fn test_create_named_style() {
let mut model = new_empty_model();
model._set("A1", "42");
let mut style = model.get_style_for_cell(0, 1, 1);
let mut style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(!style.font.b);
style.font.b = true;
@@ -59,6 +59,6 @@ fn test_create_named_style() {
let e = model.set_cell_style_by_name(0, 1, 1, "bold");
assert!(e.is_ok());
let style = model.get_style_for_cell(0, 1, 1);
let style = model.get_style_for_cell(0, 1, 1).unwrap();
assert!(style.font.b);
}

View File

@@ -100,7 +100,9 @@ fn test_worksheet_dimension_progressive() {
}
);
model.set_user_input(0, 30, 50, "Hello World".to_string());
model
.set_user_input(0, 30, 50, "Hello World".to_string())
.unwrap();
assert_eq!(
model.workbook.worksheet(0).unwrap().dimension(),
WorksheetDimension {
@@ -111,7 +113,9 @@ fn test_worksheet_dimension_progressive() {
}
);
model.set_user_input(0, 10, 15, "Hello World".to_string());
model
.set_user_input(0, 10, 15, "Hello World".to_string())
.unwrap();
assert_eq!(
model.workbook.worksheet(0).unwrap().dimension(),
WorksheetDimension {
@@ -122,7 +126,9 @@ fn test_worksheet_dimension_progressive() {
}
);
model.set_user_input(0, 5, 25, "Hello World".to_string());
model
.set_user_input(0, 5, 25, "Hello World".to_string())
.unwrap();
assert_eq!(
model.workbook.worksheet(0).unwrap().dimension(),
WorksheetDimension {
@@ -133,7 +139,9 @@ fn test_worksheet_dimension_progressive() {
}
);
model.set_user_input(0, 10, 250, "Hello World".to_string());
model
.set_user_input(0, 10, 250, "Hello World".to_string())
.unwrap();
assert_eq!(
model.workbook.worksheet(0).unwrap().dimension(),
WorksheetDimension {
@@ -162,12 +170,14 @@ fn test_worksheet_navigate_to_edge_in_direction() {
for (row_index, row) in inline_spreadsheet.into_iter().enumerate() {
for (column_index, value) in row.into_iter().enumerate() {
if value != 0 {
model.update_cell_with_number(
0,
(row_index as i32) + 1,
(column_index as i32) + 1,
value.into(),
);
model
.update_cell_with_number(
0,
(row_index as i32) + 1,
(column_index as i32) + 1,
value.into(),
)
.unwrap();
}
}
}

View File

@@ -20,7 +20,8 @@ impl Model {
let cell_reference = self._parse_reference(cell);
let column = cell_reference.column;
let row = cell_reference.row;
self.set_user_input(cell_reference.sheet, row, column, value.to_string());
self.set_user_input(cell_reference.sheet, row, column, value.to_string())
.unwrap();
}
pub fn _has_formula(&self, cell: &str) -> bool {
self._get_formula_opt(cell).is_some()

View File

@@ -86,12 +86,15 @@ fn get_units_from_format_string(num_fmt: &str) -> Option<Units> {
impl Model {
fn compute_cell_units(&self, cell_reference: &CellReferenceIndex) -> Option<Units> {
let style = &self.get_style_for_cell(
let cell_style_res = &self.get_style_for_cell(
cell_reference.sheet,
cell_reference.row,
cell_reference.column,
);
get_units_from_format_string(&style.num_fmt)
match cell_style_res {
Ok(style) => get_units_from_format_string(&style.num_fmt),
Err(_) => None,
}
}
pub(crate) fn compute_node_units(

View File

@@ -331,7 +331,7 @@ impl UserModel {
.cell(row, column)
.cloned();
self.model
.set_user_input(sheet, row, column, value.to_string());
.set_user_input(sheet, row, column, value.to_string())?;
self.evaluate_if_not_paused();
@@ -457,7 +457,7 @@ impl UserModel {
.worksheet(sheet)?
.cell(row, column)
.cloned();
let old_style = self.model.get_style_for_cell(sheet, row, column);
let old_style = self.model.get_style_for_cell(sheet, row, column)?;
self.model.cell_clear_all(sheet, row, column)?;
diff_list.push(Diff::CellClearAll {
sheet,
@@ -720,7 +720,7 @@ impl UserModel {
let row_index = ((row - row_start) % styles_heigh) as usize;
let column_index = ((column - column_start) % styles_width) as usize;
let style = &styles[row_index][column_index];
let old_value = self.model.get_style_for_cell(sheet, row, column);
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
self.model.set_cell_style(sheet, row, column, style)?;
diff_list.push(Diff::SetCellStyle {
sheet,
@@ -755,7 +755,7 @@ impl UserModel {
let last_column = range.column + range.width - 1;
for row in range.row..=last_row {
for column in range.column..=last_column {
let old_value = self.model.get_style_for_cell(sheet, row, column);
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
let mut style = old_value.clone();
// First remove all existing borders
@@ -852,7 +852,7 @@ impl UserModel {
let mut diff_list = Vec::new();
for row in range.row..range.row + range.height {
for column in range.column..range.column + range.width {
let old_value = self.model.get_style_for_cell(sheet, row, column);
let old_value = self.model.get_style_for_cell(sheet, row, column)?;
let mut style = old_value.clone();
match style_path {
"font.b" => {
@@ -951,7 +951,7 @@ impl UserModel {
/// * [Model::get_style_for_cell]
#[inline]
pub fn get_cell_style(&mut self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
Ok(self.model.get_style_for_cell(sheet, row, column))
self.model.get_style_for_cell(sheet, row, column)
}
/// Fills the cells from `source_area` until `to_row`.
@@ -1017,7 +1017,7 @@ impl UserModel {
.worksheet(sheet)?
.cell(row, column)
.cloned();
let old_style = self.model.get_style_for_cell(sheet, row, column);
let old_style = self.model.get_style_for_cell(sheet, row, column)?;
// compute the new value and set it
let source_row = anchor_row + index;
@@ -1025,10 +1025,10 @@ impl UserModel {
.model
.extend_to(sheet, source_row, column, row, column)?;
self.model
.set_user_input(sheet, row, column, target_value.to_string());
.set_user_input(sheet, row, column, target_value.to_string())?;
// Compute the new style and set it
let new_style = self.model.get_style_for_cell(sheet, source_row, column);
let new_style = self.model.get_style_for_cell(sheet, source_row, column)?;
self.model.set_cell_style(sheet, row, column, &new_style)?;
// Add the diffs
@@ -1118,7 +1118,7 @@ impl UserModel {
.worksheet(sheet)?
.cell(row, column)
.cloned();
let old_style = self.model.get_style_for_cell(sheet, row, column);
let old_style = self.model.get_style_for_cell(sheet, row, column)?;
// compute the new value and set it
let source_column = anchor_column + index;
@@ -1126,10 +1126,10 @@ impl UserModel {
.model
.extend_to(sheet, row, source_column, row, column)?;
self.model
.set_user_input(sheet, row, column, target_value.to_string());
.set_user_input(sheet, row, column, target_value.to_string())?;
// Compute the new style and set it
let new_style = self.model.get_style_for_cell(sheet, row, source_column);
let new_style = self.model.get_style_for_cell(sheet, row, source_column)?;
self.model.set_cell_style(sheet, row, column, &new_style)?;
// Add the diffs
@@ -1216,7 +1216,7 @@ impl UserModel {
self.model
.workbook
.worksheet_mut(*sheet)?
.update_cell(*row, *column, value);
.update_cell(*row, *column, value)?;
}
None => {
self.model.cell_clear_all(*sheet, *row, *column)?;
@@ -1246,7 +1246,7 @@ impl UserModel {
self.model
.workbook
.worksheet_mut(*sheet)?
.update_cell(*row, *column, value);
.update_cell(*row, *column, value)?;
}
}
Diff::CellClearAll {
@@ -1261,7 +1261,7 @@ impl UserModel {
self.model
.workbook
.worksheet_mut(*sheet)?
.update_cell(*row, *column, value);
.update_cell(*row, *column, value)?;
self.model
.set_cell_style(*sheet, *row, *column, old_style)?;
}
@@ -1307,7 +1307,7 @@ impl UserModel {
// puts all the data back
let worksheet = self.model.workbook.worksheet_mut(*sheet)?;
for (row, cell) in &old_data.data {
worksheet.update_cell(*row, *column, cell.clone());
worksheet.update_cell(*row, *column, cell.clone())?;
}
// makes sure that the width and style is correct
if let Some(col) = &old_data.column {
@@ -1375,7 +1375,7 @@ impl UserModel {
} => {
needs_evaluation = true;
self.model
.set_user_input(*sheet, *row, *column, new_value.to_string());
.set_user_input(*sheet, *row, *column, new_value.to_string())?;
}
Diff::SetColumnWidth {
sheet,

View File

@@ -42,7 +42,17 @@ impl Worksheet {
self.sheet_data.get_mut(&row)?.get_mut(&column)
}
pub(crate) fn update_cell(&mut self, row: i32, column: i32, new_cell: Cell) {
pub(crate) fn update_cell(
&mut self,
row: i32,
column: i32,
new_cell: Cell,
) -> Result<(), String> {
// validate row and column arg before updating cell of worksheet
if !is_valid_row(row) || !is_valid_column_number(column) {
return Err("Incorrect row or column".to_string());
}
match self.sheet_data.get_mut(&row) {
Some(column_data) => match column_data.get(&column) {
Some(_cell) => {
@@ -58,6 +68,7 @@ impl Worksheet {
self.sheet_data.insert(row, column_data);
}
}
Ok(())
}
// TODO [MVP]: Pass the cell style from the model
@@ -128,53 +139,94 @@ impl Worksheet {
Ok(())
}
pub fn set_cell_style(&mut self, row: i32, column: i32, style_index: i32) {
pub fn set_cell_style(
&mut self,
row: i32,
column: i32,
style_index: i32,
) -> Result<(), String> {
match self.cell_mut(row, column) {
Some(cell) => {
cell.set_style(style_index);
}
None => {
self.cell_clear_contents_with_style(row, column, style_index);
self.cell_clear_contents_with_style(row, column, style_index)?;
}
}
Ok(())
// TODO: cleanup check if the old cell style is still in use
}
pub fn set_cell_with_formula(&mut self, row: i32, column: i32, index: i32, style: i32) {
pub fn set_cell_with_formula(
&mut self,
row: i32,
column: i32,
index: i32,
style: i32,
) -> Result<(), String> {
let cell = Cell::new_formula(index, style);
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn set_cell_with_number(&mut self, row: i32, column: i32, value: f64, style: i32) {
pub fn set_cell_with_number(
&mut self,
row: i32,
column: i32,
value: f64,
style: i32,
) -> Result<(), String> {
let cell = Cell::new_number(value, style);
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn set_cell_with_string(&mut self, row: i32, column: i32, index: i32, style: i32) {
pub fn set_cell_with_string(
&mut self,
row: i32,
column: i32,
index: i32,
style: i32,
) -> Result<(), String> {
let cell = Cell::new_string(index, style);
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn set_cell_with_boolean(&mut self, row: i32, column: i32, value: bool, style: i32) {
pub fn set_cell_with_boolean(
&mut self,
row: i32,
column: i32,
value: bool,
style: i32,
) -> Result<(), String> {
let cell = Cell::new_boolean(value, style);
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn set_cell_with_error(&mut self, row: i32, column: i32, error: Error, style: i32) {
pub fn set_cell_with_error(
&mut self,
row: i32,
column: i32,
error: Error,
style: i32,
) -> Result<(), String> {
let cell = Cell::new_error(error, style);
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn cell_clear_contents(&mut self, row: i32, column: i32) {
pub fn cell_clear_contents(&mut self, row: i32, column: i32) -> Result<(), String> {
let s = self.get_style(row, column);
let cell = Cell::EmptyCell { s };
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn cell_clear_contents_with_style(&mut self, row: i32, column: i32, style: i32) {
pub fn cell_clear_contents_with_style(
&mut self,
row: i32,
column: i32,
style: i32,
) -> Result<(), String> {
let cell = Cell::EmptyCell { s: style };
self.update_cell(row, column, cell);
self.update_cell(row, column, cell)
}
pub fn set_frozen_rows(&mut self, frozen_rows: i32) -> Result<(), String> {