diff --git a/.changelog/unreleased/features/ibc-relayer-cli/2358-add-unit-testing-commands.md b/.changelog/unreleased/features/ibc-relayer-cli/2358-add-unit-testing-commands.md new file mode 100644 index 0000000000..101c190ded --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer-cli/2358-add-unit-testing-commands.md @@ -0,0 +1,2 @@ +- Add unit tests for all Hermes commands with at least one argument + ([#2358](https://github.com/informalsystems/ibc-rs/issues/2358)) \ No newline at end of file diff --git a/docs/architecture/adr-010-unified-cli-arguments-hermes.md b/docs/architecture/adr-010-unified-cli-arguments-hermes.md index 7b96d2b268..29f77d14b6 100644 --- a/docs/architecture/adr-010-unified-cli-arguments-hermes.md +++ b/docs/architecture/adr-010-unified-cli-arguments-hermes.md @@ -51,14 +51,17 @@ The following commands are implemented, with the binary name `hermes` often omit ### Create a channel * `create channel --a-chain --a-connection --a-port --b-port ` - * Optional: `[--chan-version ] [--order ]` + * Optional: `[--channel-version ] [--order ]` -* `create channel --a-chain --b-chain --a-port --b-port --new-client-conn` - * Optional: `[--chan-version ] [--order ]` +* `create channel --a-chain --b-chain --a-port --b-port --new-client-connection` + * Optional: `[--channel-version ] [--order ] [--yes]` ### Commands for keys -* `keys add --chain --key-file --mnemonic-file ` +* `keys add --chain --key-file ` + * Optional: `[--hd-path ] [--key-name ]` + +* `keys add --chain --mnemonic-file ` * Optional: `[--hd-path ] [--key-name ]` * `keys balance --chain ` @@ -86,8 +89,8 @@ The following commands are implemented, with the binary name `hermes` often omit ### Clear packets -* `clear packets --chain --port --channel - --key-name --counterparty-key-name ` +* `clear packets [OPTIONS] --chain --port --channel ` + * Optional: `[--key-name ] [--counterparty-key-name ]` ### Queries diff --git a/guide/src/commands/keys/index.md b/guide/src/commands/keys/index.md index f91153961c..8361b0e478 100644 --- a/guide/src/commands/keys/index.md +++ b/guide/src/commands/keys/index.md @@ -76,20 +76,20 @@ DESCRIPTION: FLAGS: --chain - identifier of the chain + Identifier of the chain --key-file - path to the key file + Path to the key file --mnemonic-file - path to file containing mnemonic to restore the key from + Path to file containing mnemonic to restore the key from OPTIONS: --key-name - name of the key (defaults to the `key_name` defined in the config) + Name of the key (defaults to the `key_name` defined in the config) --hd-path - derivation path for this key [default: m/44'/118'/0'/0/0] + Derivation path for this key [default: m/44'/118'/0'/0/0] ``` #### Add a private key to a chain from a key file @@ -102,17 +102,17 @@ DESCRIPTION: FLAGS: --chain - identifier of the chain + Identifier of the chain --key-file - path to the key file + Path to the key file OPTIONS: --key-name - name of the key (defaults to the `key_name` defined in the config) + Name of the key (defaults to the `key_name` defined in the config) --hd-path - derivation path for this key [default: m/44'/118'/0'/0/0] + Derivation path for this key [default: m/44'/118'/0'/0/0] ``` To add a private key file to a chain: @@ -157,17 +157,17 @@ DESCRIPTION: FLAGS: --chain - identifier of the chain + Identifier of the chain --mnemonic-file - path to file containing mnemonic to restore the key from + Path to file containing mnemonic to restore the key from OPTIONS: --key-name - name of the key (defaults to the `key_name` defined in the config) + Name of the key (defaults to the `key_name` defined in the config) --hd-path - derivation path for this key [default: m/44'/118'/0'/0/0] + Derivation path for this key [default: m/44'/118'/0'/0/0] ``` To restore a key from its mnemonic: @@ -336,4 +336,4 @@ If the command is successful a message with the following format will be display }, "status": "success" } -``` \ No newline at end of file +``` diff --git a/guide/src/commands/path-setup/channels.md b/guide/src/commands/path-setup/channels.md index 975f5107fc..634e8fd89e 100644 --- a/guide/src/commands/path-setup/channels.md +++ b/guide/src/commands/path-setup/channels.md @@ -13,10 +13,10 @@ USAGE: hermes create channel [OPTIONS] --a-chain --a-port --b-port DESCRIPTION: - Create a new channel between two chains using a pre-existing connection. + Create a new channel between two chains. - Alternatively, create a new client and a new connection underlying the new channel if a pre-existing - connection is not provided. + Can create a new channel using a pre-existing connection or alternatively, create a new client and a + new connection underlying the new channel if a pre-existing connection is not provided. FLAGS: --a-chain Identifier of the side `a` chain for the new channel @@ -26,13 +26,14 @@ FLAGS: OPTIONS: --a-connection Identifier of the connection on chain `a` to use in creating - the new channel. + the new channel --b-chain Identifier of the side `b` chain for the new channel --chan-version The version for the new channel --new-client-connection Indicates that a new client and connection will be created underlying the new channel --order The channel ordering, valid options 'unordered' (default) and 'ordered' [default: ORDER_UNORDERED] + --yes Skip new_client_connection confirmation ``` ## Examples @@ -210,7 +211,7 @@ interactive prompt that pops up notifying you that a new client and a new connection will be initialized as part of the process: ```shell -hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --order unordered --new-client-conn +hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --order unordered --new-client-connection ``` ```json diff --git a/guide/src/commands/queries/channel.md b/guide/src/commands/queries/channel.md index a0a397c24f..3d71f18acb 100644 --- a/guide/src/commands/queries/channel.md +++ b/guide/src/commands/queries/channel.md @@ -15,11 +15,11 @@ DESCRIPTION: FLAGS: --chain - identifier of the chain to query + Identifier of the chain to query OPTIONS: --verbose - enable verbose output, displaying the client and connection ids for each channel in the + Enable verbose output, displaying the client and connection ids for each channel in the response ``` @@ -410,4 +410,4 @@ If the command is successful a message with the following format will be display }, "status":"success" } -``` \ No newline at end of file +``` diff --git a/guide/src/commands/queries/client.md b/guide/src/commands/queries/client.md index ff09bd3f08..85994fb00a 100644 --- a/guide/src/commands/queries/client.md +++ b/guide/src/commands/queries/client.md @@ -17,14 +17,14 @@ DESCRIPTION: FLAGS: --host-chain - identifier of the chain to query + Identifier of the chain to query OPTIONS: --omit-chain-ids - omit printing the reference (or target) chain for each client + Omit printing the reference (or target) chain for each client --reference-chain - filter for clients which target a specific chain id (implies '--omit-chain-ids') + Filter for clients which target a specific chain id (implies '--omit-chain-ids') ``` __Example__ @@ -160,20 +160,20 @@ DESCRIPTION: FLAGS: --chain - identifier of the chain to query + Identifier of the chain to query --client - identifier of the client to query + Identifier of the client to query OPTIONS: --consensus-height - height of the client's consensus state to query + Height of the client's consensus state to query --height - the chain height context to be used, applicable only to a specific height + The chain height context to be used, applicable only to a specific height --heights-only - show only consensus heights + Show only consensus heights ``` __Example__ diff --git a/guide/src/commands/queries/packet.md b/guide/src/commands/queries/packet.md index 357a360c8b..7d70c22497 100644 --- a/guide/src/commands/queries/packet.md +++ b/guide/src/commands/queries/packet.md @@ -19,6 +19,7 @@ SUBCOMMANDS: pending Output a summary of pending packets in both directions unreceived-acks Query unreceived acknowledgments unreceived-packets Query unreceived packets + help Print this message or the help of the given subcommand(s) ``` ## Table of Contents diff --git a/guide/src/commands/queries/tx.md b/guide/src/commands/queries/tx.md index c0fb5917b3..102783214f 100644 --- a/guide/src/commands/queries/tx.md +++ b/guide/src/commands/queries/tx.md @@ -57,4 +57,4 @@ Success: [ }, ), ] -``` \ No newline at end of file +``` diff --git a/guide/src/commands/raw/packet.md b/guide/src/commands/raw/packet.md index 5522eac79a..5876290d17 100644 --- a/guide/src/commands/raw/packet.md +++ b/guide/src/commands/raw/packet.md @@ -18,38 +18,38 @@ DESCRIPTION: FLAGS: --amount - amount of coins (samoleans, by default) to send (e.g. `100000`) + Amount of coins (samoleans, by default) to send (e.g. `100000`) --dst-chain - identifier of the destination chain + Identifier of the destination chain --src-chain - identifier of the source chain + Identifier of the source chain --src-chan - identifier of the source channel + Identifier of the source channel --src-port - identifier of the source port + Identifier of the source port OPTIONS: --denom - denomination of the coins to send [default: samoleans] + Denomination of the coins to send [default: samoleans] --key-name - use the given signing key name (default: `key_name` config) + Use the given signing key name (default: `key_name` config) --number-msgs - number of messages to send + Number of messages to send --receiver - receiving account address on the destination chain + Receiving account address on the destination chain --timeout-height-offset - timeout in number of blocks since current [default: 0] + Timeout in number of blocks since current [default: 0] --timeout-seconds - timeout in seconds since current [default: 0] + Timeout in seconds since current [default: 0] ``` __Example__ diff --git a/guide/src/commands/raw/upgrade.md b/guide/src/commands/raw/upgrade.md index c5b11b3290..d8f35033c2 100644 --- a/guide/src/commands/raw/upgrade.md +++ b/guide/src/commands/raw/upgrade.md @@ -159,4 +159,4 @@ hermes tx raw upgrade-chain --dst-chain ibc-0 --src-chain ibc-1 --src-client 07- ``` Success: transaction::Hash(779713508B6103E37FADE60483BEE964A90BD67E5F20037B2CC4AE0E90B707C3) -``` \ No newline at end of file +``` diff --git a/guide/src/commands/upgrade/test.md b/guide/src/commands/upgrade/test.md index 5f38ece8e0..51ca667291 100644 --- a/guide/src/commands/upgrade/test.md +++ b/guide/src/commands/upgrade/test.md @@ -275,4 +275,4 @@ It might be due to the chain not being at the height defined for the upgrade. Th INFO ThreadId(01) [ibc-0 -> ibc-1:07-tendermint-0] upgrade Height: 0-82 ``` -Where in this case the chain is at height 82. \ No newline at end of file +Where in this case the chain is at height 82. diff --git a/guide/src/help.md b/guide/src/help.md index a076612b70..8c09ea13c2 100644 --- a/guide/src/help.md +++ b/guide/src/help.md @@ -60,13 +60,15 @@ This can provide further specific guidance if we add additional parameters, e.g. hermes help create channel ``` -``` +```shell USAGE: hermes create channel [OPTIONS] --a-chain --a-port --b-port DESCRIPTION: - Create a new channel between two chains using a pre-existing connection. Alternatively, create a new - client and a new connection underlying the new channel if a pre-existing connection is not provided + Create a new channel between two chains. + + Can create a new channel using a pre-existing connection or alternatively, create a new client and a + new connection underlying the new channel if a pre-existing connection is not provided. FLAGS: --a-chain Identifier of the side `a` chain for the new channel @@ -74,14 +76,16 @@ FLAGS: --b-port Identifier of the side `b` port for the new channel OPTIONS: + --a-connection Identifier of the connection on chain `a` to use in creating - the new channel. + the new channel --b-chain Identifier of the side `b` chain for the new channel --chan-version The version for the new channel --new-client-connection Indicates that a new client and connection will be created underlying the new channel --order The channel ordering, valid options 'unordered' (default) and 'ordered' [default: ORDER_UNORDERED] + --yes Skip new_client_connection confirmation ``` Additionally, the `-h`/`--help` flags typical for CLI applications work on diff --git a/guide/src/installation.md b/guide/src/installation.md index 75f1fcac24..ee19666b4d 100644 --- a/guide/src/installation.md +++ b/guide/src/installation.md @@ -200,19 +200,19 @@ and any further necessary modifications to the shell's startup files. ### Bash ```sh -hermes completions bash > ~/.local/share/bash-completion/completions/hermes +hermes completions --shell bash > ~/.local/share/bash-completion/completions/hermes ``` On a MacOS installation with Homebrew `bash-completion` formula installed, use ```sh -hermes completions bash > $(brew --prefix)/etc/bash_completion.d/hermes.bash-completion +hermes completions --shell bash > $(brew --prefix)/etc/bash_completion.d/hermes.bash-completion ``` ### Zsh ```sh -hermes completions zsh > ~/.zfunc/_hermes +hermes completions --shell zsh > ~/.zfunc/_hermes ``` To make the shell load the script on initialization, add the directory to `fpath` diff --git a/guide/src/tutorials/local-chains/raw/packet.md b/guide/src/tutorials/local-chains/raw/packet.md index d3030ef81b..bc5c799045 100644 --- a/guide/src/tutorials/local-chains/raw/packet.md +++ b/guide/src/tutorials/local-chains/raw/packet.md @@ -89,4 +89,4 @@ Next we will test the packet timeouts. ```shell hermes tx raw packet-recv --dst-chain ibc-1 --src-chain ibc-0 --src-port transfer --src-chan channel-0 - ``` \ No newline at end of file + ``` diff --git a/guide/src/tutorials/local-chains/relay-paths/create-new-path.md b/guide/src/tutorials/local-chains/relay-paths/create-new-path.md index b6c2d3b456..c93b74671b 100644 --- a/guide/src/tutorials/local-chains/relay-paths/create-new-path.md +++ b/guide/src/tutorials/local-chains/relay-paths/create-new-path.md @@ -3,7 +3,7 @@ Perform client creation, connection and channel handshake to establish a new path between the `transfer` ports on `ibc-0` and `ibc-1` chains. ```shell -hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --new-client-conn +hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --new-client-connection ``` If all the handshakes are performed successfully you should see a message similar to the one below: diff --git a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md index 6ae7f5b5de..c8b6db50e0 100644 --- a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md +++ b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md @@ -100,7 +100,7 @@ Follow the steps below to connect three chains together and relay packets betwee making an exception. Execute the following command: ```shell - hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --new-client-conn + hermes create channel --a-chain ibc-0 --b-chain ibc-1 --a-port transfer --b-port transfer --new-client-connection ``` Then respond 'yes' to the prompt that pops up. Once the command has run to @@ -166,7 +166,7 @@ Follow the steps below to connect three chains together and relay packets betwee previous invocation we used to create a channel between `ibc-0` and `ibc-1`: ```shell - hermes create channel --a-chain ibc-1 --b-chain ibc-2 --a-port transfer --b-port transfer --new-client-conn + hermes create channel --a-chain ibc-1 --b-chain ibc-2 --a-port transfer --b-port transfer --new-client-connection ``` ```json diff --git a/relayer-cli/src/commands/clear.rs b/relayer-cli/src/commands/clear.rs index 931e3d9347..7f91636253 100644 --- a/relayer-cli/src/commands/clear.rs +++ b/relayer-cli/src/commands/clear.rs @@ -23,7 +23,7 @@ pub enum ClearCmds { Packets(ClearPacketsCmd), } -#[derive(Debug, Parser, Command)] +#[derive(Debug, Parser, Command, PartialEq)] pub struct ClearPacketsCmd { #[clap( long = "chain", @@ -51,13 +51,13 @@ pub struct ClearPacketsCmd { channel_id: ChannelId, #[clap( - long, + long = "key-name", help = "use the given signing key for the specified chain (default: `key_name` config)" )] key_name: Option, #[clap( - long, + long = "counterparty-key-name", help = "use the given signing key for the counterparty chain (default: `counterparty_key_name` config)" )] counterparty_key_name: Option, @@ -147,3 +147,137 @@ where Err(e) => Output::error(Error::link(e)).exit(), }; } + +#[cfg(test)] +mod tests { + use super::ClearPacketsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_clear_packets_required_only() { + assert_eq!( + ClearPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + key_name: None, + counterparty_key_name: None, + }, + ClearPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_clear_packets_chan_alias() { + assert_eq!( + ClearPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + key_name: None, + counterparty_key_name: None + }, + ClearPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_clear_packets_key_name() { + assert_eq!( + ClearPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + key_name: Some("key_name".to_owned()), + counterparty_key_name: None, + }, + ClearPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--key-name", + "key_name" + ]) + ) + } + + #[test] + fn test_clear_packets_counterparty_key_name() { + assert_eq!( + ClearPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + key_name: None, + counterparty_key_name: Some("counterparty_key_name".to_owned()), + }, + ClearPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--counterparty-key-name", + "counterparty_key_name" + ]) + ) + } + + #[test] + fn test_clear_packets_no_chan() { + assert!(ClearPacketsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_clear_packets_no_port() { + assert!(ClearPacketsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_clear_packets_no_chain() { + assert!(ClearPacketsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/completions.rs b/relayer-cli/src/commands/completions.rs index bc7ca6c235..7a79ea33a2 100644 --- a/relayer-cli/src/commands/completions.rs +++ b/relayer-cli/src/commands/completions.rs @@ -5,7 +5,7 @@ use clap::IntoApp; use clap_complete::Shell; use std::io; -#[derive(Debug, Parser)] +#[derive(Debug, Parser, PartialEq)] pub struct CompletionsCmd { #[clap(long = "shell", value_name = "SHELL", arg_enum)] shell: Shell, @@ -18,3 +18,34 @@ impl Runnable for CompletionsCmd { clap_complete::generate(self.shell, &mut app, app_name, &mut io::stdout()); } } + +#[cfg(test)] +mod tests { + use super::CompletionsCmd; + + use abscissa_core::clap::Parser; + use clap_complete::Shell; + + #[test] + fn test_completions() { + assert_eq!( + CompletionsCmd { shell: Shell::Zsh }, + CompletionsCmd::parse_from(&["test", "--shell", "zsh"]) + ) + } + + #[test] + fn test_completions_no_shell() { + assert!(CompletionsCmd::try_parse_from(&["test", "--shell"]).is_err()) + } + + #[test] + fn test_completions_no_shell_flag() { + assert!(CompletionsCmd::try_parse_from(&["test"]).is_err()) + } + + #[test] + fn test_completions_unknown_shell() { + assert!(CompletionsCmd::try_parse_from(&["test", "--shell", "my_shell"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/create.rs b/relayer-cli/src/commands/create.rs index d736d877ae..0bb2dd9e19 100644 --- a/relayer-cli/src/commands/create.rs +++ b/relayer-cli/src/commands/create.rs @@ -18,9 +18,10 @@ pub enum CreateCmds { /// Create a new connection between two chains Connection(CreateConnectionCommand), - /// Create a new channel between two chains using a pre-existing connection. + /// Create a new channel between two chains. /// - /// Alternatively, create a new client and a new connection underlying + /// Can create a new channel using a pre-existing connection or + /// alternatively, create a new client and a new connection underlying /// the new channel if a pre-existing connection is not provided. Channel(CreateChannelCommand), } diff --git a/relayer-cli/src/commands/create/channel.rs b/relayer-cli/src/commands/create/channel.rs index 0181586d9f..ef10baa24a 100644 --- a/relayer-cli/src/commands/create/channel.rs +++ b/relayer-cli/src/commands/create/channel.rs @@ -30,11 +30,11 @@ static HINT: &str = "Consider using the default invocation\n\nhermes create chan /// /// There are two possible ways to invoke this command: /// -/// `create channel --a-port --b-port --a-chain --a-conn ` +/// `create channel --a-port --b-port --a-chain --a-connection ` /// is the default way in which this command should be used, specifying a `Connection-ID` /// associated with chain A for this new channel to re-use. /// -/// `create channel --a-port --b-port --a-chain --b-chain --new-client-conn` +/// `create channel --a-port --b-port --a-chain --b-chain --new-client-connection` /// can alternatively be used to indicate that a new connection/client pair is being /// created as part of this new channel. This brings up an interactive yes/no prompt /// to ensure that the operator at least considers the fact that they're initializing a @@ -44,7 +44,7 @@ static HINT: &str = "Consider using the default invocation\n\nhermes create chan /// Note that `Connection-ID`s have to be considered based off of the chain's perspective. Although /// chain A and chain B might refer to the connection with different names, they are actually referring /// to the same connection. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct CreateChannelCommand { #[clap( long = "a-chain", @@ -57,15 +57,20 @@ pub struct CreateChannelCommand { #[clap( long = "b-chain", value_name = "B_CHAIN_ID", + required = true, + requires = "new-client-connection", + group = "b_chain_group", help = "Identifier of the side `b` chain for the new channel" )] chain_b: Option, #[clap( long = "a-connection", - alias = "a-conn", + visible_alias = "a-conn", value_name = "A_CONNECTION_ID", - help = "Identifier of the connection on chain `a` to use in creating the new channel." + required = true, + groups = &["b_chain_group", "new_client_group"], + help = "Identifier of the connection on chain `a` to use in creating the new channel" )] connection_a: Option, @@ -95,7 +100,7 @@ pub struct CreateChannelCommand { #[clap( long = "channel-version", - alias = "chan-version", + visible_alias = "chan-version", value_name = "VERSION", help = "The version for the new channel" )] @@ -103,12 +108,18 @@ pub struct CreateChannelCommand { #[clap( long = "new-client-connection", - alias = "new-client-conn", + visible_alias = "new-client-conn", + required = true, + group = "new_client_group", help = "Indicates that a new client and connection will be created underlying the new channel" )] - new_client_conn: bool, + new_client_connection: bool, - #[clap(long, help = "Skip new_client_conn confirmation")] + #[clap( + long = "yes", + requires = "new-client-connection", + help = "Skip new_client_connection confirmation" + )] yes: bool, } @@ -118,7 +129,7 @@ impl Runnable for CreateChannelCommand { Some(conn) => self.run_reusing_connection(conn), None => match &self.chain_b { Some(chain_b) => { - if self.new_client_conn { + if self.new_client_connection { if self.yes { self.run_using_new_connection(chain_b); } else { @@ -147,17 +158,9 @@ impl Runnable for CreateChannelCommand { } } } - } else { - Output::error( - "The `--new-client-conn` flag is required if invoking with `--b-chain`" - .to_string(), - ) - .exit(); } } - None => { - Output::error("Missing one of `--b-chain` or `--a-conn`".to_string()).exit() - } + None => {} }, } } @@ -256,3 +259,355 @@ impl CreateChannelCommand { Output::success(channel).exit(); } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use super::CreateChannelCommand; + use abscissa_core::clap::Parser; + + use ibc::core::ics04_channel::channel::Order; + use ibc::core::ics04_channel::Version; + use ibc::core::ics24_host::identifier::{ChainId, ConnectionId, PortId}; + + #[test] + fn test_create_channel_a_conn_required() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: None, + connection_a: Some(ConnectionId::from_str("connection_a").unwrap()), + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: None, + new_client_connection: false, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b" + ]) + ) + } + + #[test] + fn test_create_channel_version() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: None, + connection_a: Some(ConnectionId::from_str("connection_a").unwrap()), + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: Some(Version::new("v1".to_owned())), + new_client_connection: false, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--channel-version", + "v1" + ]) + ) + } + + #[test] + fn test_create_channel_order() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: None, + connection_a: Some(ConnectionId::from_str("connection_a").unwrap()), + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Ordered, + version: None, + new_client_connection: false, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--order", + "ordered" + ]) + ) + } + + #[test] + fn test_create_channel_a_conn_alias() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: None, + connection_a: Some(ConnectionId::from_str("connection_a").unwrap()), + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: None, + new_client_connection: false, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-conn", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b" + ]) + ) + } + + #[test] + fn test_create_channel_a_conn_with_new_client_conn() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--new-client-connection" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_a_conn_with_yes() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--order", + "ordered", + "--yes" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_a_conn_with_b_chain() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--order", + "ordered" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_b_chain() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: Some(ChainId::from_string("chain_b")), + connection_a: None, + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: None, + new_client_connection: true, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--new-client-connection" + ]) + ) + } + + #[test] + fn test_create_channel_b_chain_yes() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: Some(ChainId::from_string("chain_b")), + connection_a: None, + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: None, + new_client_connection: true, + yes: true + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--new-client-connection", + "--yes" + ]) + ) + } + + #[test] + fn test_create_channel_b_new_client_conn_alias() { + assert_eq!( + CreateChannelCommand { + chain_a: ChainId::from_string("chain_a"), + chain_b: Some(ChainId::from_string("chain_b")), + connection_a: None, + port_a: PortId::from_str("port_id_a").unwrap(), + port_b: PortId::from_str("port_id_b").unwrap(), + order: Order::Unordered, + version: None, + new_client_connection: true, + yes: false + }, + CreateChannelCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b", + "--new-client-conn" + ]) + ) + } + + #[test] + fn test_create_channel_b_chain_without_new_client() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_no_b_port() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_no_a_port() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-connection", + "connection_a", + "--b-port", + "port_id_b" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_no_b_chain_nor_a_conn() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b" + ]) + .is_err()) + } + + #[test] + fn test_create_channel_no_a_chain() { + assert!(CreateChannelCommand::try_parse_from(&[ + "test", + "--b-chain", + "chain_b", + "--a-connection", + "connection_a", + "--a-port", + "port_id_a", + "--b-port", + "port_id_b" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/create/connection.rs b/relayer-cli/src/commands/create/connection.rs index 83f48bc8a1..f4d6fdbc2b 100644 --- a/relayer-cli/src/commands/create/connection.rs +++ b/relayer-cli/src/commands/create/connection.rs @@ -14,7 +14,7 @@ use crate::cli_utils::{spawn_chain_runtime, ChainHandlePair}; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct CreateConnectionCommand { #[clap( long = "a-chain", @@ -26,21 +26,27 @@ pub struct CreateConnectionCommand { #[clap( long = "b-chain", + required = true, value_name = "B_CHAIN_ID", + groups = &["a_client", "b_client"], help = "Identifier of the side `b` chain for the new connection" )] chain_b_id: Option, #[clap( long = "a-client", + required = true, value_name = "A_CLIENT_ID", + group = "a_client", help = "Identifier of client hosted on chain `a`; default: None (creates a new client)" )] client_a: Option, #[clap( long = "b-client", + required = true, value_name = "B_CLIENT_ID", + group = "b_client", help = "Identifier of client hosted on chain `b`; default: None (creates a new client)" )] client_b: Option, @@ -74,16 +80,6 @@ impl CreateConnectionCommand { let chains = ChainHandlePair::spawn(&config, &self.chain_a_id, chain_b_id) .unwrap_or_else(exit_with_unrecoverable_error); - // Validate the other options. Bail if the CLI was invoked with incompatible options. - if self.client_a.is_some() { - Output::error("Option `` is incompatible with `--a-client`".to_string()) - .exit(); - } - if self.client_b.is_some() { - Output::error("Option `` is incompatible with `--b-client`".to_string()) - .exit(); - } - info!( "Creating new clients hosted on chains {} and {}", self.chain_a_id, chain_b_id @@ -171,3 +167,163 @@ impl CreateConnectionCommand { } } } + +#[cfg(test)] +mod tests { + use super::CreateConnectionCommand; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ClientId}; + + use std::str::FromStr; + + #[test] + fn test_create_connection_b_chain() { + assert_eq!( + CreateConnectionCommand { + chain_a_id: ChainId::from_string("chain_a"), + chain_b_id: Some(ChainId::from_string("chain_b")), + client_a: None, + client_b: None, + delay: 0 + }, + CreateConnectionCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b" + ]) + ) + } + + #[test] + fn test_create_connection_b_chain_with_delay() { + assert_eq!( + CreateConnectionCommand { + chain_a_id: ChainId::from_string("chain_a"), + chain_b_id: Some(ChainId::from_string("chain_b")), + client_a: None, + client_b: None, + delay: 42 + }, + CreateConnectionCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--delay", + "42" + ]) + ) + } + + #[test] + fn create_connection_a_chain_and_clients() { + assert_eq!( + CreateConnectionCommand { + chain_a_id: ChainId::from_string("chain_a"), + chain_b_id: None, + client_a: Some(ClientId::from_str("07-client_a").unwrap()), + client_b: Some(ClientId::from_str("07-client_b").unwrap()), + delay: 0 + }, + CreateConnectionCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-client", + "07-client_a", + "--b-client", + "07-client_b" + ]) + ) + } + + #[test] + fn create_connection_a_chain_and_clients_with_delay() { + assert_eq!( + CreateConnectionCommand { + chain_a_id: ChainId::from_string("chain_a"), + chain_b_id: None, + client_a: Some(ClientId::from_str("07-client_a").unwrap()), + client_b: Some(ClientId::from_str("07-client_b").unwrap()), + delay: 42 + }, + CreateConnectionCommand::parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-client", + "07-client_a", + "--b-client", + "07-client_b", + "--delay", + "42" + ]) + ) + } + + #[test] + fn test_create_connection_a_chain_only() { + assert!(CreateConnectionCommand::try_parse_from(&["test", "--a-chain", "chain_a"]).is_err()) + } + + #[test] + fn test_create_connection_no_a_chain() { + assert!(CreateConnectionCommand::try_parse_from(&["test", "--b-chain", "chain_b"]).is_err()) + } + + #[test] + fn test_create_connection_b_client_without_a_client() { + assert!(CreateConnectionCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-client", + "client_b" + ]) + .is_err()) + } + + #[test] + fn test_create_connection_a_client_required_without_b_client() { + assert!(CreateConnectionCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--a-client", + "client_a" + ]) + .is_err()) + } + + #[test] + fn test_create_connection_b_chain_with_a_client() { + assert!(CreateConnectionCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--a-client", + "07-client_a" + ]) + .is_err()) + } + + #[test] + fn test_create_connection_b_chain_with_b_client() { + assert!(CreateConnectionCommand::try_parse_from(&[ + "test", + "--a-chain", + "chain_a", + "--b-chain", + "chain_b", + "--b-client", + "07-client_b" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/keys/add.rs b/relayer-cli/src/commands/keys/add.rs index d49a2b9d67..13dd710a86 100644 --- a/relayer-cli/src/commands/keys/add.rs +++ b/relayer-cli/src/commands/keys/add.rs @@ -143,8 +143,10 @@ impl Runnable for KeysAddCmd { // This case should never trigger. // The 'required' parameter for the flags will trigger an error if both flags have not been given. // And the 'group' parameter for the flags will trigger an error if both flags are given. - _ => Output::error("--mnemonic-file and --key-file can't both be None".to_string()) - .exit(), + _ => Output::error( + "--mnemonic-file and --key-file can't both be set or both None".to_string(), + ) + .exit(), } } } @@ -179,3 +181,71 @@ pub fn restore_key( keyring.add_key(key_name, key_entry.clone())?; Ok(key_entry) } + +#[cfg(test)] +mod tests { + + use super::KeysAddCmd; + use std::path::PathBuf; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_keys_add_key_file() { + assert_eq!( + KeysAddCmd { + chain_id: ChainId::from_string("chain_id"), + key_file: Some(PathBuf::from("key_file")), + mnemonic_file: None, + key_name: None, + hd_path: "m/44'/118'/0'/0/0".to_string() + }, + KeysAddCmd::parse_from(&["test", "--chain", "chain_id", "--key-file", "key_file"]) + ) + } + + #[test] + fn test_keys_add_mnemonic_file() { + assert_eq!( + KeysAddCmd { + chain_id: ChainId::from_string("chain_id"), + key_file: None, + mnemonic_file: Some(PathBuf::from("mnemonic_file")), + key_name: None, + hd_path: "m/44'/118'/0'/0/0".to_string() + }, + KeysAddCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--mnemonic-file", + "mnemonic_file" + ]) + ) + } + + #[test] + fn test_keys_add_no_file_nor_mnemonic() { + assert!(KeysAddCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()); + } + + #[test] + fn test_keys_add_key_and_mnemonic() { + assert!(KeysAddCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--key-file", + "key_file", + "--mnemonic-file", + "mnemonic_file" + ]) + .is_err()); + } + + #[test] + fn test_keys_add_no_chain() { + assert!(KeysAddCmd::try_parse_from(&["test", "--key-file", "key_file"]).is_err()); + } +} diff --git a/relayer-cli/src/commands/keys/balance.rs b/relayer-cli/src/commands/keys/balance.rs index 7473e22ea0..cd32bce391 100644 --- a/relayer-cli/src/commands/keys/balance.rs +++ b/relayer-cli/src/commands/keys/balance.rs @@ -17,7 +17,7 @@ use crate::conclude::{exit_with_unrecoverable_error, json, Output}; /// If no key name is given, it will be taken from the configuration file. /// If successful the balance and denominator of the account, associated with the key name /// on the given chain, will be displayed. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct KeyBalanceCmd { #[clap( long = "chain", @@ -69,3 +69,39 @@ impl Runnable for KeyBalanceCmd { } } } + +#[cfg(test)] +mod tests { + + use super::KeyBalanceCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_keys_balance_required_only() { + assert_eq!( + KeyBalanceCmd { + chain_id: ChainId::from_string("chain_id"), + key_name: None + }, + KeyBalanceCmd::parse_from(&["test", "--chain", "chain_id"]) + ) + } + + #[test] + fn test_keys_balance_name() { + assert_eq!( + KeyBalanceCmd { + chain_id: ChainId::from_string("chain_id"), + key_name: Some("kname".to_owned()) + }, + KeyBalanceCmd::parse_from(&["test", "--chain", "chain_id", "--key-name", "kname"]) + ) + } + + #[test] + fn test_keys_balance_no_chain() { + assert!(KeyBalanceCmd::try_parse_from(&["test", "--key-name", "kname"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/keys/delete.rs b/relayer-cli/src/commands/keys/delete.rs index 9d6430bbc8..e424e5f911 100644 --- a/relayer-cli/src/commands/keys/delete.rs +++ b/relayer-cli/src/commands/keys/delete.rs @@ -10,7 +10,7 @@ use ibc_relayer::{ use crate::application::app_config; use crate::conclude::Output; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct KeysDeleteCmd { #[clap( long = "chain", @@ -20,10 +20,21 @@ pub struct KeysDeleteCmd { )] chain_id: ChainId, - #[clap(long = "key-name", value_name = "KEY_NAME", help = "Name of the key")] + #[clap( + long = "key-name", + required = true, + value_name = "KEY_NAME", + group = "delete_mode", + help = "Name of the key" + )] key_name: Option, - #[clap(long = "all", help = "Delete all keys")] + #[clap( + long = "all", + required = true, + group = "delete_mode", + help = "Delete all keys" + )] all: bool, } @@ -37,14 +48,13 @@ impl KeysDeleteCmd { .ok_or_else(|| format!("chain '{}' not found in configuration file", self.chain_id))?; let id = match (self.all, &self.key_name) { - (true, Some(_)) => { - return Err("cannot set both --key-name and --all".to_owned().into()); - } - (false, None) => { - return Err("must provide either --key-name or --all".to_owned().into()); - } (true, None) => KeysDeleteId::All, (false, Some(ref key_name)) => KeysDeleteId::Named(key_name), + // This case should never trigger. + // The 'required' parameter for the flags will trigger an error if both flags have not been given. + // And the 'group' parameter for the flags will trigger an error if both flags are given. + _ => Output::error("--key-name and --all can't both be set or both None".to_string()) + .exit(), }; Ok(KeysDeleteOptions { @@ -109,3 +119,58 @@ pub fn delete_all_keys(config: &ChainConfig) -> Result<(), Box( Ok(()) } + +#[cfg(test)] +mod tests { + use super::MisbehaviourCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ClientId}; + + #[test] + fn test_misbehaviour() { + assert_eq!( + MisbehaviourCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap() + }, + MisbehaviourCmd::parse_from(&["test", "--chain", "chain_id", "--client", "client_id"]) + ) + } + + #[test] + fn test_misbehaviour_no_client() { + assert!(MisbehaviourCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_misbehaviour_no_chain() { + assert!(MisbehaviourCmd::try_parse_from(&["test", "--client", "client_id"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/channel.rs b/relayer-cli/src/commands/query/channel.rs index 5245d9d8b6..fae9ac33c3 100644 --- a/relayer-cli/src/commands/query/channel.rs +++ b/relayer-cli/src/commands/query/channel.rs @@ -11,7 +11,7 @@ use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::prelude::*; use ibc::core::ics04_channel::channel::State; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryChannelEndCmd { #[clap( long = "chain", @@ -31,7 +31,7 @@ pub struct QueryChannelEndCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -84,3 +84,110 @@ impl Runnable for QueryChannelEndCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryChannelEndCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_channel_end_required_only() { + assert_eq!( + QueryChannelEndCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None + }, + QueryChannelEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_end_chan_alias() { + assert_eq!( + QueryChannelEndCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None + }, + QueryChannelEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_end_height() { + assert_eq!( + QueryChannelEndCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: Some(42) + }, + QueryChannelEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_channel_end_no_chan() { + assert!(QueryChannelEndCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_end_no_port() { + assert!(QueryChannelEndCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_end_no_chain() { + assert!(QueryChannelEndCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/channel_client.rs b/relayer-cli/src/commands/query/channel_client.rs index 9df2ff2c3a..02212a35e3 100644 --- a/relayer-cli/src/commands/query/channel_client.rs +++ b/relayer-cli/src/commands/query/channel_client.rs @@ -14,7 +14,7 @@ use crate::conclude::{exit_with_unrecoverable_error, Output}; /// `query channel client --chain --port --channel ` /// /// If successful the channel's client state is displayed. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryChannelClientCmd { #[clap( long = "chain", @@ -34,7 +34,7 @@ pub struct QueryChannelClientCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -58,3 +58,85 @@ impl Runnable for QueryChannelClientCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryChannelClientCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_channel_client() { + assert_eq!( + QueryChannelClientCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryChannelClientCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_client_chan_alias() { + assert_eq!( + QueryChannelClientCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryChannelClientCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_client_no_chan() { + assert!(QueryChannelClientCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_client_no_port() { + assert!(QueryChannelClientCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_client_no_chain() { + assert!(QueryChannelClientCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/channel_ends.rs b/relayer-cli/src/commands/query/channel_ends.rs index 414e4d518c..34403d9623 100644 --- a/relayer-cli/src/commands/query/channel_ends.rs +++ b/relayer-cli/src/commands/query/channel_ends.rs @@ -17,7 +17,7 @@ use ibc_relayer::registry::Registry; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryChannelEndsCmd { #[clap( long = "chain", @@ -37,7 +37,7 @@ pub struct QueryChannelEndsCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -240,3 +240,136 @@ impl Runnable for QueryChannelEndsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryChannelEndsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_channel_ends_required_only() { + assert_eq!( + QueryChannelEndsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None, + verbose: false + }, + QueryChannelEndsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_ends_chan_alias() { + assert_eq!( + QueryChannelEndsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None, + verbose: false + }, + QueryChannelEndsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_channel_ends_height() { + assert_eq!( + QueryChannelEndsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: Some(42), + verbose: false + }, + QueryChannelEndsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_channel_ends_verbose() { + assert_eq!( + QueryChannelEndsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None, + verbose: true + }, + QueryChannelEndsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--verbose" + ]) + ) + } + + #[test] + fn test_query_channel_client_no_chan() { + assert!(QueryChannelEndsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_client_no_port() { + assert!(QueryChannelEndsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_channel_client_no_chain() { + assert!(QueryChannelEndsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/channels.rs b/relayer-cli/src/commands/query/channels.rs index d68d0ff940..1ab5335ba2 100644 --- a/relayer-cli/src/commands/query/channels.rs +++ b/relayer-cli/src/commands/query/channels.rs @@ -18,7 +18,7 @@ use crate::commands::query::channel_ends::ChannelEnds; use crate::conclude::Output; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryChannelsCmd { #[clap( long = "chain", @@ -273,3 +273,38 @@ impl Debug for QueryChannelsOutput { } } } + +#[cfg(test)] +mod tests { + use super::QueryChannelsCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_query_channels_required_only() { + assert_eq!( + QueryChannelsCmd { + chain_id: ChainId::from_string("chain_id"), + verbose: false + }, + QueryChannelsCmd::parse_from(&["test", "--chain", "chain_id"]) + ) + } + + #[test] + fn test_query_channels_verbose() { + assert_eq!( + QueryChannelsCmd { + chain_id: ChainId::from_string("chain_id"), + verbose: true + }, + QueryChannelsCmd::parse_from(&["test", "--chain", "chain_id", "--verbose"]) + ) + } + + #[test] + fn test_query_channels_no_chain() { + assert!(QueryChannelsCmd::try_parse_from(&["test"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/client.rs b/relayer-cli/src/commands/query/client.rs index 21038efa1a..dcc128c7a1 100644 --- a/relayer-cli/src/commands/query/client.rs +++ b/relayer-cli/src/commands/query/client.rs @@ -20,7 +20,7 @@ use crate::cli_utils::spawn_chain_runtime; use crate::conclude::{exit_with_unrecoverable_error, Output}; /// Query client state command -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryClientStateCmd { #[clap( long = "chain", @@ -74,7 +74,7 @@ impl Runnable for QueryClientStateCmd { } /// Query client consensus command -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryClientConsensusCmd { #[clap( long = "chain", @@ -187,7 +187,7 @@ impl Runnable for QueryClientConsensusCmd { } } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryClientHeaderCmd { #[clap( long = "chain", @@ -274,7 +274,7 @@ impl Runnable for QueryClientHeaderCmd { } /// Query client connections command -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryClientConnectionsCmd { #[clap( long = "chain", @@ -320,3 +320,293 @@ impl Runnable for QueryClientConnectionsCmd { } } } + +#[cfg(test)] +mod tests { + use super::{ + QueryClientConnectionsCmd, QueryClientConsensusCmd, QueryClientHeaderCmd, + QueryClientStateCmd, + }; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ClientId}; + + #[test] + fn test_query_client_connections_required_only() { + assert_eq!( + QueryClientConnectionsCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + height: None + }, + QueryClientConnectionsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id" + ]) + ) + } + + #[test] + fn test_query_client_connections_height() { + assert_eq!( + QueryClientConnectionsCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + height: Some(42) + }, + QueryClientConnectionsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_client_connections_no_client() { + assert!( + QueryClientConnectionsCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err() + ) + } + + #[test] + fn test_query_client_connections_no_chain() { + assert!( + QueryClientConnectionsCmd::try_parse_from(&["test", "--client", "client_id"]).is_err() + ) + } + + #[test] + fn test_query_client_consensus_required_only() { + assert_eq!( + QueryClientConsensusCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: None, + heights_only: false, + height: None + }, + QueryClientConsensusCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id" + ]) + ) + } + + #[test] + fn test_query_client_consensus_consensus_height() { + assert_eq!( + QueryClientConsensusCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: Some(42), + heights_only: false, + height: None + }, + QueryClientConsensusCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--consensus-height", + "42" + ]) + ) + } + + #[test] + fn test_query_client_consensus_height() { + assert_eq!( + QueryClientConsensusCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: None, + heights_only: false, + height: Some(42) + }, + QueryClientConsensusCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_client_consensus_heights_only() { + assert_eq!( + QueryClientConsensusCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: None, + heights_only: true, + height: None + }, + QueryClientConsensusCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--heights-only" + ]) + ) + } + + #[test] + fn test_query_client_consensus_no_client() { + assert!(QueryClientConsensusCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_query_client_consensus_no_chain() { + assert!( + QueryClientConsensusCmd::try_parse_from(&["test", "--client", "client_id"]).is_err() + ) + } + + #[test] + fn test_query_client_header_required_only() { + assert_eq!( + QueryClientHeaderCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: 42, + height: None + }, + QueryClientHeaderCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--consensus-height", + "42" + ]) + ) + } + + #[test] + fn test_query_client_header_height() { + assert_eq!( + QueryClientHeaderCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + consensus_height: 42, + height: Some(21) + }, + QueryClientHeaderCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--consensus-height", + "42", + "--height", + "21" + ]) + ) + } + + #[test] + fn test_query_client_header_no_consensus_height() { + assert!(QueryClientHeaderCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id" + ]) + .is_err()) + } + + #[test] + fn test_query_client_header_no_client() { + assert!(QueryClientHeaderCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--consensus-height", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_client_header_no_chain() { + assert!(QueryClientHeaderCmd::try_parse_from(&[ + "test", + "--client", + "client_id", + "--consensus-height", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_client_state_required_only() { + assert_eq!( + QueryClientStateCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + height: None + }, + QueryClientStateCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id" + ]) + ) + } + + #[test] + fn test_query_client_state_height() { + assert_eq!( + QueryClientStateCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_id").unwrap(), + height: Some(42) + }, + QueryClientStateCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--client", + "client_id", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_client_state_no_client() { + assert!(QueryClientStateCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_query_client_state_no_chain() { + assert!(QueryClientStateCmd::try_parse_from(&["test", "--client", "client_id"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/clients.rs b/relayer-cli/src/commands/query/clients.rs index 5e5d310d67..6cb6bd1e63 100644 --- a/relayer-cli/src/commands/query/clients.rs +++ b/relayer-cli/src/commands/query/clients.rs @@ -13,7 +13,7 @@ use crate::error::Error; use crate::prelude::*; /// Query clients command -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryAllClientsCmd { #[clap( long = "host-chain", @@ -108,3 +108,63 @@ impl Runnable for QueryAllClientsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryAllClientsCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_query_clients_required_only() { + assert_eq!( + QueryAllClientsCmd { + chain_id: ChainId::from_string("chain_host_id"), + src_chain_id: None, + omit_chain_ids: false + }, + QueryAllClientsCmd::parse_from(&["test", "--host-chain", "chain_host_id"]) + ) + } + + #[test] + fn test_query_clients_omit_chain_ids() { + assert_eq!( + QueryAllClientsCmd { + chain_id: ChainId::from_string("chain_host_id"), + src_chain_id: None, + omit_chain_ids: true + }, + QueryAllClientsCmd::parse_from(&[ + "test", + "--host-chain", + "chain_host_id", + "--omit-chain-ids" + ]) + ) + } + + #[test] + fn test_query_clients_reference_chain() { + assert_eq!( + QueryAllClientsCmd { + chain_id: ChainId::from_string("chain_host_id"), + src_chain_id: Some(ChainId::from_string("reference_chain_id")), + omit_chain_ids: false + }, + QueryAllClientsCmd::parse_from(&[ + "test", + "--host-chain", + "chain_host_id", + "--reference-chain", + "reference_chain_id" + ]) + ) + } + + #[test] + fn test_query_clients_no_chain() { + assert!(QueryAllClientsCmd::try_parse_from(&["test"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index 6e6fb60ef1..cf2ca3845a 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -16,7 +16,7 @@ use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryConnectionEndCmd { #[clap( long = "chain", @@ -28,7 +28,7 @@ pub struct QueryConnectionEndCmd { #[clap( long = "connection", - alias = "conn", + visible_alias = "conn", required = true, value_name = "CONNECTION_ID", help = "Identifier of the connection to query" @@ -85,7 +85,7 @@ impl Runnable for QueryConnectionEndCmd { /// Command for querying the channel identifiers associated with a connection. /// Sample invocation: /// `cargo run --bin hermes -- query connection channels ibc-0 connection-0` -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryConnectionChannelsCmd { #[clap( long = "chain", @@ -97,7 +97,7 @@ pub struct QueryConnectionChannelsCmd { #[clap( long = "connection", - alias = "conn", + visible_alias = "conn", required = true, value_name = "CONNECTION_ID", help = "Identifier of the connection to query" @@ -136,3 +136,133 @@ impl Runnable for QueryConnectionChannelsCmd { } } } + +#[cfg(test)] +mod tests { + use super::{QueryConnectionChannelsCmd, QueryConnectionEndCmd}; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ConnectionId}; + + #[test] + fn test_query_connection_channels() { + assert_eq!( + QueryConnectionChannelsCmd { + chain_id: ChainId::from_string("chain_id"), + connection_id: ConnectionId::from_str("connection_id").unwrap() + }, + QueryConnectionChannelsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--connection", + "connection_id" + ]) + ) + } + + #[test] + fn test_query_connection_channels_conn_alias() { + assert_eq!( + QueryConnectionChannelsCmd { + chain_id: ChainId::from_string("chain_id"), + connection_id: ConnectionId::from_str("connection_id").unwrap() + }, + QueryConnectionChannelsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--conn", + "connection_id" + ]) + ) + } + + #[test] + fn test_query_connection_channels_no_conn() { + assert!( + QueryConnectionChannelsCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err() + ) + } + + #[test] + fn test_query_connection_channels_no_chain() { + assert!(QueryConnectionChannelsCmd::try_parse_from(&[ + "test", + "--connection", + "connection_id" + ]) + .is_err()) + } + + #[test] + fn test_query_connection_end_required_only() { + assert_eq!( + QueryConnectionEndCmd { + chain_id: ChainId::from_string("chain_id"), + connection_id: ConnectionId::from_str("connection_id").unwrap(), + height: None + }, + QueryConnectionEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--connection", + "connection_id" + ]) + ) + } + + #[test] + fn test_query_connection_end_conn_alias() { + assert_eq!( + QueryConnectionEndCmd { + chain_id: ChainId::from_string("chain_id"), + connection_id: ConnectionId::from_str("connection_id").unwrap(), + height: None + }, + QueryConnectionEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--conn", + "connection_id" + ]) + ) + } + + #[test] + fn test_query_connection_end_height() { + assert_eq!( + QueryConnectionEndCmd { + chain_id: ChainId::from_string("chain_id"), + connection_id: ConnectionId::from_str("connection_id").unwrap(), + height: Some(42) + }, + QueryConnectionEndCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--connection", + "connection_id", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_query_connection_end_no_conn() { + assert!(QueryConnectionEndCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_query_connection_end_no_chain() { + assert!( + QueryConnectionEndCmd::try_parse_from(&["test", "--connection", "connection_id"]) + .is_err() + ) + } +} diff --git a/relayer-cli/src/commands/query/connections.rs b/relayer-cli/src/commands/query/connections.rs index 6b789ecf29..abc502d403 100644 --- a/relayer-cli/src/commands/query/connections.rs +++ b/relayer-cli/src/commands/query/connections.rs @@ -9,7 +9,7 @@ use crate::cli_utils::spawn_chain_runtime; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryConnectionsCmd { #[clap( long = "chain", @@ -47,3 +47,26 @@ impl Runnable for QueryConnectionsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryConnectionsCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_query_connections() { + assert_eq!( + QueryConnectionsCmd { + chain_id: ChainId::from_string("chain_id") + }, + QueryConnectionsCmd::parse_from(&["test", "--chain", "chain_id"]) + ) + } + + #[test] + fn test_query_connections_no_chain() { + assert!(QueryConnectionsCmd::try_parse_from(&["test"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/ack.rs b/relayer-cli/src/commands/query/packet/ack.rs index b255970e52..46b63e53f7 100644 --- a/relayer-cli/src/commands/query/packet/ack.rs +++ b/relayer-cli/src/commands/query/packet/ack.rs @@ -12,7 +12,7 @@ use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryPacketAcknowledgmentCmd { #[clap( long = "chain", @@ -32,7 +32,7 @@ pub struct QueryPacketAcknowledgmentCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -41,7 +41,7 @@ pub struct QueryPacketAcknowledgmentCmd { #[clap( long = "sequence", - alias = "seq", + visible_alias = "seq", required = true, value_name = "SEQUENCE", help = "Sequence of packet to query" @@ -96,3 +96,144 @@ impl Runnable for QueryPacketAcknowledgmentCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryPacketAcknowledgmentCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics04_channel::packet::Sequence; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_ack_required_only() { + assert_eq!( + QueryPacketAcknowledgmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: None + }, + QueryPacketAcknowledgmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + ) + } + + #[test] + fn test_query_packet_ack_aliases() { + assert_eq!( + QueryPacketAcknowledgmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: None + }, + QueryPacketAcknowledgmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07", + "--seq", + "42" + ]) + ) + } + + #[test] + fn test_query_packet_ack_height() { + assert_eq!( + QueryPacketAcknowledgmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: Some(21) + }, + QueryPacketAcknowledgmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42", + "--height", + "21" + ]) + ) + } + + #[test] + fn test_query_packet_ack_no_seq() { + assert!(QueryPacketAcknowledgmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_ack_no_chan() { + assert!(QueryPacketAcknowledgmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--sequence", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_ack_no_port() { + assert!(QueryPacketAcknowledgmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_ack_no_chain() { + assert!(QueryPacketAcknowledgmentCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/acks.rs b/relayer-cli/src/commands/query/packet/acks.rs index 0209faccf3..d8c09cecfe 100644 --- a/relayer-cli/src/commands/query/packet/acks.rs +++ b/relayer-cli/src/commands/query/packet/acks.rs @@ -19,7 +19,7 @@ struct PacketSeqs { seqs: Vec, } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryPacketAcknowledgementsCmd { #[clap( long = "chain", @@ -39,7 +39,7 @@ pub struct QueryPacketAcknowledgementsCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -77,3 +77,85 @@ impl Runnable for QueryPacketAcknowledgementsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryPacketAcknowledgementsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_acks() { + assert_eq!( + QueryPacketAcknowledgementsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPacketAcknowledgementsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_acks_chan_alias() { + assert_eq!( + QueryPacketAcknowledgementsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPacketAcknowledgementsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_acks_no_chan() { + assert!(QueryPacketAcknowledgementsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_acks_no_port() { + assert!(QueryPacketAcknowledgementsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_acks_no_chain() { + assert!(QueryPacketAcknowledgementsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/commitment.rs b/relayer-cli/src/commands/query/packet/commitment.rs index 64535352a2..fb1116a10b 100644 --- a/relayer-cli/src/commands/query/packet/commitment.rs +++ b/relayer-cli/src/commands/query/packet/commitment.rs @@ -20,7 +20,7 @@ struct PacketSeqs { seqs: Vec, } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryPacketCommitmentCmd { #[clap( long = "chain", @@ -40,7 +40,7 @@ pub struct QueryPacketCommitmentCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -49,7 +49,7 @@ pub struct QueryPacketCommitmentCmd { #[clap( long = "sequence", - alias = "seq", + visible_alias = "seq", required = true, value_name = "SEQUENCE", help = "Sequence of packet to query" @@ -107,3 +107,146 @@ impl Runnable for QueryPacketCommitmentCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryPacketCommitmentCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::{ + ics04_channel::packet::Sequence, + ics24_host::identifier::{ChainId, ChannelId, PortId}, + }; + + #[test] + fn test_query_packet_commitment_required_only() { + assert_eq!( + QueryPacketCommitmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: None + }, + QueryPacketCommitmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + ) + } + + #[test] + fn test_query_packet_commitment_aliases() { + assert_eq!( + QueryPacketCommitmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: None + }, + QueryPacketCommitmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07", + "--seq", + "42" + ]) + ) + } + + #[test] + fn test_query_packet_commitment_height() { + assert_eq!( + QueryPacketCommitmentCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap(), + sequence: Sequence::from(42), + height: Some(21) + }, + QueryPacketCommitmentCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42", + "--height", + "21" + ]) + ) + } + + #[test] + fn test_query_packet_commitment_no_seq() { + assert!(QueryPacketCommitmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_commitment_no_chan() { + assert!(QueryPacketCommitmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--sequence", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_commitment_no_port() { + assert!(QueryPacketCommitmentCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_commitment_no_chain() { + assert!(QueryPacketCommitmentCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07", + "--sequence", + "42" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/commitments.rs b/relayer-cli/src/commands/query/packet/commitments.rs index c5258ebdc1..c3a20bd5a0 100644 --- a/relayer-cli/src/commands/query/packet/commitments.rs +++ b/relayer-cli/src/commands/query/packet/commitments.rs @@ -18,7 +18,7 @@ struct PacketSeqs { seqs: Vec, } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryPacketCommitmentsCmd { #[clap( long = "chain", @@ -38,7 +38,7 @@ pub struct QueryPacketCommitmentsCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Identifier of the channel to query" @@ -72,3 +72,85 @@ impl Runnable for QueryPacketCommitmentsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryPacketCommitmentsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_commitments() { + assert_eq!( + QueryPacketCommitmentsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPacketCommitmentsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_commitments_chan_alias() { + assert_eq!( + QueryPacketCommitmentsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPacketCommitmentsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_commitments_no_chan() { + assert!(QueryPacketCommitmentsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_commitments_no_port() { + assert!(QueryPacketCommitmentsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_commitments_no_chain() { + assert!(QueryPacketCommitmentsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/pending.rs b/relayer-cli/src/commands/query/packet/pending.rs index 12e1115a4e..777b04b124 100644 --- a/relayer-cli/src/commands/query/packet/pending.rs +++ b/relayer-cli/src/commands/query/packet/pending.rs @@ -29,7 +29,7 @@ struct Summary { /// 2. queries both chains for all packet commitments/ sequences for the given port and channel /// and its counterparty. /// 3. queries both chains for the unreceived sequences and acks out of the lists obtained in 2. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryPendingPacketsCmd { #[clap( long = "chain", @@ -49,7 +49,7 @@ pub struct QueryPendingPacketsCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Channel identifier on the chain given by " @@ -100,3 +100,85 @@ impl Runnable for QueryPendingPacketsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryPendingPacketsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_pending() { + assert_eq!( + QueryPendingPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPendingPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_pending_chan_alias() { + assert_eq!( + QueryPendingPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryPendingPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_pending_no_chan() { + assert!(QueryPendingPacketsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_pending_no_port() { + assert!(QueryPendingPacketsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_pending_no_chain() { + assert!(QueryPendingPacketsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/unreceived_acks.rs b/relayer-cli/src/commands/query/packet/unreceived_acks.rs index c1a627d05f..0ca55b2edb 100644 --- a/relayer-cli/src/commands/query/packet/unreceived_acks.rs +++ b/relayer-cli/src/commands/query/packet/unreceived_acks.rs @@ -15,7 +15,7 @@ use crate::prelude::*; /// 1. queries the chain to get its counterparty, channel and port identifiers (needed in 2) /// 2. queries the chain for all packet commitments/ sequences for a given port and channel /// 3. queries the counterparty chain for the unacknowledged sequences out of the list obtained in 2. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryUnreceivedAcknowledgementCmd { #[clap( long = "chain", @@ -35,7 +35,7 @@ pub struct QueryUnreceivedAcknowledgementCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Channel identifier" @@ -74,3 +74,85 @@ impl Runnable for QueryUnreceivedAcknowledgementCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryUnreceivedAcknowledgementCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_unreceived_acks() { + assert_eq!( + QueryUnreceivedAcknowledgementCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryUnreceivedAcknowledgementCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_unreceived_acks_chan_alias() { + assert_eq!( + QueryUnreceivedAcknowledgementCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryUnreceivedAcknowledgementCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_unreceived_acks_no_chan() { + assert!(QueryUnreceivedAcknowledgementCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_unreceived_acks_no_port() { + assert!(QueryUnreceivedAcknowledgementCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_unreceived_acks_no_chain() { + assert!(QueryUnreceivedAcknowledgementCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/packet/unreceived_packets.rs b/relayer-cli/src/commands/query/packet/unreceived_packets.rs index 2dd5025ee3..8ef6355241 100644 --- a/relayer-cli/src/commands/query/packet/unreceived_packets.rs +++ b/relayer-cli/src/commands/query/packet/unreceived_packets.rs @@ -15,7 +15,7 @@ use crate::prelude::*; /// 1. queries the chain to get its counterparty chain, channel and port identifiers (needed in 2) /// 2. queries the counterparty chain for all packet commitments/ sequences for a given port and channel /// 3. queries the chain for the unreceived sequences out of the list obtained in 2. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryUnreceivedPacketsCmd { #[clap( long = "chain", @@ -35,7 +35,7 @@ pub struct QueryUnreceivedPacketsCmd { #[clap( long = "channel", - alias = "chan", + visible_alias = "chan", required = true, value_name = "CHANNEL_ID", help = "Channel identifier" @@ -74,3 +74,85 @@ impl Runnable for QueryUnreceivedPacketsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryUnreceivedPacketsCmd; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_query_packet_unreceived_packets() { + assert_eq!( + QueryUnreceivedPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryUnreceivedPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_unreceived_packets_chan_alias() { + assert_eq!( + QueryUnreceivedPacketsCmd { + chain_id: ChainId::from_string("chain_id"), + port_id: PortId::from_str("port_id").unwrap(), + channel_id: ChannelId::from_str("channel-07").unwrap() + }, + QueryUnreceivedPacketsCmd::parse_from(&[ + "test", + "--chain", + "chain_id", + "--port", + "port_id", + "--chan", + "channel-07" + ]) + ) + } + + #[test] + fn test_query_packet_unreceived_packets_no_chan() { + assert!(QueryUnreceivedPacketsCmd::try_parse_from(&[ + "test", "--chain", "chain_id", "--port", "port_id" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_unreceived_packets_no_port() { + assert!(QueryUnreceivedPacketsCmd::try_parse_from(&[ + "test", + "--chain", + "chain_id", + "--channel", + "channel-07" + ]) + .is_err()) + } + + #[test] + fn test_query_packet_unreceived_packets_no_chain() { + assert!(QueryUnreceivedPacketsCmd::try_parse_from(&[ + "test", + "--port", + "port_id", + "--channel", + "channel-07" + ]) + .is_err()) + } +} diff --git a/relayer-cli/src/commands/query/transfer/denom_trace.rs b/relayer-cli/src/commands/query/transfer/denom_trace.rs index 310bd4525f..85e59de073 100644 --- a/relayer-cli/src/commands/query/transfer/denom_trace.rs +++ b/relayer-cli/src/commands/query/transfer/denom_trace.rs @@ -15,7 +15,7 @@ use crate::conclude::{exit_with_unrecoverable_error, json, Output}; /// `query transfer denom-trace --chain --hash ` /// /// If successful the the base denomination and the path will be displayed. -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct DenomTraceCmd { #[clap(long = "chain", required = true, help = "Identifier of the chain")] chain_id: ChainId, @@ -46,3 +46,32 @@ impl Runnable for DenomTraceCmd { } } } + +#[cfg(test)] +mod tests { + use super::DenomTraceCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_transfer_denom_trace() { + assert_eq!( + DenomTraceCmd { + chain_id: ChainId::from_string("chain_id"), + hash: "abcdefg".to_owned() + }, + DenomTraceCmd::parse_from(&["test", "--chain", "chain_id", "--hash", "abcdefg"]) + ) + } + + #[test] + fn test_transfer_denom_trace_no_hash() { + assert!(DenomTraceCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_transfer_denom_trace_no_chain() { + assert!(DenomTraceCmd::try_parse_from(&["test", "--hash", "abcdefg"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/query/tx/events.rs b/relayer-cli/src/commands/query/tx/events.rs index cd2d2cfbf7..619d761a3e 100644 --- a/relayer-cli/src/commands/query/tx/events.rs +++ b/relayer-cli/src/commands/query/tx/events.rs @@ -17,7 +17,7 @@ use crate::error::Error; use crate::prelude::app_config; /// Query the events emitted by transaction -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct QueryTxEventsCmd { #[clap( long = "chain", @@ -60,3 +60,32 @@ impl Runnable for QueryTxEventsCmd { } } } + +#[cfg(test)] +mod tests { + use super::QueryTxEventsCmd; + + use abscissa_core::clap::Parser; + use ibc::core::ics24_host::identifier::ChainId; + + #[test] + fn test_query_tx_events() { + assert_eq!( + QueryTxEventsCmd { + chain_id: ChainId::from_string("chain_id"), + hash: "abcdefg".to_owned() + }, + QueryTxEventsCmd::parse_from(&["test", "--chain", "chain_id", "--hash", "abcdefg"]) + ) + } + + #[test] + fn test_query_tx_events_no_hash() { + assert!(QueryTxEventsCmd::try_parse_from(&["test", "--chain", "chain_id"]).is_err()) + } + + #[test] + fn test_query_tx_events_no_chain() { + assert!(QueryTxEventsCmd::try_parse_from(&["test", "--hash", "abcdefg"]).is_err()) + } +} diff --git a/relayer-cli/src/commands/start.rs b/relayer-cli/src/commands/start.rs index a5f9c02ef9..cf440761c3 100644 --- a/relayer-cli/src/commands/start.rs +++ b/relayer-cli/src/commands/start.rs @@ -16,7 +16,7 @@ use crate::conclude::json; use crate::conclude::Output; use crate::prelude::*; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct StartCmd { #[clap( long = "full-scan", @@ -187,3 +187,26 @@ fn make_supervisor( }, )?) } + +#[cfg(test)] +mod tests { + use super::StartCmd; + + use abscissa_core::clap::Parser; + + #[test] + fn test_start_required_only() { + assert_eq!( + StartCmd { full_scan: false }, + StartCmd::parse_from(&["test"]) + ) + } + + #[test] + fn test_start_full_scan() { + assert_eq!( + StartCmd { full_scan: true }, + StartCmd::parse_from(&["test", "--full-scan"]) + ) + } +} diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 459eec5d48..5f55f05668 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -21,7 +21,7 @@ use crate::cli_utils::{spawn_chain_runtime, spawn_chain_runtime_generic, ChainHa use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct TxCreateClientCmd { #[clap( long = "host-chain", @@ -101,7 +101,7 @@ impl Runnable for TxCreateClientCmd { } } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct TxUpdateClientCmd { #[clap( long = "host-chain", @@ -191,7 +191,7 @@ impl Runnable for TxUpdateClientCmd { } } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct TxUpgradeClientCmd { #[clap( long = "host-chain", @@ -270,7 +270,7 @@ impl Runnable for TxUpgradeClientCmd { } } -#[derive(Clone, Command, Debug, Parser)] +#[derive(Clone, Command, Debug, Parser, PartialEq)] pub struct TxUpgradeClientsCmd { #[clap( long = "reference-chain", @@ -459,7 +459,17 @@ impl OutputBuffer { #[cfg(test)] mod tests { - use super::parse_trust_threshold; + use super::{ + parse_trust_threshold, TxCreateClientCmd, TxUpdateClientCmd, TxUpgradeClientCmd, + TxUpgradeClientsCmd, + }; + + use std::str::FromStr; + + use abscissa_core::clap::Parser; + use humantime::Duration; + use ibc::core::ics24_host::identifier::{ChainId, ClientId}; + use tendermint_light_client_verifier::types::TrustThreshold; #[test] fn test_parse_trust_threshold() { @@ -475,4 +485,354 @@ mod tests { assert_eq!(threshold.numerator(), 3); assert_eq!(threshold.denominator(), 5); } + + #[test] + fn test_create_client_required_only() { + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: None, + trusting_period: None, + trust_threshold: None + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain" + ]) + ) + } + + #[test] + fn test_create_client_clock_drift() { + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: Some("5s".parse::().unwrap()), + trusting_period: None, + trust_threshold: None + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--clock-drift", + "5sec" + ]) + ); + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: Some("3s".parse::().unwrap()), + trusting_period: None, + trust_threshold: None + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--clock-drift", + "3s" + ]) + ); + } + + #[test] + fn test_create_client_trusting_period() { + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: None, + trusting_period: Some("5s".parse::().unwrap()), + trust_threshold: None + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--trusting-period", + "5sec" + ]) + ); + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: None, + trusting_period: Some("3s".parse::().unwrap()), + trust_threshold: None + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--trusting-period", + "3s" + ]) + ); + } + + #[test] + fn test_create_client_trust_threshold() { + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: None, + trusting_period: None, + trust_threshold: Some(TrustThreshold::new(1, 2).unwrap()) + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--trust-threshold", + "1/2" + ]) + ) + } + + #[test] + fn test_create_client_all_options() { + assert_eq!( + TxCreateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + src_chain_id: ChainId::from_string("reference_chain"), + clock_drift: Some("5s".parse::().unwrap()), + trusting_period: Some("3s".parse::().unwrap()), + trust_threshold: Some(TrustThreshold::new(1, 2).unwrap()) + }, + TxCreateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--reference-chain", + "reference_chain", + "--clock-drift", + "5sec", + "--trusting-period", + "3s", + "--trust-threshold", + "1/2" + ]) + ) + } + + #[test] + fn test_create_client_no_host_chain() { + assert!(TxCreateClientCmd::try_parse_from(&[ + "test", + "--reference-chain", + "reference_chain", + "--clock-drift", + "5sec", + "--trusting-period", + "3s", + "--trust-threshold", + "1/2" + ]) + .is_err()) + } + + #[test] + fn test_create_client_no_reference_chain() { + assert!(TxCreateClientCmd::try_parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--clock-drift", + "5sec", + "--trusting-period", + "3s", + "--trust-threshold", + "1/2" + ]) + .is_err()) + } + + #[test] + fn test_create_client_no_chain() { + assert!(TxCreateClientCmd::try_parse_from(&[ + "test", + "--clock-drift", + "5sec", + "--trusting-period", + "3s", + "--trust-threshold", + "1/2" + ]) + .is_err()) + } + + #[test] + fn test_update_client_required_only() { + assert_eq!( + TxUpdateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + dst_client_id: ClientId::from_str("client_to_update").unwrap(), + target_height: None, + trusted_height: None + }, + TxUpdateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--client", + "client_to_update" + ]) + ) + } + + #[test] + fn test_update_client_height() { + assert_eq!( + TxUpdateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + dst_client_id: ClientId::from_str("client_to_update").unwrap(), + target_height: Some(42), + trusted_height: None + }, + TxUpdateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--client", + "client_to_update", + "--height", + "42" + ]) + ) + } + + #[test] + fn test_update_client_trusted_height() { + assert_eq!( + TxUpdateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + dst_client_id: ClientId::from_str("client_to_update").unwrap(), + target_height: None, + trusted_height: Some(42) + }, + TxUpdateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--client", + "client_to_update", + "--trusted-height", + "42" + ]) + ) + } + + #[test] + fn test_update_client_all_options() { + assert_eq!( + TxUpdateClientCmd { + dst_chain_id: ChainId::from_string("host_chain"), + dst_client_id: ClientId::from_str("client_to_update").unwrap(), + target_height: Some(21), + trusted_height: Some(42) + }, + TxUpdateClientCmd::parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--client", + "client_to_update", + "--height", + "21", + "--trusted-height", + "42" + ]) + ) + } + + #[test] + fn test_update_client_no_chain() { + assert!(TxUpdateClientCmd::try_parse_from(&[ + "test", + "--client", + "client_to_update", + "--height", + "21", + "--trusted-height", + "42" + ]) + .is_err()) + } + + #[test] + fn test_update_client_no_client() { + assert!(TxUpdateClientCmd::try_parse_from(&[ + "test", + "--host-chain", + "host_chain", + "--height", + "21", + "--trusted-height", + "42" + ]) + .is_err()) + } + + #[test] + fn test_upgrade_client_required_only() { + assert_eq!( + TxUpgradeClientCmd { + chain_id: ChainId::from_string("chain_id"), + client_id: ClientId::from_str("client_to_upgrade").unwrap() + }, + TxUpgradeClientCmd::parse_from(&[ + "test", + "--host-chain", + "chain_id", + "--client", + "client_to_upgrade" + ]) + ) + } + + #[test] + fn test_upgrade_client_no_chain() { + assert!( + TxUpgradeClientCmd::try_parse_from(&["test", "--client", "client_to_upgrade"]).is_err() + ) + } + + #[test] + fn test_upgrade_client_no_client() { + assert!(TxUpgradeClientCmd::try_parse_from(&["test", "--host-chain", "chain_id"]).is_err()) + } + + #[test] + fn test_upgrade_clients_required_only() { + assert_eq!( + TxUpgradeClientsCmd { + src_chain_id: ChainId::from_string("chain_id") + }, + TxUpgradeClientsCmd::parse_from(&["test", "--reference-chain", "chain_id"]) + ) + } + + #[test] + fn test_upgrade_clients_no_chain() { + assert!(TxUpgradeClientsCmd::try_parse_from(&["test"]).is_err()) + } }