diff options
Diffstat (limited to 'src/eval/test.rs')
-rw-r--r-- | src/eval/test.rs | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/eval/test.rs b/src/eval/test.rs new file mode 100644 index 0000000..83749e0 --- /dev/null +++ b/src/eval/test.rs | |||
@@ -0,0 +1,371 @@ | |||
1 | use super::*; | ||
2 | use crate::ast::*; | ||
3 | use std::io::Write; | ||
4 | use expect_test::{expect, Expect}; | ||
5 | |||
6 | fn gen_test(file: &str, program: &str, expected: Expect) { | ||
7 | let language = tree_sitter_python::language(); | ||
8 | let mut parser = tree_sitter::Parser::new(); | ||
9 | let _ = parser.set_language(&language); | ||
10 | let tree = parser.parse(file, None).unwrap(); | ||
11 | let program = ast::Program::new().with_file(program).unwrap(); | ||
12 | |||
13 | let mut output = Vec::new(); | ||
14 | let result; | ||
15 | |||
16 | { | ||
17 | let mut ctx = Context::new(language) | ||
18 | .with_input(file.to_owned()) | ||
19 | .with_tree(tree) | ||
20 | .with_program(program) | ||
21 | .with_output_stream(Box::new(&mut output) as Box<dyn io::Write>); | ||
22 | |||
23 | result = ctx.eval(); | ||
24 | } | ||
25 | |||
26 | if let Err(e) = result { | ||
27 | writeln!(output, "{e:?}").unwrap(); | ||
28 | } | ||
29 | expected.assert_eq(&String::from_utf8(output).unwrap()) | ||
30 | } | ||
31 | |||
32 | #[test] | ||
33 | fn bin() { | ||
34 | let language = tree_sitter_python::language(); | ||
35 | let mut ctx = Context::new(language).with_program(Program::new()); | ||
36 | assert_eq!( | ||
37 | ctx.eval_expr(&Expr::bin(Expr::int(5), "+", Expr::int(10),)), | ||
38 | Ok(Value::Integer(15)) | ||
39 | ); | ||
40 | assert_eq!( | ||
41 | ctx.eval_expr(&Expr::bin(Expr::int(5), "==", Expr::int(10),)), | ||
42 | Ok(Value::Boolean(false)) | ||
43 | ); | ||
44 | assert_eq!( | ||
45 | ctx.eval_expr(&Expr::bin(Expr::int(5), "<", Expr::int(10),)), | ||
46 | Ok(Value::Boolean(true)) | ||
47 | ); | ||
48 | assert_eq!( | ||
49 | ctx.eval_expr(&Expr::bin( | ||
50 | Expr::bin(Expr::int(5), "<", Expr::int(10),), | ||
51 | "&&", | ||
52 | Expr::false_(), | ||
53 | )), | ||
54 | Ok(Value::Boolean(false)) | ||
55 | ); | ||
56 | } | ||
57 | |||
58 | #[test] | ||
59 | fn test_evaluate_blocks() { | ||
60 | let language = tree_sitter_python::language(); | ||
61 | let mut ctx = Context::new(language).with_program(Program::new()); | ||
62 | assert_eq!( | ||
63 | ctx.eval_block(&Block { | ||
64 | body: vec![ | ||
65 | Statement::Declaration(Declaration { | ||
66 | ty: Type::Integer, | ||
67 | name: "a".to_owned(), | ||
68 | init: None, | ||
69 | }), | ||
70 | Statement::Bare(Expr::bin(Expr::ident("a"), "+=", Expr::int(5),)), | ||
71 | ] | ||
72 | }), | ||
73 | Ok(Value::Unit) | ||
74 | ); | ||
75 | assert_eq!( | ||
76 | ctx.lookup(&String::from("a")).unwrap().clone(), | ||
77 | Variable { | ||
78 | ty: Type::Integer, | ||
79 | name: "a".to_owned(), | ||
80 | value: Value::Integer(5) | ||
81 | } | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | #[test] | ||
86 | fn test_evaluate_if() { | ||
87 | let language = tree_sitter_python::language(); | ||
88 | let mut ctx = Context::new(language).with_program(Program::new()); | ||
89 | assert_eq!( | ||
90 | ctx.eval_block(&Block { | ||
91 | body: vec![ | ||
92 | Statement::Declaration(Declaration { | ||
93 | ty: Type::Integer, | ||
94 | name: "a".to_owned(), | ||
95 | init: Some(Expr::int(1).boxed()), | ||
96 | }), | ||
97 | Statement::Bare(Expr::If(IfExpr { | ||
98 | condition: Expr::true_().boxed(), | ||
99 | then: Block { | ||
100 | body: vec![Statement::Bare(Expr::bin( | ||
101 | Expr::Ident("a".to_owned()), | ||
102 | "+=", | ||
103 | Expr::int(5), | ||
104 | ))] | ||
105 | }, | ||
106 | else_: Block { | ||
107 | body: vec![Statement::Bare(Expr::bin( | ||
108 | Expr::ident("a"), | ||
109 | "+=", | ||
110 | Expr::int(10), | ||
111 | ))] | ||
112 | } | ||
113 | })) | ||
114 | ] | ||
115 | }), | ||
116 | Ok(Value::Unit) | ||
117 | ); | ||
118 | assert_eq!( | ||
119 | ctx.lookup(&String::from("a")).unwrap().clone(), | ||
120 | Variable { | ||
121 | ty: Type::Integer, | ||
122 | name: "a".to_owned(), | ||
123 | value: Value::Integer(6) | ||
124 | } | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
129 | fn test_substring() { | ||
130 | let language = tree_sitter_python::language(); | ||
131 | let mut ctx = Context::new(language).with_program(Program::new()); | ||
132 | assert_eq!( | ||
133 | ctx.eval_block(&Block { | ||
134 | body: vec![ | ||
135 | Statement::Declaration(Declaration { | ||
136 | ty: Type::String, | ||
137 | name: "a".to_owned(), | ||
138 | init: Some(Expr::str("foobar").boxed()), | ||
139 | }), | ||
140 | Statement::Declaration(Declaration { | ||
141 | ty: Type::String, | ||
142 | name: "b".to_owned(), | ||
143 | init: Some( | ||
144 | Expr::call( | ||
145 | "substr", | ||
146 | [Expr::Ident("a".to_owned()), Expr::int(0), Expr::int(3),] | ||
147 | ) | ||
148 | .boxed() | ||
149 | ), | ||
150 | }), | ||
151 | ] | ||
152 | }), | ||
153 | Ok(Value::Unit) | ||
154 | ); | ||
155 | assert_eq!( | ||
156 | ctx.lookup(&String::from("b")).unwrap().clone(), | ||
157 | Variable { | ||
158 | ty: Type::String, | ||
159 | name: "b".to_owned(), | ||
160 | value: "foo".into() | ||
161 | } | ||
162 | ); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn test_list() { | ||
167 | let language = tree_sitter_python::language(); | ||
168 | let mut ctx = Context::new(language).with_program(Program::new()); | ||
169 | assert_eq!( | ||
170 | ctx.eval_block(&Block { | ||
171 | body: vec![Statement::Declaration(Declaration { | ||
172 | ty: Type::List, | ||
173 | name: "a".to_owned(), | ||
174 | init: Some( | ||
175 | Expr::List(List { | ||
176 | items: vec![Expr::int(5)] | ||
177 | }) | ||
178 | .boxed() | ||
179 | ), | ||
180 | }),] | ||
181 | }), | ||
182 | Ok(Value::Unit) | ||
183 | ); | ||
184 | assert_eq!( | ||
185 | ctx.lookup(&String::from("a")).unwrap().clone(), | ||
186 | Variable { | ||
187 | ty: Type::List, | ||
188 | name: "a".to_owned(), | ||
189 | value: vec![5usize.into()].into(), | ||
190 | } | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn list_1() { | ||
196 | gen_test( | ||
197 | "", | ||
198 | "BEGIN { | ||
199 | list a = [5]; | ||
200 | print(a); | ||
201 | } | ||
202 | ", | ||
203 | expect!["[5]"], | ||
204 | ); | ||
205 | } | ||
206 | |||
207 | #[test] | ||
208 | fn list_2() { | ||
209 | gen_test( | ||
210 | "", | ||
211 | "BEGIN { | ||
212 | list a = [5, 4, 3]; | ||
213 | print(length(a)); | ||
214 | } | ||
215 | ", | ||
216 | expect!["3"], | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn list_3() { | ||
222 | gen_test( | ||
223 | "", | ||
224 | r#"BEGIN { | ||
225 | list a = [5, 4, 3]; | ||
226 | print(member(a, 3)); | ||
227 | print(", "); | ||
228 | print(member(a, 6)); | ||
229 | } | ||
230 | "#, | ||
231 | expect!["true, false"], | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn list_4() { | ||
237 | gen_test( | ||
238 | "", | ||
239 | r#"BEGIN { | ||
240 | list a = [5]; | ||
241 | println(a); | ||
242 | push(a, 4); | ||
243 | println(a); | ||
244 | push(a, 3); | ||
245 | println(a); | ||
246 | pop(a); | ||
247 | println(a); | ||
248 | pop(a); | ||
249 | println(a); | ||
250 | } | ||
251 | "#, | ||
252 | expect![[r#" | ||
253 | [5] | ||
254 | [5, 4] | ||
255 | [5, 4, 3] | ||
256 | [5, 4] | ||
257 | [5] | ||
258 | "#]], | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn list_5() { | ||
264 | gen_test( | ||
265 | "", | ||
266 | r#"BEGIN { | ||
267 | list a = [5]; | ||
268 | println(isempty(a)); | ||
269 | pop(a); | ||
270 | println(isempty(a)); | ||
271 | } | ||
272 | "#, | ||
273 | expect![[r#" | ||
274 | false | ||
275 | true | ||
276 | "#]], | ||
277 | ); | ||
278 | } | ||
279 | |||
280 | #[test] | ||
281 | fn string_1() { | ||
282 | gen_test( | ||
283 | "", | ||
284 | r#"BEGIN { | ||
285 | string a = "Foo"; | ||
286 | println(toupper(a)); | ||
287 | println(tolower(a)); | ||
288 | } | ||
289 | "#, | ||
290 | expect![[r#" | ||
291 | FOO | ||
292 | foo | ||
293 | "#]], | ||
294 | ); | ||
295 | } | ||
296 | |||
297 | #[test] | ||
298 | fn string_2() { | ||
299 | gen_test( | ||
300 | "", | ||
301 | r#"BEGIN { | ||
302 | string a = "foo"; | ||
303 | println(a, " is upper? ", isupper(a)); | ||
304 | println(a, " is lower? ", islower(a)); | ||
305 | |||
306 | string b = "Foo"; | ||
307 | println(b, " is upper? ", isupper(b)); | ||
308 | println(b, " is lower? ", islower(b)); | ||
309 | |||
310 | string c = "FOO"; | ||
311 | println(c, " is upper? ", isupper(c)); | ||
312 | println(c, " is lower? ", islower(c)); | ||
313 | } | ||
314 | "#, | ||
315 | expect![[r#" | ||
316 | foo is upper? false | ||
317 | foo is lower? true | ||
318 | Foo is upper? false | ||
319 | Foo is lower? false | ||
320 | FOO is upper? true | ||
321 | FOO is lower? false | ||
322 | "#]], | ||
323 | ); | ||
324 | } | ||
325 | |||
326 | #[test] | ||
327 | fn string_3() { | ||
328 | gen_test( | ||
329 | "", | ||
330 | r#"BEGIN { | ||
331 | string a = "foo bar baz"; | ||
332 | println("a[3:5]: `", substr(a, 3, 5), "`"); | ||
333 | println("a[2:9]: `", substr(a, 2, 9), "`"); | ||
334 | } | ||
335 | "#, | ||
336 | expect![[r#" | ||
337 | a[3:5]: ` b` | ||
338 | a[2:9]: `o bar b` | ||
339 | "#]], | ||
340 | ); | ||
341 | } | ||
342 | |||
343 | #[test] | ||
344 | fn string_4() { | ||
345 | gen_test( | ||
346 | "", | ||
347 | r#"BEGIN { | ||
348 | string a = "foo bar baz"; | ||
349 | println("a[9:20]: `", substr(a, 9, 20), "`"); | ||
350 | } | ||
351 | "#, | ||
352 | expect![[r#" | ||
353 | a[9:20]: `InvalidStringSlice { length: 11, start: 9, end: 20 } | ||
354 | "#]], | ||
355 | ); | ||
356 | } | ||
357 | |||
358 | #[test] | ||
359 | fn node_1() { | ||
360 | gen_test( | ||
361 | "def foo(a, b): hello()", | ||
362 | r#"enter function_definition { | ||
363 | println(text(node)); | ||
364 | println(text(node.name)); | ||
365 | }"#, | ||
366 | expect![[r#" | ||
367 | def foo(a, b): hello() | ||
368 | foo | ||
369 | "#]], | ||
370 | ); | ||
371 | } | ||