Coverage Report

Created: 2025-09-05 15:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/runtime/repl_function_tests.rs
Line
Count
Source
1
//! Unit tests for function call evaluation in REPL
2
3
#[cfg(test)]
4
#[allow(clippy::panic)] // Tests may panic on failure
5
#[allow(clippy::expect_used)] // Tests use expect for error messages
6
mod tests {
7
    use super::super::*;
8
    use anyhow::Result;
9
10
    /// Test basic println function call
11
    #[test]
12
1
    fn test_println_basic() -> Result<()> {
13
1
        let mut repl = Repl::new()
?0
;
14
1
        let result = repl.eval(r#"println("Hello, World!")"#)
?0
;
15
1
        assert_eq!(result, "");
16
1
        Ok(())
17
1
    }
18
19
    /// Test println with multiple arguments
20
    #[test]
21
1
    fn test_println_multiple_args() -> Result<()> {
22
1
        let mut repl = Repl::new()
?0
;
23
1
        let result = repl.eval(r#"println("Hello", "World", "!")"#)
?0
;
24
1
        assert_eq!(result, "");
25
1
        Ok(())
26
1
    }
27
28
    /// Test println with variables
29
    #[test]
30
1
    fn test_println_with_variables() -> Result<()> {
31
1
        let mut repl = Repl::new()
?0
;
32
1
        repl.eval("let x = 42")
?0
;
33
1
        let result = repl.eval("println(x)")
?0
;
34
1
        assert_eq!(result, "");
35
1
        Ok(())
36
1
    }
37
38
    /// Test println with expressions
39
    #[test]
40
1
    fn test_println_with_expressions() -> Result<()> {
41
1
        let mut repl = Repl::new()
?0
;
42
1
        let result = repl.eval("println(2 + 3)")
?0
;
43
1
        assert_eq!(result, "");
44
1
        Ok(())
45
1
    }
46
47
    /// Test println with different value types
48
    #[test]
49
1
    fn test_println_different_types() -> Result<()> {
50
1
        let mut repl = Repl::new()
?0
;
51
52
        // Integer
53
1
        let result = repl.eval("println(42)")
?0
;
54
1
        assert_eq!(result, "");
55
56
        // Float
57
1
        let result = repl.eval("println(3.14)")
?0
;
58
1
        assert_eq!(result, "");
59
60
        // Boolean
61
1
        let result = repl.eval("println(true)")
?0
;
62
1
        assert_eq!(result, "");
63
64
        // String
65
1
        let result = repl.eval(r#"println("test")"#)
?0
;
66
1
        assert_eq!(result, "");
67
68
1
        Ok(())
69
1
    }
70
71
    /// Test print function (without newline)
72
    #[test]
73
1
    fn test_print_function() -> Result<()> {
74
1
        let mut repl = Repl::new()
?0
;
75
1
        let result = repl.eval(r#"print("Hello")"#)
?0
;
76
1
        assert_eq!(result, "");
77
1
        Ok(())
78
1
    }
79
80
    /// Test print with multiple arguments
81
    #[test]
82
1
    fn test_print_multiple_args() -> Result<()> {
83
1
        let mut repl = Repl::new()
?0
;
84
1
        let result = repl.eval(r#"print("A", "B", "C")"#)
?0
;
85
1
        assert_eq!(result, "");
86
1
        Ok(())
87
1
    }
88
89
    /// Test unknown function error
90
    #[test]
91
1
    fn test_unknown_function_error() {
92
1
        let Ok(mut repl) = Repl::new() else {
93
0
            panic!("REPL creation should succeed");
94
        };
95
1
        let result = repl.eval("unknown_function()");
96
1
        assert!(result.is_err());
97
1
        if let Err(error) = result {
98
1
            let error_msg = error.to_string();
99
1
            assert!(error_msg.contains("Unknown function"));
100
0
        }
101
1
    }
102
103
    /// Test complex function calls with nested expressions
104
    #[test]
105
1
    fn test_complex_function_calls() -> Result<()> {
106
1
        let mut repl = Repl::new()
?0
;
107
1
        repl.eval("let x = 10")
?0
;
108
1
        repl.eval("let y = 20")
?0
;
109
1
        let result = repl.eval("println(x + y, x * y)")
?0
;
110
1
        assert_eq!(result, "");
111
1
        Ok(())
112
1
    }
113
114
    /// Test function calls with string interpolation-like behavior
115
    #[test]
116
1
    fn test_function_call_string_formatting() -> Result<()> {
117
1
        let mut repl = Repl::new()
?0
;
118
1
        repl.eval("let name = \"World\"")
?0
;
119
1
        let result = repl.eval(r#"println("Hello,", name, "!")"#)
?0
;
120
1
        assert_eq!(result, "");
121
1
        Ok(())
122
1
    }
123
124
    /// Test function calls return unit type
125
    #[test]
126
1
    fn test_function_calls_return_unit() -> Result<()> {
127
1
        let mut repl = Repl::new()
?0
;
128
1
        let result = repl.eval(r#"println("test")"#)
?0
;
129
1
        assert_eq!(result, "");
130
131
        // Test that we can assign function call results
132
1
        let result = repl.eval(r#"let result = println("assign test")"#)
?0
;
133
1
        assert_eq!(result, "");
134
1
        Ok(())
135
1
    }
136
137
    /// Test function calls work in expressions
138
    #[test]
139
1
    fn test_function_calls_in_expressions() -> Result<()> {
140
1
        let mut repl = Repl::new()
?0
;
141
        // Function calls in if expressions
142
1
        let result =
143
1
            repl.eval(r#"if true { println("true branch") } else { println("false branch") }"#)
?0
;
144
1
        assert_eq!(result, "");
145
1
        Ok(())
146
1
    }
147
148
    /// Property-based test: all function calls should return unit
149
    #[test]
150
1
    fn test_property_all_builtin_calls_return_unit() -> Result<()> {
151
1
        let mut repl = Repl::new()
?0
;
152
1
        let builtin_calls = vec![
153
            r#"println("test")"#,
154
1
            r#"print("test")"#,
155
1
            r"println(42)",
156
1
            r"print(3.14)",
157
1
            r"println(true)",
158
1
            r"print(false)",
159
        ];
160
161
7
        for 
call6
in builtin_calls {
162
6
            let result = repl.eval(call)
?0
;
163
6
            assert_eq!(result, "", 
"Function call {call} should return unit"0
);
164
        }
165
1
        Ok(())
166
1
    }
167
168
    /// Test memory bounds with function calls
169
    #[test]
170
1
    fn test_function_call_memory_bounds() -> Result<()> {
171
1
        let mut repl = Repl::new()
?0
;
172
        // Test with large string arguments
173
1
        let large_string = "x".repeat(1000);
174
1
        let call = format!(r#"println("{large_string}")"#);
175
1
        let result = repl.eval(&call)
?0
;
176
1
        assert_eq!(result, "");
177
1
        Ok(())
178
1
    }
179
}
180
181
#[cfg(test)]
182
#[allow(clippy::panic)] // Tests may panic on failure
183
#[allow(clippy::expect_used)] // Tests use expect for error messages
184
mod property_tests {
185
    use super::super::*;
186
    use anyhow::Result;
187
188
    /// Property-like test: All builtin function calls should return unit type
189
    #[test]
190
1
    fn test_builtin_calls_always_return_unit() -> Result<()> {
191
1
        let mut repl = Repl::new()
?0
;
192
193
1
        let test_cases = vec![
194
            "println()",
195
1
            "println(42)",
196
1
            "println(\"test\")",
197
1
            "println(true)",
198
1
            "println(1, 2, 3)",
199
1
            "print(\"hello\")",
200
1
            "print(42, \"world\")",
201
        ];
202
203
8
        for 
call7
in test_cases {
204
7
            let result = repl.eval(call)
?0
;
205
7
            assert_eq!(result, "", 
"Function call '{call}' should return unit (suppressed)"0
);
206
        }
207
1
        Ok(())
208
1
    }
209
210
    /// Property-like test: Function calls work with various expression types
211
    #[test]
212
1
    fn test_function_calls_with_different_expressions() -> Result<()> {
213
1
        let mut repl = Repl::new()
?0
;
214
1
        repl.eval("let x = 10")
?0
;
215
1
        repl.eval("let y = 20")
?0
;
216
217
1
        let test_cases = vec![
218
            "println(x + y)",
219
1
            "println(x * y, x - y)",
220
1
            "println(x > y, x < y)",
221
1
            "println(x == 10 && y == 20)",
222
1
            "print(\"Result: \", x + y * 2)",
223
        ];
224
225
6
        for 
call5
in test_cases {
226
5
            let result = repl.eval(call)
?0
;
227
5
            assert_eq!(result, "", 
"Expression call '{call}' should return unit"0
);
228
        }
229
1
        Ok(())
230
1
    }
231
232
    /// Property-like test: Function calls handle edge cases correctly
233
    #[test]
234
1
    fn test_function_call_edge_cases() -> Result<()> {
235
1
        let mut repl = Repl::new()
?0
;
236
237
        // Empty arguments
238
1
        let result = repl.eval("println()")
?0
;
239
1
        assert_eq!(result, "");
240
241
        // Single arguments of each type
242
1
        let result = repl.eval("println(42)")
?0
;
243
1
        assert_eq!(result, "");
244
245
1
        let result = repl.eval("println(3.14)")
?0
;
246
1
        assert_eq!(result, "");
247
248
1
        let result = repl.eval(r#"println("string")"#)
?0
;
249
1
        assert_eq!(result, "");
250
251
1
        let result = repl.eval("println(true)")
?0
;
252
1
        assert_eq!(result, "");
253
254
1
        Ok(())
255
1
    }
256
257
    /// Property-like test: print and println have consistent return types
258
    #[test]
259
1
    fn test_print_vs_println_consistency() -> Result<()> {
260
1
        let mut repl = Repl::new()
?0
;
261
262
1
        let args_list = vec![r#""hello""#, "42", "true", r#""a", "b", "c""#, "1, 2, 3"];
263
264
6
        for 
args5
in args_list {
265
5
            let print_call = format!("print({args})");
266
5
            let println_call = format!("println({args})");
267
268
5
            let print_result = repl.eval(&print_call)
?0
;
269
5
            let println_result = repl.eval(&println_call)
?0
;
270
271
5
            assert_eq!(print_result, "", 
"print({args}) should return unit"0
);
272
5
            assert_eq!(println_result, "", 
"println({args}) should return unit"0
);
273
5
            assert_eq!(
274
                print_result, println_result,
275
0
                "print and println should have same return type"
276
            );
277
        }
278
279
1
        Ok(())
280
1
    }
281
}