Skip to content

Commit

Permalink
Merge pull request #360 from tgauth/add-mod-function
Browse files Browse the repository at this point in the history
Add mod function
  • Loading branch information
SteveL-MSFT authored Mar 8, 2024
2 parents 9667b23 + 166d645 commit 2cea11d
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
2 changes: 2 additions & 0 deletions dsc_lib/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod concat;
pub mod create_array;
pub mod div;
pub mod envvar;
pub mod mod_function;
pub mod mul;
pub mod parameters;
pub mod resource_id;
Expand Down Expand Up @@ -64,6 +65,7 @@ impl FunctionDispatcher {
functions.insert("createArray".to_string(), Box::new(create_array::CreateArray{}));
functions.insert("div".to_string(), Box::new(div::Div{}));
functions.insert("envvar".to_string(), Box::new(envvar::Envvar{}));
functions.insert("mod".to_string(), Box::new(mod_function::Mod{}));
functions.insert("mul".to_string(), Box::new(mul::Mul{}));
functions.insert("parameters".to_string(), Box::new(parameters::Parameters{}));
functions.insert("resourceId".to_string(), Box::new(resource_id::ResourceId{}));
Expand Down
79 changes: 79 additions & 0 deletions dsc_lib/src/functions/mod_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 Mod {}

impl Function for Mod {
fn min_args(&self) -> usize {
2
}

fn max_args(&self) -> usize {
2
}

fn accepted_arg_types(&self) -> Vec<AcceptedArgKind> {
vec![AcceptedArgKind::Number]
}

fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> {
debug!("mod function");
if let (Some(arg1), Some(arg2)) = (args[0].as_i64(), args[1].as_i64()) {
if arg2 == 0 {
return Err(DscError::Parser("Cannot divide by zero".to_string()));
}
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("[mod(7, 3)]", &Context::new()).unwrap();
assert_eq!(result, 1);
}

#[test]
fn nested() {
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[mod(18, mod(8, 3))]", &Context::new()).unwrap();
assert_eq!(result, 0);
}

#[test]
fn invalid_one_parameter() {
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[mod(5)]", &Context::new());
assert!(result.is_err());
}

#[test]
fn invalid_div_by_zero() {
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[mod(5, 0)]", &Context::new());
assert!(result.is_err());
}

#[test]
fn overflow_input() {
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("[mod(9223372036854775808, 2)]", &Context::new());
assert!(result.is_err());
}
}

0 comments on commit 2cea11d

Please sign in to comment.