Skip to main content

node_gui/
cli.rs

1//! Command-line interface contract.
2
3use clap::{Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(name = "node-gui")]
7#[command(author = "wowlab")]
8#[command(version)]
9#[command(about = "WoW Lab distributed simulation node", long_about = None)]
10pub(crate) struct Cli {
11    #[command(subcommand)]
12    pub(crate) command: Option<Command>,
13
14    /// Skip automatic update check on startup.
15    #[arg(long, global = true)]
16    pub(crate) no_update: bool,
17}
18
19#[derive(Debug, Eq, PartialEq, Subcommand)]
20pub(crate) enum Command {
21    /// Update to the latest version.
22    Update {
23        /// Check for updates without installing.
24        #[arg(long)]
25        check: bool,
26    },
27    /// Start the node GUI (default behavior)
28    Run,
29}
30
31#[cfg(test)]
32mod tests {
33    use clap::{CommandFactory, error::ErrorKind};
34    use googletest::prelude::*;
35
36    use super::*;
37
38    #[gtest]
39    fn no_subcommand_starts_gui_with_update_check() -> Result<()> {
40        let cli = Cli::try_parse_from(["node-gui"]).or_fail()?;
41
42        verify_that!(cli.command, none())?;
43
44        verify_false!(cli.no_update)
45    }
46
47    #[gtest]
48    fn update_check_is_distinct_from_install() -> Result<()> {
49        let check = Cli::try_parse_from(["node-gui", "update", "--check"]).or_fail()?;
50        let install = Cli::try_parse_from(["node-gui", "update"]).or_fail()?;
51
52        verify_that!(check.command, eq(&Some(Command::Update { check: true })))?;
53
54        verify_that!(install.command, eq(&Some(Command::Update { check: false })))
55    }
56
57    #[gtest]
58    fn no_update_is_global_before_or_after_run_subcommand() -> Result<()> {
59        for arguments in [
60            ["node-gui", "--no-update", "run"],
61            ["node-gui", "run", "--no-update"],
62        ] {
63            let cli = Cli::try_parse_from(arguments).or_fail()?;
64
65            verify_that!(cli.command, eq(&Some(Command::Run)))?;
66            verify_true!(cli.no_update)?;
67        }
68
69        Ok(())
70    }
71
72    #[gtest]
73    fn invalid_subcommand_remains_a_command_line_error() -> Result<()> {
74        let error = Cli::try_parse_from(["node-gui", "unknown"])
75            .err()
76            .or_fail()?;
77
78        verify_that!(error.kind(), eq(ErrorKind::InvalidSubcommand))
79    }
80
81    #[gtest]
82    fn top_level_help_lists_commands_and_global_flag() -> Result<()> {
83        let mut command = Cli::command();
84        let mut help = Vec::new();
85
86        command.write_long_help(&mut help).or_fail()?;
87        let help = String::from_utf8(help).or_fail()?;
88
89        verify_that!(
90            help,
91            all!(
92                contains_substring("update"),
93                contains_substring("run"),
94                contains_substring("--no-update")
95            )
96        )
97    }
98}