use super::harness::*; #[test] fn ramp_at_beat_zero() { let ctx = ctx_with(|c| c.beat = 0.0); let f = forth(); f.evaluate("1.0 2.0 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.0).abs() < 1e-9, "expected 0.0, got {}", val); } #[test] fn ramp_linear() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 1.0 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.5).abs() < 1e-9, "expected 0.5, got {}", val); } #[test] fn ramp_quadratic() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 2.0 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.25).abs() < 1e-9, "expected 0.25, got {}", val); } #[test] fn ramp_sqrt() { let ctx = ctx_with(|c| c.beat = 0.25); let f = forth(); f.evaluate("1.0 0.5 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.5).abs() < 1e-9, "expected 0.5, got {}", val); } #[test] fn ramp_wraps() { let ctx = ctx_with(|c| c.beat = 1.5); let f = forth(); f.evaluate("1.0 1.0 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.5).abs() < 1e-9, "expected 0.5, got {}", val); } #[test] fn ramp_freq_half() { let ctx = ctx_with(|c| c.beat = 1.0); let f = forth(); f.evaluate("0.5 1.0 ramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.5).abs() < 1e-9, "expected 0.5, got {}", val); } #[test] fn ramp_underflow() { expect_error("1.0 ramp", "stack underflow"); } #[test] fn range_mid() { let ctx = default_ctx(); let f = forth(); f.evaluate("0.5 100.0 200.0 range", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 150.0).abs() < 1e-9, "expected 150.0, got {}", val); } #[test] fn range_at_zero() { let ctx = default_ctx(); let f = forth(); f.evaluate("0.0 100.0 200.0 range", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 100.0).abs() < 1e-9, "expected 100.0, got {}", val); } #[test] fn range_at_one() { let ctx = default_ctx(); let f = forth(); f.evaluate("1.0 100.0 200.0 range", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 200.0).abs() < 1e-9, "expected 200.0, got {}", val); } #[test] fn range_underflow() { expect_error("0.5 100.0 range", "stack underflow"); } #[test] fn linramp() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 linramp", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 0.5).abs() < 1e-9, "expected 0.5, got {}", val); } #[test] fn expramp() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 expramp", &ctx).unwrap(); let val = stack_float(&f); let expected = 0.5_f64.powf(3.0); assert!((val - expected).abs() < 1e-9, "expected {}, got {}", expected, val); } #[test] fn logramp() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 logramp", &ctx).unwrap(); let val = stack_float(&f); let expected = 0.5_f64.powf(0.3); assert!((val - expected).abs() < 1e-9, "expected {}, got {}", expected, val); } #[test] fn ramp_with_range() { let ctx = ctx_with(|c| c.beat = 0.5); let f = forth(); f.evaluate("1.0 1.0 ramp 200.0 800.0 range", &ctx).unwrap(); let val = stack_float(&f); assert!((val - 500.0).abs() < 1e-9, "expected 500.0, got {}", val); } #[test] fn perlin_deterministic() { let ctx = ctx_with(|c| c.beat = 2.7); let f = forth(); f.evaluate("1.0 perlin", &ctx).unwrap(); let val1 = stack_float(&f); f.evaluate("1.0 perlin", &ctx).unwrap(); let val2 = stack_float(&f); assert!((val1 - val2).abs() < 1e-9, "perlin should be deterministic"); } #[test] fn perlin_in_range() { for i in 0..100 { let ctx = ctx_with(|c| c.beat = i as f64 * 0.1); let f = forth(); f.evaluate("1.0 perlin", &ctx).unwrap(); let val = stack_float(&f); assert!(val >= 0.0 && val <= 1.0, "perlin out of range: {}", val); } } #[test] fn perlin_varies() { let ctx1 = ctx_with(|c| c.beat = 0.5); let ctx2 = ctx_with(|c| c.beat = 1.5); let f = forth(); f.evaluate("1.0 perlin", &ctx1).unwrap(); let val1 = stack_float(&f); f.evaluate("1.0 perlin", &ctx2).unwrap(); let val2 = stack_float(&f); assert!((val1 - val2).abs() > 1e-9, "perlin should vary with beat"); } #[test] fn perlin_smooth() { let f = forth(); let mut prev = 0.0; for i in 0..100 { let ctx = ctx_with(|c| c.beat = i as f64 * 0.01); f.evaluate("1.0 perlin", &ctx).unwrap(); let val = stack_float(&f); if i > 0 { assert!((val - prev).abs() < 0.2, "perlin not smooth: jump {} at step {}", (val - prev).abs(), i); } prev = val; } } #[test] fn perlin_with_range() { let ctx = ctx_with(|c| c.beat = 1.3); let f = forth(); f.evaluate("1.0 perlin 200.0 800.0 range", &ctx).unwrap(); let val = stack_float(&f); assert!(val >= 200.0 && val <= 800.0, "perlin+range out of bounds: {}", val); } #[test] fn perlin_underflow() { expect_error("perlin", "stack underflow"); }