Skip to content
This repository was archived by the owner on Dec 29, 2021. It is now read-only.

Commit aed80a1

Browse files
committed
Introduce a glorious new cli arg splitter
Allow &str and &[&str] as input for `command` Fixes #25
1 parent b386d23 commit aed80a1

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ pub use macros::flatten_escaped_string;
119119
mod output;
120120
use output::{OutputAssertion, StdErr, StdOut};
121121

122+
mod parse_cmd;
123+
use parse_cmd::ToCmd;
124+
122125
mod diff;
123126

124127
/// Assertions for a specific command.
@@ -178,9 +181,16 @@ impl Assert {
178181
/// assert_cli::Assert::command(&["echo", "1337"])
179182
/// .unwrap();
180183
/// ```
181-
pub fn command(cmd: &[&str]) -> Self {
184+
///
185+
/// ```rust
186+
/// extern crate assert_cli;
187+
///
188+
/// assert_cli::Assert::command("echo 1337")
189+
/// .unwrap();
190+
/// ```
191+
pub fn command<'a, T: ToCmd<'a> + 'a + ?Sized>(cmd: &'a T) -> Self {
182192
Assert {
183-
cmd: cmd.into_iter().cloned().map(String::from).collect(),
193+
cmd: cmd.to_cmd(),
184194
..Self::default()
185195
}
186196
}

src/parse_cmd.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
pub trait ToCmd<'a> {
2+
fn to_cmd(&'a self) -> Vec<String>;
3+
}
4+
5+
impl<'a> ToCmd<'a> for str {
6+
fn to_cmd(&'a self) -> Vec<String> {
7+
let mut args = Vec::new();
8+
let mut current_arg = String::new();
9+
let mut in_quote = Vec::new();
10+
11+
for c in self.chars() {
12+
if in_quote.is_empty() && c.is_whitespace() {
13+
args.push(current_arg);
14+
current_arg = String::new();
15+
continue;
16+
}
17+
18+
current_arg.push(c);
19+
20+
if c == '"' || c == '\'' {
21+
if in_quote.last() == Some(&c) {
22+
in_quote.pop();
23+
} else {
24+
in_quote.push(c);
25+
}
26+
}
27+
}
28+
29+
if !current_arg.is_empty() {
30+
args.push(current_arg);
31+
}
32+
33+
args
34+
}
35+
}
36+
37+
impl<'a, 'b, T> ToCmd<'a> for T where
38+
&'a T: AsRef<[&'b str]> + Sized,
39+
T: 'a,
40+
{
41+
fn to_cmd(&'a self) -> Vec<String> {
42+
self.as_ref().into_iter().map(|x| x.to_string()).collect()
43+
}
44+
}
45+
46+
#[cfg(test)]
47+
mod test {
48+
use super::ToCmd;
49+
50+
#[test]
51+
fn slices() {
52+
assert_eq!(
53+
ToCmd::to_cmd(&["echo", "42"]),
54+
vec!["echo", "42"]
55+
);
56+
}
57+
58+
#[test]
59+
fn simple() {
60+
assert_eq!(
61+
"echo 42".to_cmd(),
62+
vec!["echo", "42"]
63+
);
64+
assert_eq!(
65+
r#"echo "42""#.to_cmd(),
66+
vec!["echo", "\"42\""]
67+
);
68+
assert_eq!(
69+
r#"echo '42'"#.to_cmd(),
70+
vec!["echo", "\'42\'"]
71+
);
72+
assert_eq!(
73+
r#"echo '42 is the answer'"#.to_cmd(),
74+
vec!["echo", "\'42 is the answer\'"]
75+
);
76+
}
77+
78+
#[test]
79+
fn real_world() {
80+
assert_eq!(
81+
r#"cargo run --bin whatever -- --input="Lorem ipsum" -f"#.to_cmd(),
82+
vec!["cargo", "run", "--bin", "whatever", "--", "--input=\"Lorem ipsum\"", "-f"]
83+
);
84+
}
85+
86+
#[test]
87+
fn nested_quotes() {
88+
assert_eq!(
89+
r#"echo "lorem ipsum 'dolor' sit amet""#.to_cmd(),
90+
vec!["echo", "\"lorem ipsum 'dolor' sit amet\""]
91+
);
92+
93+
assert_eq!(
94+
r#"echo "lorem ipsum ('dolor "doloris" septetur') sit amet""#.to_cmd(),
95+
vec!["echo", "\"lorem ipsum ('dolor \"doloris\" septetur') sit amet\""]
96+
);
97+
}
98+
}

0 commit comments

Comments
 (0)