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
1
        assert_eq!(result, Value::Nil);
37
1
    }
38

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

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

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

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

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

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

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

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

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

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