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

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

            
15
#[cfg(test)]
16
mod map_function_tests {
17
    use super::*;
18

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

            
26
    #[test]
27
1
    fn test_map_single_list() {
28
1
        let result = eval_expr("(map 'car '((1 2) (3 4) (5 6)))").unwrap();
29
        // Should return (1 3 5)
30
1
        assert_eq!(result, Value::String("(1 3 5)".to_string()));
31
1
    }
32

            
33
    #[test]
34
1
    fn test_map_empty_list() {
35
1
        let result = eval_expr("(map '+ '())").unwrap();
36
        // Should return empty list
37
1
        assert_eq!(result, Value::String("()".to_string()));
38
1
    }
39

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

            
47
    #[test]
48
1
    fn test_map_wrong_arity() {
49
1
        let result = eval_expr("(map '+)");
50
1
        assert!(
51
1
            result.is_err(),
52
            "MAP with insufficient arguments should fail"
53
        );
54
1
    }
55

            
56
    #[test]
57
1
    fn test_map_non_list_argument() {
58
1
        let result = eval_expr("(map '+ 42)");
59
1
        assert!(result.is_err(), "MAP with non-list argument should fail");
60
1
    }
61
}
62

            
63
#[cfg(test)]
64
mod mapcar_macro_tests {
65
    use super::*;
66

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

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

            
86
    #[test]
87
1
    fn test_mapcar_multiple_lists() {
88
1
        let result = eval_expr("(mapcar '+ '(1 2) '(10 20))");
89
1
        assert!(result.is_ok(), "MAPCAR with multiple lists should work");
90
1
    }
91
}
92

            
93
#[cfg(test)]
94
mod mapc_macro_tests {
95
    use super::*;
96

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

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