256 lines
6.2 KiB
Rust
256 lines
6.2 KiB
Rust
use super::harness::*;
|
|
|
|
#[test]
|
|
fn rand_in_range() {
|
|
let f = forth_seeded(12345);
|
|
f.evaluate("0 10 rand", &default_ctx()).unwrap();
|
|
let val = stack_float(&f);
|
|
assert!(val >= 0.0 && val < 10.0, "rand {} not in [0, 10)", val);
|
|
}
|
|
|
|
#[test]
|
|
fn rand_deterministic() {
|
|
let f1 = forth_seeded(99);
|
|
let f2 = forth_seeded(99);
|
|
f1.evaluate("0 100 rand", &default_ctx()).unwrap();
|
|
f2.evaluate("0 100 rand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn seed_resets() {
|
|
let f1 = forth_seeded(1);
|
|
f1.evaluate("42 seed 0 100 rand", &default_ctx()).unwrap();
|
|
let f2 = forth_seeded(999);
|
|
f2.evaluate("42 seed 0 100 rand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn coin_binary() {
|
|
let f = forth_seeded(42);
|
|
f.evaluate("coin", &default_ctx()).unwrap();
|
|
let val = stack_int(&f);
|
|
assert!(val == 0 || val == 1);
|
|
}
|
|
|
|
#[test]
|
|
fn chance_zero() {
|
|
// 0.0 probability should never execute the quotation
|
|
let f = run("99 { 42 } 0.0 chance");
|
|
assert_eq!(stack_int(&f), 99); // quotation not executed, 99 still on stack
|
|
}
|
|
|
|
#[test]
|
|
fn chance_one() {
|
|
// 1.0 probability should always execute the quotation
|
|
let f = run("{ 42 } 1.0 chance");
|
|
assert_eq!(stack_int(&f), 42);
|
|
}
|
|
|
|
#[test]
|
|
fn choose_from_list() {
|
|
let f = forth_seeded(42);
|
|
f.evaluate("10 20 30 3 choose", &default_ctx()).unwrap();
|
|
let val = stack_int(&f);
|
|
assert!(val == 10 || val == 20 || val == 30);
|
|
}
|
|
|
|
#[test]
|
|
fn choose_underflow() {
|
|
expect_error("1 2 5 choose", "stack underflow");
|
|
}
|
|
|
|
#[test]
|
|
fn cycle_deterministic() {
|
|
for runs in 0..6 {
|
|
let ctx = ctx_with(|c| c.runs = runs);
|
|
let f = run_ctx("10 20 30 3 cycle", &ctx);
|
|
let expected = [10, 20, 30][runs % 3];
|
|
assert_eq!(stack_int(&f), expected, "cycle at runs={}", runs);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn cycle_zero_count() {
|
|
expect_error("1 2 3 0 cycle", "cycle count must be > 0");
|
|
}
|
|
|
|
#[test]
|
|
fn mtof_a4() {
|
|
expect_float("69 mtof", 440.0);
|
|
}
|
|
|
|
#[test]
|
|
fn mtof_octave() {
|
|
expect_float("81 mtof", 880.0);
|
|
}
|
|
|
|
#[test]
|
|
fn mtof_c4() {
|
|
expect_floats_close("60 mtof", 261.6255653, 0.001);
|
|
}
|
|
|
|
#[test]
|
|
fn ftom_440() {
|
|
expect_float("440 ftom", 69.0);
|
|
}
|
|
|
|
#[test]
|
|
fn ftom_880() {
|
|
expect_float("880 ftom", 81.0);
|
|
}
|
|
|
|
#[test]
|
|
fn mtof_ftom_roundtrip() {
|
|
expect_float("60 mtof ftom", 60.0);
|
|
}
|
|
|
|
#[test]
|
|
fn exprand_in_range() {
|
|
let f = forth_seeded(12345);
|
|
f.evaluate("1.0 100.0 exprand", &default_ctx()).unwrap();
|
|
let val = stack_float(&f);
|
|
assert!(val >= 1.0 && val <= 100.0, "exprand {} not in [1, 100]", val);
|
|
}
|
|
|
|
#[test]
|
|
fn exprand_deterministic() {
|
|
let f1 = forth_seeded(99);
|
|
let f2 = forth_seeded(99);
|
|
f1.evaluate("1.0 100.0 exprand", &default_ctx()).unwrap();
|
|
f2.evaluate("1.0 100.0 exprand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn exprand_swapped_args() {
|
|
let f1 = forth_seeded(42);
|
|
let f2 = forth_seeded(42);
|
|
f1.evaluate("1.0 100.0 exprand", &default_ctx()).unwrap();
|
|
f2.evaluate("100.0 1.0 exprand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn exprand_requires_positive() {
|
|
expect_error("0.0 10.0 exprand", "exprand requires positive values");
|
|
expect_error("-1.0 10.0 exprand", "exprand requires positive values");
|
|
expect_error("1.0 0.0 exprand", "exprand requires positive values");
|
|
}
|
|
|
|
#[test]
|
|
fn logrand_in_range() {
|
|
let f = forth_seeded(12345);
|
|
f.evaluate("1.0 100.0 logrand", &default_ctx()).unwrap();
|
|
let val = stack_float(&f);
|
|
assert!(val >= 1.0 && val <= 100.0, "logrand {} not in [1, 100]", val);
|
|
}
|
|
|
|
#[test]
|
|
fn logrand_deterministic() {
|
|
let f1 = forth_seeded(99);
|
|
let f2 = forth_seeded(99);
|
|
f1.evaluate("1.0 100.0 logrand", &default_ctx()).unwrap();
|
|
f2.evaluate("1.0 100.0 logrand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn logrand_swapped_args() {
|
|
let f1 = forth_seeded(42);
|
|
let f2 = forth_seeded(42);
|
|
f1.evaluate("1.0 100.0 logrand", &default_ctx()).unwrap();
|
|
f2.evaluate("100.0 1.0 logrand", &default_ctx()).unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn logrand_requires_positive() {
|
|
expect_error("0.0 10.0 logrand", "logrand requires positive values");
|
|
expect_error("-1.0 10.0 logrand", "logrand requires positive values");
|
|
expect_error("1.0 0.0 logrand", "logrand requires positive values");
|
|
}
|
|
|
|
#[test]
|
|
fn rand_equal_bounds() {
|
|
expect_float("5.0 5.0 rand", 5.0);
|
|
}
|
|
|
|
// bounce
|
|
|
|
#[test]
|
|
fn bounce_sequence() {
|
|
let expected = [60, 64, 67, 72, 67, 64, 60, 64];
|
|
for (runs, &exp) in expected.iter().enumerate() {
|
|
let ctx = ctx_with(|c| c.runs = runs);
|
|
let f = run_ctx("60 64 67 72 4 bounce", &ctx);
|
|
assert_eq!(stack_int(&f), exp, "bounce at runs={}", runs);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bounce_single() {
|
|
for runs in 0..5 {
|
|
let ctx = ctx_with(|c| c.runs = runs);
|
|
let f = run_ctx("42 1 bounce", &ctx);
|
|
assert_eq!(stack_int(&f), 42, "bounce single at runs={}", runs);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bounce_zero_count() {
|
|
expect_error("1 2 3 0 bounce", "bounce count must be > 0");
|
|
}
|
|
|
|
#[test]
|
|
fn bounce_underflow() {
|
|
expect_error("1 2 5 bounce", "stack underflow");
|
|
}
|
|
|
|
// wchoose
|
|
|
|
#[test]
|
|
fn wchoose_all_weight_one_item() {
|
|
for _ in 0..10 {
|
|
let f = forth_seeded(42);
|
|
f.evaluate("10 0.0 20 1.0 2 wchoose", &default_ctx())
|
|
.unwrap();
|
|
assert_eq!(stack_int(&f), 20);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn wchoose_deterministic() {
|
|
let f1 = forth_seeded(99);
|
|
let f2 = forth_seeded(99);
|
|
f1.evaluate("60 0.6 64 0.3 67 0.1 3 wchoose", &default_ctx())
|
|
.unwrap();
|
|
f2.evaluate("60 0.6 64 0.3 67 0.1 3 wchoose", &default_ctx())
|
|
.unwrap();
|
|
assert_eq!(f1.stack(), f2.stack());
|
|
}
|
|
|
|
#[test]
|
|
fn wchoose_zero_count() {
|
|
expect_error("0 wchoose", "wchoose count must be > 0");
|
|
}
|
|
|
|
#[test]
|
|
fn wchoose_underflow() {
|
|
expect_error("10 0.5 2 wchoose", "stack underflow");
|
|
}
|
|
|
|
#[test]
|
|
fn wchoose_negative_weight() {
|
|
expect_error("10 -0.5 20 1.0 2 wchoose", "negative weight");
|
|
}
|
|
|
|
#[test]
|
|
fn wchoose_quotation() {
|
|
let f = forth_seeded(42);
|
|
f.evaluate("{ 10 } 0.0 { 20 } 1.0 2 wchoose", &default_ctx())
|
|
.unwrap();
|
|
assert_eq!(stack_int(&f), 20);
|
|
}
|