use xqvm::bytecode::{InstructionBuilder, Register};
use xqvm::{JsonTracer, Vm};
fn is_valid_json(s: &str) -> bool {
let s = s.trim();
s.starts_with('{') && s.ends_with('}')
}
#[test]
fn json_tracer_produces_valid_jsonl() {
let mut b = InstructionBuilder::new();
let _ = b
.emit_push(3)
.emit_push(4)
.emit_add()
.emit_stow(Register(0))
.emit_halt();
let program = b.build().unwrap();
let mut buf = Vec::new();
let mut tracer = JsonTracer::new(&mut buf);
let mut vm = Vm::new();
vm.run_trace(&mut tracer, &program).unwrap();
let output = String::from_utf8(buf).unwrap();
let lines: Vec<&str> = output.lines().collect();
assert_eq!(lines.len(), 5, "expected 5 lines, got:\n{output}");
for (i, line) in lines.iter().enumerate() {
assert!(is_valid_json(line), "line {i} is not valid JSON: {line}");
}
let first = lines.first().expect("should have line 0");
let last = lines.get(4).expect("should have line 4");
assert!(first.contains("\"step\":1"));
assert!(last.contains("\"step\":5"));
let stow_line = lines.get(3).expect("should have line 3");
assert!(stow_line.contains("\"written_regs\""));
}
#[test]
fn json_tracer_each_line_has_required_fields() {
let mut b = InstructionBuilder::new();
let _ = b.emit_push(42).emit_halt();
let program = b.build().unwrap();
let mut buf = Vec::new();
let mut tracer = JsonTracer::new(&mut buf);
let mut vm = Vm::new();
vm.run_trace(&mut tracer, &program).unwrap();
let output = String::from_utf8(buf).unwrap();
for line in output.lines() {
assert!(line.contains("\"step\""), "missing step: {line}");
assert!(line.contains("\"pos\""), "missing pos: {line}");
assert!(
line.contains("\"instruction\""),
"missing instruction: {line}"
);
assert!(line.contains("\"stack\""), "missing stack: {line}");
}
}