use super::*;

#[track_caller]
fn evaluate(expression: &str, expected: &str) {
  Test::new()
    .justfile(format!("set lists\nx := {expression}"))
    .unstable()
    .args(["--evaluate", "x"])
    .stdout(expected)
    .success();
}

#[test]
fn and_requires_lists_setting() {
  Test::new()
    .justfile(
      "
        x := 'foo' && 'bar'

        foo:
          @echo hi
      ",
    )
    .unstable()
    .arg("foo")
    .stderr(
      "
        error: logical operators require `set lists`
         ——▶ justfile:1:12
          │
        1 │ x := 'foo' && 'bar'
          │            ^^
      ",
    )
    .failure();
}

#[test]
fn or_requires_lists_setting() {
  Test::new()
    .justfile(
      "
        x := 'foo' || 'bar'

        foo:
          @echo hi
      ",
    )
    .unstable()
    .arg("foo")
    .stderr(
      "
        error: logical operators require `set lists`
         ——▶ justfile:1:12
          │
        1 │ x := 'foo' || 'bar'
          │            ^^
      ",
    )
    .failure();
}

#[test]
fn and_returns_empty_list_if_lhs_is_falsy() {
  evaluate("[] && 'hello'", "");
}

#[test]
fn and_returns_rhs_if_lhs_is_truthy() {
  evaluate("'hello' && 'goodbye'", "goodbye");
}

#[test]
fn or_returns_rhs_if_lhs_is_falsy() {
  evaluate("[] || 'hello'", "hello");
}

#[test]
fn or_returns_lhs_if_lhs_is_truthy() {
  evaluate("'hello' || 'goodbye'", "hello");
}

#[test]
fn empty_string_is_truthy() {
  evaluate("'' || 'fallback'", "");
  evaluate("'' && 'rhs'", "rhs");
}

#[test]
fn and_has_lower_precedence_than_plus() {
  evaluate("[] && 'goodbye' + 'foo'", "");
  evaluate("'foo' + 'hello' && 'goodbye'", "goodbye");
  evaluate("'foo' + '' && 'goodbye'", "goodbye");
  evaluate("'foo' + 'hello' && 'goodbye' + 'bar'", "goodbyebar");
}

#[test]
fn or_has_lower_precedence_than_plus() {
  evaluate("[] || 'goodbye' + 'foo'", "goodbyefoo");
  evaluate("'foo' + 'hello' || 'goodbye'", "foohello");
  evaluate("'foo' + '' || 'goodbye'", "foo");
  evaluate("'foo' + 'hello' || 'goodbye' + 'bar'", "foohello");
}

#[test]
fn and_has_higher_precedence_than_or() {
  evaluate("([] && 'foo') || 'bar'", "bar");
  evaluate("[] && 'foo' || 'bar'", "bar");
  evaluate("'a' && 'b' || 'c'", "b");
}

#[test]
fn nesting() {
  evaluate("[] || [] || [] || [] || 'foo'", "foo");
  evaluate("'foo' && 'foo' && 'foo' && 'foo' && 'bar'", "bar");
}
