|  | 
|  | 1 | +// Copyright (c) Microsoft Corporation. | 
|  | 2 | +// Licensed under the MIT License. | 
|  | 3 | + | 
|  | 4 | +use crate::DscError; | 
|  | 5 | +use crate::configure::context::Context; | 
|  | 6 | +use crate::functions::{AcceptedArgKind, Function}; | 
|  | 7 | +use serde_json::Value; | 
|  | 8 | +use tracing::debug; | 
|  | 9 | + | 
|  | 10 | +#[derive(Debug, Default)] | 
|  | 11 | +pub struct Sub {} | 
|  | 12 | + | 
|  | 13 | +impl Function for Sub { | 
|  | 14 | +    fn min_args(&self) -> usize { | 
|  | 15 | +        2 | 
|  | 16 | +    } | 
|  | 17 | + | 
|  | 18 | +    fn max_args(&self) -> usize { | 
|  | 19 | +        2 | 
|  | 20 | +    } | 
|  | 21 | + | 
|  | 22 | +    fn accepted_arg_types(&self) -> Vec<AcceptedArgKind> { | 
|  | 23 | +        vec![AcceptedArgKind::Number] | 
|  | 24 | +    } | 
|  | 25 | + | 
|  | 26 | +    fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> { | 
|  | 27 | +        debug!("sub function"); | 
|  | 28 | +        if let (Some(arg1), Some(arg2)) = (args[0].as_i64(), args[1].as_i64()) { | 
|  | 29 | +            Ok(Value::Number((arg1 - arg2).into())) | 
|  | 30 | +        } else { | 
|  | 31 | +            Err(DscError::Parser("Invalid argument(s)".to_string())) | 
|  | 32 | +        } | 
|  | 33 | +    } | 
|  | 34 | +} | 
|  | 35 | + | 
|  | 36 | +#[cfg(test)] | 
|  | 37 | +mod tests { | 
|  | 38 | +    use crate::configure::context::Context; | 
|  | 39 | +    use crate::parser::Statement; | 
|  | 40 | + | 
|  | 41 | +    #[test] | 
|  | 42 | +    fn numbers() { | 
|  | 43 | +        let mut parser = Statement::new().unwrap(); | 
|  | 44 | +        let result = parser.parse_and_execute("[sub(7, 3)]", &Context::new()).unwrap(); | 
|  | 45 | +        assert_eq!(result, 4); | 
|  | 46 | +    } | 
|  | 47 | + | 
|  | 48 | +    #[test] | 
|  | 49 | +    fn nested() { | 
|  | 50 | +        let mut parser = Statement::new().unwrap(); | 
|  | 51 | +        let result = parser.parse_and_execute("[sub(9, sub(5, 3))]", &Context::new()).unwrap(); | 
|  | 52 | +        assert_eq!(result, 7); | 
|  | 53 | +    } | 
|  | 54 | + | 
|  | 55 | +    #[test] | 
|  | 56 | +    fn invalid_one_parameter() { | 
|  | 57 | +        let mut parser = Statement::new().unwrap(); | 
|  | 58 | +        let result = parser.parse_and_execute("[sub(5)]", &Context::new()); | 
|  | 59 | +        assert!(result.is_err()); | 
|  | 60 | +    } | 
|  | 61 | + | 
|  | 62 | +    #[test] | 
|  | 63 | +    fn overflow_result() { | 
|  | 64 | +        let mut parser = Statement::new().unwrap(); | 
|  | 65 | +        // max value for i64 is 2^63 -1 (or 9,223,372,036,854,775,807) | 
|  | 66 | +        let result = parser.parse_and_execute("[sub(9223372036854775807, -2)]", &Context::new()); | 
|  | 67 | +        assert!(result.is_err()); | 
|  | 68 | +    } | 
|  | 69 | + | 
|  | 70 | +    #[test] | 
|  | 71 | +    fn overflow_input() { | 
|  | 72 | +        let mut parser = Statement::new().unwrap(); | 
|  | 73 | +        let result = parser.parse_and_execute("[sub(9223372036854775808, 2)]", &Context::new()); | 
|  | 74 | +        assert!(result.is_err()); | 
|  | 75 | +    } | 
|  | 76 | +} | 
0 commit comments