use super::harness::*;

#[test]
fn add_integers() {
    expect_int("2 3 +", 5);
}

#[test]
fn add_floats() {
    expect_int("2.5 3.5 +", 6);
}

#[test]
fn add_mixed() {
    expect_float("2 3.5 +", 5.5);
}

#[test]
fn sub() {
    expect_int("10 3 -", 7);
}

#[test]
fn sub_negative() {
    expect_int("3 10 -", -7);
}

#[test]
fn mul() {
    expect_int("4 5 *", 20);
}

#[test]
fn mul_floats() {
    expect_int("2.5 4 *", 10);
}

#[test]
fn div() {
    expect_int("10 2 /", 5);
}

#[test]
fn div_float_result() {
    expect_float("7 2 /", 3.5);
}

#[test]
fn modulo() {
    expect_int("7 3 mod", 1);
}

#[test]
fn modulo_exact() {
    expect_int("9 3 mod", 0);
}

#[test]
fn neg_int() {
    expect_int("5 neg", -5);
}

#[test]
fn neg_float() {
    expect_float("3.5 neg", -3.5);
}

#[test]
fn neg_double() {
    expect_int("-5 neg", 5);
}

#[test]
fn abs_positive() {
    expect_int("5 abs", 5);
}

#[test]
fn abs_negative() {
    expect_int("-5 abs", 5);
}

#[test]
fn abs_float() {
    expect_float("-3.5 abs", 3.5);
}

#[test]
fn floor() {
    expect_int("3.7 floor", 3);
}

#[test]
fn floor_negative() {
    expect_int("-3.2 floor", -4);
}

#[test]
fn ceil() {
    expect_int("3.2 ceil", 4);
}

#[test]
fn ceil_negative() {
    expect_int("-3.7 ceil", -3);
}

#[test]
fn round_down() {
    expect_int("3.4 round", 3);
}

#[test]
fn round_up() {
    expect_int("3.6 round", 4);
}

#[test]
fn round_half() {
    expect_int("3.5 round", 4);
}

#[test]
fn min() {
    expect_int("3 5 min", 3);
}

#[test]
fn min_reverse() {
    expect_int("5 3 min", 3);
}

#[test]
fn max() {
    expect_int("3 5 max", 5);
}

#[test]
fn max_reverse() {
    expect_int("5 3 max", 5);
}

#[test]
fn chain() {
    // (2 + 3) * 4 - 1 = 19
    expect_int("2 3 + 4 * 1 -", 19);
}

#[test]
fn underflow() {
    expect_error("1 +", "stack underflow");
}

#[test]
fn pow_int() {
    expect_int("2 3 pow", 8);
}

#[test]
fn pow_float() {
    expect_float("2 0.5 pow", std::f64::consts::SQRT_2);
}

#[test]
fn sqrt() {
    expect_int("16 sqrt", 4);
}

#[test]
fn sqrt_float() {
    expect_float("2 sqrt", std::f64::consts::SQRT_2);
}

#[test]
fn sin_zero() {
    expect_int("0 sin", 0);
}

#[test]
fn sin_pi_half() {
    expect_float("3.14159265358979 2 / sin", 1.0);
}

#[test]
fn cos_zero() {
    expect_int("0 cos", 1);
}

#[test]
fn cos_pi() {
    expect_int("3.14159265358979 cos", -1);
}

#[test]
fn log_e() {
    expect_float("2.718281828459045 log", 1.0);
}

#[test]
fn log_one() {
    expect_int("1 log", 0);
}

#[test]
fn shorthand_float() {
    expect_float(".25 .5 +", 0.75);
}

#[test]
fn shorthand_float_negative() {
    expect_float("-.5 1 +", 0.5);
}

// linmap

#[test]
fn linmap_basic() {
    expect_float("64 0 127 200 2000 linmap", 200.0 + (64.0 / 127.0) * 1800.0);
}

#[test]
fn linmap_at_bounds() {
    expect_float("0 0 127 200 2000 linmap", 200.0);
}

#[test]
fn linmap_at_upper() {
    expect_float("127 0 127 200 2000 linmap", 2000.0);
}

#[test]
fn linmap_equal_input_range() {
    expect_float("5 5 5 100 200 linmap", 100.0);
}

// expmap

#[test]
fn expmap_at_zero() {
    expect_float("0 200 8000 expmap", 200.0);
}

#[test]
fn expmap_at_one() {
    expect_float("1 200 8000 expmap", 8000.0);
}

#[test]
fn expmap_midpoint() {
    expect_float("0.5 100 10000 expmap", 1000.0);
}

#[test]
fn expmap_negative_bound() {
    expect_error("0.5 -100 8000 expmap", "expmap requires positive bounds");
}
