use super::harness::*;

#[test]
fn empty_script() {
    expect_error("", "empty script");
}

#[test]
fn whitespace_only() {
    expect_error("   \n\t  ", "empty script");
}

#[test]
fn unknown_word_becomes_string() {
    expect_str("foobar", "foobar");
}

#[test]
fn string_not_number() {
    expect_error(r#""hello" neg"#, "expected number");
}

#[test]
fn comment_ignored() {
    expect_int("1 ;; this is a comment\n2 +", 3);
}

#[test]
fn multiline_comment() {
    expect_int("1 ;; first comment\n;; entire line comment\n2 +", 3);
}

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

#[test]
fn float_literal() {
    let f = run("3.14159");
    let val = stack_float(&f);
    assert!((val - 3.14159).abs() < 1e-9);
}

#[test]
fn string_with_spaces() {
    let f = run(r#""hello world" !x @x"#);
    match stack_top(&f) {
        cagire::forth::Value::Str(s, _) => assert_eq!(s.as_ref(), "hello world"),
        other => panic!("expected string, got {:?}", other),
    }
}

#[test]
fn conditional_based_on_step() {
    let ctx0 = ctx_with(|c| c.step = 0);
    let ctx1 = ctx_with(|c| c.step = 1);

    let f0 = run_ctx("step 2 mod 0 = if 100 else 200 then", &ctx0);
    let f1 = run_ctx("step 2 mod 0 = if 100 else 200 then", &ctx1);

    assert_eq!(stack_int(&f0), 100);
    assert_eq!(stack_int(&f1), 200);
}

#[test]
fn accumulator() {
    let f = forth();
    let ctx = default_ctx();
    f.evaluate(r#"0 !acc"#, &ctx).unwrap();
    for _ in 0..5 {
        f.clear_stack();
        f.evaluate(r#"@acc 1 + dup !acc"#, &ctx).unwrap();
    }
    assert_eq!(stack_int(&f), 5);
}
