Skip to main content

dec_cryptor/
args.rs

1use std::path::Path;
2
3#[derive(Debug, PartialEq)]
4pub enum Op { Enc, Dec }
5
6#[derive(Debug)]
7pub struct Args {
8    pub op: Op,
9    pub input_path: String,
10    pub output_path: String,
11    pub password: Option<String>,
12    pub quiet: bool,
13}
14pub fn parse_args(args: &Vec<String>) -> Result<Args, String> {
15    // 标准:~ -e file (两个往上)
16    if args.len() < 2 {
17        return Err("arg too short".to_string());
18    }
19
20    // 参数分类
21    let op = {
22        match args[0].as_str() {
23            "-e" | "--encrypt" => { Op::Enc }
24            "-d" | "--decrypt" => { Op::Dec }
25            _ => {
26                return Err("unknown operation".to_string())
27            }
28        }
29    };
30
31    // 获取 输出文件路径
32    let input_path = args[1].clone();
33
34    // 检查 输入文件 是否存在
35    if !Path::new(&input_path).exists() {
36        return Err("no such file".to_string())
37    }
38
39    let mut quiet = false;
40    let mut output_path: Option<String> = None;
41    let mut password: Option<String> = None;
42
43    if args.len() > 2 {
44        let mut skip = false;
45        let mut i: usize = 2;
46        for v in &args[2..] {
47            i += 1;
48            if skip { skip = false; continue; }
49            match v.as_str() {
50                "-q" | "--quiet" => { quiet = true; }
51
52                "-p" | "--password" => {
53                    if password == None {
54                        password = Some(args[i].clone());
55                        skip = true;
56                    } else {
57                        return Err("one password option only".to_string());
58                    }
59                }
60
61                "-o" | "--output" => {
62                    if output_path == None {
63                        output_path = Some(args[i].clone());
64                        skip = true;
65                    } else {
66                        return Err("one output option only".to_string());
67                    }
68                }
69
70                _ => {
71                    return Err("unknown option".to_string());
72                }
73            }
74        }
75    }
76
77    // 当未指定 输出文件路径 时
78    if output_path == None {
79        match op {
80            Op::Enc => output_path = Some(format!("{}.decx", input_path)),
81            Op::Dec => {
82                if input_path.ends_with(".decx") {
83                    output_path = Some(input_path[..input_path.len() - 5].to_string());
84                } else {
85                    output_path = Some(format!("{}.out", input_path));
86                }
87            }
88        }
89    }
90
91    let output = match output_path {
92        Some(s) => s,
93        _ => unreachable!()
94    };
95
96    Ok(Args { op, input_path, output_path: output, password, quiet })
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_parse_args_encrypt_basic() {
105        // 创建一个测试文件
106        let test_file = create_test_file("test_input.txt");
107
108        let args = vec![
109            "-e".to_string(),
110            test_file.path().to_str().unwrap().to_string()
111        ];
112
113        let result = parse_args(&args);
114        assert!(result.is_ok());
115        let parsed_args = result.unwrap();
116        assert_eq!(parsed_args.op, Op::Enc);
117        assert_eq!(parsed_args.output_path, format!("{}.decx", test_file.path().to_str().unwrap()));
118        assert_eq!(parsed_args.quiet, false);
119    }
120
121    #[test]
122    fn test_parse_args_decrypt_with_options() {
123        // 创建一个测试文件
124        let test_file = create_test_file("test_input.decx");
125
126        let args = vec![
127            "-d".to_string(),
128            test_file.path().to_str().unwrap().to_string(),
129            "-o".to_string(),
130            "custom_output.txt".to_string(),
131            "-p".to_string(),
132            "testpassword".to_string(),
133            "-q".to_string()
134        ];
135
136        let result = parse_args(&args);
137        assert!(result.is_ok());
138        let parsed_args = result.unwrap();
139        assert_eq!(parsed_args.op, Op::Dec);
140        assert_eq!(parsed_args.output_path, "custom_output.txt");
141        assert_eq!(parsed_args.password, Some("testpassword".to_string()));
142        assert_eq!(parsed_args.quiet, true);
143    }
144
145    #[test]
146    fn test_parse_args_invalid_operation() {
147        let args = vec!["-x".to_string(), "input.txt".to_string()];
148        let result = parse_args(&args);
149        assert!(result.is_err());
150        assert_eq!(result.unwrap_err(), "unknown operation");
151    }
152
153    #[test]
154    fn test_parse_args_missing_arguments() {
155        let args = vec!["-e".to_string()];
156        let result = parse_args(&args);
157        assert!(result.is_err());
158        assert_eq!(result.unwrap_err(), "arg too short");
159    }
160
161    #[test]
162    fn test_parse_args_file_not_found() {
163        let args = vec!["-e".to_string(), "nonexistent.txt".to_string()];
164        let result = parse_args(&args);
165        assert!(result.is_err());
166        assert_eq!(result.unwrap_err(), "no such file");
167    }
168
169    // 辅助函数:创建临时测试文件
170    fn create_test_file(_name: &str) -> tempfile::NamedTempFile {
171        let file = tempfile::NamedTempFile::new().unwrap();
172        std::fs::write(file.path(), "test content").unwrap();
173        file
174    }
175}