use super::harness::*; #[test] fn step() { let ctx = ctx_with(|c| c.step = 7); let f = run_ctx("step", &ctx); assert_eq!(stack_int(&f), 7); } #[test] fn beat() { let ctx = ctx_with(|c| c.beat = 4.5); let f = run_ctx("beat", &ctx); assert!((stack_float(&f) - 4.5).abs() < 1e-9); } #[test] fn pattern() { let ctx = ctx_with(|c| c.pattern = 3); let f = run_ctx("pattern", &ctx); assert_eq!(stack_int(&f), 3); } #[test] fn tempo() { let ctx = ctx_with(|c| c.tempo = 140.0); let f = run_ctx("tempo", &ctx); assert!((stack_float(&f) - 140.0).abs() < 1e-9); } #[test] fn phase() { let ctx = ctx_with(|c| c.phase = 0.25); let f = run_ctx("phase", &ctx); assert!((stack_float(&f) - 0.25).abs() < 1e-9); } #[test] fn slot() { let ctx = ctx_with(|c| c.slot = 5); let f = run_ctx("slot", &ctx); assert_eq!(stack_int(&f), 5); } #[test] fn runs() { let ctx = ctx_with(|c| c.runs = 10); let f = run_ctx("runs", &ctx); assert_eq!(stack_int(&f), 10); } #[test] fn iter() { let ctx = ctx_with(|c| c.iter = 5); let f = run_ctx("iter", &ctx); assert_eq!(stack_int(&f), 5); } #[test] fn every_true_on_zero() { let ctx = ctx_with(|c| c.iter = 0); let f = run_ctx("( 100 ) 4 every", &ctx); assert_eq!(stack_int(&f), 100); } #[test] fn every_true_on_multiple() { let ctx = ctx_with(|c| c.iter = 8); let f = run_ctx("( 100 ) 4 every", &ctx); assert_eq!(stack_int(&f), 100); } #[test] fn every_false_between() { for i in 1..4 { let ctx = ctx_with(|c| c.iter = i); let f = run_ctx("( 100 ) 4 every", &ctx); assert!(f.stack().is_empty(), "iter={} should not execute quotation", i); } } #[test] fn every_zero_count() { expect_error("( 1 ) 0 every", "every count must be > 0"); } #[test] fn stepdur() { // stepdur = 60.0 / tempo / 4.0 / speed = 60 / 120 / 4 / 1 = 0.125 let f = run("stepdur"); assert!((stack_float(&f) - 0.125).abs() < 1e-9); } #[test] fn context_in_computation() { let ctx = ctx_with(|c| c.step = 3); let f = run_ctx("60 step +", &ctx); assert_eq!(stack_int(&f), 63); } // bjork (runs-based) #[test] fn bjork_tresillo() { // Bresenham(3,8) hits at positions 0, 2, 5 for runs in 0..8 { let ctx = ctx_with(|c| c.runs = runs); let f = run_ctx("( 100 ) 3 8 bjork", &ctx); let hit = ((runs + 1) * 3) / 8 != (runs * 3) / 8; if hit { assert_eq!(stack_int(&f), 100, "runs={} should hit", runs); } else { assert!(f.stack().is_empty(), "runs={} should miss", runs); } } } #[test] fn bjork_hit_count() { // Bjorklund(3,8) should produce exactly 3 hits let mut hit_count = 0; for runs in 0..8 { let ctx = ctx_with(|c| c.runs = runs); let f = run_ctx("( 100 ) 3 8 bjork", &ctx); if !f.stack().is_empty() { hit_count += 1; } } assert_eq!(hit_count, 3); } #[test] fn bjork_all_hits() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("( 100 ) 8 8 bjork", &ctx); assert_eq!(stack_int(&f), 100); } #[test] fn bjork_zero_hits() { let ctx = ctx_with(|c| c.runs = 0); let f = run_ctx("( 100 ) 0 8 bjork", &ctx); assert!(f.stack().is_empty()); } #[test] fn bjork_invalid() { expect_error("( 1 ) 3 0 bjork", "bjork"); } // pbjork (iter-based) #[test] fn pbjork_cinquillo() { let mut hit_count = 0; for iter in 0..8 { let ctx = ctx_with(|c| c.iter = iter); let f = run_ctx("( 100 ) 5 8 pbjork", &ctx); if !f.stack().is_empty() { hit_count += 1; } } assert_eq!(hit_count, 5); } #[test] fn pbjork_wraps() { let ctx0 = ctx_with(|c| c.iter = 0); let ctx8 = ctx_with(|c| c.iter = 8); let f0 = run_ctx("( 100 ) 3 8 pbjork", &ctx0); let f8 = run_ctx("( 100 ) 3 8 pbjork", &ctx8); assert_eq!(f0.stack().is_empty(), f8.stack().is_empty()); }