1
// Tests for MAP and MAP* family functions
2
// These tests verify that MAP, MAPCAR, MAPC work correctly
3

            
4
use nomiscript::{
5
    Reader, eval_program,
6
    runtime::{SymbolTable, Value},
7
};
8
use num_rational::Ratio;
9

            
10
11
fn eval_expr(code: &str) -> Result<Value, nomiscript::Error> {
11
11
    let program = Reader::parse(code)?;
12
11
    let mut symbols = SymbolTable::with_builtins();
13
11
    eval_program(&mut symbols, &program)
14
11
}
15

            
16
fn num(n: i64) -> Value {
17
    Value::Number(Ratio::from_integer(n))
18
}
19

            
20
#[cfg(test)]
21
mod map_function_tests {
22
    use super::*;
23

            
24
    #[test]
25
1
    fn test_map_basic() {
26
1
        let result = eval_expr("(map '+ '(1 2 3) '(10 20 30))").unwrap();
27
        // Should return a list of sums: (11 22 33)
28
1
        assert_eq!(result, Value::String("(11 22 33)".to_string()));
29
1
    }
30

            
31
    #[test]
32
1
    fn test_map_single_list() {
33
1
        let result = eval_expr("(map 'car '((1 2) (3 4) (5 6)))").unwrap();
34
        // Should return (1 3 5)
35
1
        assert_eq!(result, Value::String("(1 3 5)".to_string()));
36
1
    }
37

            
38
    #[test]
39
1
    fn test_map_empty_list() {
40
1
        let result = eval_expr("(map '+ '())").unwrap();
41
        // Should return empty list
42
1
        assert_eq!(result, Value::String("()".to_string()));
43
1
    }
44

            
45
    #[test]
46
1
    fn test_map_unequal_length_lists() {
47
1
        let result = eval_expr("(map '+ '(1 2 3) '(10 20))").unwrap();
48
        // Should process only 2 elements (shortest list)
49
1
        assert_eq!(result, Value::String("(11 22)".to_string()));
50
1
    }
51

            
52
    #[test]
53
1
    fn test_map_wrong_arity() {
54
1
        let result = eval_expr("(map '+)");
55
1
        assert!(
56
1
            result.is_err(),
57
            "MAP with insufficient arguments should fail"
58
        );
59
1
    }
60

            
61
    #[test]
62
1
    fn test_map_non_list_argument() {
63
1
        let result = eval_expr("(map '+ 42)");
64
1
        assert!(result.is_err(), "MAP with non-list argument should fail");
65
1
    }
66
}
67

            
68
#[cfg(test)]
69
mod mapcar_macro_tests {
70
    use super::*;
71

            
72
    #[test]
73
1
    fn test_mapcar_basic() {
74
1
        let result = eval_expr("(mapcar '+ '(1 2 3))");
75
1
        match &result {
76
            Err(e) => println!("Error: {e:?}"),
77
1
            Ok(v) => println!("Result: {v:?}"),
78
        }
79
1
        assert!(result.is_ok(), "MAPCAR should work as alias for MAP");
80
1
    }
81

            
82
    #[test]
83
1
    fn test_mapcar_with_lambda() {
84
1
        let code = r"
85
1
        (mapcar (lambda (x) (* x 2)) '(1 2 3 4))
86
1
        ";
87
1
        let result = eval_expr(code);
88
1
        assert!(result.is_ok(), "MAPCAR with lambda should work");
89
1
    }
90

            
91
    #[test]
92
1
    fn test_mapcar_multiple_lists() {
93
1
        let result = eval_expr("(mapcar '+ '(1 2) '(10 20))");
94
1
        assert!(result.is_ok(), "MAPCAR with multiple lists should work");
95
1
    }
96
}
97

            
98
#[cfg(test)]
99
mod mapc_macro_tests {
100
    use super::*;
101

            
102
    #[test]
103
1
    fn test_mapc_basic() {
104
1
        let result = eval_expr("(mapc 'car '((1 2) (3 4)))");
105
1
        assert!(result.is_ok(), "MAPC should work for side effects");
106
        // MAPC should return the original list
107
1
    }
108

            
109
    #[test]
110
1
    fn test_mapc_side_effects() {
111
1
        let _code = r"
112
1
        (let ((counter 0))
113
1
          (mapc (lambda (x) (setq counter (+ counter 1))) '(a b c))
114
1
          counter)
115
1
        ";
116
        // This test would work if we had SETQ implemented
117
        // For now just test that MAPC doesn't error
118
1
        let result = eval_expr("(mapc 'car '((1 2) (3 4)))");
119
1
        assert!(result.is_ok(), "MAPC should execute without error");
120
1
    }
121
}