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