1 //! Tests for profiles defined in config files.
2 
3 use cargo_test_support::paths::CargoPathExt;
4 use cargo_test_support::registry::Package;
5 use cargo_test_support::{basic_lib_manifest, paths, project};
6 
7 #[cargo_test]
named_profile_gated()8 fn named_profile_gated() {
9     // Named profile in config requires enabling in Cargo.toml.
10     let p = project()
11         .file("src/lib.rs", "")
12         .file(
13             ".cargo/config",
14             r#"
15             [profile.foo]
16             inherits = 'dev'
17             opt-level = 1
18             "#,
19         )
20         .build();
21     p.cargo("build --profile foo -Zunstable-options")
22         .masquerade_as_nightly_cargo()
23         .with_stderr(
24             "\
25 [ERROR] config profile `foo` is not valid (defined in `[..]/foo/.cargo/config`)
26 
27 Caused by:
28   feature `named-profiles` is required
29 
30   consider adding `cargo-features = [\"named-profiles\"]` to the manifest
31 ",
32         )
33         .with_status(101)
34         .run();
35 }
36 
37 #[cargo_test]
profile_config_validate_warnings()38 fn profile_config_validate_warnings() {
39     let p = project()
40         .file("Cargo.toml", &basic_lib_manifest("foo"))
41         .file("src/lib.rs", "")
42         .file(
43             ".cargo/config",
44             r#"
45                 [profile.test]
46                 opt-level = 3
47 
48                 [profile.asdf]
49                 opt-level = 3
50 
51                 [profile.dev]
52                 bad-key = true
53 
54                 [profile.dev.build-override]
55                 bad-key-bo = true
56 
57                 [profile.dev.package.bar]
58                 bad-key-bar = true
59             "#,
60         )
61         .build();
62 
63     p.cargo("build")
64         .with_stderr_unordered(
65             "\
66 [WARNING] unused config key `profile.dev.bad-key` in `[..].cargo/config`
67 [WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[..].cargo/config`
68 [WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[..].cargo/config`
69 [COMPILING] foo [..]
70 [FINISHED] [..]
71 ",
72         )
73         .run();
74 }
75 
76 #[cargo_test]
profile_config_error_paths()77 fn profile_config_error_paths() {
78     // Errors in config show where the error is located.
79     let p = project()
80         .file("Cargo.toml", &basic_lib_manifest("foo"))
81         .file("src/lib.rs", "")
82         .file(
83             ".cargo/config",
84             r#"
85                 [profile.dev]
86                 opt-level = 3
87             "#,
88         )
89         .file(
90             paths::home().join(".cargo/config"),
91             r#"
92             [profile.dev]
93             rpath = "foo"
94             "#,
95         )
96         .build();
97 
98     p.cargo("build")
99         .with_status(101)
100         .with_stderr(
101             "\
102 [ERROR] error in [..]/foo/.cargo/config: could not load config key `profile.dev`
103 
104 Caused by:
105   error in [..]/home/.cargo/config: `profile.dev.rpath` expected true/false, but found a string
106 ",
107         )
108         .run();
109 }
110 
111 #[cargo_test]
profile_config_validate_errors()112 fn profile_config_validate_errors() {
113     let p = project()
114         .file("Cargo.toml", &basic_lib_manifest("foo"))
115         .file("src/lib.rs", "")
116         .file(
117             ".cargo/config",
118             r#"
119                 [profile.dev.package.foo]
120                 panic = "abort"
121             "#,
122         )
123         .build();
124 
125     p.cargo("build")
126         .with_status(101)
127         .with_stderr(
128             "\
129 [ERROR] config profile `dev` is not valid (defined in `[..]/foo/.cargo/config`)
130 
131 Caused by:
132   `panic` may not be specified in a `package` profile
133 ",
134         )
135         .run();
136 }
137 
138 #[cargo_test]
profile_config_syntax_errors()139 fn profile_config_syntax_errors() {
140     let p = project()
141         .file("Cargo.toml", &basic_lib_manifest("foo"))
142         .file("src/lib.rs", "")
143         .file(
144             ".cargo/config",
145             r#"
146                 [profile.dev]
147                 codegen-units = "foo"
148             "#,
149         )
150         .build();
151 
152     p.cargo("build")
153         .with_status(101)
154         .with_stderr(
155             "\
156 [ERROR] error in [..]/.cargo/config: could not load config key `profile.dev`
157 
158 Caused by:
159   error in [..]/foo/.cargo/config: `profile.dev.codegen-units` expected an integer, but found a string
160 ",
161         )
162         .run();
163 }
164 
165 #[cargo_test]
profile_config_override_spec_multiple()166 fn profile_config_override_spec_multiple() {
167     let p = project()
168         .file(
169             "Cargo.toml",
170             r#"
171             [package]
172             name = "foo"
173             version = "0.0.1"
174 
175             [dependencies]
176             bar = { path = "bar" }
177             "#,
178         )
179         .file(
180             ".cargo/config",
181             r#"
182                 [profile.dev.package.bar]
183                 opt-level = 3
184 
185                 [profile.dev.package."bar:0.5.0"]
186                 opt-level = 3
187             "#,
188         )
189         .file("src/lib.rs", "")
190         .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
191         .file("bar/src/lib.rs", "")
192         .build();
193 
194     // Unfortunately this doesn't tell you which file, hopefully it's not too
195     // much of a problem.
196     p.cargo("build -v")
197         .with_status(101)
198         .with_stderr(
199             "\
200 [ERROR] multiple package overrides in profile `dev` match package `bar v0.5.0 ([..])`
201 found package specs: bar, bar:0.5.0",
202         )
203         .run();
204 }
205 
206 #[cargo_test]
profile_config_all_options()207 fn profile_config_all_options() {
208     // Ensure all profile options are supported.
209     let p = project()
210         .file("src/main.rs", "fn main() {}")
211         .file(
212             ".cargo/config",
213             r#"
214             [profile.release]
215             opt-level = 1
216             debug = true
217             debug-assertions = true
218             overflow-checks = false
219             rpath = true
220             lto = true
221             codegen-units = 2
222             panic = "abort"
223             incremental = true
224             "#,
225         )
226         .build();
227 
228     p.cargo("build --release -v")
229         .env_remove("CARGO_INCREMENTAL")
230         .with_stderr(
231             "\
232 [COMPILING] foo [..]
233 [RUNNING] `rustc --crate-name foo [..] \
234             -C opt-level=1 \
235             -C panic=abort \
236             -C lto[..]\
237             -C codegen-units=2 \
238             -C debuginfo=2 \
239             -C debug-assertions=on \
240             -C overflow-checks=off [..]\
241             -C rpath [..]\
242             -C incremental=[..]
243 [FINISHED] release [optimized + debuginfo] [..]
244 ",
245         )
246         .run();
247 }
248 
249 #[cargo_test]
profile_config_override_precedence()250 fn profile_config_override_precedence() {
251     // Config values take precedence over manifest values.
252     let p = project()
253         .file(
254             "Cargo.toml",
255             r#"
256                 [package]
257                 name = "foo"
258                 version = "0.0.1"
259 
260                 [dependencies]
261                 bar = {path = "bar"}
262 
263                 [profile.dev]
264                 codegen-units = 2
265 
266                 [profile.dev.package.bar]
267                 opt-level = 3
268             "#,
269         )
270         .file("src/lib.rs", "")
271         .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
272         .file("bar/src/lib.rs", "")
273         .file(
274             ".cargo/config",
275             r#"
276                 [profile.dev.package.bar]
277                 opt-level = 2
278             "#,
279         )
280         .build();
281 
282     p.cargo("build -v")
283         .with_stderr(
284             "\
285 [COMPILING] bar [..]
286 [RUNNING] `rustc --crate-name bar [..] -C opt-level=2[..]-C codegen-units=2 [..]
287 [COMPILING] foo [..]
288 [RUNNING] `rustc --crate-name foo [..]-C codegen-units=2 [..]
289 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
290         )
291         .run();
292 }
293 
294 #[cargo_test]
profile_config_no_warn_unknown_override()295 fn profile_config_no_warn_unknown_override() {
296     let p = project()
297         .file("Cargo.toml", &basic_lib_manifest("foo"))
298         .file("src/lib.rs", "")
299         .file(
300             ".cargo/config",
301             r#"
302                 [profile.dev.package.bar]
303                 codegen-units = 4
304             "#,
305         )
306         .build();
307 
308     p.cargo("build")
309         .with_stderr_does_not_contain("[..]warning[..]")
310         .run();
311 }
312 
313 #[cargo_test]
profile_config_mixed_types()314 fn profile_config_mixed_types() {
315     let p = project()
316         .file("Cargo.toml", &basic_lib_manifest("foo"))
317         .file("src/lib.rs", "")
318         .file(
319             ".cargo/config",
320             r#"
321                 [profile.dev]
322                 opt-level = 3
323             "#,
324         )
325         .file(
326             paths::home().join(".cargo/config"),
327             r#"
328             [profile.dev]
329             opt-level = 's'
330             "#,
331         )
332         .build();
333 
334     p.cargo("build -v")
335         .with_stderr_contains("[..]-C opt-level=3 [..]")
336         .run();
337 }
338 
339 #[cargo_test]
named_config_profile()340 fn named_config_profile() {
341     // Exercises config named profies.
342     // foo -> middle -> bar -> dev
343     // middle exists in Cargo.toml, the others in .cargo/config
344     use super::config::ConfigBuilder;
345     use cargo::core::compiler::{CompileKind, CompileMode};
346     use cargo::core::profiles::{Profiles, UnitFor};
347     use cargo::core::{PackageId, Workspace};
348     use cargo::util::interning::InternedString;
349     use std::fs;
350     paths::root().join(".cargo").mkdir_p();
351     fs::write(
352         paths::root().join(".cargo/config"),
353         r#"
354             [profile.foo]
355             inherits = "middle"
356             codegen-units = 2
357             [profile.foo.build-override]
358             codegen-units = 6
359             [profile.foo.package.dep]
360             codegen-units = 7
361 
362             [profile.middle]
363             inherits = "bar"
364             codegen-units = 3
365 
366             [profile.bar]
367             inherits = "dev"
368             codegen-units = 4
369             debug = 1
370         "#,
371     )
372     .unwrap();
373     fs::write(
374         paths::root().join("Cargo.toml"),
375         r#"
376             cargo-features = ['named-profiles']
377 
378             [workspace]
379 
380             [profile.middle]
381             inherits = "bar"
382             codegen-units = 1
383             opt-level = 1
384             [profile.middle.package.dep]
385             overflow-checks = false
386 
387             [profile.foo.build-override]
388             codegen-units = 5
389             debug-assertions = false
390             [profile.foo.package.dep]
391             codegen-units = 8
392         "#,
393     )
394     .unwrap();
395     let config = ConfigBuilder::new().nightly_features_allowed(true).build();
396     let profile_name = InternedString::new("foo");
397     let ws = Workspace::new(&paths::root().join("Cargo.toml"), &config).unwrap();
398     let profiles = Profiles::new(&ws, profile_name).unwrap();
399 
400     let crates_io = cargo::core::source::SourceId::crates_io(&config).unwrap();
401     let a_pkg = PackageId::new("a", "0.1.0", crates_io).unwrap();
402     let dep_pkg = PackageId::new("dep", "0.1.0", crates_io).unwrap();
403 
404     // normal package
405     let mode = CompileMode::Build;
406     let kind = CompileKind::Host;
407     let p = profiles.get_profile(a_pkg, true, true, UnitFor::new_normal(), mode, kind);
408     assert_eq!(p.name, "foo");
409     assert_eq!(p.codegen_units, Some(2)); // "foo" from config
410     assert_eq!(p.opt_level, "1"); // "middle" from manifest
411     assert_eq!(p.debuginfo, Some(1)); // "bar" from config
412     assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override)
413     assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override)
414 
415     // build-override
416     let bo = profiles.get_profile(a_pkg, true, true, UnitFor::new_host(false), mode, kind);
417     assert_eq!(bo.name, "foo");
418     assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config
419     assert_eq!(bo.opt_level, "0"); // default to zero
420     assert_eq!(bo.debuginfo, Some(1)); // SAME as normal
421     assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest
422     assert_eq!(bo.overflow_checks, true); // SAME as normal
423 
424     // package overrides
425     let po = profiles.get_profile(dep_pkg, false, true, UnitFor::new_normal(), mode, kind);
426     assert_eq!(po.name, "foo");
427     assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config
428     assert_eq!(po.opt_level, "1"); // SAME as normal
429     assert_eq!(po.debuginfo, Some(1)); // SAME as normal
430     assert_eq!(po.debug_assertions, true); // SAME as normal
431     assert_eq!(po.overflow_checks, false); // "middle" package override from manifest
432 }
433 
434 #[cargo_test]
named_env_profile()435 fn named_env_profile() {
436     // Environment variables used to define a named profile.
437     let p = project()
438         .file(
439             "Cargo.toml",
440             r#"
441             cargo-features = ["named-profiles"]
442             [package]
443             name = "foo"
444             version = "0.1.0"
445             "#,
446         )
447         .file("src/lib.rs", "")
448         .build();
449 
450     p.cargo("build -v -Zunstable-options --profile=other")
451         .masquerade_as_nightly_cargo()
452         .env("CARGO_PROFILE_OTHER_CODEGEN_UNITS", "1")
453         .env("CARGO_PROFILE_OTHER_INHERITS", "dev")
454         .with_stderr_contains("[..]-C codegen-units=1 [..]")
455         .run();
456 }
457 
458 #[cargo_test]
test_with_dev_profile()459 fn test_with_dev_profile() {
460     // `cargo test` uses "dev" profile for dependencies.
461     Package::new("somedep", "1.0.0").publish();
462     let p = project()
463         .file(
464             "Cargo.toml",
465             r#"
466             [package]
467             name = "foo"
468             version = "0.1.0"
469 
470             [dependencies]
471             somedep = "1.0"
472             "#,
473         )
474         .file("src/lib.rs", "")
475         .build();
476     p.cargo("test --lib --no-run -v")
477         .env("CARGO_PROFILE_DEV_DEBUG", "0")
478         .with_stderr(
479             "\
480 [UPDATING] [..]
481 [DOWNLOADING] [..]
482 [DOWNLOADED] [..]
483 [COMPILING] somedep v1.0.0
484 [RUNNING] `rustc --crate-name somedep [..]-C debuginfo=0[..]
485 [COMPILING] foo v0.1.0 [..]
486 [RUNNING] `rustc --crate-name foo [..]-C debuginfo=2[..]
487 [FINISHED] [..]
488 ",
489         )
490         .run();
491 }
492