FIX: Forbid unwrap, expect and panic in the base code

This commit is contained in:
Nicolás Hatcher
2024-11-16 14:18:12 +01:00
committed by Nicolás Hatcher Andrés
parent bdd2c8fe04
commit 49ae2d8915
43 changed files with 341 additions and 128 deletions

View File

@@ -26,6 +26,7 @@ pub struct SetCellValue {
}
impl Model {
#[allow(clippy::expect_used)]
pub(crate) fn shift_cell_formula(
&mut self,
sheet: u32,
@@ -57,6 +58,7 @@ impl Model {
}
}
#[allow(clippy::expect_used)]
pub fn forward_references(
&mut self,
source_area: &Area,

View File

@@ -1,3 +1,5 @@
#![allow(clippy::expect_used)]
use crate::expressions::{
lexer::util::get_tokens,
token::{OpCompare, OpSum, TokenType},

View File

@@ -52,7 +52,9 @@ pub fn get_tokens(formula: &str) -> Vec<MarkedToken> {
let mut lexer = Lexer::new(
formula,
LexerMode::A1,
#[allow(clippy::expect_used)]
get_locale("en").expect(""),
#[allow(clippy::expect_used)]
get_language("en").expect(""),
);
let mut start = lexer.get_position();

View File

@@ -63,7 +63,9 @@ pub(crate) fn parse_range(formula: &str) -> Result<(i32, i32, i32, i32), String>
let mut lexer = lexer::Lexer::new(
formula,
lexer::LexerMode::A1,
#[allow(clippy::expect_used)]
get_locale("en").expect(""),
#[allow(clippy::expect_used)]
get_language("en").expect(""),
);
if let TokenType::Range {
@@ -202,7 +204,9 @@ impl Parser {
let lexer = lexer::Lexer::new(
"",
lexer::LexerMode::A1,
#[allow(clippy::expect_used)]
get_locale("en").expect(""),
#[allow(clippy::expect_used)]
get_language("en").expect(""),
);
Parser {
@@ -675,14 +679,23 @@ impl Parser {
}
};
// table-name => table
let table = self.tables.get(&table_name).unwrap_or_else(|| {
panic!(
"Table not found: '{table_name}' at '{}!{}{}'",
context.sheet,
number_to_column(context.column).expect(""),
context.row
)
});
let table = match self.tables.get(&table_name) {
Some(t) => t,
None => {
let message = format!(
"Table not found: '{table_name}' at '{}!{}{}'",
context.sheet,
number_to_column(context.column)
.unwrap_or(format!("{}", context.column)),
context.row
);
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: 0,
message,
};
}
};
let table_sheet_index = match self.get_sheet_index_by_name(&table.sheet_name) {
Some(i) => i,
None => {
@@ -701,6 +714,7 @@ impl Parser {
};
// context must be with tables.reference
#[allow(clippy::expect_used)]
let (column_start, mut row_start, column_end, mut row_end) =
parse_range(&table.reference).expect("Failed parsing range");

View File

@@ -1,3 +1,5 @@
#![allow(clippy::panic)]
use std::collections::HashMap;
use crate::expressions::lexer::LexerMode;

View File

@@ -5,6 +5,7 @@ use chrono::NaiveDate;
use crate::constants::EXCEL_DATE_BASE;
pub fn from_excel_date(days: i64) -> NaiveDate {
#[allow(clippy::expect_used)]
let dt = NaiveDate::from_ymd_opt(1900, 1, 1).expect("problem with chrono::NaiveDate");
dt + Duration::days(days - 2)
}

View File

@@ -220,7 +220,13 @@ impl Model {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_row;
}
@@ -228,7 +234,13 @@ impl Model {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_column;
}
@@ -283,7 +295,13 @@ impl Model {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_row;
}
@@ -291,7 +309,13 @@ impl Model {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_column;
}
@@ -359,7 +383,13 @@ impl Model {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_row;
}
@@ -367,7 +397,13 @@ impl Model {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.map_err(|_| {
CalcResult::new_error(
Error::ERROR,
*cell,
format!("Invalid worksheet index: '{}'", left.sheet),
)
})?
.dimension()
.max_column;
}
@@ -862,20 +898,28 @@ impl Model {
let column1 = left.column;
let mut column2 = right.column;
if row1 == 1 && row2 == LAST_ROW {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
row2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
if column1 == 1 && column2 == LAST_COLUMN {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
column2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
for row in row1..row2 + 1 {
for column in column1..(column2 + 1) {

View File

@@ -128,20 +128,28 @@ impl Model {
let column1 = left.column;
let mut column2 = right.column;
if row1 == 1 && row2 == LAST_ROW {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
row2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
if column1 == 1 && column2 == LAST_COLUMN {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
column2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
for row in row1..row2 + 1 {
for column in column1..(column2 + 1) {
@@ -195,20 +203,28 @@ impl Model {
let column1 = left.column;
let mut column2 = right.column;
if row1 == 1 && row2 == LAST_ROW {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
row2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
if column1 == 1 && column2 == LAST_COLUMN {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
column2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
for row in row1..row2 + 1 {
for column in column1..(column2 + 1) {

View File

@@ -1148,6 +1148,7 @@ impl Model {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use std::{
fs::File,
io::{BufRead, BufReader},

View File

@@ -381,11 +381,16 @@ impl Model {
let right_row = first_range.right.row;
let right_column = first_range.right.column;
let dimension = self
.workbook
.worksheet(first_range.left.sheet)
.expect("Sheet expected during evaluation.")
.dimension();
let dimension = match self.workbook.worksheet(first_range.left.sheet) {
Ok(s) => s.dimension(),
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", first_range.left.sheet),
)
}
};
let max_row = dimension.max_row;
let max_column = dimension.max_column;
@@ -526,20 +531,28 @@ impl Model {
let mut right_column = sum_range.right.column;
if left_row == 1 && right_row == LAST_ROW {
right_row = self
.workbook
.worksheet(sum_range.left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
right_row = match self.workbook.worksheet(sum_range.left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return Err(CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", sum_range.left.sheet),
));
}
};
}
if left_column == 1 && right_column == LAST_COLUMN {
right_column = self
.workbook
.worksheet(sum_range.left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
right_column = match self.workbook.worksheet(sum_range.left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return Err(CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", sum_range.left.sheet),
));
}
};
}
for row in left_row..right_row + 1 {

View File

@@ -53,8 +53,13 @@ impl Model {
false
}
fn cell_hidden_status(&self, sheet_index: u32, row: i32, column: i32) -> CellTableStatus {
let worksheet = self.workbook.worksheet(sheet_index).expect("");
fn cell_hidden_status(
&self,
sheet_index: u32,
row: i32,
column: i32,
) -> Result<CellTableStatus, String> {
let worksheet = self.workbook.worksheet(sheet_index)?;
let mut hidden = false;
for row_style in &worksheet.rows {
if row_style.r == row {
@@ -63,13 +68,13 @@ impl Model {
}
}
if !hidden {
return CellTableStatus::Normal;
return Ok(CellTableStatus::Normal);
}
// The row is hidden we need to know if the table has filters
if self.get_table_for_cell(sheet_index, row, column) {
CellTableStatus::Filtered
Ok(CellTableStatus::Filtered)
} else {
CellTableStatus::Hidden
Ok(CellTableStatus::Hidden)
}
}
@@ -143,7 +148,11 @@ impl Model {
let column2 = right.column;
for row in row1..=row2 {
let cell_status = self.cell_hidden_status(left.sheet, row, column1);
let cell_status = self
.cell_hidden_status(left.sheet, row, column1)
.map_err(|message| {
CalcResult::new_error(Error::ERROR, cell, message)
})?;
if cell_status == CellTableStatus::Filtered {
continue;
}
@@ -380,7 +389,14 @@ impl Model {
let column2 = right.column;
for row in row1..=row2 {
let cell_status = self.cell_hidden_status(left.sheet, row, column1);
let cell_status = match self
.cell_hidden_status(left.sheet, row, column1)
{
Ok(s) => s,
Err(message) => {
return CalcResult::new_error(Error::ERROR, cell, message);
}
};
if cell_status == CellTableStatus::Filtered {
continue;
}
@@ -449,7 +465,14 @@ impl Model {
let column2 = right.column;
for row in row1..=row2 {
let cell_status = self.cell_hidden_status(left.sheet, row, column1);
let cell_status = match self
.cell_hidden_status(left.sheet, row, column1)
{
Ok(s) => s,
Err(message) => {
return CalcResult::new_error(Error::ERROR, cell, message);
}
};
if cell_status == CellTableStatus::Filtered {
continue;
}

View File

@@ -888,20 +888,28 @@ impl Model {
let column1 = left.column;
let mut column2 = right.column;
if row1 == 1 && row2 == LAST_ROW {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
row2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
if column1 == 1 && column2 == LAST_COLUMN {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
column2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
for row in row1..row2 + 1 {
for column in column1..(column2 + 1) {

View File

@@ -251,20 +251,28 @@ impl Model {
let column1 = left.column;
if row1 == 1 && row2 == LAST_ROW {
row2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_row;
row2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_row,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
if column1 == 1 && column2 == LAST_COLUMN {
column2 = self
.workbook
.worksheet(left.sheet)
.expect("Sheet expected during evaluation.")
.dimension()
.max_column;
column2 = match self.workbook.worksheet(left.sheet) {
Ok(s) => s.dimension().max_column,
Err(_) => {
return CalcResult::new_error(
Error::ERROR,
cell,
format!("Invalid worksheet index: '{}'", left.sheet),
);
}
};
}
let left = CellReferenceIndex {
sheet: left.sheet,

View File

@@ -31,6 +31,7 @@ pub struct Language {
pub errors: Errors,
}
#[allow(clippy::expect_used)]
static LANGUAGES: Lazy<HashMap<String, Language>> = Lazy::new(|| {
bitcode::decode(include_bytes!("language.bin")).expect("Failed parsing language file")
});

View File

@@ -65,6 +65,7 @@ pub struct DecimalFormats {
pub standard: String,
}
#[allow(clippy::expect_used)]
static LOCALES: Lazy<HashMap<String, Locale>> =
Lazy::new(|| bitcode::decode(include_bytes!("locales.bin")).expect("Failed parsing locale"));

View File

@@ -41,6 +41,7 @@ pub use crate::mock_time::get_milliseconds_since_epoch;
/// * Or mocked for tests
#[cfg(not(test))]
#[cfg(not(target_arch = "wasm32"))]
#[allow(clippy::expect_used)]
pub fn get_milliseconds_since_epoch() -> i64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
@@ -529,6 +530,7 @@ impl Model {
}
}
#[allow(clippy::expect_used)]
fn cell_reference_to_string(
&self,
cell_reference: &CellReferenceIndex,
@@ -544,6 +546,7 @@ impl Model {
/// Sets `result` in the cell given by `sheet` sheet index, row and column
/// Note that will panic if the cell does not exist
/// It will do nothing if the cell does not have a formula
#[allow(clippy::expect_used)]
fn set_cell_value(&mut self, cell_reference: CellReferenceIndex, result: &CalcResult) {
let CellReferenceIndex { sheet, column, row } = cell_reference;
let cell = &self.workbook.worksheets[sheet as usize].sheet_data[&row][&column];
@@ -875,6 +878,7 @@ impl Model {
.map_err(|_| format!("Invalid timezone: {}", workbook.settings.tz))?;
// FIXME: Add support for display languages
#[allow(clippy::expect_used)]
let language = get_language("en").expect("").clone();
let mut shared_strings = HashMap::new();
for (index, s) in workbook.shared_strings.iter().enumerate() {
@@ -1986,6 +1990,7 @@ impl Model {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
use super::CellReferenceIndex as CellReference;
use crate::{test::util::new_empty_model, types::Cell};

View File

@@ -392,6 +392,7 @@ impl Model {
let cells = HashMap::new();
// FIXME: Add support for display languages
#[allow(clippy::expect_used)]
let language = get_language("en").expect("").clone();
let mut model = Model {

View File

@@ -1,4 +1,5 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::panic)]
use crate::test::util::new_empty_model;
use crate::types::Cell;

View File

@@ -1,3 +1,5 @@
#![allow(clippy::unwrap_used)]
use crate::test::util::new_empty_model;
#[test]

View File

@@ -1,3 +1,5 @@
#![allow(clippy::unwrap_used)]
use crate::{expressions::token, test::util::new_empty_model, types::Cell};
#[test]

View File

@@ -1,3 +1,5 @@
#![allow(clippy::unwrap_used)]
use crate::{
constants::{DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_HEIGHT},
test::util::new_empty_model,

View File

@@ -1,3 +1,5 @@
#![allow(clippy::unwrap_used)]
use crate::{expressions::types::Area, UserModel};
#[test]

View File

@@ -571,7 +571,10 @@ impl UserModel {
break;
}
}
let data = worksheet.sheet_data.get(&row).unwrap().clone();
let data = match worksheet.sheet_data.get(&row) {
Some(s) => s.clone(),
None => return Err(format!("Row number '{row}' is not valid.")),
};
let old_data = Box::new(RowData {
row: row_data,
data,
@@ -1369,11 +1372,16 @@ impl UserModel {
);
text_row.push(text);
}
wtr.write_record(text_row).unwrap();
wtr.write_record(text_row)
.map_err(|e| format!("Error while processing csv: {}", e))?;
data.insert(row, data_row);
}
let csv = String::from_utf8(wtr.into_inner().unwrap()).unwrap();
let csv = String::from_utf8(
wtr.into_inner()
.map_err(|e| format!("Processing error: '{}'", e))?,
)
.map_err(|e| format!("Error converting from utf8: '{}'", e))?;
Ok(Clipboard {
csv,

View File

@@ -34,6 +34,7 @@ impl ParsedReference {
locale: &Locale,
get_sheet_index_by_name: F,
) -> Result<ParsedReference, String> {
#[allow(clippy::expect_used)]
let language = get_language("en").expect("");
let mut lexer = Lexer::new(reference, LexerMode::A1, locale, language);
@@ -151,6 +152,8 @@ pub(crate) fn is_valid_hex_color(color: &str) -> bool {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
use super::*;
use crate::language::get_language;
use crate::locale::{get_locale, Locale};

View File

@@ -254,7 +254,7 @@ impl Worksheet {
/// Changes the height of a row.
/// * If the row does not a have a style we add it.
/// * If it has we modify the height and make sure it is applied.
///
///
/// Fails if column index is outside allowed range.
pub fn set_row_height(&mut self, row: i32, height: f64) -> Result<(), String> {
if !is_valid_row(row) {
@@ -283,7 +283,7 @@ impl Worksheet {
/// Changes the width of a column.
/// * If the column does not a have a width we simply add it
/// * If it has, it might be part of a range and we ned to split the range.
///
///
/// Fails if column index is outside allowed range.
pub fn set_column_width(&mut self, column: i32, width: f64) -> Result<(), String> {
self.set_column_width_and_style(column, width, None)