/*
 * Copyright (c) Radim Kolar 2013, 2018, 2023.
 * SPDX-License-Identifier: MIT
 *
 * getopt3 library is licensed under MIT license:
 *   https://spdx.org/licenses/MIT.html
*/

use crate::new;

/** converts iterable &str into String Vec */
fn toStringVec<'a>(iter: impl IntoIterator<Item = &'a str>) -> Vec<String> {
    iter.into_iter().map(|s| s.to_string()).collect()
}


//  basic getopt parsing


#[test]
fn basic_no_options() {
   let g = new(toStringVec( ["one","two"]), "a");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments.len(), 2 );
   assert_eq! ( g.options.len(), 0 );
}

#[test]
fn basic_one_option_without_arg() {
   let g = new(toStringVec( ["one","two","-a"]), "a".to_string());
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments.len(), 2 );
   assert_eq! ( g.options.len(), 1 );
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
}

#[test]
fn basic_one_option_with_arg() {
   let g = new(toStringVec( ["one","-a","two"]), "a:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.options.get(&'a'), Some(&"two".to_string()) );
   assert_eq! ( g.arguments, toStringVec(["one"]) );
}

#[test]
fn basic_two_options_without_arg() {
   let g = new(toStringVec( ["one","-a","-b","two"]), "ab");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
   assert_eq! ( g.options.get(&'b'), Some(&"".to_string()) );
   assert_eq! ( g.arguments, toStringVec(["one","two"]) );
}

#[test]
fn basic_two_option_with_missing_arg() {
   let g = new(toStringVec( ["one","two","-c"]), "c:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","two"]) );
   assert_eq! ( g.options.get(&'c'), Some(&"".to_string()) );
}

#[test]
fn basic_question_mark_option_without_arg() {
   let g = new(toStringVec( ["-?"]), "?".to_string());
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments.len(), 0 );
   assert_eq! ( g.options.len(), 1 );
   assert_eq! ( g.options.get(&'?'), Some(&"".to_string()) );
}



//  advanced getopt parsing


#[test]
fn advanced_one_with_arg_in_same_element() {
   let g = new(toStringVec( ["one","-atwo","three"]), "a:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","three"]) );
   assert_eq! ( g.options.get(&'a'), Some(&"two".to_string()) );
}

#[test]
fn advanced_two_options_chained_together_without_arg() {
   let g = new(toStringVec( ["one","-ab","two"]), "ab");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","two"]) );
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
   assert_eq! ( g.options.get(&'b'), Some(&"".to_string()) );
}

#[test]
fn advanced_dash_without_an_option() {
   let g = new(toStringVec( ["one","-","two"]), "ab");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","-","two"]) );
   assert_eq! ( g.options.len(), 0 );
}

#[test]
fn advanced_two_options_with_arg_in_same_element() {
   let g = new(toStringVec( ["one","-abtwo","three"]), "ab:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","three"]) );
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
   assert_eq! ( g.options.get(&'b'), Some(&"two".to_string()) );
}

#[test]
fn advanced_two_options_with_arg_in_the_next_element() {
   let g = new(toStringVec( ["one","-ab","two","three"]), "ab:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","three"]) );
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
   assert_eq! ( g.options.get(&'b'), Some(&"two".to_string()) );
}


// unknown options parsing


#[test]
fn unknown_option_without_arg() {
   let g = new(toStringVec( ["one","two","-c","-a"]), "a");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","two"]) );
   assert_eq! ( g.options.get(&'a'), Some(&"".to_string()) );
   assert_eq! ( g.options.get(&'c'), Some(&"".to_string()) );
}

#[test]
fn unknown_option_with_arg() {
   let g = new(toStringVec( ["one","two","-c","kalo"]), "a");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments, toStringVec(["one","two","kalo"]) );
   assert_eq! ( g.options.get(&'c'), Some(&"".to_string()) );
}


// misc tests


#[test]
fn bad_input_zero_sized_string() {
   let g = new(toStringVec( ["one","two","-c",""]), "c");
   assert! ( g.is_ok() );
}

#[test]
fn bad_input_zero_sized_arg() {
   let g = new(toStringVec( ["one","two","-c",""]), "c:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.options.get(&'c'), Some(&"".to_string()) );
}


// checks for getopt.len()


#[test]
fn basic_getopt_len() {
   let g = new(toStringVec( ["one","two"]), "a");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.arguments.len(), 2 );
   assert_eq! ( g.len(), 2 );
   assert_eq! ( g.options.len(), 0 );
}


// checks for getopt.get()

#[test]
fn basic_getopt_get() {
   let g = new(toStringVec( ["one","-a","two"]), "a:");
   assert! ( g.is_ok() );
   let g = g.unwrap();
   assert_eq! ( g.options.get(&'a'), Some(&"two".to_string()) );
   assert_eq! ( g.get('a'), Some(&"two".to_string()) );
}
