Documentation
/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Dia-Args

Copyright (C) 2018-2019, 2021-2025  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2018-2019".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

use {
    std::{env, fs},
    dia_args::Result,
};

const OPTION_TEST: &[&str] = &["-t", "--test"];
const OPTION_DEBUG: &[&str] = &["--debug"];
const OPTION_FLAG: &[&str] = &["-f", "--flag"];
const OPTION_SOME: &[&str] = &["--some"];

#[test]
fn sub_cmds() -> Result<()> {
    let args = dia_args::parse_strings(["help", "version", "1"])?;
    let (cmd, args) = args.try_into_sub_cmd()?;
    assert_eq!(cmd.unwrap(), "help");

    let (cmd, mut args) = args.try_into_sub_cmd()?;
    assert_eq!(cmd.unwrap(), "version");
    assert_eq!(args.take_args()?, &["1"]);

    for _ in 0..9 {
        let (cmd, mut new) = args.try_into_sub_cmd()?;
        assert_eq!(cmd, None);
        assert!(new.take_args()?.is_empty());
        args = new;
    }

    Ok(())
}

#[test]
fn default_boolean_options() -> Result<()> {
    let mut args = dia_args::parse_strings(["--debug"])?;
    assert_eq!(true, args.take(&["--debug"])?.unwrap());

    let mut args = dia_args::parse_strings(["--debug", "something"])?;
    assert_eq!("something", args.take::<String>(&["--debug"])?.unwrap());

    let mut args = dia_args::parse_strings(["--debug", "false"])?;
    assert_eq!(false, args.take(&["--debug"])?.unwrap());
    assert!(args.is_empty());

    let mut args = dia_args::parse_strings(["--debug", "some"])?;
    assert_eq!(true, args.take(&["--debug"])?.unwrap());
    assert_eq!(args.take_args()?, &["some"]);
    assert!(args.is_empty());

    let mut args = dia_args::parse_strings(["--debug=false", "something"])?;
    assert_eq!(false, args.take(&["--debug"])?.unwrap());

    let mut args = dia_args::parse_strings(["--debug=false", "--other"])?;
    assert_eq!(false, args.take(&["--debug"])?.unwrap());

    let mut args = dia_args::parse_strings(["--debug", "-x"])?;
    assert_eq!(true, args.take(&["--debug"])?.unwrap());

    Ok(())
}

#[test]
fn parse_file() -> Result<()> {
    let file = env::temp_dir().join(format!("{}{}", dia_args::ID, dia_args::DIA_ARGS_FILE_NAME));

    if file.is_file() {
        fs::remove_file(&file)?;
    }

    fs::write(
        &file,
        concat!(
            "           command            \n",
            "           sub-command            \n",
            "--passphrase=something \t secret\n",
            "--type\togg\n",
            "--type         rs              \n",
            "# Some comment here\n",
            "   #       Some comment there\n",
            "--port     =       9999            \n",
        )
    )?;

    // Test max size
    for max_size in &[0, 1, 2] {
        assert!(dia_args::parse_file(Some(&file), Some(*max_size)).is_err());
    }

    let (cmd, args) = dia_args::parse_file(Some(&file), Some(file.metadata()?.len()))?.unwrap().try_into_sub_cmd()?;
    assert_eq!(cmd.unwrap(), "command");

    let (cmd, mut args) = args.try_into_sub_cmd()?;
    assert_eq!(cmd.unwrap(), "sub-command");
    assert_eq!(args.take::<String>(&["--passphrase"])?.unwrap(), "something \t secret");
    assert_eq!(vec!["ogg", "rs"], {
        let mut vec = args.take_vec::<String>(&["--type"])?.unwrap();
        vec.sort();
        vec
    });
    assert_eq!(args.take::<u16>(&["--port"])?.unwrap(), 9999);
    assert!(args.is_empty());

    Ok(())
}

#[test]
fn parse_streams() -> Result<()> {
    let stream = b"some\0command\0--debug=true\0--some\0\0--test\0false\0\0\0\0--flag=0\0--flag\01\0--flag\02\0--\0sub\0args\0--some=none\0";

    // Test max size
    for max_size in &[0, 1, 2] {
        assert!(dia_args::parse_stream(&mut &stream[..], Some(*max_size)).is_err());
    }

    let mut args = dia_args::parse_stream(&mut &stream[..], Some(stream.len() as u64))?;
    assert_eq!(args.take(OPTION_DEBUG)?, Some(true));
    assert_eq!(args.take(OPTION_TEST)?, Some(false));
    assert!(args.take::<String>(OPTION_SOME)?.unwrap().is_empty());
    assert_eq!(args.take_vec::<u8>(OPTION_FLAG)?.unwrap(), &[0, 1, 2]);
    assert_eq!(args.take_args().unwrap(), &["some", "command"]);
    assert_eq!(args.take_sub_args(), &["sub", "args", "--some=none"]);
    assert!(args.is_empty());

    Ok(())
}