Files
Cagire/tests/forth/harness.rs
Raphaël Forment dd853b8e1b
Some checks failed
Deploy Website / deploy (push) Failing after 4m46s
Feat: begin slight refactoring
2026-02-01 12:38:48 +01:00

139 lines
3.3 KiB
Rust

use cagire::forth::{Dictionary, Forth, Rng, StepContext, Value, Variables};
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
pub fn default_ctx() -> StepContext {
StepContext {
step: 0,
beat: 0.0,
bank: 0,
pattern: 0,
tempo: 120.0,
phase: 0.0,
slot: 0,
runs: 0,
iter: 0,
speed: 1.0,
fill: false,
nudge_secs: 0.0,
cc_access: None,
}
}
pub fn ctx_with(f: impl FnOnce(&mut StepContext)) -> StepContext {
let mut ctx = default_ctx();
f(&mut ctx);
ctx
}
pub fn new_vars() -> Variables {
Arc::new(Mutex::new(HashMap::new()))
}
pub fn new_dict() -> Dictionary {
Arc::new(Mutex::new(HashMap::new()))
}
pub fn seeded_rng(seed: u64) -> Rng {
Arc::new(Mutex::new(StdRng::seed_from_u64(seed)))
}
pub fn forth() -> Forth {
Forth::new(new_vars(), new_dict(), seeded_rng(42))
}
pub fn forth_seeded(seed: u64) -> Forth {
Forth::new(new_vars(), new_dict(), seeded_rng(seed))
}
pub fn run(script: &str) -> Forth {
let f = forth();
f.evaluate(script, &default_ctx()).unwrap();
f
}
pub fn run_ctx(script: &str, ctx: &StepContext) -> Forth {
let f = forth();
f.evaluate(script, ctx).unwrap();
f
}
pub fn stack_top(f: &Forth) -> Value {
f.stack().pop().expect("stack empty")
}
pub fn stack_int(f: &Forth) -> i64 {
match stack_top(f) {
Value::Int(i, _) => i,
other => panic!("expected Int, got {:?}", other),
}
}
pub fn stack_float(f: &Forth) -> f64 {
match stack_top(f) {
Value::Float(x, _) => x,
Value::Int(i, _) => i as f64,
other => panic!("expected number, got {:?}", other),
}
}
pub fn expect_stack(script: &str, expected: &[Value]) {
let f = run(script);
let stack = f.stack();
assert_eq!(stack, expected, "script: {}", script);
}
pub fn expect_int(script: &str, expected: i64) {
expect_stack(script, &[Value::Int(expected, None)]);
}
pub fn expect_str(script: &str, expected: &str) {
expect_stack(script, &[Value::Str(expected.to_string(), None)]);
}
pub fn expect_float(script: &str, expected: f64) {
let f = run(script);
let stack = f.stack();
assert_eq!(stack.len(), 1, "expected single value on stack");
let val = stack_float(&f);
assert!(
(val - expected).abs() < 1e-9,
"expected {}, got {}",
expected,
val
);
}
pub fn expect_floats_close(script: &str, expected: f64, epsilon: f64) {
let f = run(script);
let val = stack_float(&f);
assert!(
(val - expected).abs() < epsilon,
"expected ~{}, got {}",
expected,
val
);
}
pub fn expect_error(script: &str, expected_substr: &str) {
let f = forth();
let result = f.evaluate(script, &default_ctx());
assert!(result.is_err(), "expected error for '{}'", script);
let err = result.unwrap_err();
assert!(
err.contains(expected_substr),
"error '{}' does not contain '{}'",
err,
expected_substr
);
}
pub fn expect_outputs(script: &str, count: usize) -> Vec<String> {
let f = forth();
let outputs = f.evaluate(script, &default_ctx()).unwrap();
assert_eq!(outputs.len(), count, "expected {} outputs", count);
outputs
}