]> git.proxmox.com Git - proxmox-backup.git/blob - src/getopts.rs
getopts: more tests
[proxmox-backup.git] / src / getopts.rs
1 use crate::api::schema::*;
2
3 use failure::*;
4 use std::collections::HashMap;
5 use serde_json::{json, Value};
6
7 #[derive(Debug)]
8 enum RawArgument {
9 Separator,
10 Argument { value: String },
11 Option { name: String, value: Option<String> },
12 }
13
14 fn parse_argument(arg: &str) -> RawArgument {
15
16 let chars: Vec<char> = arg.chars().collect();
17
18 let length = chars.len();
19
20 if length >= 2 {
21
22 if chars[0] == '-' {
23 let mut first = 1;
24
25 if chars[1] == '-' {
26 if length == 2 { return RawArgument::Separator; }
27 first = 2;
28 }
29
30 for start in first..length {
31 if chars[start] == '=' {
32 let name: String = chars[first..start].iter().collect();
33 let value: String = chars[start+1..length].iter().collect();
34 return RawArgument::Option { name, value: Some(value) }
35 }
36 }
37
38 let name: String = chars[first..].iter().collect();
39 return RawArgument::Option { name: name, value: None }
40 }
41 }
42
43 RawArgument::Argument { value: arg.to_string() }
44 }
45
46 pub fn parse_arguments(
47 args: &Vec<String>,
48 schema: &ObjectSchema,
49 ) -> Result<(Value,Vec<String>), ParameterError> {
50
51 let mut errors = ParameterError::new();
52
53 let properties = &schema.properties;
54
55 let mut data: Vec<(String, String)> = vec![];
56 let mut rest: Vec<String> = vec![];
57
58 let mut pos = 0;
59
60 let mut skip = false;
61
62 loop {
63 if skip {
64 rest.push(args[pos].clone());
65 } else {
66 match parse_argument(&args[pos]) {
67 RawArgument::Separator => {
68 skip = true;
69 }
70 RawArgument::Option { name, value } => {
71 match value {
72 None => {
73 let param_schema = properties.get::<str>(&name);
74 let (want_bool, can_default) = match param_schema {
75 Some(Schema::Boolean(boolean_schema)) => {
76 if let Some(default) = boolean_schema.default {
77 if default == true { (true, false); }
78 }
79 (true, true)
80 }
81 _ => (false, false),
82 };
83
84 let mut next_is_argument = false;
85 let mut next_is_bool = false;
86
87 if (pos + 1) < args.len() {
88 let next = &args[pos+1];
89 if let RawArgument::Argument { value: _} = parse_argument(next) {
90 next_is_argument = true;
91 if let Ok(_) = parse_boolean(next) { next_is_bool = true; }
92 }
93 }
94
95 if want_bool {
96 if next_is_bool {
97 pos += 1;
98 data.push((name, args[pos].clone()));
99 } else if can_default {
100 data.push((name, "true".to_string()));
101 } else {
102 errors.push(format_err!("parameter '{}': {}", name,
103 "missing boolean value."));
104 }
105
106 } else {
107
108 if next_is_argument {
109 pos += 1;
110 data.push((name, args[pos].clone()));
111 } else {
112 errors.push(format_err!("parameter '{}': {}", name,
113 "missing parameter value."));
114 }
115 }
116 }
117 Some(v) => {
118 data.push((name, v));
119 }
120 }
121 }
122 RawArgument::Argument { value } => {
123 rest.push(value);
124 }
125 }
126 }
127
128 pos += 1;
129 if pos >= args.len() { break; }
130 }
131
132 if errors.len() > 0 { return Err(errors); }
133
134 let options = parse_parameter_strings(&data, schema, true)?;
135
136 Ok((options,rest))
137 }
138
139
140 #[test]
141 fn test_boolean_arg() {
142
143 let schema = parameter!{enable => Boolean!{ optional => false }};
144
145 let mut variants: Vec<(Vec<&str>, bool)> = vec![];
146 variants.push((vec!["-enable"], true));
147 variants.push((vec!["-enable=1"], true));
148 variants.push((vec!["-enable", "yes"], true));
149 variants.push((vec!["-enable", "Yes"], true));
150 variants.push((vec!["--enable", "1"], true));
151 variants.push((vec!["--enable", "ON"], true));
152 variants.push((vec!["--enable", "true"], true));
153
154 variants.push((vec!["--enable", "0"], false));
155 variants.push((vec!["--enable", "no"], false));
156 variants.push((vec!["--enable", "off"], false));
157 variants.push((vec!["--enable", "false"], false));
158
159 for (args, expect) in variants {
160 let string_args = args.iter().map(|s| s.to_string()).collect();
161 let res = parse_arguments(&string_args, &schema);
162 assert!(res.is_ok());
163 if let Ok((options, rest)) = res {
164 assert!(options["enable"] == expect);
165 assert!(rest.len() == 0);
166 }
167 }
168
169 }