From 726bf677ed81a195cbd88cc9593d86162156c8ba Mon Sep 17 00:00:00 2001 From: Bruno Carvalhal Date: Sun, 10 Nov 2024 14:25:10 +0100 Subject: [PATCH] Implement UNICODE function --- base/src/functions/mod.rs | 7 ++++- base/src/functions/text.rs | 45 ++++++++++++++++++++++++++++++++ base/src/test/mod.rs | 1 + base/src/test/test_fn_unicode.rs | 41 +++++++++++++++++++++++++++++ wiki/functions.md | 1 + 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 base/src/test/test_fn_unicode.rs diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index f637288..8397fd1 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -122,6 +122,7 @@ pub enum Function { Textbefore, Textjoin, Trim, + Unicode, Upper, Value, Valuetotext, @@ -246,7 +247,7 @@ pub enum Function { } impl Function { - pub fn into_iter() -> IntoIter { + pub fn into_iter() -> IntoIter { [ Function::And, Function::False, @@ -316,6 +317,7 @@ impl Function { Function::Search, Function::Text, Function::Trim, + Function::Unicode, Function::Upper, Function::Isnumber, Function::Isnontext, @@ -567,6 +569,7 @@ impl Function { "SEARCH" => Some(Function::Search), "TEXT" => Some(Function::Text), "TRIM" => Some(Function::Trim), + "UNICODE" => Some(Function::Unicode), "UPPER" => Some(Function::Upper), "REPT" => Some(Function::Rept), @@ -779,6 +782,7 @@ impl fmt::Display for Function { Function::Search => write!(f, "SEARCH"), Function::Text => write!(f, "TEXT"), Function::Trim => write!(f, "TRIM"), + Function::Unicode => write!(f, "UNICODE"), Function::Upper => write!(f, "UPPER"), Function::Isnumber => write!(f, "ISNUMBER"), Function::Isnontext => write!(f, "ISNONTEXT"), @@ -1012,6 +1016,7 @@ impl Model { Function::Search => self.fn_search(args, cell), Function::Text => self.fn_text(args, cell), Function::Trim => self.fn_trim(args, cell), + Function::Unicode => self.fn_unicode(args, cell), Function::Upper => self.fn_upper(args, cell), // Information Function::Isnumber => self.fn_isnumber(args, cell), diff --git a/base/src/functions/text.rs b/base/src/functions/text.rs index 3a48767..f7717be 100644 --- a/base/src/functions/text.rs +++ b/base/src/functions/text.rs @@ -342,6 +342,51 @@ impl Model { CalcResult::new_args_number_error(cell) } + pub(crate) fn fn_unicode(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() == 1 { + let s = match self.evaluate_node_in_context(&args[0], cell) { + CalcResult::Number(v) => format!("{}", v), + CalcResult::String(v) => v, + CalcResult::Boolean(b) => { + if b { + "TRUE".to_string() + } else { + "FALSE".to_string() + } + } + error @ CalcResult::Error { .. } => return error, + CalcResult::Range { .. } => { + // Implicit Intersection not implemented + return CalcResult::Error { + error: Error::NIMPL, + origin: cell, + message: "Implicit Intersection not implemented".to_string(), + }; + } + CalcResult::EmptyCell | CalcResult::EmptyArg => { + return CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "Empty cell".to_string(), + } + } + }; + + // TODO: Needed? + if s.len() == 0 { + return CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "Empty cell".to_string(), + }; + } + + let unicode_number = s.chars().nth(0).unwrap() as u32; + return CalcResult::String(unicode_number.to_string()); + } + CalcResult::new_args_number_error(cell) + } + pub(crate) fn fn_upper(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { if args.len() == 1 { let s = match self.evaluate_node_in_context(&args[0], cell) { diff --git a/base/src/test/mod.rs b/base/src/test/mod.rs index c34fbd8..a6571f0 100644 --- a/base/src/test/mod.rs +++ b/base/src/test/mod.rs @@ -24,6 +24,7 @@ mod test_fn_sum; mod test_fn_sumifs; mod test_fn_textbefore; mod test_fn_textjoin; +mod test_fn_unicode; mod test_forward_references; mod test_frozen_rows_columns; mod test_general; diff --git a/base/src/test/test_fn_unicode.rs b/base/src/test/test_fn_unicode.rs new file mode 100644 index 0000000..ad011db --- /dev/null +++ b/base/src/test/test_fn_unicode.rs @@ -0,0 +1,41 @@ +#![allow(clippy::unwrap_used)] + +use crate::test::util::new_empty_model; + +#[test] +fn simple_cases() { + let mut model = new_empty_model(); + model._set("A1", "=UNICODE(\"1,00\")"); + model._set("A2", "=UNICODE(\"1\")"); + model._set("A3", "=UNICODE(\"T\")"); + model._set("A4", "=UNICODE(\"TRUE\")"); + model._set("A5", "=UNICODE(\"の\")"); + model._set("A6", "=UNICODE(\" \")"); + + model.evaluate(); + + assert_eq!(model._get_text("A1"), *"49"); + assert_eq!(model._get_text("A2"), *"49"); + assert_eq!(model._get_text("A3"), *"84"); + assert_eq!(model._get_text("A4"), *"84"); + assert_eq!(model._get_text("A5"), *"12398"); + assert_eq!(model._get_text("A6"), *"32"); +} + +#[test] +fn value_errors() { + let mut model = new_empty_model(); + model._set("A1", "=UNICODE(\"\")"); + model.evaluate(); + + assert_eq!(model._get_text("A1"), *"#VALUE!"); +} + +#[test] +fn wrong_number_of_arguments() { + let mut model = new_empty_model(); + model._set("A1", "=UNICODE()"); + model.evaluate(); + + assert_eq!(model._get_text("A1"), *"#ERROR!"); +} diff --git a/wiki/functions.md b/wiki/functions.md index cd1195d..98ac639 100644 --- a/wiki/functions.md +++ b/wiki/functions.md @@ -68,6 +68,7 @@ * SEARCH * TEXT * TRIM +* UNICODE * UPPER * ISNUMBER * ISNONTEXT