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

/* tests for private helpers functions */

use super::*;


//    validate_optstring tests


#[test]
fn validate_optstring_ok() {
   assert! ( validate_optstring("valid").is_ok() );
}

#[test]
fn validate_optstring_ok_question_mark() {
   assert! ( validate_optstring("valid?").is_ok() );
}

#[test]
fn validate_optstring_ok_semi() {
   assert! ( validate_optstring("val:id").is_ok() );
}

#[test]
fn validate_optstring_invalid_char() {
   assert! ( validate_optstring("!valid").is_err() );
}

#[test]
fn validate_optstring_invalid_semi_start() {
   assert! ( validate_optstring(":valid").is_err() );
}

#[test]
fn validate_optstring_invalid_plus_start() {
   assert! ( validate_optstring("+posix").is_err() );
}

#[test]
fn validate_optstring_invalid_double_semi_start() {
   assert! ( validate_optstring("::notvalid").is_err() );
}

#[test]
fn validate_optstring_invalid_double_semi_mid() {
   assert! ( validate_optstring("double::semi").is_err() );
}

#[test]
fn validate_optstring_invalid_tripple_semi_mid() {
   assert! ( validate_optstring("tripple:::semi").is_err() );
}

#[test]
fn validate_optstring_invalid_empty() {
   assert! ( validate_optstring("").is_err() );
}

#[test]
fn validate_optstring_invalid_not_alphanum() {
   assert! ( validate_optstring("@#$%!").is_err() );
}

#[test]
fn validate_optstring_spaces_outside() {
   assert! ( validate_optstring(" a:b ").is_err() );
}

#[test]
fn validate_optstring_spaces_inside() {
   assert! ( validate_optstring("a: b").is_err() );
}

#[test]
fn validate_optstring_spaces_only() {
   assert! ( validate_optstring("  ").is_err() );
}


//    validate_optchar tests


#[test]
fn validate_optchar_collon() {
   assert! ( validate_optchar(':').is_err() );
}

#[test]
fn validate_optchar_plus() {
   assert! ( validate_optchar('+').is_err() );
}

#[test]
fn validate_optchar_dash() {
   assert! ( validate_optchar('-').is_err() );
}

#[test]
fn validate_optchar_question_mark() {
   assert! ( validate_optchar('?').is_ok() );
}

#[test]
fn validate_optchar_number() {
   assert! ( validate_optchar('6').is_ok() );
}

#[test]
fn validate_optchar_lowercase() {
   assert! ( validate_optchar('a').is_ok() );
}

#[test]
fn validate_optchar_uppercase() {
   assert! ( validate_optchar('B').is_ok() );
}


//    build_options_map tests


#[test]
fn optionsmap_arg_tail() {
   let map = build_options_map("ab:");
   assert_eq!( map.get(&'a'), Some(&false));
   assert_eq!( map.get(&'b'), Some(&true));
   assert_eq!( map.get(&':'), None);
   assert_eq!( map.len(), 2);
}

#[test]
fn optionsmap_without_args() {
   let map = build_options_map("abc");
   assert_eq!( map.get(&'a'), Some(&false));
   assert_eq!( map.get(&'b'), Some(&false));
   assert_eq!( map.get(&'c'), Some(&false));
   assert_eq!( map.get(&':'), None);
   assert_eq!( map.len(), 3);
}

#[test]
fn optionsmap_with_args() {
   let map = build_options_map("a:b:c:");
   assert_eq!( map.get(&'a'), Some(&true));
   assert_eq!( map.get(&'b'), Some(&true));
   assert_eq!( map.get(&'c'), Some(&true));
   assert_eq!( map.get(&':'), None);
   assert_eq!( map.len(), 3);
}

#[test]
fn optionsmap_arg_in_middle() {
   let map = build_options_map("ab:c");
   assert_eq!( map.get(&'a'), Some(&false));
   assert_eq!( map.get(&'b'), Some(&true));
   assert_eq!( map.get(&'c'), Some(&false));
   assert_eq!( map.get(&':'), None);
   assert_eq!( map.len(), 3);
}


//   parseElement function tests


use std::io::ErrorKind;

/** options map used for further testing */
fn gopt() -> HashMap<char, bool> {
   build_options_map("a:b")
}

#[test]
fn parseElement_empty() {
   let gopt = gopt();
   assert!  (parseElement("", &gopt).is_err());
   let err = parseElement("", &gopt).err().unwrap();
   assert! ( err.kind() != ErrorKind::UnexpectedEof );
}

#[test]
fn parseElement_double_dash() {
   let gopt = gopt();
   assert!  (parseElement("--", &gopt).is_err());
   let err = parseElement("--", &gopt).err().unwrap();
   assert_eq! ( err.kind(), ErrorKind::UnexpectedEof );
}

#[test]
fn parseElement_non_option_element() {
   let gopt = gopt();
   let rc = parseElement("karel", &gopt);

   assert! (rc.is_ok());
   let rc = rc.unwrap();
   assert_eq! (rc.0.len(), 0);
   assert_eq! (rc.1 , Some("karel".to_string()));
   assert_eq! (rc.2 , None);
}

#[test]
fn parseElement_option_without_argument() {
   let gopt = gopt();
   let rc = parseElement("-b", &gopt);

   assert! (rc.is_ok());
   let (a1, a2, a3) = rc.unwrap();
   assert_eq! ( a1.get(&'b').map(|s| s.to_string()), Some(String::new()));
   assert_eq! ( a2, None );
   assert_eq! ( a3, None );
}

#[test]
fn parseElement_unknown_option() {
   let gopt = gopt();
   let rc = parseElement("-Z", &gopt);

   assert! (rc.is_ok());
   let (a1, a2, a3) = rc.unwrap();
   assert_eq! ( a1.get(&'Z').map(|s| s.to_string()), Some(String::new()));
   assert_eq! ( a2, None );
   assert_eq! ( a3, None );
}

#[test]
fn parseElement_option_with_argument() {
   let gopt = gopt();
   let rc = parseElement("-amazing", &gopt);

   assert! (rc.is_ok());
   let (a1, a2, a3) = rc.unwrap();
   assert_eq! ( a1.get(&'a').map(|s| s.to_string()), Some(String::from("mazing")));
   assert_eq! ( a2, None );
   assert_eq! ( a3, None );
}

#[test]
fn parseElement_option_value_in_next_element() {
   let gopt = gopt();
   let rc = parseElement("-a", &gopt);

   assert! (rc.is_ok());
   let (a1, a2, a3) = rc.unwrap();
   assert_eq! ( a1.len(), 0);
   assert_eq! ( a2, None );
   assert_eq! ( a3, Some('a') );
}
