1 //! Tests for the `cargo config` command.
2 
3 use super::config::write_config_at;
4 use cargo_test_support::paths;
5 use std::fs;
6 use std::path::PathBuf;
7 
cargo_process(s: &str) -> cargo_test_support::Execs8 fn cargo_process(s: &str) -> cargo_test_support::Execs {
9     let mut p = cargo_test_support::cargo_process(s);
10     // Clear out some of the environment added by the default cargo_process so
11     // the tests don't need to deal with it.
12     p.env_remove("CARGO_PROFILE_DEV_SPLIT_DEBUGINFO")
13         .env_remove("CARGO_PROFILE_TEST_SPLIT_DEBUGINFO")
14         .env_remove("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO")
15         .env_remove("CARGO_PROFILE_BENCH_SPLIT_DEBUGINFO")
16         .env_remove("CARGO_INCREMENTAL");
17     p
18 }
19 
20 #[cargo_test]
gated()21 fn gated() {
22     cargo_process("config get")
23         .masquerade_as_nightly_cargo()
24         .with_status(101)
25         .with_stderr("\
26 error: the `cargo config` command is unstable, pass `-Z unstable-options` to enable it
27 See https://github.com/rust-lang/cargo/issues/9301 for more information about the `cargo config` command.
28 ")
29         .run();
30 }
31 
common_setup() -> PathBuf32 fn common_setup() -> PathBuf {
33     write_config_at(
34         paths::home().join(".cargo/config.toml"),
35         "
36         [alias]
37         foo = \"abc --xyz\"
38         [build]
39         jobs = 99
40         rustflags = [\"--flag-global\"]
41         [profile.dev]
42         opt-level = 3
43         [profile.dev.package.foo]
44         opt-level = 1
45         [target.'cfg(target_os = \"linux\")']
46         runner = \"runme\"
47 
48         # How unknown keys are handled.
49         [extra-table]
50         somekey = \"somevalue\"
51         ",
52     );
53     let sub_folder = paths::root().join("foo/.cargo");
54     write_config_at(
55         sub_folder.join("config.toml"),
56         "
57         [alias]
58         sub-example = [\"sub\", \"example\"]
59         [build]
60         rustflags = [\"--flag-directory\"]
61         ",
62     );
63     sub_folder
64 }
65 
66 #[cargo_test]
get_toml()67 fn get_toml() {
68     // Notes:
69     // - The "extra-table" is shown without a warning. I'm not sure how that
70     //   should be handled, since displaying warnings could cause problems
71     //   with ingesting the output.
72     // - Environment variables aren't loaded. :(
73     let sub_folder = common_setup();
74     cargo_process("config get -Zunstable-options")
75         .cwd(&sub_folder.parent().unwrap())
76         .masquerade_as_nightly_cargo()
77         .env("CARGO_ALIAS_BAR", "cat dog")
78         .env("CARGO_BUILD_JOBS", "100")
79         // The weird forward slash in the linux line is due to testsuite normalization.
80         .with_stdout(
81             "\
82 alias.foo = \"abc --xyz\"
83 alias.sub-example = [\"sub\", \"example\"]
84 build.jobs = 99
85 build.rustflags = [\"--flag-directory\", \"--flag-global\"]
86 extra-table.somekey = \"somevalue\"
87 profile.dev.opt-level = 3
88 profile.dev.package.foo.opt-level = 1
89 target.\"cfg(target_os = \\\"linux\\\")\".runner = \"runme\"
90 # The following environment variables may affect the loaded values.
91 # CARGO_ALIAS_BAR=[..]cat dog[..]
92 # CARGO_BUILD_JOBS=100
93 # CARGO_HOME=[ROOT]/home/.cargo
94 ",
95         )
96         .with_stderr("")
97         .run();
98 
99     // Env keys work if they are specific.
100     cargo_process("config get build.jobs -Zunstable-options")
101         .cwd(&sub_folder.parent().unwrap())
102         .masquerade_as_nightly_cargo()
103         .env("CARGO_BUILD_JOBS", "100")
104         .with_stdout("build.jobs = 100")
105         .with_stderr("")
106         .run();
107 
108     // Array value.
109     cargo_process("config get build.rustflags -Zunstable-options")
110         .cwd(&sub_folder.parent().unwrap())
111         .masquerade_as_nightly_cargo()
112         .with_stdout("build.rustflags = [\"--flag-directory\", \"--flag-global\"]")
113         .with_stderr("")
114         .run();
115 
116     // Sub-table
117     cargo_process("config get profile -Zunstable-options")
118         .cwd(&sub_folder.parent().unwrap())
119         .masquerade_as_nightly_cargo()
120         .with_stdout(
121             "\
122 profile.dev.opt-level = 3
123 profile.dev.package.foo.opt-level = 1
124 ",
125         )
126         .with_stderr("")
127         .run();
128 
129     // Specific profile entry.
130     cargo_process("config get profile.dev.opt-level -Zunstable-options")
131         .cwd(&sub_folder.parent().unwrap())
132         .masquerade_as_nightly_cargo()
133         .with_stdout("profile.dev.opt-level = 3")
134         .with_stderr("")
135         .run();
136 
137     // A key that isn't set.
138     cargo_process("config get build.rustc -Zunstable-options")
139         .cwd(&sub_folder.parent().unwrap())
140         .masquerade_as_nightly_cargo()
141         .with_status(101)
142         .with_stdout("")
143         .with_stderr("error: config value `build.rustc` is not set")
144         .run();
145 
146     // A key that is not part of Cargo's config schema.
147     cargo_process("config get not.set -Zunstable-options")
148         .cwd(&sub_folder.parent().unwrap())
149         .masquerade_as_nightly_cargo()
150         .with_status(101)
151         .with_stdout("")
152         .with_stderr("error: config value `not.set` is not set")
153         .run();
154 }
155 
156 #[cargo_test]
get_json()157 fn get_json() {
158     // Notes:
159     // - This does not show env vars at all. :(
160     let all_json = r#"
161             {
162               "alias": {
163                 "foo": "abc --xyz",
164                 "sub-example": [
165                   "sub",
166                   "example"
167                 ]
168               },
169               "build": {
170                 "jobs": 99,
171                 "rustflags": [
172                   "--flag-directory",
173                   "--flag-global"
174                 ]
175               },
176               "extra-table": {
177                 "somekey": "somevalue"
178               },
179               "profile": {
180                 "dev": {
181                   "opt-level": 3,
182                   "package": {
183                     "foo": {
184                       "opt-level": 1
185                     }
186                   }
187                 }
188               },
189               "target": {
190                 "cfg(target_os = \"linux\")": {
191                   "runner": "runme"
192                 }
193               }
194             }
195             "#;
196     let sub_folder = common_setup();
197     cargo_process("config get --format=json -Zunstable-options")
198         .cwd(&sub_folder.parent().unwrap())
199         .masquerade_as_nightly_cargo()
200         .env("CARGO_ALIAS_BAR", "cat dog")
201         .env("CARGO_BUILD_JOBS", "100")
202         .with_json(all_json)
203         .with_stderr(
204             "\
205 note: The following environment variables may affect the loaded values.
206 CARGO_ALIAS_BAR=[..]cat dog[..]
207 CARGO_BUILD_JOBS=100
208 CARGO_HOME=[ROOT]/home/.cargo
209 ",
210         )
211         .run();
212 
213     // json-value is the same for the entire root table
214     cargo_process("config get --format=json-value -Zunstable-options")
215         .cwd(&sub_folder.parent().unwrap())
216         .masquerade_as_nightly_cargo()
217         .with_json(all_json)
218         .with_stderr(
219             "\
220 note: The following environment variables may affect the loaded values.
221 CARGO_HOME=[ROOT]/home/.cargo
222 ",
223         )
224         .run();
225 
226     cargo_process("config get --format=json build.jobs -Zunstable-options")
227         .cwd(&sub_folder.parent().unwrap())
228         .masquerade_as_nightly_cargo()
229         .with_json(
230             r#"
231             {"build": {"jobs": 99}}
232             "#,
233         )
234         .with_stderr("")
235         .run();
236 
237     cargo_process("config get --format=json-value build.jobs -Zunstable-options")
238         .cwd(&sub_folder.parent().unwrap())
239         .masquerade_as_nightly_cargo()
240         .with_stdout("99")
241         .with_stderr("")
242         .run();
243 }
244 
245 #[cargo_test]
show_origin_toml()246 fn show_origin_toml() {
247     let sub_folder = common_setup();
248     cargo_process("config get --show-origin -Zunstable-options")
249         .cwd(&sub_folder.parent().unwrap())
250         .masquerade_as_nightly_cargo()
251         .with_stdout(
252             "\
253 alias.foo = \"abc --xyz\" # [ROOT]/home/.cargo/config.toml
254 alias.sub-example = [
255     \"sub\", # [ROOT]/foo/.cargo/config.toml
256     \"example\", # [ROOT]/foo/.cargo/config.toml
257 ]
258 build.jobs = 99 # [ROOT]/home/.cargo/config.toml
259 build.rustflags = [
260     \"--flag-directory\", # [ROOT]/foo/.cargo/config.toml
261     \"--flag-global\", # [ROOT]/home/.cargo/config.toml
262 ]
263 extra-table.somekey = \"somevalue\" # [ROOT]/home/.cargo/config.toml
264 profile.dev.opt-level = 3 # [ROOT]/home/.cargo/config.toml
265 profile.dev.package.foo.opt-level = 1 # [ROOT]/home/.cargo/config.toml
266 target.\"cfg(target_os = \\\"linux\\\")\".runner = \"runme\" # [ROOT]/home/.cargo/config.toml
267 # The following environment variables may affect the loaded values.
268 # CARGO_HOME=[ROOT]/home/.cargo
269 ",
270         )
271         .with_stderr("")
272         .run();
273 
274     cargo_process("config get --show-origin build.rustflags -Zunstable-options")
275         .cwd(&sub_folder.parent().unwrap())
276         .masquerade_as_nightly_cargo()
277         .env("CARGO_BUILD_RUSTFLAGS", "env1 env2")
278         .with_stdout(
279             "\
280 build.rustflags = [
281     \"--flag-directory\", # [ROOT]/foo/.cargo/config.toml
282     \"--flag-global\", # [ROOT]/home/.cargo/config.toml
283     \"env1\", # environment variable `CARGO_BUILD_RUSTFLAGS`
284     \"env2\", # environment variable `CARGO_BUILD_RUSTFLAGS`
285 ]
286 ",
287         )
288         .with_stderr("")
289         .run();
290 }
291 
292 #[cargo_test]
show_origin_toml_cli()293 fn show_origin_toml_cli() {
294     let sub_folder = common_setup();
295     cargo_process("config get --show-origin build.jobs -Zunstable-options --config build.jobs=123")
296         .cwd(&sub_folder.parent().unwrap())
297         .masquerade_as_nightly_cargo()
298         .env("CARGO_BUILD_JOBS", "1")
299         .with_stdout("build.jobs = 123 # --config cli option")
300         .with_stderr("")
301         .run();
302 
303     cargo_process("config get --show-origin build.rustflags -Zunstable-options --config")
304         .arg("build.rustflags=[\"cli1\",\"cli2\"]")
305         .cwd(&sub_folder.parent().unwrap())
306         .masquerade_as_nightly_cargo()
307         .env("CARGO_BUILD_RUSTFLAGS", "env1 env2")
308         .with_stdout(
309             "\
310 build.rustflags = [
311     \"--flag-directory\", # [ROOT]/foo/.cargo/config.toml
312     \"--flag-global\", # [ROOT]/home/.cargo/config.toml
313     \"cli1\", # --config cli option
314     \"cli2\", # --config cli option
315     \"env1\", # environment variable `CARGO_BUILD_RUSTFLAGS`
316     \"env2\", # environment variable `CARGO_BUILD_RUSTFLAGS`
317 ]
318 ",
319         )
320         .with_stderr("")
321         .run();
322 }
323 
324 #[cargo_test]
show_origin_json()325 fn show_origin_json() {
326     let sub_folder = common_setup();
327     cargo_process("config get --show-origin --format=json -Zunstable-options")
328         .cwd(&sub_folder.parent().unwrap())
329         .masquerade_as_nightly_cargo()
330         .with_status(101)
331         .with_stderr("error: the `json` format does not support --show-origin, try the `toml` format instead")
332         .run();
333 }
334 
335 #[cargo_test]
unmerged_toml()336 fn unmerged_toml() {
337     let sub_folder = common_setup();
338     cargo_process("config get --merged=no -Zunstable-options")
339         .cwd(&sub_folder.parent().unwrap())
340         .masquerade_as_nightly_cargo()
341         .env("CARGO_ALIAS_BAR", "cat dog")
342         .env("CARGO_BUILD_JOBS", "100")
343         .with_stdout(
344             "\
345 # Environment variables
346 # CARGO=[..]
347 # CARGO_ALIAS_BAR=[..]cat dog[..]
348 # CARGO_BUILD_JOBS=100
349 # CARGO_HOME=[ROOT]/home/.cargo
350 
351 # [ROOT]/foo/.cargo/config.toml
352 alias.sub-example = [\"sub\", \"example\"]
353 build.rustflags = [\"--flag-directory\"]
354 
355 # [ROOT]/home/.cargo/config.toml
356 alias.foo = \"abc --xyz\"
357 build.jobs = 99
358 build.rustflags = [\"--flag-global\"]
359 extra-table.somekey = \"somevalue\"
360 profile.dev.opt-level = 3
361 profile.dev.package.foo.opt-level = 1
362 target.\"cfg(target_os = \\\"linux\\\")\".runner = \"runme\"
363 
364 ",
365         )
366         .with_stderr("")
367         .run();
368 
369     cargo_process("config get --merged=no build.rustflags -Zunstable-options")
370         .cwd(&sub_folder.parent().unwrap())
371         .masquerade_as_nightly_cargo()
372         .env("CARGO_BUILD_RUSTFLAGS", "env1 env2")
373         .with_stdout(
374             "\
375 # Environment variables
376 # CARGO_BUILD_RUSTFLAGS=[..]env1 env2[..]
377 
378 # [ROOT]/foo/.cargo/config.toml
379 build.rustflags = [\"--flag-directory\"]
380 
381 # [ROOT]/home/.cargo/config.toml
382 build.rustflags = [\"--flag-global\"]
383 
384 ",
385         )
386         .with_stderr("")
387         .run();
388 
389     cargo_process("config get --merged=no does.not.exist -Zunstable-options")
390         .cwd(&sub_folder.parent().unwrap())
391         .masquerade_as_nightly_cargo()
392         .with_stderr("")
393         .with_stderr("")
394         .run();
395 
396     cargo_process("config get --merged=no build.rustflags.extra -Zunstable-options")
397         .cwd(&sub_folder.parent().unwrap())
398         .masquerade_as_nightly_cargo()
399         .with_status(101)
400         .with_stderr(
401             "error: expected table for configuration key `build.rustflags`, \
402              but found array in [ROOT]/foo/.cargo/config.toml",
403         )
404         .run();
405 }
406 
407 #[cargo_test]
unmerged_toml_cli()408 fn unmerged_toml_cli() {
409     let sub_folder = common_setup();
410     cargo_process("config get --merged=no build.rustflags -Zunstable-options --config")
411         .arg("build.rustflags=[\"cli1\",\"cli2\"]")
412         .cwd(&sub_folder.parent().unwrap())
413         .masquerade_as_nightly_cargo()
414         .env("CARGO_BUILD_RUSTFLAGS", "env1 env2")
415         .with_stdout(
416             "\
417 # --config cli option
418 build.rustflags = [\"cli1\", \"cli2\"]
419 
420 # Environment variables
421 # CARGO_BUILD_RUSTFLAGS=[..]env1 env2[..]
422 
423 # [ROOT]/foo/.cargo/config.toml
424 build.rustflags = [\"--flag-directory\"]
425 
426 # [ROOT]/home/.cargo/config.toml
427 build.rustflags = [\"--flag-global\"]
428 
429 ",
430         )
431         .with_stderr("")
432         .run();
433 }
434 
435 #[cargo_test]
unmerged_json()436 fn unmerged_json() {
437     let sub_folder = common_setup();
438     cargo_process("config get --merged=no --format=json -Zunstable-options")
439         .cwd(&sub_folder.parent().unwrap())
440         .masquerade_as_nightly_cargo()
441         .with_status(101)
442         .with_stderr(
443             "error: the `json` format does not support --merged=no, try the `toml` format instead",
444         )
445         .run();
446 }
447 
448 #[cargo_test]
includes()449 fn includes() {
450     let sub_folder = common_setup();
451     fs::write(
452         sub_folder.join("config.toml"),
453         "
454         include = 'other.toml'
455         [build]
456         rustflags = [\"--flag-directory\"]
457         ",
458     )
459     .unwrap();
460     fs::write(
461         sub_folder.join("other.toml"),
462         "
463         [build]
464         rustflags = [\"--flag-other\"]
465         ",
466     )
467     .unwrap();
468 
469     cargo_process("config get build.rustflags -Zunstable-options -Zconfig-include")
470         .cwd(&sub_folder.parent().unwrap())
471         .masquerade_as_nightly_cargo()
472         .with_stdout(r#"build.rustflags = ["--flag-other", "--flag-directory", "--flag-global"]"#)
473         .with_stderr("")
474         .run();
475 
476     cargo_process(
477         "config get build.rustflags --show-origin=yes -Zunstable-options -Zconfig-include",
478     )
479     .cwd(&sub_folder.parent().unwrap())
480     .masquerade_as_nightly_cargo()
481     .with_stdout(
482         "\
483 build.rustflags = [
484     \"--flag-other\", # [ROOT]/foo/.cargo/other.toml
485     \"--flag-directory\", # [ROOT]/foo/.cargo/config.toml
486     \"--flag-global\", # [ROOT]/home/.cargo/config.toml
487 ]
488 ",
489     )
490     .with_stderr("")
491     .run();
492 
493     cargo_process("config get --merged=no -Zunstable-options -Zconfig-include")
494         .cwd(&sub_folder.parent().unwrap())
495         .masquerade_as_nightly_cargo()
496         .with_stdout(
497             "\
498 # Environment variables
499 # CARGO=[..]
500 # CARGO_HOME=[ROOT]/home/.cargo
501 
502 # [ROOT]/foo/.cargo/other.toml
503 build.rustflags = [\"--flag-other\"]
504 
505 # [ROOT]/foo/.cargo/config.toml
506 build.rustflags = [\"--flag-directory\"]
507 include = \"other.toml\"
508 
509 # [ROOT]/home/.cargo/config.toml
510 alias.foo = \"abc --xyz\"
511 build.jobs = 99
512 build.rustflags = [\"--flag-global\"]
513 extra-table.somekey = \"somevalue\"
514 profile.dev.opt-level = 3
515 profile.dev.package.foo.opt-level = 1
516 target.\"cfg(target_os = \\\"linux\\\")\".runner = \"runme\"
517 
518 ",
519         )
520         .with_stderr("")
521         .run();
522 }
523