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