use super::*;
fn lines(s: &[&str]) -> Vec<String> {
s.iter().map(|l| l.to_string()).collect()
}
#[test]
fn push_add() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["push 1", "push 2", "add"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![3]);
}
#[test]
fn dup_swap() {
let mut s = StackState::new(vec![10, 20]);
s.execute(&lines(&["dup 1", "swap 1"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![10, 10, 20]);
}
#[test]
fn underflow_is_error() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["add"]));
assert!(!s.is_valid());
}
#[test]
fn goldilocks_arithmetic() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["push 18446744069414584320", "push 1", "add"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![0]); }
#[test]
fn mul_field() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["push 3", "push 5", "mul"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![15]);
}
#[test]
fn split_instruction() {
let mut s = StackState::new(vec![]);
let val = 3u64 * (1u64 << 32) + 5;
s.stack.push(val);
s.execute(&lines(&["split"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![3, 5]); }
#[test]
fn eq_comparison() {
let mut s = StackState::new(vec![42, 42]);
s.execute(&lines(&["eq"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![1]);
let mut s2 = StackState::new(vec![42, 43]);
s2.execute(&lines(&["eq"]));
assert!(s2.is_valid());
assert_eq!(s2.stack, vec![0]);
}
#[test]
fn negative_push() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["push 5", "push -1", "add"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![4]);
}
#[test]
fn control_flow_is_error() {
let mut s = StackState::new(vec![1]);
s.execute(&lines(&["skiz"]));
assert!(!s.is_valid());
}
#[test]
fn comments_and_labels_ignored() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["// comment", "__label:", "push 1", ""]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![1]);
}
#[test]
fn verify_equivalent_same() {
let baseline = lines(&["push 1", "push 2", "add"]);
let candidate = lines(&["push 3"]); assert!(verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn verify_equivalent_different() {
let baseline = lines(&["push 1", "push 2", "add"]);
let candidate = lines(&["push 4"]); assert!(!verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn verify_with_stack_input() {
let baseline = lines(&["dup 0", "dup 2", "add"]);
let candidate = lines(&["dup 0", "dup 2", "add"]);
assert!(verify_equivalent(&baseline, &candidate, 123));
}
#[test]
fn pow_instruction() {
let mut s = StackState::new(vec![]);
s.execute(&lines(&["push 2", "push 10", "pow"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![1024]); }
#[test]
fn pop_count_instruction() {
let mut s = StackState::new(vec![0b1010_1010]);
s.execute(&lines(&["pop_count"]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![4]);
}
#[test]
fn sbox_pattern() {
let x = 7u64;
let mut s = StackState::new(vec![x]);
s.execute(&lines(&[
"dup 0", "dup 0", "mul", "dup 0", "mul", "mul", ]));
assert!(s.is_valid());
assert_eq!(s.stack, vec![16807]);
}
#[test]
fn verify_rejects_when_baseline_errors() {
let baseline = lines(&["push 1", "call some_fn", "add"]);
let candidate = lines(&["push 42"]);
assert!(!verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn verify_rejects_when_candidate_errors() {
let baseline = lines(&["push 1", "push 2", "add"]);
let bad_candidate = lines(&["pop 100"]); assert!(!verify_equivalent(&baseline, &bad_candidate, 42));
}
#[test]
fn verify_rejects_both_error() {
let baseline = lines(&["call foo"]); let candidate = lines(&["call bar"]); assert!(!verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn generate_test_stack_deterministic() {
let a = generate_test_stack(42, 8);
let b = generate_test_stack(42, 8);
assert_eq!(a, b);
let c = generate_test_stack(43, 8);
assert_ne!(a, c);
}
#[test]
fn generate_test_stack_in_range() {
use crate::field::goldilocks::MODULUS;
let stack = generate_test_stack(99, 100);
for val in &stack {
assert!(*val < MODULUS, "value {} >= MODULUS", val);
}
}
#[test]
fn write_io_removal_caught() {
let baseline = lines(&["write_io 1"]);
let candidate = lines(&["pop 1"]);
assert!(!verify_equivalent(&baseline, &candidate, 77));
}
#[test]
fn write_io_equivalent_accepted() {
let baseline = lines(&["write_io 1"]);
let candidate = lines(&["write_io 1"]);
assert!(verify_equivalent(&baseline, &candidate, 77));
}
#[test]
fn assert_removal_caught() {
let baseline = lines(&["push 1", "assert"]);
let candidate = lines(&["push 1", "pop 1"]);
assert!(!verify_equivalent(&baseline, &candidate, 88));
}
#[test]
fn assert_equivalent_accepted() {
let baseline = lines(&["push 1", "assert"]);
let candidate = lines(&["push 1", "assert"]);
assert!(verify_equivalent(&baseline, &candidate, 88));
}
#[test]
fn divine_replacement_caught() {
let baseline = lines(&["divine 1"]);
let candidate = lines(&["push 0"]);
assert!(!verify_equivalent(&baseline, &candidate, 99));
}
#[test]
fn divine_equivalent_accepted() {
let baseline = lines(&["divine 1"]);
let candidate = lines(&["divine 1"]);
assert!(verify_equivalent(&baseline, &candidate, 99));
}
#[test]
fn halt_removal_caught() {
let baseline = lines(&["halt", "push 99"]);
let candidate = lines(&["push 99"]);
assert!(!verify_equivalent(&baseline, &candidate, 55));
}
#[test]
fn halt_equivalent_accepted() {
let baseline = lines(&["push 1", "halt"]);
let candidate = lines(&["push 1", "halt"]);
assert!(verify_equivalent(&baseline, &candidate, 55));
}
#[test]
fn split_now_verifiable() {
let baseline = lines(&["split"]);
let candidate = lines(&["split"]);
assert!(verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn split_wrong_replacement_caught() {
let baseline = lines(&["split"]);
let candidate = lines(&["dup 0"]); assert!(!verify_equivalent(&baseline, &candidate, 42));
}
#[test]
fn assert_vector_removal_caught() {
let baseline = lines(&[
"push 1",
"push 2",
"push 3",
"push 4",
"push 5",
"push 1",
"push 2",
"push 3",
"push 4",
"push 5",
"assert_vector",
]);
let candidate = lines(&[
"push 1", "push 2", "push 3", "push 4", "push 5", "push 1", "push 2", "push 3",
"push 4", "push 5", "pop 5",
]);
assert!(!verify_equivalent(&baseline, &candidate, 66));
}
#[test]
fn score_candidate_crash_returns_zero() {
let baseline = lines(&["push 1", "push 2", "add"]);
let candidate = lines(&["pop 5", "pop 5", "pop 5", "pop 5", "pop 1"]);
assert_eq!(score_candidate(&baseline, &candidate, 42), 0);
}
#[test]
fn score_candidate_no_crash_wrong_depth() {
let baseline = lines(&["push 1", "push 2", "add"]); let candidate = lines(&["push 1", "push 2"]); let score = score_candidate(&baseline, &candidate, 42);
assert_eq!(score, 100); }
#[test]
fn score_candidate_right_depth_wrong_values() {
let baseline = lines(&["push 1"]); let candidate = lines(&["push 2"]); let score = score_candidate(&baseline, &candidate, 42);
assert!(
score >= 200,
"right depth should score >= 200, got {}",
score
);
}
#[test]
fn score_candidate_identical_scores_900() {
let baseline = lines(&["push 1", "push 2", "add"]);
let candidate = lines(&["push 1", "push 2", "add"]);
let score = score_candidate(&baseline, &candidate, 42);
assert_eq!(score, 900);
}
#[test]
fn score_candidate_nop_equivalent_scores_900() {
let baseline = lines(&["push 5"]);
let candidate = lines(&["push 5", "nop"]);
let score = score_candidate(&baseline, &candidate, 42);
assert_eq!(score, 900);
}