core/
arguments.rs

1use std::ffi::OsString;
2
3use pico_args::Arguments;
4
5use crate::{exit::Exit, module::ExitStatus};
6
7#[derive(Debug, Eq, PartialEq)]
8pub(crate) enum Mode {
9	Editor,
10	Help,
11	Version,
12	License,
13}
14
15#[derive(Debug)]
16pub(crate) struct Args {
17	mode: Mode,
18	todo_file_path: Option<String>,
19}
20
21impl Args {
22	pub(crate) const fn mode(&self) -> &Mode {
23		&self.mode
24	}
25
26	pub(crate) const fn todo_file_path(&self) -> &Option<String> {
27		&self.todo_file_path
28	}
29}
30
31impl TryFrom<Vec<OsString>> for Args {
32	type Error = Exit;
33
34	fn try_from(args: Vec<OsString>) -> Result<Self, Self::Error> {
35		let mut pargs = Arguments::from_vec(args);
36
37		let mode = if pargs.contains(["-h", "--help"]) {
38			Mode::Help
39		}
40		else if pargs.contains(["-v", "--version"]) {
41			Mode::Version
42		}
43		else if pargs.contains("--license") {
44			Mode::License
45		}
46		else {
47			Mode::Editor
48		};
49
50		let todo_file_path = pargs
51			.opt_free_from_str()
52			.map_err(|err| Exit::new(ExitStatus::StateError, err.to_string().as_str()))?;
53
54		Ok(Self { mode, todo_file_path })
55	}
56}
57
58#[cfg(test)]
59mod tests {
60	use super::*;
61
62	fn create_args(args: &[&str]) -> Vec<OsString> {
63		args.iter().map(OsString::from).collect()
64	}
65
66	#[test]
67	fn mode_help() {
68		assert_eq!(Args::try_from(create_args(&["-h"])).unwrap().mode(), &Mode::Help);
69		assert_eq!(Args::try_from(create_args(&["--help"])).unwrap().mode(), &Mode::Help);
70	}
71
72	#[test]
73	fn mode_version() {
74		assert_eq!(Args::try_from(create_args(&["-v"])).unwrap().mode(), &Mode::Version);
75		assert_eq!(
76			Args::try_from(create_args(&["--version"])).unwrap().mode(),
77			&Mode::Version
78		);
79	}
80
81	#[test]
82	fn mode_license() {
83		assert_eq!(
84			Args::try_from(create_args(&["--license"])).unwrap().mode(),
85			&Mode::License
86		);
87	}
88
89	#[test]
90	fn todo_file_ok() {
91		let args = Args::try_from(create_args(&["todofile"])).unwrap();
92		assert_eq!(args.mode(), &Mode::Editor);
93		assert_eq!(args.todo_file_path(), &Some(String::from("todofile")));
94	}
95
96	#[test]
97	fn todo_file_missing() {
98		let args = Args::try_from(create_args(&[])).unwrap();
99		assert_eq!(args.mode(), &Mode::Editor);
100		assert!(args.todo_file_path().is_none());
101	}
102
103	#[cfg(unix)]
104	#[test]
105	#[allow(unsafe_code)]
106	fn todo_file_invalid() {
107		let args = unsafe { vec![OsString::from(String::from_utf8_unchecked(vec![0xC3, 0x28]))] };
108		_ = Args::try_from(args).unwrap_err();
109	}
110}