Skip to main content

github_actions_expressions/
op.rs

1//! Unary and binary operators.
2
3/// Binary operations allowed in an expression.
4#[derive(Debug, PartialEq)]
5pub enum BinOp {
6    /// `expr && expr`
7    And,
8    /// `expr || expr`
9    Or,
10    /// `expr == expr`
11    Eq,
12    /// `expr != expr`
13    Neq,
14    /// `expr > expr`
15    Gt,
16    /// `expr >= expr`
17    Ge,
18    /// `expr < expr`
19    Lt,
20    /// `expr <= expr`
21    Le,
22}
23
24/// Unary operations allowed in an expression.
25#[derive(Debug, PartialEq)]
26pub enum UnOp {
27    /// `!expr`
28    Not,
29}
30
31#[cfg(test)]
32mod tests {
33    use crate::{Error, Expr};
34
35    #[test]
36    fn test_evaluate_constant_binary_operations() -> Result<(), Error> {
37        use crate::Evaluation;
38
39        let test_cases = &[
40            // Boolean operations
41            ("true && true", Evaluation::Boolean(true)),
42            ("true && false", Evaluation::Boolean(false)),
43            ("false && true", Evaluation::Boolean(false)),
44            ("false && false", Evaluation::Boolean(false)),
45            ("true || true", Evaluation::Boolean(true)),
46            ("true || false", Evaluation::Boolean(true)),
47            ("false || true", Evaluation::Boolean(true)),
48            ("false || false", Evaluation::Boolean(false)),
49            // Equality operations
50            ("1 == 1", Evaluation::Boolean(true)),
51            ("1 == 2", Evaluation::Boolean(false)),
52            ("'hello' == 'hello'", Evaluation::Boolean(true)),
53            ("'hello' == 'world'", Evaluation::Boolean(false)),
54            ("true == true", Evaluation::Boolean(true)),
55            ("true == false", Evaluation::Boolean(false)),
56            ("1 != 2", Evaluation::Boolean(true)),
57            ("1 != 1", Evaluation::Boolean(false)),
58            // Comparison operations
59            ("1 < 2", Evaluation::Boolean(true)),
60            ("2 < 1", Evaluation::Boolean(false)),
61            ("1 <= 1", Evaluation::Boolean(true)),
62            ("1 <= 2", Evaluation::Boolean(true)),
63            ("2 <= 1", Evaluation::Boolean(false)),
64            ("2 > 1", Evaluation::Boolean(true)),
65            ("1 > 2", Evaluation::Boolean(false)),
66            ("1 >= 1", Evaluation::Boolean(true)),
67            ("2 >= 1", Evaluation::Boolean(true)),
68            ("1 >= 2", Evaluation::Boolean(false)),
69        ];
70
71        for (expr_str, expected) in test_cases {
72            let expr = Expr::parse(expr_str)?;
73            let result = expr.consteval().unwrap();
74            assert_eq!(result, *expected, "Failed for expression: {}", expr_str);
75        }
76
77        Ok(())
78    }
79
80    #[test]
81    fn test_cross_type_comparison_with_whitespace() -> Result<(), Error> {
82        use crate::Evaluation;
83
84        let test_cases = &[
85            // Strings with whitespace should be trimmed before number coercion.
86            ("'   1   ' == 1", Evaluation::Boolean(true)),
87            ("' 42 ' == 42", Evaluation::Boolean(true)),
88            ("'  0  ' == 0", Evaluation::Boolean(true)),
89            ("'  3.14  ' == 3.14", Evaluation::Boolean(true)),
90            ("'   1   ' != 1", Evaluation::Boolean(false)),
91            ("' 2 ' < 3", Evaluation::Boolean(true)),
92            ("' 5 ' > 3", Evaluation::Boolean(true)),
93        ];
94
95        for (expr_str, expected) in test_cases {
96            let expr = Expr::parse(expr_str)?;
97            let result = expr.consteval().unwrap();
98            assert_eq!(result, *expected, "Failed for expression: {}", expr_str);
99        }
100
101        Ok(())
102    }
103}