]> git.proxmox.com Git - cargo.git/blame - tests/testsuite/cargo_command.rs
Improve test suite for `-Zbuild-std`
[cargo.git] / tests / testsuite / cargo_command.rs
CommitLineData
ee5e24ff 1use std::env;
a6dad622
AC
2use std::fs::{self, File};
3use std::io::prelude::*;
4use std::path::{Path, PathBuf};
8cce8996 5use std::str;
8cce8996 6
04ddd4d0
DW
7use crate::support::cargo_process;
8use crate::support::paths::{self, CargoPathExt};
9use crate::support::registry::Package;
10use crate::support::{basic_bin_manifest, basic_manifest, cargo_exe, project, Project};
fecb7246 11use cargo;
a3f6a404 12
1e682848 13#[cfg_attr(windows, allow(dead_code))]
974d5834
JB
14enum FakeKind<'a> {
15 Executable,
1e682848 16 Symlink { target: &'a Path },
974d5834
JB
17}
18
f7c91ba6
AR
19/// Adds an empty file with executable flags (and platform-dependent suffix).
20//
21// TODO: move this to `Project` if other cases using this emerge.
6d1d3a68 22fn fake_file(proj: Project, dir: &Path, name: &str, kind: &FakeKind<'_>) -> Project {
85984a87
DW
23 let path = proj
24 .root()
1e682848
AC
25 .join(dir)
26 .join(&format!("{}{}", name, env::consts::EXE_SUFFIX));
763ba535 27 path.parent().unwrap().mkdir_p();
23591fe5 28 match *kind {
974d5834
JB
29 FakeKind::Executable => {
30 File::create(&path).unwrap();
31 make_executable(&path);
1e682848
AC
32 }
33 FakeKind::Symlink { target } => {
34 make_symlink(&path, target);
974d5834
JB
35 }
36 }
a6dad622
AC
37 return proj;
38
39 #[cfg(unix)]
40 fn make_executable(p: &Path) {
41 use std::os::unix::prelude::*;
42
53cc3ce8 43 let mut perms = fs::metadata(p).unwrap().permissions();
a6dad622
AC
44 let mode = perms.mode();
45 perms.set_mode(mode | 0o111);
46 fs::set_permissions(p, perms).unwrap();
47 }
48 #[cfg(windows)]
49 fn make_executable(_: &Path) {}
974d5834
JB
50 #[cfg(unix)]
51 fn make_symlink(p: &Path, t: &Path) {
1e682848 52 ::std::os::unix::fs::symlink(t, p).expect("Failed to create symlink");
974d5834
JB
53 }
54 #[cfg(windows)]
55 fn make_symlink(_: &Path, _: &Path) {
56 panic!("Not supported")
57 }
a3f6a404 58}
59
a6dad622 60fn path() -> Vec<PathBuf> {
23591fe5 61 env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect()
db3823a8 62}
ee5e24ff 63
0e0d9688 64#[cargo_test]
af2c3555
DW
65fn list_commands_with_descriptions() {
66 let p = project().build();
a173fc0a 67 p.cargo("--list")
fecb7246
AC
68 .with_stdout_contains(
69 " build Compile a local package and all of its dependencies",
70 )
f7c91ba6
AR
71 // Assert that `read-manifest` prints the right one-line description followed by another
72 // command, indented.
fecb7246
AC
73 .with_stdout_contains(
74 " read-manifest Print a JSON representation of a Cargo.toml manifest.",
75 )
a173fc0a 76 .run();
af2c3555
DW
77}
78
0e0d9688 79#[cargo_test]
6950bbb0 80fn list_command_looks_at_path() {
f8c9928c 81 let proj = project().build();
1e682848
AC
82 let proj = fake_file(
83 proj,
84 Path::new("path-test"),
85 "cargo-1",
86 &FakeKind::Executable,
87 );
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
f7c91ba6 104// Windows and symlinks don't currently mix well.
974d5834 105#[cfg(unix)]
0e0d9688 106#[cargo_test]
6950bbb0 107fn list_command_resolves_symlinks() {
f8c9928c 108 let proj = project().build();
1e682848
AC
109 let proj = fake_file(
110 proj,
111 Path::new("path-test"),
112 "cargo-2",
113 &FakeKind::Symlink {
114 target: &cargo_exe(),
115 },
116 );
974d5834
JB
117
118 let mut path = path();
119 path.push(proj.root().join("path-test"));
120 let path = env::join_paths(path.iter()).unwrap();
fecb7246
AC
121 let output = cargo_process("-v --list")
122 .env("PATH", &path)
123 .exec_with_output()
124 .unwrap();
63b34b64
DW
125 let output = str::from_utf8(&output.stdout).unwrap();
126 assert!(
127 output.contains("\n 2 "),
128 "missing 2: {}",
129 output
130 );
6950bbb0 131}
974d5834 132
0e0d9688 133#[cargo_test]
6950bbb0 134fn find_closest_biuld_to_build() {
85984a87
DW
135 cargo_process("biuld")
136 .with_status(101)
137 .with_stderr_contains(
1e682848 138 "\
a1735c7a
AK
139error: no such subcommand: `biuld`
140
141<tab>Did you mean `build`?
1e682848 142",
fecb7246
AC
143 )
144 .run();
a1735c7a
AK
145
146 // But, if we actually have `biuld`, it must work!
147 // https://github.com/rust-lang/cargo/issues/5201
148 Package::new("cargo-biuld", "1.0.0")
149 .file(
150 "src/main.rs",
151 r#"
152 fn main() {
153 println!("Similar, but not identical to, build");
154 }
155 "#,
fecb7246
AC
156 )
157 .publish();
85984a87
DW
158
159 cargo_process("install cargo-biuld").run();
160 cargo_process("biuld")
161 .with_stdout("Similar, but not identical to, build\n")
162 .run();
163 cargo_process("--list")
164 .with_stdout_contains(
165 " build Compile a local package and all of its dependencies\n",
fecb7246
AC
166 )
167 .with_stdout_contains(" biuld\n")
85984a87 168 .run();
6950bbb0 169}
12f5de8e 170
f7c91ba6 171// If a subcommand is more than an edit distance of 3 away, we don't make a suggestion.
0e0d9688 172#[cargo_test]
6950bbb0 173fn find_closest_dont_correct_nonsense() {
85984a87
DW
174 cargo_process("there-is-no-way-that-there-is-a-command-close-to-this")
175 .cwd(&paths::root())
176 .with_status(101)
177 .with_stderr(
1e682848 178 "[ERROR] no such subcommand: \
1671630b 179 `there-is-no-way-that-there-is-a-command-close-to-this`
1e682848 180",
fecb7246
AC
181 )
182 .run();
79858995
KA
183}
184
0e0d9688 185#[cargo_test]
79858995 186fn displays_subcommand_on_error() {
85984a87
DW
187 cargo_process("invalid-command")
188 .with_status(101)
189 .with_stderr("[ERROR] no such subcommand: `invalid-command`\n")
190 .run();
6950bbb0 191}
2badab8c 192
0e0d9688 193#[cargo_test]
6950bbb0 194fn override_cargo_home() {
2badab8c
BA
195 let root = paths::root();
196 let my_home = root.join("my_home");
a6dad622 197 fs::create_dir(&my_home).unwrap();
1e682848
AC
198 File::create(&my_home.join("config"))
199 .unwrap()
200 .write_all(
201 br#"
2badab8c
BA
202 [cargo-new]
203 name = "foo"
204 email = "bar"
205 git = false
1e682848 206 "#,
fecb7246
AC
207 )
208 .unwrap();
2badab8c 209
85984a87
DW
210 cargo_process("new foo")
211 .env("USER", "foo")
212 .env("CARGO_HOME", &my_home)
213 .run();
2badab8c
BA
214
215 let toml = paths::root().join("foo/Cargo.toml");
a6dad622 216 let mut contents = String::new();
1e682848
AC
217 File::open(&toml)
218 .unwrap()
219 .read_to_string(&mut contents)
220 .unwrap();
a6dad622 221 assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
6950bbb0 222}
2ff5f53b 223
0e0d9688 224#[cargo_test]
015a08a0 225fn cargo_subcommand_env() {
1e682848
AC
226 let src = format!(
227 r#"
015a08a0
VK
228 use std::env;
229
230 fn main() {{
231 println!("{{}}", env::var("{}").unwrap());
232 }}
1e682848
AC
233 "#,
234 cargo::CARGO_ENV
235 );
015a08a0 236
85984a87
DW
237 let p = project()
238 .at("cargo-envtest")
015a08a0 239 .file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
d43ee1dd
NK
240 .file("src/main.rs", &src)
241 .build();
015a08a0
VK
242
243 let target_dir = p.target_debug_dir();
244
85984a87 245 p.cargo("build").run();
570fe892 246 assert!(p.bin("cargo-envtest").is_file());
015a08a0 247
015a08a0
VK
248 let cargo = cargo_exe().canonicalize().unwrap();
249 let mut path = path();
250 path.push(target_dir);
251 let path = env::join_paths(path.iter()).unwrap();
252
85984a87
DW
253 cargo_process("envtest")
254 .env("PATH", &path)
255 .with_stdout(cargo.to_str().unwrap())
256 .run();
015a08a0
VK
257}
258
0e0d9688 259#[cargo_test]
deb1c1e1 260fn cargo_subcommand_args() {
85984a87
DW
261 let p = project()
262 .at("cargo-foo")
ab19c483 263 .file("Cargo.toml", &basic_manifest("cargo-foo", "0.0.1"))
deb1c1e1
AK
264 .file(
265 "src/main.rs",
266 r#"
267 fn main() {
268 let args: Vec<_> = ::std::env::args().collect();
269 println!("{:?}", args);
270 }
271 "#,
fecb7246
AC
272 )
273 .build();
deb1c1e1 274
85984a87 275 p.cargo("build").run();
deb1c1e1 276 let cargo_foo_bin = p.bin("cargo-foo");
570fe892 277 assert!(cargo_foo_bin.is_file());
deb1c1e1
AK
278
279 let mut path = path();
280 path.push(p.target_debug_dir());
281 let path = env::join_paths(path.iter()).unwrap();
282
85984a87
DW
283 cargo_process("foo bar -v --help")
284 .env("PATH", &path)
092f7bae
DW
285 .with_stdout(
286 r#"["[CWD]/cargo-foo/target/debug/cargo-foo[EXE]", "foo", "bar", "-v", "--help"]"#,
287 )
49f73b9c 288 .run();
deb1c1e1
AK
289}
290
0e0d9688 291#[cargo_test]
6950bbb0 292fn cargo_help() {
85984a87
DW
293 cargo_process("").run();
294 cargo_process("help").run();
295 cargo_process("-h").run();
296 cargo_process("help build").run();
297 cargo_process("build -h").run();
298 cargo_process("help help").run();
6950bbb0 299}
8dad57e8 300
0e0d9688 301#[cargo_test]
9e41e383
AR
302fn cargo_help_external_subcommand() {
303 Package::new("cargo-fake-help", "1.0.0")
304 .file(
305 "src/main.rs",
306 r#"
307 fn main() {
308 if ::std::env::args().nth(2) == Some(String::from("--help")) {
309 println!("fancy help output");
310 }
311 }"#,
fecb7246
AC
312 )
313 .publish();
85984a87
DW
314 cargo_process("install cargo-fake-help").run();
315 cargo_process("help fake-help")
316 .with_stdout("fancy help output\n")
317 .run();
9e41e383
AR
318}
319
0e0d9688 320#[cargo_test]
6950bbb0 321fn explain() {
85984a87
DW
322 cargo_process("--explain E0001")
323 .with_stdout_contains(
b0c181d9 324 "This error suggests that the expression arm corresponding to the noted pattern",
fecb7246
AC
325 )
326 .run();
6950bbb0 327}
a4104914 328
f7c91ba6
AR
329// Test that the output of `cargo -Z help` shows a different help screen with
330// all the `-Z` flags.
0e0d9688 331#[cargo_test]
a4104914 332fn z_flags_help() {
85984a87
DW
333 cargo_process("-Z help")
334 .with_stdout_contains(
9af095ad 335 " -Z unstable-options -- Allow the usage of unstable options such as --registry",
fecb7246
AC
336 )
337 .run();
a4104914 338}