use quickcheck::{quickcheck, TestResult};
use bfir::AstNode;
use execution::{execute_with_state, ExecutionState};
use execution::Outcome::*;
use peephole::*;
fn transform_is_sound<F>(instrs: Vec<AstNode>, transform: F, check_cells: bool, dummy_read_value: Option<i8>) -> TestResult
where F: Fn(Vec<AstNode>) -> Vec<AstNode>
{
let max_steps = 1000;
let mut state = ExecutionState::initial(&instrs[..]);
let result = execute_with_state(&instrs[..], &mut state, max_steps, dummy_read_value);
match result {
RuntimeError(_) | OutOfSteps => return TestResult::discard(),
_ => (),
}
let optimised_instrs = transform(instrs.clone());
let mut state2 = ExecutionState::initial(&instrs[..]);
let result2 = execute_with_state(&optimised_instrs[..], &mut state2, max_steps, dummy_read_value);
match (result, result2) {
(Completed(_), Completed(_)) => (),
(ReachedRuntimeValue, ReachedRuntimeValue) => (),
(_, _) => {
println!("Optimised program did not terminate properly!");
return TestResult::failed();
}
}
if state.outputs != state2.outputs {
println!("Different outputs! Original outputs: {:?} Optimised: {:?}",
state.outputs, state2.outputs);
return TestResult::failed();
}
if check_cells {
if state.cells != state2.cells {
println!("Different cell states! Optimised state: {:?} Optimised: {:?}",
state.cells, state2.cells);
return TestResult::failed();
}
}
TestResult::passed()
}
#[test]
fn combine_increments_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, combine_increments, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn combine_ptr_increments_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, combine_ptr_increments, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn annotate_known_zero_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, annotate_known_zero, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn extract_multiply_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, extract_multiply, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn simplify_loops_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, zeroing_loops, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn combine_set_and_increments_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, combine_set_and_increments, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn remove_dead_loops_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, remove_dead_loops, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn remove_redundant_sets_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, remove_redundant_sets, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn combine_before_read_is_sound() {
fn is_sound(instrs: Vec<AstNode>, read_value: Option<i8>) -> TestResult {
transform_is_sound(instrs, remove_read_clobber, false, read_value)
}
quickcheck(is_sound as fn(Vec<AstNode>, Option<i8>) -> TestResult)
}
#[test]
fn remove_pure_code_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, |instrs| remove_pure_code(instrs).0, false, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn sort_by_offset_is_sound() {
fn is_sound(instrs: Vec<AstNode>) -> TestResult {
transform_is_sound(instrs, sort_by_offset, true, None)
}
quickcheck(is_sound as fn(Vec<AstNode>) -> TestResult)
}
#[test]
fn test_overall_optimize_is_sound() {
fn optimize_ignore_warnings(instrs: Vec<AstNode>) -> Vec<AstNode> {
optimize(instrs, &None).0
}
fn optimizations_sound_together(instrs: Vec<AstNode>, read_value: Option<i8>) -> TestResult {
transform_is_sound(instrs, optimize_ignore_warnings, false, read_value)
}
quickcheck(optimizations_sound_together as fn(Vec<AstNode>, Option<i8>) -> TestResult);
}