use cromulent::*;

#[test]
fn default() {
    let words = WordExpander::default().expand("$((1 + 1))").unwrap();
    let word = words[0].to_str().unwrap();

    assert_eq!(word, "2");
}

#[test]
fn disallowed_command() {
    let error = WordExpander::default().expand("$(echo hi)");
    assert_eq!(error, Err(WordError::CommandSubstitution))
}

#[test]
fn allowed_command() {
    let words = WordExpander::default()
        .allow_commands()
        .expand("$(echo hi)")
        .unwrap();
    let word = words[0].to_str().unwrap();

    assert_eq!(word, "hi");
}

#[test]
fn defined_variable() {
    assert!(
        std::env::var("CARGO_PKG_NAME").is_ok(),
        "Test invalid due to absence of environment variable."
    );

    // TODO: Can/should we assume that the tests will always have access to this
    // variable?
    let words = WordExpander::default().expand("$CARGO_PKG_NAME").unwrap();
    let word = words[0].to_str().unwrap();

    assert_eq!(word, "cromulent");
}

#[test]
fn disallowed_undefined_variable() {
    assert!(
        std::env::var("hopefully_undefined_variable").is_err(),
        "Test invalid due to presence of environment variable."
    );

    let error = WordExpander::default().expand("this_is_a$hopefully_undefined_variable");

    assert_eq!(error, Err(WordError::UndefinedVariable));
}

#[test]
fn allowed_undefined_variable() {
    assert!(
        std::env::var("hopefully_undefined_variable").is_err(),
        "Test invalid due to presence of environment variable."
    );

    let words = WordExpander::default()
        .allow_undefined()
        .expand("this_is_a$hopefully_undefined_variable")
        .unwrap();
    let word = words[0].to_str().unwrap();

    assert_eq!(word, "this_is_a");
}

#[test]
fn is_empty() {
    let words = WordExpander::default().expand("").unwrap();

    assert!(words.is_empty());
}

#[test]
fn not_is_empty() {
    let words = WordExpander::default().expand("something").unwrap();

    assert!(!words.is_empty());
}

#[test]
fn len_0() {
    let words = WordExpander::default().expand("").unwrap();

    assert_eq!(words.len(), 0);
}

#[test]
fn len_1() {
    let words = WordExpander::default().expand("something").unwrap();

    assert_eq!(words.len(), 1);
}

#[test]
fn len_2() {
    let words = WordExpander::default().expand("two things").unwrap();

    assert_eq!(words.len(), 2);
}

#[test]
fn index_1() {
    let words = WordExpander::default().expand("something").unwrap();
    let word = words[0].to_str().unwrap();

    assert_eq!(word, "something");
}

#[test]
fn index_2() {
    let words = WordExpander::default().expand("two things").unwrap();
    let word = words[1].to_str().unwrap();

    assert_eq!(word, "things");
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn out_of_bounds_0() {
    let words = WordExpander::default().expand("").unwrap();

    let _ = &words[0];
}

#[test]
#[should_panic(expected = "index out of bounds")]
fn out_of_bounds_2() {
    let words = WordExpander::default().expand("two things").unwrap();

    let _ = &words[2];
}

#[test]
fn iteration() {
    let words = WordExpander::default().expand("1 2 3").unwrap();
    let words = words
        .into_iter()
        .map(std::ffi::CStr::to_str)
        .collect::<Result<Vec<_>, _>>()
        .unwrap();

    assert_eq!(words, vec!["1", "2", "3"]);
}
