]>
Commit | Line | Data |
---|---|---|
83571aee EH |
1 | //! Tests for custom cargo commands and other global command features. |
2 | ||
ee5e24ff | 3 | use std::env; |
dde290e6 | 4 | use std::fs; |
7274307a | 5 | use std::io::Read; |
a6dad622 | 6 | use std::path::{Path, PathBuf}; |
7274307a | 7 | use std::process::Stdio; |
8cce8996 | 8 | use std::str; |
8cce8996 | 9 | |
9115b2c3 | 10 | use cargo_test_support::cargo_process; |
dde290e6 | 11 | use cargo_test_support::paths; |
9115b2c3 | 12 | use cargo_test_support::registry::Package; |
1c5e68b4 | 13 | use cargo_test_support::{basic_bin_manifest, basic_manifest, cargo_exe, project, project_in_home}; |
a3f6a404 | 14 | |
a6dad622 | 15 | fn path() -> Vec<PathBuf> { |
23591fe5 | 16 | env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect() |
db3823a8 | 17 | } |
ee5e24ff | 18 | |
0e0d9688 | 19 | #[cargo_test] |
af2c3555 DW |
20 | fn list_commands_with_descriptions() { |
21 | let p = project().build(); | |
a173fc0a | 22 | p.cargo("--list") |
fecb7246 AC |
23 | .with_stdout_contains( |
24 | " build Compile a local package and all of its dependencies", | |
25 | ) | |
f7c91ba6 AR |
26 | // Assert that `read-manifest` prints the right one-line description followed by another |
27 | // command, indented. | |
fecb7246 AC |
28 | .with_stdout_contains( |
29 | " read-manifest Print a JSON representation of a Cargo.toml manifest.", | |
30 | ) | |
a173fc0a | 31 | .run(); |
af2c3555 DW |
32 | } |
33 | ||
7b16c7c1 | 34 | #[cargo_test] |
1c5e68b4 | 35 | fn list_builtin_aliases_with_descriptions() { |
7b16c7c1 C |
36 | let p = project().build(); |
37 | p.cargo("--list") | |
38 | .with_stdout_contains(" b alias: build") | |
39 | .with_stdout_contains(" c alias: check") | |
40 | .with_stdout_contains(" r alias: run") | |
41 | .with_stdout_contains(" t alias: test") | |
42 | .run(); | |
43 | } | |
44 | ||
1c5e68b4 DM |
45 | #[cargo_test] |
46 | fn list_custom_aliases_with_descriptions() { | |
47 | let p = project_in_home("proj") | |
48 | .file( | |
49 | &paths::home().join(".cargo").join("config"), | |
50 | r#" | |
51 | [alias] | |
52 | myaliasstr = "foo --bar" | |
53 | myaliasvec = ["foo", "--bar"] | |
54 | "#, | |
55 | ) | |
56 | .build(); | |
57 | ||
58 | p.cargo("--list") | |
59 | .with_stdout_contains(" myaliasstr foo --bar") | |
60 | .with_stdout_contains(" myaliasvec foo --bar") | |
61 | .run(); | |
62 | } | |
63 | ||
0e0d9688 | 64 | #[cargo_test] |
6950bbb0 | 65 | fn list_command_looks_at_path() { |
dde290e6 NK |
66 | let proj = project() |
67 | .executable(Path::new("path-test").join("cargo-1"), "") | |
68 | .build(); | |
a3f6a404 | 69 | |
5d0cb3f2 | 70 | let mut path = path(); |
db3823a8 | 71 | path.push(proj.root().join("path-test")); |
ee5e24ff | 72 | let path = env::join_paths(path.iter()).unwrap(); |
fecb7246 AC |
73 | let output = cargo_process("-v --list") |
74 | .env("PATH", &path) | |
75 | .exec_with_output() | |
76 | .unwrap(); | |
63b34b64 DW |
77 | let output = str::from_utf8(&output.stdout).unwrap(); |
78 | assert!( | |
79 | output.contains("\n 1 "), | |
80 | "missing 1: {}", | |
81 | output | |
82 | ); | |
6950bbb0 | 83 | } |
12f5de8e | 84 | |
0e0d9688 | 85 | #[cargo_test] |
6950bbb0 | 86 | fn list_command_resolves_symlinks() { |
dde290e6 NK |
87 | let proj = project() |
88 | .symlink(cargo_exe(), Path::new("path-test").join("cargo-2")) | |
89 | .build(); | |
974d5834 JB |
90 | |
91 | let mut path = path(); | |
92 | path.push(proj.root().join("path-test")); | |
93 | let path = env::join_paths(path.iter()).unwrap(); | |
fecb7246 AC |
94 | let output = cargo_process("-v --list") |
95 | .env("PATH", &path) | |
96 | .exec_with_output() | |
97 | .unwrap(); | |
63b34b64 DW |
98 | let output = str::from_utf8(&output.stdout).unwrap(); |
99 | assert!( | |
100 | output.contains("\n 2 "), | |
101 | "missing 2: {}", | |
102 | output | |
103 | ); | |
6950bbb0 | 104 | } |
974d5834 | 105 | |
0e0d9688 | 106 | #[cargo_test] |
6950bbb0 | 107 | fn find_closest_biuld_to_build() { |
85984a87 DW |
108 | cargo_process("biuld") |
109 | .with_status(101) | |
110 | .with_stderr_contains( | |
1e682848 | 111 | "\ |
a1735c7a AK |
112 | error: no such subcommand: `biuld` |
113 | ||
114 | <tab>Did you mean `build`? | |
1e682848 | 115 | ", |
fecb7246 AC |
116 | ) |
117 | .run(); | |
a1735c7a AK |
118 | |
119 | // But, if we actually have `biuld`, it must work! | |
120 | // https://github.com/rust-lang/cargo/issues/5201 | |
121 | Package::new("cargo-biuld", "1.0.0") | |
122 | .file( | |
123 | "src/main.rs", | |
124 | r#" | |
6f8c7d5a EH |
125 | fn main() { |
126 | println!("Similar, but not identical to, build"); | |
127 | } | |
128 | "#, | |
fecb7246 AC |
129 | ) |
130 | .publish(); | |
85984a87 DW |
131 | |
132 | cargo_process("install cargo-biuld").run(); | |
133 | cargo_process("biuld") | |
134 | .with_stdout("Similar, but not identical to, build\n") | |
135 | .run(); | |
136 | cargo_process("--list") | |
137 | .with_stdout_contains( | |
138 | " build Compile a local package and all of its dependencies\n", | |
fecb7246 AC |
139 | ) |
140 | .with_stdout_contains(" biuld\n") | |
85984a87 | 141 | .run(); |
6950bbb0 | 142 | } |
12f5de8e | 143 | |
ff3e880c ZL |
144 | #[cargo_test] |
145 | fn find_closest_alias() { | |
146 | let root = paths::root(); | |
147 | let my_home = root.join("my_home"); | |
148 | fs::create_dir(&my_home).unwrap(); | |
4ae79d2f EH |
149 | fs::write( |
150 | &my_home.join("config"), | |
151 | r#" | |
152 | [alias] | |
153 | myalias = "build" | |
154 | "#, | |
155 | ) | |
156 | .unwrap(); | |
ff3e880c ZL |
157 | |
158 | cargo_process("myalais") | |
159 | .env("CARGO_HOME", &my_home) | |
160 | .with_status(101) | |
161 | .with_stderr_contains( | |
162 | "\ | |
163 | error: no such subcommand: `myalais` | |
164 | ||
165 | <tab>Did you mean `myalias`? | |
166 | ", | |
167 | ) | |
168 | .run(); | |
169 | ||
170 | // But, if no alias is defined, it must not suggest one! | |
171 | cargo_process("myalais") | |
172 | .with_status(101) | |
173 | .with_stderr_contains( | |
174 | "\ | |
175 | error: no such subcommand: `myalais` | |
176 | ", | |
177 | ) | |
178 | .with_stderr_does_not_contain( | |
179 | "\ | |
180 | <tab>Did you mean `myalias`? | |
181 | ", | |
182 | ) | |
183 | .run(); | |
184 | } | |
185 | ||
f7c91ba6 | 186 | // If a subcommand is more than an edit distance of 3 away, we don't make a suggestion. |
0e0d9688 | 187 | #[cargo_test] |
6950bbb0 | 188 | fn find_closest_dont_correct_nonsense() { |
85984a87 DW |
189 | cargo_process("there-is-no-way-that-there-is-a-command-close-to-this") |
190 | .cwd(&paths::root()) | |
191 | .with_status(101) | |
192 | .with_stderr( | |
1e682848 | 193 | "[ERROR] no such subcommand: \ |
1671630b | 194 | `there-is-no-way-that-there-is-a-command-close-to-this` |
1e682848 | 195 | ", |
fecb7246 AC |
196 | ) |
197 | .run(); | |
79858995 KA |
198 | } |
199 | ||
0e0d9688 | 200 | #[cargo_test] |
79858995 | 201 | fn displays_subcommand_on_error() { |
85984a87 DW |
202 | cargo_process("invalid-command") |
203 | .with_status(101) | |
204 | .with_stderr("[ERROR] no such subcommand: `invalid-command`\n") | |
205 | .run(); | |
6950bbb0 | 206 | } |
2badab8c | 207 | |
b0998864 J |
208 | #[cargo_test] |
209 | fn override_cargo_home() { | |
210 | let root = paths::root(); | |
211 | let my_home = root.join("my_home"); | |
212 | fs::create_dir(&my_home).unwrap(); | |
213 | fs::write( | |
214 | &my_home.join("config"), | |
215 | r#" | |
216 | [cargo-new] | |
217 | vcs = "none" | |
218 | "#, | |
219 | ) | |
220 | .unwrap(); | |
221 | ||
222 | cargo_process("new foo").env("CARGO_HOME", &my_home).run(); | |
223 | ||
224 | assert!(!paths::root().join("foo/.git").is_dir()); | |
225 | ||
226 | cargo_process("new foo2").run(); | |
227 | ||
228 | assert!(paths::root().join("foo2/.git").is_dir()); | |
229 | } | |
230 | ||
0e0d9688 | 231 | #[cargo_test] |
015a08a0 | 232 | fn cargo_subcommand_env() { |
1e682848 AC |
233 | let src = format!( |
234 | r#" | |
015a08a0 VK |
235 | use std::env; |
236 | ||
237 | fn main() {{ | |
238 | println!("{{}}", env::var("{}").unwrap()); | |
239 | }} | |
1e682848 AC |
240 | "#, |
241 | cargo::CARGO_ENV | |
242 | ); | |
015a08a0 | 243 | |
85984a87 DW |
244 | let p = project() |
245 | .at("cargo-envtest") | |
015a08a0 | 246 | .file("Cargo.toml", &basic_bin_manifest("cargo-envtest")) |
d43ee1dd NK |
247 | .file("src/main.rs", &src) |
248 | .build(); | |
015a08a0 VK |
249 | |
250 | let target_dir = p.target_debug_dir(); | |
251 | ||
85984a87 | 252 | p.cargo("build").run(); |
570fe892 | 253 | assert!(p.bin("cargo-envtest").is_file()); |
015a08a0 | 254 | |
015a08a0 VK |
255 | let cargo = cargo_exe().canonicalize().unwrap(); |
256 | let mut path = path(); | |
257 | path.push(target_dir); | |
258 | let path = env::join_paths(path.iter()).unwrap(); | |
259 | ||
85984a87 DW |
260 | cargo_process("envtest") |
261 | .env("PATH", &path) | |
262 | .with_stdout(cargo.to_str().unwrap()) | |
263 | .run(); | |
015a08a0 VK |
264 | } |
265 | ||
0e0d9688 | 266 | #[cargo_test] |
deb1c1e1 | 267 | fn cargo_subcommand_args() { |
85984a87 DW |
268 | let p = project() |
269 | .at("cargo-foo") | |
ab19c483 | 270 | .file("Cargo.toml", &basic_manifest("cargo-foo", "0.0.1")) |
deb1c1e1 AK |
271 | .file( |
272 | "src/main.rs", | |
273 | r#" | |
6f8c7d5a EH |
274 | fn main() { |
275 | let args: Vec<_> = ::std::env::args().collect(); | |
aea5ca3c | 276 | println!("{}", args.join(" ")); |
6f8c7d5a EH |
277 | } |
278 | "#, | |
fecb7246 AC |
279 | ) |
280 | .build(); | |
deb1c1e1 | 281 | |
85984a87 | 282 | p.cargo("build").run(); |
deb1c1e1 | 283 | let cargo_foo_bin = p.bin("cargo-foo"); |
570fe892 | 284 | assert!(cargo_foo_bin.is_file()); |
deb1c1e1 AK |
285 | |
286 | let mut path = path(); | |
287 | path.push(p.target_debug_dir()); | |
288 | let path = env::join_paths(path.iter()).unwrap(); | |
289 | ||
85984a87 DW |
290 | cargo_process("foo bar -v --help") |
291 | .env("PATH", &path) | |
aea5ca3c | 292 | .with_stdout("[CWD]/cargo-foo/target/debug/cargo-foo[EXE] foo bar -v --help") |
49f73b9c | 293 | .run(); |
deb1c1e1 AK |
294 | } |
295 | ||
0e0d9688 | 296 | #[cargo_test] |
6950bbb0 | 297 | fn explain() { |
85984a87 DW |
298 | cargo_process("--explain E0001") |
299 | .with_stdout_contains( | |
b0c181d9 | 300 | "This error suggests that the expression arm corresponding to the noted pattern", |
fecb7246 AC |
301 | ) |
302 | .run(); | |
6950bbb0 | 303 | } |
a4104914 | 304 | |
7274307a EH |
305 | #[cargo_test] |
306 | fn closed_output_ok() { | |
307 | // Checks that closed output doesn't cause an error. | |
308 | let mut p = cargo_process("--list").build_command(); | |
309 | p.stdout(Stdio::piped()).stderr(Stdio::piped()); | |
310 | let mut child = p.spawn().unwrap(); | |
311 | // Close stdout | |
312 | drop(child.stdout.take()); | |
313 | // Read stderr | |
314 | let mut s = String::new(); | |
315 | child | |
316 | .stderr | |
317 | .as_mut() | |
318 | .unwrap() | |
319 | .read_to_string(&mut s) | |
320 | .unwrap(); | |
321 | let status = child.wait().unwrap(); | |
322 | assert!(status.success()); | |
f5a3d559 | 323 | assert!(s.is_empty(), "{}", s); |
7274307a | 324 | } |