1 //! Tests for custom cargo commands and other global command features.
4 use std
::fs
::{self, File}
;
5 use std
::io
::prelude
::*;
6 use std
::path
::{Path, PathBuf}
;
10 use cargo_test_support
::cargo_process
;
11 use cargo_test_support
::paths
::{self, CargoPathExt}
;
12 use cargo_test_support
::registry
::Package
;
13 use cargo_test_support
::{basic_bin_manifest, basic_manifest, cargo_exe, project, Project}
;
15 #[cfg_attr(windows, allow(dead_code))]
18 Symlink { target: &'a Path }
,
21 /// Adds an empty file with executable flags (and platform-dependent suffix).
23 // TODO: move this to `Project` if other cases using this emerge.
24 fn fake_file(proj
: Project
, dir
: &Path
, name
: &str, kind
: &FakeKind
<'_
>) -> Project
{
28 .join(&format
!("{}{}", name
, env
::consts
::EXE_SUFFIX
));
29 path
.parent().unwrap().mkdir_p();
31 FakeKind
::Executable
=> {
32 File
::create(&path
).unwrap();
33 make_executable(&path
);
35 FakeKind
::Symlink { target }
=> {
36 make_symlink(&path
, target
);
42 fn make_executable(p
: &Path
) {
43 use std
::os
::unix
::prelude
::*;
45 let mut perms
= fs
::metadata(p
).unwrap().permissions();
46 let mode
= perms
.mode();
47 perms
.set_mode(mode
| 0o111);
48 fs
::set_permissions(p
, perms
).unwrap();
51 fn make_executable(_
: &Path
) {}
53 fn make_symlink(p
: &Path
, t
: &Path
) {
54 ::std
::os
::unix
::fs
::symlink(t
, p
).expect("Failed to create symlink");
57 fn make_symlink(_
: &Path
, _
: &Path
) {
58 panic
!("Not supported")
62 fn path() -> Vec
<PathBuf
> {
63 env
::split_paths(&env
::var_os("PATH").unwrap_or_default()).collect()
67 fn list_commands_with_descriptions() {
68 let p
= project().build();
70 .with_stdout_contains(
71 " build Compile a local package and all of its dependencies",
73 // Assert that `read-manifest` prints the right one-line description followed by another
75 .with_stdout_contains(
76 " read-manifest Print a JSON representation of a Cargo.toml manifest.",
82 fn list_command_looks_at_path() {
83 let proj
= project().build();
86 Path
::new("path-test"),
88 &FakeKind
::Executable
,
91 let mut path
= path();
92 path
.push(proj
.root().join("path-test"));
93 let path
= env
::join_paths(path
.iter()).unwrap();
94 let output
= cargo_process("-v --list")
98 let output
= str::from_utf8(&output
.stdout
).unwrap();
100 output
.contains("\n 1 "),
106 // Windows and symlinks don't currently mix well.
109 fn list_command_resolves_symlinks() {
110 let proj
= project().build();
111 let proj
= fake_file(
113 Path
::new("path-test"),
116 target
: &cargo_exe(),
120 let mut path
= path();
121 path
.push(proj
.root().join("path-test"));
122 let path
= env
::join_paths(path
.iter()).unwrap();
123 let output
= cargo_process("-v --list")
127 let output
= str::from_utf8(&output
.stdout
).unwrap();
129 output
.contains("\n 2 "),
136 fn find_closest_biuld_to_build() {
137 cargo_process("biuld")
139 .with_stderr_contains(
141 error: no such subcommand: `biuld`
143 <tab>Did you mean `build`?
148 // But, if we actually have `biuld`, it must work!
149 // https://github.com/rust-lang/cargo/issues/5201
150 Package
::new("cargo-biuld", "1.0.0")
155 println!("Similar, but not identical to, build");
161 cargo_process("install cargo-biuld").run();
162 cargo_process("biuld")
163 .with_stdout("Similar, but not identical to, build\n")
165 cargo_process("--list")
166 .with_stdout_contains(
167 " build Compile a local package and all of its dependencies\n",
169 .with_stdout_contains(" biuld\n")
174 fn find_closest_alias() {
175 let root
= paths
::root();
176 let my_home
= root
.join("my_home");
177 fs
::create_dir(&my_home
).unwrap();
178 File
::create(&my_home
.join("config"))
188 cargo_process("myalais")
189 .env("CARGO_HOME", &my_home
)
191 .with_stderr_contains(
193 error: no such subcommand: `myalais`
195 <tab>Did you mean `myalias`?
200 // But, if no alias is defined, it must not suggest one!
201 cargo_process("myalais")
203 .with_stderr_contains(
205 error: no such subcommand: `myalais`
208 .with_stderr_does_not_contain(
210 <tab>Did you mean `myalias`?
216 // If a subcommand is more than an edit distance of 3 away, we don't make a suggestion.
218 fn find_closest_dont_correct_nonsense() {
219 cargo_process("there-is-no-way-that-there-is-a-command-close-to-this")
223 "[ERROR] no such subcommand: \
224 `there-is-no-way-that-there-is-a-command-close-to-this`
231 fn displays_subcommand_on_error() {
232 cargo_process("invalid-command")
234 .with_stderr("[ERROR] no such subcommand: `invalid-command`\n")
239 fn override_cargo_home() {
240 let root
= paths
::root();
241 let my_home
= root
.join("my_home");
242 fs
::create_dir(&my_home
).unwrap();
243 File
::create(&my_home
.join("config"))
255 cargo_process("new foo")
257 .env("CARGO_HOME", &my_home
)
260 let toml
= paths
::root().join("foo/Cargo.toml");
261 let mut contents
= String
::new();
264 .read_to_string(&mut contents
)
266 assert
!(contents
.contains(r
#"authors = ["foo <bar>"]"#));
270 fn cargo_subcommand_env() {
276 println!("{{}}", env::var("{}").unwrap());
284 .file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
285 .file("src/main.rs", &src
)
288 let target_dir
= p
.target_debug_dir();
290 p
.cargo("build").run();
291 assert
!(p
.bin("cargo-envtest").is_file());
293 let cargo
= cargo_exe().canonicalize().unwrap();
294 let mut path
= path();
295 path
.push(target_dir
);
296 let path
= env
::join_paths(path
.iter()).unwrap();
298 cargo_process("envtest")
300 .with_stdout(cargo
.to_str().unwrap())
305 fn cargo_subcommand_args() {
308 .file("Cargo.toml", &basic_manifest("cargo-foo", "0.0.1"))
313 let args: Vec<_> = ::std::env::args().collect();
314 println!("{:?}", args);
320 p
.cargo("build").run();
321 let cargo_foo_bin
= p
.bin("cargo-foo");
322 assert
!(cargo_foo_bin
.is_file());
324 let mut path
= path();
325 path
.push(p
.target_debug_dir());
326 let path
= env
::join_paths(path
.iter()).unwrap();
328 cargo_process("foo bar -v --help")
331 r
#"["[CWD]/cargo-foo/target/debug/cargo-foo[EXE]", "foo", "bar", "-v", "--help"]"#,
338 cargo_process("").run();
339 cargo_process("help").run();
340 cargo_process("-h").run();
341 cargo_process("help build").run();
342 cargo_process("build -h").run();
343 cargo_process("help help").run();
347 fn cargo_help_external_subcommand() {
348 Package
::new("cargo-fake-help", "1.0.0")
353 if ::std::env::args().nth(2) == Some(String::from("--help")) {
354 println!("fancy help output");
359 cargo_process("install cargo-fake-help").run();
360 cargo_process("help fake-help")
361 .with_stdout("fancy help output\n")
367 cargo_process("--explain E0001")
368 .with_stdout_contains(
369 "This error suggests that the expression arm corresponding to the noted pattern",
374 // Test that the output of `cargo -Z help` shows a different help screen with
375 // all the `-Z` flags.
378 cargo_process("-Z help")
379 .with_stdout_contains(
380 " -Z unstable-options -- Allow the usage of unstable options such as --registry",