]> git.proxmox.com Git - cargo.git/blob - tests/testsuite/cargo_command.rs
Auto merge of #7333 - ehuss:allow-dev-dep-path, r=alexcrichton
[cargo.git] / tests / testsuite / cargo_command.rs
1 use std::env;
2 use std::fs::{self, File};
3 use std::io::prelude::*;
4 use std::path::{Path, PathBuf};
5 use std::str;
6
7 use cargo;
8 use cargo_test_support::cargo_process;
9 use cargo_test_support::paths::{self, CargoPathExt};
10 use cargo_test_support::registry::Package;
11 use cargo_test_support::{basic_bin_manifest, basic_manifest, cargo_exe, project, Project};
12
13 #[cfg_attr(windows, allow(dead_code))]
14 enum FakeKind<'a> {
15 Executable,
16 Symlink { target: &'a Path },
17 }
18
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.
22 fn fake_file(proj: Project, dir: &Path, name: &str, kind: &FakeKind<'_>) -> Project {
23 let path = proj
24 .root()
25 .join(dir)
26 .join(&format!("{}{}", name, env::consts::EXE_SUFFIX));
27 path.parent().unwrap().mkdir_p();
28 match *kind {
29 FakeKind::Executable => {
30 File::create(&path).unwrap();
31 make_executable(&path);
32 }
33 FakeKind::Symlink { target } => {
34 make_symlink(&path, target);
35 }
36 }
37 return proj;
38
39 #[cfg(unix)]
40 fn make_executable(p: &Path) {
41 use std::os::unix::prelude::*;
42
43 let mut perms = fs::metadata(p).unwrap().permissions();
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) {}
50 #[cfg(unix)]
51 fn make_symlink(p: &Path, t: &Path) {
52 ::std::os::unix::fs::symlink(t, p).expect("Failed to create symlink");
53 }
54 #[cfg(windows)]
55 fn make_symlink(_: &Path, _: &Path) {
56 panic!("Not supported")
57 }
58 }
59
60 fn path() -> Vec<PathBuf> {
61 env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect()
62 }
63
64 #[cargo_test]
65 fn list_commands_with_descriptions() {
66 let p = project().build();
67 p.cargo("--list")
68 .with_stdout_contains(
69 " build Compile a local package and all of its dependencies",
70 )
71 // Assert that `read-manifest` prints the right one-line description followed by another
72 // command, indented.
73 .with_stdout_contains(
74 " read-manifest Print a JSON representation of a Cargo.toml manifest.",
75 )
76 .run();
77 }
78
79 #[cargo_test]
80 fn list_command_looks_at_path() {
81 let proj = project().build();
82 let proj = fake_file(
83 proj,
84 Path::new("path-test"),
85 "cargo-1",
86 &FakeKind::Executable,
87 );
88
89 let mut path = path();
90 path.push(proj.root().join("path-test"));
91 let path = env::join_paths(path.iter()).unwrap();
92 let output = cargo_process("-v --list")
93 .env("PATH", &path)
94 .exec_with_output()
95 .unwrap();
96 let output = str::from_utf8(&output.stdout).unwrap();
97 assert!(
98 output.contains("\n 1 "),
99 "missing 1: {}",
100 output
101 );
102 }
103
104 // Windows and symlinks don't currently mix well.
105 #[cfg(unix)]
106 #[cargo_test]
107 fn list_command_resolves_symlinks() {
108 let proj = project().build();
109 let proj = fake_file(
110 proj,
111 Path::new("path-test"),
112 "cargo-2",
113 &FakeKind::Symlink {
114 target: &cargo_exe(),
115 },
116 );
117
118 let mut path = path();
119 path.push(proj.root().join("path-test"));
120 let path = env::join_paths(path.iter()).unwrap();
121 let output = cargo_process("-v --list")
122 .env("PATH", &path)
123 .exec_with_output()
124 .unwrap();
125 let output = str::from_utf8(&output.stdout).unwrap();
126 assert!(
127 output.contains("\n 2 "),
128 "missing 2: {}",
129 output
130 );
131 }
132
133 #[cargo_test]
134 fn find_closest_biuld_to_build() {
135 cargo_process("biuld")
136 .with_status(101)
137 .with_stderr_contains(
138 "\
139 error: no such subcommand: `biuld`
140
141 <tab>Did you mean `build`?
142 ",
143 )
144 .run();
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 "#,
156 )
157 .publish();
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",
166 )
167 .with_stdout_contains(" biuld\n")
168 .run();
169 }
170
171 // If a subcommand is more than an edit distance of 3 away, we don't make a suggestion.
172 #[cargo_test]
173 fn find_closest_dont_correct_nonsense() {
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(
178 "[ERROR] no such subcommand: \
179 `there-is-no-way-that-there-is-a-command-close-to-this`
180 ",
181 )
182 .run();
183 }
184
185 #[cargo_test]
186 fn displays_subcommand_on_error() {
187 cargo_process("invalid-command")
188 .with_status(101)
189 .with_stderr("[ERROR] no such subcommand: `invalid-command`\n")
190 .run();
191 }
192
193 #[cargo_test]
194 fn override_cargo_home() {
195 let root = paths::root();
196 let my_home = root.join("my_home");
197 fs::create_dir(&my_home).unwrap();
198 File::create(&my_home.join("config"))
199 .unwrap()
200 .write_all(
201 br#"
202 [cargo-new]
203 name = "foo"
204 email = "bar"
205 git = false
206 "#,
207 )
208 .unwrap();
209
210 cargo_process("new foo")
211 .env("USER", "foo")
212 .env("CARGO_HOME", &my_home)
213 .run();
214
215 let toml = paths::root().join("foo/Cargo.toml");
216 let mut contents = String::new();
217 File::open(&toml)
218 .unwrap()
219 .read_to_string(&mut contents)
220 .unwrap();
221 assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
222 }
223
224 #[cargo_test]
225 fn cargo_subcommand_env() {
226 let src = format!(
227 r#"
228 use std::env;
229
230 fn main() {{
231 println!("{{}}", env::var("{}").unwrap());
232 }}
233 "#,
234 cargo::CARGO_ENV
235 );
236
237 let p = project()
238 .at("cargo-envtest")
239 .file("Cargo.toml", &basic_bin_manifest("cargo-envtest"))
240 .file("src/main.rs", &src)
241 .build();
242
243 let target_dir = p.target_debug_dir();
244
245 p.cargo("build").run();
246 assert!(p.bin("cargo-envtest").is_file());
247
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
253 cargo_process("envtest")
254 .env("PATH", &path)
255 .with_stdout(cargo.to_str().unwrap())
256 .run();
257 }
258
259 #[cargo_test]
260 fn cargo_subcommand_args() {
261 let p = project()
262 .at("cargo-foo")
263 .file("Cargo.toml", &basic_manifest("cargo-foo", "0.0.1"))
264 .file(
265 "src/main.rs",
266 r#"
267 fn main() {
268 let args: Vec<_> = ::std::env::args().collect();
269 println!("{:?}", args);
270 }
271 "#,
272 )
273 .build();
274
275 p.cargo("build").run();
276 let cargo_foo_bin = p.bin("cargo-foo");
277 assert!(cargo_foo_bin.is_file());
278
279 let mut path = path();
280 path.push(p.target_debug_dir());
281 let path = env::join_paths(path.iter()).unwrap();
282
283 cargo_process("foo bar -v --help")
284 .env("PATH", &path)
285 .with_stdout(
286 r#"["[CWD]/cargo-foo/target/debug/cargo-foo[EXE]", "foo", "bar", "-v", "--help"]"#,
287 )
288 .run();
289 }
290
291 #[cargo_test]
292 fn cargo_help() {
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();
299 }
300
301 #[cargo_test]
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 }"#,
312 )
313 .publish();
314 cargo_process("install cargo-fake-help").run();
315 cargo_process("help fake-help")
316 .with_stdout("fancy help output\n")
317 .run();
318 }
319
320 #[cargo_test]
321 fn explain() {
322 cargo_process("--explain E0001")
323 .with_stdout_contains(
324 "This error suggests that the expression arm corresponding to the noted pattern",
325 )
326 .run();
327 }
328
329 // Test that the output of `cargo -Z help` shows a different help screen with
330 // all the `-Z` flags.
331 #[cargo_test]
332 fn z_flags_help() {
333 cargo_process("-Z help")
334 .with_stdout_contains(
335 " -Z unstable-options -- Allow the usage of unstable options such as --registry",
336 )
337 .run();
338 }