From 6d07a0c9d9a9b39247a9727dea2d90eba4e1fe9e Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sat, 5 Jan 2019 21:41:22 -0800 Subject: Supply customizable stdio channels to argparse In order to properly test the program we need to have a way to intercept data printed to the stdio channels. There are different ways to accomplish that task. While it is reasonably easy to just start the program as a dedicated process doing so properly may be problematic from inside a test because either the path to the binary has to be retrieved or cargo -- the entity which knows the path -- be invoked. None of these approaches is very appealing from a testing and code complexity point of view: an additional fork means additional sources of errors and flakiness, executing cargo has the potential to even cause rebuilds of parts of the program, and while we are already testing against a slow I/O device this additional code running is unlikely to go unnoticed in the long-term. Lastly, doing so also means that we leave Rust's type safety behind when dealing with errors that could be nicely match'ed on when the test invocation is just a function call. To avoid all this complexity we instead strive for basically just running the main function. This patch marks a first step towards achieving this goal. It introduces the infrastructure to supply custom Write objects to the argument parsing functionality. Once more we piggy-back on the command execution context and add objects representing stdout and stderr to it. We further ensure that this context is passed to the argument parser invocations. --- nitrocli/src/main.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'nitrocli/src/main.rs') diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index 4f39fdb..ad79c6e 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -1,7 +1,7 @@ // main.rs // ************************************************************************* -// * Copyright (C) 2017-2018 Daniel Mueller (deso@posteo.net) * +// * Copyright (C) 2017-2019 Daniel Mueller (deso@posteo.net) * // * * // * This program is free software: you can redistribute it and/or modify * // * it under the terms of the GNU General Public License as published by * @@ -73,6 +73,8 @@ mod commands; mod error; mod pinentry; +use std::env; +use std::io; use std::process; use std::result; @@ -80,9 +82,16 @@ use crate::error::Error; type Result = result::Result; -fn run() -> i32 { - let args = std::env::args().collect(); - match args::handle_arguments(args) { +/// The context used when running the program. +pub(crate) struct RunCtx<'io> { + /// The `Write` object used as standard output throughout the program. + pub stdout: &'io mut dyn io::Write, + /// The `Write` object used as standard error throughout the program. + pub stderr: &'io mut dyn io::Write, +} + +fn run<'ctx, 'io: 'ctx>(ctx: &'ctx mut RunCtx<'io>, args: Vec) -> i32 { + match args::handle_arguments(ctx, args) { Ok(()) => 0, Err(err) => match err { Error::ArgparseError(err) => match err { @@ -100,5 +109,11 @@ fn run() -> i32 { } fn main() { - process::exit(run()); + let args = env::args().collect::>(); + let ctx = &mut RunCtx { + stdout: &mut io::stdout(), + stderr: &mut io::stderr(), + }; + + process::exit(run(ctx, args)); } -- cgit v1.2.1