refactor and test the multi-call code

main
_ 2021-10-02 18:47:10 +00:00
parent f44613540e
commit 4329562aa3
1 changed files with 100 additions and 19 deletions

View File

@ -1,7 +1,9 @@
use std::{ use std::{
ffi::OsString,
iter::FromIterator, iter::FromIterator,
}; };
#[derive (Debug, PartialEq)]
enum Subcommand { enum Subcommand {
PtthServer, PtthServer,
PtthQuicEndServer, PtthQuicEndServer,
@ -22,30 +24,109 @@ fn parse_subcommand (name: &str) -> Option <Subcommand>
} }
} }
fn parse_args (args: &[OsString]) -> anyhow::Result <(Subcommand, &[OsString])>
{
let arg_0 = match args.get (0) {
Some (x) => x,
None => anyhow::bail! ("arg 0 must be the exe name"),
};
let arg_0 = arg_0.to_str ().ok_or_else (|| anyhow::anyhow! ("arg 0 should be valid UTF-8"))?;
match parse_subcommand (arg_0) {
Some (x) => return Ok ((x, args)),
None => (),
}
let arg_1 = match args.get (1) {
Some (x) => x,
None => anyhow::bail! ("arg 1 must be the subcommand if arg 0 is not"),
};
let arg_1 = arg_1.to_str ().ok_or_else (|| anyhow::anyhow! ("arg 1 subcommand should be valid UTF-8"))?;
match parse_subcommand (arg_1) {
Some (x) => return Ok ((x, &args [1..])),
None => (),
}
anyhow::bail! ("Subcommand must be either arg 0 (exe name) or arg 1")
}
#[tokio::main] #[tokio::main]
async fn main () -> anyhow::Result <()> { async fn main () -> anyhow::Result <()> {
tracing_subscriber::fmt::init (); tracing_subscriber::fmt::init ();
let args = Vec::from_iter (std::env::args_os ()); let args = Vec::from_iter (std::env::args_os ());
let arg_0 = args [0].to_str ().expect ("exe name should be valid UTF-8"); let (subcommand, args) = parse_args (&args)?;
match parse_subcommand (arg_0) { match subcommand {
Some (Subcommand::PtthServer) => return ptth_server::executable::main (&args).await, Subcommand::PtthServer => ptth_server::executable::main (&args).await,
Some (Subcommand::PtthQuicEndServer) => return quic_demo::executable_end_server::main (&args).await, Subcommand::PtthQuicEndServer => quic_demo::executable_end_server::main (&args).await,
_ => (), }
} }
let arg_1 = match args.get (1) { #[cfg (test)]
Some (x) => x, mod tests {
None => anyhow::bail! ("Subcommand must be the first argument if it's not the exe name"), use super::*;
};
let arg_1 = arg_1.to_str ().expect ("subcommand should be valid UTF-8"); #[test]
match parse_subcommand (arg_1) { fn multi_call () -> anyhow::Result <()> {
Some (Subcommand::PtthServer) => return ptth_server::executable::main (&args [1..]).await, let negative_cases = vec! [
Some (Subcommand::PtthQuicEndServer) => return quic_demo::executable_end_server::main (&args [1..]).await, vec! [],
_ => (), vec! ["invalid_exe_name"],
vec! ["ptth_multi_call_server"],
vec! ["ptth_multi_call_server", "invalid_subcommand"],
];
for input in &negative_cases {
let input: Vec <_> = input.iter ().map (OsString::from).collect ();
let actual = parse_args (&input);
assert! (actual.is_err ());
} }
anyhow::bail! ("Subcommand should be provided in exe name or first argument, e.g. `./ptth_multi_call_server ptth_server`"); let positive_cases = vec! [
(vec! ["ptth_server"], (Subcommand::PtthServer, vec! ["ptth_server"])),
(vec! ["ptth_server", "--help"], (Subcommand::PtthServer, vec! ["ptth_server", "--help"])),
(vec! ["ptth_quic_end_server", "--help"], (Subcommand::PtthQuicEndServer, vec! ["ptth_quic_end_server", "--help"])),
(vec! ["ptth_multi_call_server", "ptth_server"], (Subcommand::PtthServer, vec! ["ptth_server"])),
(
vec! [
"ptth_multi_call_server",
"ptth_server",
"--help"
],
(
Subcommand::PtthServer,
vec! [
"ptth_server",
"--help"
]
)
),
(
vec! [
"invalid_exe_name",
"ptth_server",
"--help"
],
(
Subcommand::PtthServer,
vec! [
"ptth_server",
"--help"
]
)
),
];
for (input, (expected_subcommand, expected_args)) in &positive_cases {
let input: Vec <_> = input.iter ().map (OsString::from).collect ();
let (actual_subcommand, actual_args) = parse_args (&input)?;
assert_eq! (expected_subcommand, &actual_subcommand);
assert_eq! (expected_args, actual_args);
}
Ok (())
}
} }