#![allow(unused_imports)]
use super::opcode::*;
use crate::code::definitions;
use crate::code::definitions::Instructions;
#[test]
fn test_opcode_order() {
for code in 0..(Opcode::Invalid as usize) {
let op = Opcode::from(code as u8);
assert_eq!(code, op as usize, "u8 to opcode conversion failed");
}
}
#[test]
fn test_make() {
let tests: Vec<(Opcode, Vec<usize>, Vec<u8>)> = vec![
(
Opcode::Constant,
vec![65534],
vec![Opcode::Constant as u8, 255, 254],
),
(
Opcode::GetLocal,
vec![255],
vec![Opcode::GetLocal as u8, 255],
),
(Opcode::Add, vec![0], vec![Opcode::Add as u8]),
(
Opcode::Closure,
vec![65534, 255],
vec![Opcode::Closure as u8, 255, 254, 255],
),
];
for (op, operands, expected) in tests {
let instruction = definitions::make(op, &operands, 1);
assert_eq!(
instruction.len(),
expected.len(),
"instruction has wrong length. want={}, got={}",
expected.len(),
instruction.len()
);
for (i, &b) in expected.iter().enumerate() {
assert_eq!(
instruction.code[i], b,
"wrong byte at pos {}. want={}, got={}",
i, b, instruction.code[i]
);
}
}
}
#[cfg(test)]
fn concat_instructions(s: &[Instructions]) -> Instructions {
let mut out = Instructions::default();
for ins in s {
out.code.extend_from_slice(&ins.code);
}
out
}
#[test]
fn test_instructions_string() {
let instructions = vec![
definitions::make(Opcode::Add, &[], 1),
definitions::make(Opcode::GetLocal, &[1], 1),
definitions::make(Opcode::Constant, &[2], 1),
definitions::make(Opcode::Constant, &[65535], 1),
definitions::make(Opcode::Closure, &[65535, 255], 1),
];
let expected = "\
0000 OpAdd\n\
0001 OpGetLocal 1\n\
0003 OpConstant 2\n\
0006 OpConstant 65535\n\
0009 OpClosure 65535 255\n";
let concatted = concat_instructions(&instructions);
assert_eq!(concatted.to_string(), expected);
}
#[test]
fn test_read_operands() {
let tests = vec![
(Opcode::GetLocal, vec![255], 1),
(Opcode::Constant, vec![65535], 2),
];
for (op, operands, bytes_read) in tests {
let instruction = definitions::make(op, &operands, 1);
let def = definitions::lookup(instruction.code[0] as u8).unwrap();
let (operands_read, n) = definitions::read_operands(def, &instruction.code[1..]);
assert_eq!(n, bytes_read, "n is wrong");
for (i, want) in operands.iter().enumerate() {
assert_eq!(operands_read[i], *want);
}
}
}