diff --git a/proxmox-api/src/cli.rs b/proxmox-api/src/cli.rs index 7bed0e20..798a1c57 100644 --- a/proxmox-api/src/cli.rs +++ b/proxmox-api/src/cli.rs @@ -180,20 +180,20 @@ impl Method { loop { match next_arg(&mut args) { Some(Arg::Opt(arg)) => { - if let Some(arg) = current_option { + if let Some(arg) = current_option.take() { self.add_parameter(&mut params, arg, None)?; } current_option = Some(arg); } Some(Arg::OptArg(arg, value)) => { - if let Some(arg) = current_option { + if let Some(arg) = current_option.take() { self.add_parameter(&mut params, arg, None)?; } self.add_parameter(&mut params, arg, Some(value))?; } - Some(Arg::Positional(value)) => match current_option { + Some(Arg::Positional(value)) => match current_option.take() { Some(arg) => self.add_parameter(&mut params, arg, Some(value))?, None => match positionals.next() { Some(arg) => self.add_parameter(&mut params, arg, Some(value))?, @@ -201,7 +201,7 @@ impl Method { }, }, None => { - if let Some(arg) = current_option { + if let Some(arg) = current_option.take() { self.add_parameter(&mut params, arg, None)?; } break; diff --git a/proxmox-api/tests/cli.rs b/proxmox-api/tests/cli.rs index 515623b2..1e8761cb 100644 --- a/proxmox-api/tests/cli.rs +++ b/proxmox-api/tests/cli.rs @@ -17,28 +17,71 @@ fn simple() { cli::Command::method(simple_method, &["foo", "bar"]), ); - let result = cli - .run(&["new", "--foo=FOO", "--bar=BAR"]) - .expect("command should execute successfully"); - let body = - std::str::from_utf8(result.body().as_ref()).expect("expected a valid utf8 repsonse body"); - assert_eq!(body, "FOO:BAR"); + check_cli(&cli, &["new", "--foo=FOO", "--bar=BAR"], Ok("FOO:BAR")); + check_cli(&cli, &["new", "--foo", "FOO", "--bar=BAR"], Ok("FOO:BAR")); + check_cli(&cli, &["new", "--foo", "FOO", "--bar", "BAR"], Ok("FOO:BAR")); + check_cli(&cli, &["new", "--foo=FOO"], Err("missing parameter: 'bar'")); + check_cli(&cli, &["new", "--bar=BAR"], Err("missing parameter: 'foo'")); + check_cli(&cli, &["new"], Err("missing parameter: 'foo'")); + + check_cli(&cli, &["newfoo", "POSFOO"], Err("missing parameter: 'bar'")); + check_cli(&cli, &["newfoo", "POSFOO", "--bar=BAR"], Ok("POSFOO:BAR")); + check_cli(&cli, &["newfoo", "--bar=BAR", "POSFOO"], Ok("POSFOO:BAR")); + check_cli(&cli, &["newfoo", "--bar=BAR"], Err("missing positional parameters: foo")); + + check_cli(&cli, &["newbar", "POSBAR"], Err("missing parameter: 'foo'")); + check_cli(&cli, &["newbar", "POSBAR", "--foo=ABC"], Ok("ABC:POSBAR")); + check_cli(&cli, &["newbar", "--foo=ABC", "POSBAR"], Ok("ABC:POSBAR")); + check_cli(&cli, &["newbar", "--foo=ABC"], Err("missing positional parameters: bar")); + + check_cli(&cli, &["newfoo", "FOO1", "--foo=FOO2", "--bar=BAR", "--baz=OMG"], Ok("FOO2:BAR:OMG")); +} + +fn check_cli(cli: &cli::App, args: &[&str], expect: Result<&str, &str>) { + match (cli.run(args), expect) { + (Ok(result), Ok(expect)) => { + let body = std::str::from_utf8(result.body().as_ref()) + .expect("expected a valid utf8 repsonse body"); + assert_eq!(body, expect, "expected successful CLI invocation"); + } + (Err(result), Err(expected)) => { + let result = result.to_string(); + assert_eq!(result, expected, "expected specific error message"); + } + (Ok(result), Err(err)) => { + match std::str::from_utf8(result.body().as_ref()) { + Ok(value) => panic!("expected error '{}', got success with value '{}'", err, value), + Err(_) => panic!("expected error '{}', got success with non-utf8 string", err), + } + } + (Err(err), Ok(expected)) => { + let err = err.to_string(); + panic!("expected success with value '{}', got error '{}'", expected, err); + } + } } mod methods { use bytes::Bytes; + use failure::{format_err, Error}; use http::Response; use lazy_static::lazy_static; use serde_json::Value; use proxmox_api::{get_type_info, ApiFuture, ApiMethod, ApiOutput, ApiType, Parameter}; + fn required_str<'a>(value: &'a Value, name: &'static str) -> Result<&'a str, Error> { + value[name].as_str().ok_or_else(|| format_err!("missing parameter: '{}'", name)) + } + pub async fn simple_method(value: Value) -> ApiOutput { - let foo = value["foo"].as_str().unwrap(); + let foo = required_str(&value, "foo")?; + let bar = required_str(&value, "bar")?; - let bar = value["bar"].as_str().unwrap(); - - let baz = value.get("baz").map(|value| value.as_str().unwrap()); + let baz = value + .get("baz") + .map(|value| value.as_str().ok_or_else(|| format_err!("'baz' must be a string"))) + .transpose()?; let output = match baz { Some(baz) => format!("{}:{}:{}", foo, bar, baz),