]>
Commit | Line | Data |
---|---|---|
ee5e24ff | 1 | use std::env; |
a6dad622 AC |
2 | use std::fs::{self, File}; |
3 | use std::io::prelude::*; | |
4 | use std::path::{Path, PathBuf}; | |
8cce8996 | 5 | use std::str; |
8cce8996 | 6 | |
04ddd4d0 DW |
7 | use crate::support::cargo_process; |
8 | use crate::support::paths::{self, CargoPathExt}; | |
9 | use crate::support::registry::Package; | |
10 | use crate::support::{basic_bin_manifest, basic_manifest, cargo_exe, project, Project}; | |
fecb7246 | 11 | use cargo; |
a3f6a404 | 12 | |
1e682848 | 13 | #[cfg_attr(windows, allow(dead_code))] |
974d5834 JB |
14 | enum 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 | 22 | fn 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 | 60 | fn 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 |
65 | fn 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 | 80 | fn 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 | 107 | fn 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 | 134 | fn find_closest_biuld_to_build() { |
85984a87 DW |
135 | cargo_process("biuld") |
136 | .with_status(101) | |
137 | .with_stderr_contains( | |
1e682848 | 138 | "\ |
a1735c7a AK |
139 | error: 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 | 173 | fn 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 | 186 | fn 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 | 194 | fn 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 | 225 | fn 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 | 260 | fn 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 | 292 | fn 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 |
302 | fn 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 | 321 | fn 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 | 332 | fn 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 | } |