DEV: DSL for table based testing using macros.

This commit is contained in:
Jeremy Wall 2019-07-08 20:11:19 -05:00
parent 3bb6f6e8eb
commit aac263be2c

View File

@ -22,32 +22,48 @@ use super::Primitive::{Bool, Float, Int, Str};
use super::Value::{C, P, T}; use super::Value::{C, P, T};
use super::VM; use super::VM;
macro_rules! assert_cases {
(__impl__ $cases:expr) => {
for case in $cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
};
(($input:expr, $result:expr), $($tok:tt)*) => {
assert_cases!(__impl__ vec![($input, $result), $($tok)*])
};
($($input:expr => $result:expr, )* ) => {
assert_cases!(
$(($input, $result),)*
)
}
}
#[test] #[test]
fn test_math_ops() { fn test_math_ops() {
let mut cases = vec![ assert_cases!(
// 1+1; // 1+1;
(vec![Val(Int(1)), Val(Int(1)), Add], P(Int(2))), vec![Val(Int(1)), Val(Int(1)), Add] => P(Int(2)),
// 1-1; // 1-1;
(vec![Val(Int(1)), Val(Int(1)), Sub], P(Int(0))), vec![Val(Int(1)), Val(Int(1)), Sub] => P(Int(0)),
// 2*2; // 2*2;
(vec![Val(Int(2)), Val(Int(2)), Mul], P(Int(4))), vec![Val(Int(2)), Val(Int(2)), Mul] => P(Int(4)),
// 6/3; // 6/3;
(vec![Val(Int(2)), Val(Int(6)), Div], P(Int(3))), vec![Val(Int(2)), Val(Int(6)), Div] => P(Int(3)),
// 1.0+1.0; // 1.0+1.0;
(vec![Val(Float(1.0)), Val(Float(1.0)), Add], P(Float(2.0))), vec![Val(Float(1.0)), Val(Float(1.0)), Add] => P(Float(2.0)),
// 1.0-1.0; // 1.0-1.0;
(vec![Val(Float(1.0)), Val(Float(1.0)), Sub], P(Float(0.0))), vec![Val(Float(1.0)), Val(Float(1.0)), Sub] => P(Float(0.0)),
// 2.0*2.0; // 2.0*2.0;
(vec![Val(Float(2.0)), Val(Float(2.0)), Mul], P(Float(4.0))), vec![Val(Float(2.0)), Val(Float(2.0)), Mul] => P(Float(4.0)),
// 6.0/3.0; // 6.0/3.0;
(vec![Val(Float(2.0)), Val(Float(6.0)), Div], P(Float(3.0))), vec![Val(Float(2.0)), Val(Float(6.0)), Div] => P(Float(3.0)),
// string concatenation // string concatenation
( vec![Val(Str("bar".to_owned())), Val(Str("foo".to_owned())), Add] => P(Str("foobar".to_owned())),
vec![Val(Str("bar".to_owned())), Val(Str("foo".to_owned())), Add],
P(Str("foobar".to_owned())),
),
// Composite operations // Composite operations
(
vec![ vec![
Val(Int(1)), Val(Int(1)),
Val(Int(1)), Val(Int(1)),
@ -56,15 +72,8 @@ fn test_math_ops() {
Add, // 2 + 1 Add, // 2 + 1
Val(Int(1)), Val(Int(1)),
Add, // 3 + 1 Add, // 3 + 1
], ] => P(Int(4)),
P(Int(4)), );
),
];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
@ -87,17 +96,10 @@ fn test_bind_op() {
#[test] #[test]
fn test_list_ops() { fn test_list_ops() {
let mut cases = vec![ assert_cases!(
(vec![InitList], C(List(Vec::new()))), vec![InitList] => C(List(Vec::new())),
( vec![InitList, Val(Int(1)), Element] => C(List(vec![P(Int(1))])),
vec![InitList, Val(Int(1)), Element], vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element] => C(List(vec![P(Int(2)), P(Int(1))])),
C(List(vec![P(Int(1))])),
),
(
vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element],
C(List(vec![P(Int(2)), P(Int(1))])),
),
(
vec![ vec![
InitList, InitList,
Val(Int(1)), Val(Int(1)),
@ -106,26 +108,15 @@ fn test_list_ops() {
Val(Int(1)), Val(Int(1)),
Add, Add,
Element, Element,
], ] => C(List(vec![P(Int(1)), P(Int(2))])),
C(List(vec![P(Int(1)), P(Int(2))])), );
),
];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_tuple_ops() { fn test_tuple_ops() {
let mut cases = vec![ assert_cases!(
(vec![InitTuple], C(Tuple(Vec::new()))), vec![InitTuple] => C(Tuple(Vec::new())),
( vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), Field] => C(Tuple(vec![("foo".to_owned(), P(Int(1)))])),
vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), Field],
C(Tuple(vec![("foo".to_owned(), P(Int(1)))])),
),
(
vec![ vec![
InitTuple, InitTuple,
Sym("bar".to_owned()), Sym("bar".to_owned()),
@ -134,13 +125,10 @@ fn test_tuple_ops() {
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Val(Int(1)), Val(Int(1)),
Field, Field,
], ] => C(Tuple(vec![
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(1))), ("foo".to_owned(), P(Int(1))),
])), ])),
),
(
vec![ vec![
InitTuple, InitTuple,
Sym("bar".to_owned()), Sym("bar".to_owned()),
@ -152,13 +140,10 @@ fn test_tuple_ops() {
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Val(Int(2)), Val(Int(2)),
Field, Field,
], ] => C(Tuple(vec![
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), P(Int(2))),
])), ])),
),
(
vec![ vec![
InitTuple, InitTuple,
Sym("bar".to_owned()), Sym("bar".to_owned()),
@ -172,13 +157,10 @@ fn test_tuple_ops() {
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Val(Int(2)), Val(Int(2)),
Field, Field,
], ] => C(Tuple(vec![
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), P(Int(2))),
])), ])),
),
(
vec![ vec![
InitTuple, // Override tuple InitTuple, // Override tuple
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
@ -194,64 +176,39 @@ fn test_tuple_ops() {
Val(Int(1)), Val(Int(1)),
Field, Field,
Cp, // Do the tuple copy operation Cp, // Do the tuple copy operation
], ] => C(Tuple(vec![
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), P(Int(2))),
])), ])),
), );
];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_jump_ops() { fn test_jump_ops() {
let mut cases = vec![ assert_cases!(
(vec![InitThunk(1), Val(Int(1)), Noop], T(0)), vec![InitThunk(1), Val(Int(1)), Noop] => T(0),
(vec![Jump(1), Val(Int(1)), Noop, Val(Int(1))], P(Int(1))), vec![Jump(1), Val(Int(1)), Noop, Val(Int(1))] => P(Int(1)),
]; );
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_equality_ops() { fn test_equality_ops() {
let mut cases = vec![ assert_cases![
(
vec![ vec![
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Equal, Equal,
], ] => P(Bool(true)),
P(Bool(true)),
),
(
vec![ vec![
Val(Str("bar".to_owned())), Val(Str("bar".to_owned())),
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Equal, Equal,
], ] => P(Bool(false)),
P(Bool(false)), vec![Val(Int(1)), Val(Int(1)), Equal] => P(Bool(true)),
), vec![Val(Int(1)), Val(Int(2)), Equal] => P(Bool(false)),
(vec![Val(Int(1)), Val(Int(1)), Equal], P(Bool(true))), vec![Val(Bool(true)), Val(Bool(true)), Equal] => P(Bool(true)),
(vec![Val(Int(1)), Val(Int(2)), Equal], P(Bool(false))), vec![Val(Bool(false)), Val(Bool(false)), Equal] => P(Bool(true)),
(vec![Val(Bool(true)), Val(Bool(true)), Equal], P(Bool(true))), vec![Val(Bool(true)), Val(Bool(false)), Equal] => P(Bool(false)),
(
vec![Val(Bool(false)), Val(Bool(false)), Equal],
P(Bool(true)),
),
(
vec![Val(Bool(true)), Val(Bool(false)), Equal],
P(Bool(false)),
),
(
vec![ vec![
InitTuple, InitTuple,
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
@ -262,10 +219,7 @@ fn test_equality_ops() {
Val(Int(1)), Val(Int(1)),
Field, Field,
Equal, Equal,
], ] => P(Bool(true)),
P(Bool(true)),
),
(
vec![ vec![
InitTuple, InitTuple,
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
@ -276,10 +230,7 @@ fn test_equality_ops() {
Val(Int(1)), Val(Int(1)),
Field, Field,
Equal, Equal,
], ] => P(Bool(false)),
P(Bool(false)),
),
(
vec![ vec![
InitList, InitList,
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
@ -288,10 +239,7 @@ fn test_equality_ops() {
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
Element, Element,
Equal, Equal,
], ] => P(Bool(true)),
P(Bool(true)),
),
(
vec![ vec![
InitList, InitList,
Val(Str("foo".to_owned())), Val(Str("foo".to_owned())),
@ -300,21 +248,13 @@ fn test_equality_ops() {
Val(Str("bar".to_owned())), Val(Str("bar".to_owned())),
Element, Element,
Equal, Equal,
], ] => P(Bool(false)),
P(Bool(false)),
),
]; ];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_conditional_jump_ops() { fn test_conditional_jump_ops() {
let mut cases = vec![ assert_cases![
(
vec![ vec![
Val(Bool(false)), Val(Bool(false)),
JumpIfTrue(2), JumpIfTrue(2),
@ -324,10 +264,7 @@ fn test_conditional_jump_ops() {
Jump(1), Jump(1),
Val(Int(2)), Val(Int(2)),
Noop, Noop,
], ] => P(Int(2)),
P(Int(2)),
),
(
vec![ vec![
Val(Bool(true)), Val(Bool(true)),
JumpIfTrue(2), JumpIfTrue(2),
@ -337,10 +274,7 @@ fn test_conditional_jump_ops() {
Jump(1), Jump(1),
Val(Int(2)), Val(Int(2)),
Noop, Noop,
], ] => P(Int(1)),
P(Int(1)),
),
(
vec![ vec![
Val(Int(1)), Val(Int(1)),
Val(Int(1)), Val(Int(1)),
@ -352,10 +286,7 @@ fn test_conditional_jump_ops() {
Jump(1), Jump(1),
Val(Int(2)), Val(Int(2)),
Noop, Noop,
], ] => P(Int(1)),
P(Int(1)),
),
(
vec![ vec![
Val(Int(1)), Val(Int(1)),
Val(Int(2)), Val(Int(2)),
@ -367,21 +298,13 @@ fn test_conditional_jump_ops() {
Jump(1), Jump(1),
Val(Int(2)), Val(Int(2)),
Noop, Noop,
], ] => P(Int(1)),
P(Int(1)),
),
]; ];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_function_definition_and_call() { fn test_function_definition_and_call() {
let mut cases = vec![ assert_cases![
(
vec![ vec![
Sym("f".to_owned()), // 0 Sym("f".to_owned()), // 0
InitList, // 1 InitList, // 1
@ -394,10 +317,7 @@ fn test_function_definition_and_call() {
Val(Int(1)), // 8 Val(Int(1)), // 8
DeRef("f".to_owned()), // 9 DeRef("f".to_owned()), // 9
FCall, // 10 FCall, // 10
], ] => P(Int(1)),
P(Int(1)),
),
(
vec![ vec![
Sym("closed".to_owned()), // 0 Sym("closed".to_owned()), // 0
Val(Int(1)), // 1 Val(Int(1)), // 1
@ -415,21 +335,13 @@ fn test_function_definition_and_call() {
Val(Int(1)), // 13 Val(Int(1)), // 13
DeRef("f".to_owned()), // 14 DeRef("f".to_owned()), // 14
FCall, // 16 FCall, // 16
], ] => P(Int(2)),
P(Int(2)),
),
]; ];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]
fn test_module_call() { fn test_module_call() {
let mut cases = vec![ assert_cases![
(
vec![ vec![
InitTuple, // 0 // override tuple InitTuple, // 0 // override tuple
Sym("one".to_owned()), // 1 Sym("one".to_owned()), // 1
@ -452,16 +364,13 @@ fn test_module_call() {
Bind, // 18 // bind module to the binding name Bind, // 18 // bind module to the binding name
DeRef("m".to_owned()), // 19 DeRef("m".to_owned()), // 19
Cp, // 20 Cp, // 20
], ] => C(Tuple(vec![(
C(Tuple(vec![(
"foo".to_owned(), "foo".to_owned(),
C(Tuple(vec![ C(Tuple(vec![
("one".to_owned(), P(Int(11))), ("one".to_owned(), P(Int(11))),
("two".to_owned(), P(Int(2))), ("two".to_owned(), P(Int(2))),
])), ])),
)])), )])),
),
(
vec![ vec![
InitTuple, // 0 // override tuple InitTuple, // 0 // override tuple
Sym("one".to_owned()), // 1 Sym("one".to_owned()), // 1
@ -487,15 +396,8 @@ fn test_module_call() {
Bind, // 21 // bind module to the binding name Bind, // 21 // bind module to the binding name
DeRef("m".to_owned()), // 22 DeRef("m".to_owned()), // 22
Cp, // 23 Cp, // 23
], ] => P(Int(1)),
P(Int(1)),
),
]; ];
for case in cases.drain(0..) {
let mut vm = VM::new(&case.0);
vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
} }
#[test] #[test]