diff --git a/dsc_lib/src/functions/add.rs b/dsc_lib/src/functions/add.rs new file mode 100644 index 00000000..71ce22e7 --- /dev/null +++ b/dsc_lib/src/functions/add.rs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::DscError; +use crate::configure::context::Context; +use crate::functions::{AcceptedArgKind, Function}; +use serde_json::Value; +use tracing::debug; + +#[derive(Debug, Default)] +pub struct Add {} + +impl Function for Add { + fn min_args(&self) -> usize { + 2 + } + + fn max_args(&self) -> usize { + 2 + } + + fn accepted_arg_types(&self) -> Vec { + vec![AcceptedArgKind::Number] + } + + fn invoke(&self, args: &[Value], _context: &Context) -> Result { + debug!("add function"); + if let (Some(arg1), Some(arg2)) = (args[0].as_i64(), args[1].as_i64()) { + Ok(Value::Number((arg1 + arg2).into())) + } else { + Err(DscError::Parser("Invalid argument(s)".to_string())) + } + } +} + +#[cfg(test)] +mod tests { + use crate::configure::context::Context; + use crate::parser::Statement; + + #[test] + fn numbers() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[add(2, 3)]", &Context::new()).unwrap(); + assert_eq!(result, 5); + } + + #[test] + fn nested() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[add(2, add(3, 4))]", &Context::new()).unwrap(); + assert_eq!(result, 9); + } + + #[test] + fn invalid_one_parameter() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[add(5)]", &Context::new()); + assert!(result.is_err()); + } + + #[test] + fn overflow_result() { + let mut parser = Statement::new().unwrap(); + // max value for i64 is 2^63 -1 (or 9,223,372,036,854,775,807) + let result = parser.parse_and_execute("[add(9223372036854775807, 2)]", &Context::new()); + assert!(result.is_err()); + } + + #[test] + fn overflow_input() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[add(9223372036854775808, 2)]", &Context::new()); + assert!(result.is_err()); + } +} diff --git a/dsc_lib/src/functions/mod.rs b/dsc_lib/src/functions/mod.rs index 023f9558..b5309d09 100644 --- a/dsc_lib/src/functions/mod.rs +++ b/dsc_lib/src/functions/mod.rs @@ -7,6 +7,7 @@ use crate::DscError; use crate::configure::context::Context; use serde_json::Value; +pub mod add; pub mod base64; pub mod concat; pub mod create_array; @@ -56,6 +57,7 @@ impl FunctionDispatcher { #[must_use] pub fn new() -> Self { let mut functions: HashMap> = HashMap::new(); + functions.insert("add".to_string(), Box::new(add::Add{})); functions.insert("base64".to_string(), Box::new(base64::Base64{})); functions.insert("concat".to_string(), Box::new(concat::Concat{})); functions.insert("createArray".to_string(), Box::new(create_array::CreateArray{}));