cargo/tests/testsuite/config_cli.rs
Alex Crichton 3a18c89a55 Migrate from the failure crate to anyhow
The `anyhow` crate interoperates with the `std::error::Error` trait
rather than a custom `Fail` trait, and this is the general trend of
error handling in Rust as well.

Note that this is mostly mechanical (sed) and intended to get the test
suite passing. As usual there's still more idiomatic cleanup that can
happen, but that's left to later commits.
2020-01-07 16:50:09 -08:00

341 lines
9.6 KiB
Rust

//! Tests for the --config CLI option.
use super::config::{assert_error, assert_match, read_output, write_config, ConfigBuilder};
use cargo::util::config::Definition;
use cargo_test_support::{paths, project};
use std::fs;
#[cargo_test]
fn config_gated() {
// Requires -Zunstable-options
let p = project().file("src/lib.rs", "").build();
p.cargo("build --config --config build.jobs=1")
.with_status(101)
.with_stderr(
"\
[ERROR] the `--config` flag is unstable, [..]
See [..]
See [..]
",
)
.run();
}
#[cargo_test]
fn basic() {
// Simple example.
let config = ConfigBuilder::new().config_arg("foo='bar'").build();
assert_eq!(config.get::<String>("foo").unwrap(), "bar");
}
#[cargo_test]
fn cli_priority() {
// Command line takes priority over files and env vars.
write_config(
"
demo_list = ['a']
[build]
jobs = 3
rustc = 'file'
[term]
verbose = false
",
);
let config = ConfigBuilder::new().build();
assert_eq!(config.get::<i32>("build.jobs").unwrap(), 3);
assert_eq!(config.get::<String>("build.rustc").unwrap(), "file");
assert_eq!(config.get::<bool>("term.verbose").unwrap(), false);
let config = ConfigBuilder::new()
.env("CARGO_BUILD_JOBS", "2")
.env("CARGO_BUILD_RUSTC", "env")
.env("CARGO_TERM_VERBOSE", "false")
.config_arg("build.jobs=1")
.config_arg("build.rustc='cli'")
.config_arg("term.verbose=true")
.build();
assert_eq!(config.get::<i32>("build.jobs").unwrap(), 1);
assert_eq!(config.get::<String>("build.rustc").unwrap(), "cli");
assert_eq!(config.get::<bool>("term.verbose").unwrap(), true);
}
#[cargo_test]
fn merges_array() {
// Array entries are appended.
write_config(
"
[build]
rustflags = ['--file']
",
);
let config = ConfigBuilder::new()
.config_arg("build.rustflags = ['--cli']")
.build();
assert_eq!(
config.get::<Vec<String>>("build.rustflags").unwrap(),
["--file", "--cli"]
);
// With normal env.
let config = ConfigBuilder::new()
.env("CARGO_BUILD_RUSTFLAGS", "--env1 --env2")
.config_arg("build.rustflags = ['--cli']")
.build();
// The order of cli/env is a little questionable here, but would require
// much more complex merging logic.
assert_eq!(
config.get::<Vec<String>>("build.rustflags").unwrap(),
["--file", "--cli", "--env1", "--env2"]
);
// With advanced-env.
let config = ConfigBuilder::new()
.unstable_flag("advanced-env")
.env("CARGO_BUILD_RUSTFLAGS", "--env")
.config_arg("build.rustflags = ['--cli']")
.build();
assert_eq!(
config.get::<Vec<String>>("build.rustflags").unwrap(),
["--file", "--cli", "--env"]
);
// Merges multiple instances.
let config = ConfigBuilder::new()
.config_arg("build.rustflags=['--one']")
.config_arg("build.rustflags=['--two']")
.build();
assert_eq!(
config.get::<Vec<String>>("build.rustflags").unwrap(),
["--file", "--one", "--two"]
);
}
#[cargo_test]
fn string_list_array() {
// Using the StringList type.
write_config(
"
[build]
rustflags = ['--file']
",
);
let config = ConfigBuilder::new()
.config_arg("build.rustflags = ['--cli']")
.build();
assert_eq!(
config
.get::<cargo::util::config::StringList>("build.rustflags")
.unwrap()
.as_slice(),
["--file", "--cli"]
);
// With normal env.
let config = ConfigBuilder::new()
.env("CARGO_BUILD_RUSTFLAGS", "--env1 --env2")
.config_arg("build.rustflags = ['--cli']")
.build();
assert_eq!(
config
.get::<cargo::util::config::StringList>("build.rustflags")
.unwrap()
.as_slice(),
["--file", "--cli", "--env1", "--env2"]
);
// With advanced-env.
let config = ConfigBuilder::new()
.unstable_flag("advanced-env")
.env("CARGO_BUILD_RUSTFLAGS", "['--env']")
.config_arg("build.rustflags = ['--cli']")
.build();
assert_eq!(
config
.get::<cargo::util::config::StringList>("build.rustflags")
.unwrap()
.as_slice(),
["--file", "--cli", "--env"]
);
}
#[cargo_test]
fn merges_table() {
// Tables are merged.
write_config(
"
[foo]
key1 = 1
key2 = 2
key3 = 3
",
);
let config = ConfigBuilder::new()
.config_arg("foo.key2 = 4")
.config_arg("foo.key3 = 5")
.config_arg("foo.key4 = 6")
.build();
assert_eq!(config.get::<i32>("foo.key1").unwrap(), 1);
assert_eq!(config.get::<i32>("foo.key2").unwrap(), 4);
assert_eq!(config.get::<i32>("foo.key3").unwrap(), 5);
assert_eq!(config.get::<i32>("foo.key4").unwrap(), 6);
// With env.
let config = ConfigBuilder::new()
.env("CARGO_FOO_KEY3", "7")
.env("CARGO_FOO_KEY4", "8")
.env("CARGO_FOO_KEY5", "9")
.config_arg("foo.key2 = 4")
.config_arg("foo.key3 = 5")
.config_arg("foo.key4 = 6")
.build();
assert_eq!(config.get::<i32>("foo.key1").unwrap(), 1);
assert_eq!(config.get::<i32>("foo.key2").unwrap(), 4);
assert_eq!(config.get::<i32>("foo.key3").unwrap(), 5);
assert_eq!(config.get::<i32>("foo.key4").unwrap(), 6);
assert_eq!(config.get::<i32>("foo.key5").unwrap(), 9);
}
#[cargo_test]
fn merge_array_mixed_def_paths() {
// Merging of arrays with different def sites.
write_config(
"
paths = ['file']
",
);
// Create a directory for CWD to differentiate the paths.
let somedir = paths::root().join("somedir");
fs::create_dir(&somedir).unwrap();
let config = ConfigBuilder::new()
.cwd(&somedir)
.config_arg("paths=['cli']")
// env is currently ignored for get_list()
.env("CARGO_PATHS", "env")
.build();
let paths = config.get_list("paths").unwrap().unwrap();
// The definition for the root value is somewhat arbitrary, but currently starts with the file because that is what is loaded first.
assert_eq!(paths.definition, Definition::Path(paths::root()));
assert_eq!(paths.val.len(), 2);
assert_eq!(paths.val[0].0, "file");
assert_eq!(paths.val[0].1.root(&config), paths::root());
assert_eq!(paths.val[1].0, "cli");
assert_eq!(paths.val[1].1.root(&config), somedir);
}
#[cargo_test]
fn unused_key() {
// Unused key passed on command line.
let config = ConfigBuilder::new()
.config_arg("build={jobs=1, unused=2}")
.build();
config.build_config().unwrap();
let output = read_output(config);
let expected = "\
warning: unused config key `build.unused` in `--config cli option`
";
assert_match(expected, &output);
}
#[cargo_test]
fn rerooted_remains() {
// Re-rooting keeps cli args.
let somedir = paths::root().join("somedir");
fs::create_dir_all(somedir.join(".cargo")).unwrap();
fs::write(
somedir.join(".cargo").join("config"),
"
a = 'file1'
b = 'file2'
",
)
.unwrap();
let mut config = ConfigBuilder::new()
.cwd(&somedir)
.config_arg("b='cli1'")
.config_arg("c='cli2'")
.build();
assert_eq!(config.get::<String>("a").unwrap(), "file1");
assert_eq!(config.get::<String>("b").unwrap(), "cli1");
assert_eq!(config.get::<String>("c").unwrap(), "cli2");
config.reload_rooted_at(paths::root()).unwrap();
assert_eq!(config.get::<Option<String>>("a").unwrap(), None);
assert_eq!(config.get::<String>("b").unwrap(), "cli1");
assert_eq!(config.get::<String>("c").unwrap(), "cli2");
}
#[cargo_test]
fn bad_parse() {
// Fail to TOML parse.
let config = ConfigBuilder::new().config_arg("abc").build_err();
assert_error(
config.unwrap_err(),
"\
failed to parse --config argument `abc`
Caused by:
expected an equals, found eof at line 1 column 4",
);
}
#[cargo_test]
fn too_many_values() {
// Currently restricted to only 1 value.
let config = ConfigBuilder::new().config_arg("a=1\nb=2").build_err();
assert_error(
config.unwrap_err(),
"\
--config argument `a=1
b=2` expected exactly one key=value pair, got 2 keys",
);
let config = ConfigBuilder::new().config_arg("").build_err();
assert_error(
config.unwrap_err(),
"\
--config argument `` expected exactly one key=value pair, got 0 keys",
);
}
#[cargo_test]
fn bad_cv_convert() {
// ConfigValue does not support all TOML types.
let config = ConfigBuilder::new().config_arg("a=2019-12-01").build_err();
assert_error(
config.unwrap_err(),
"\
failed to convert --config argument `a=2019-12-01`
Caused by:
failed to parse key `a`
Caused by:
found TOML configuration value of unknown type `datetime`",
);
}
#[cargo_test]
fn fail_to_merge_multiple_args() {
// Error message when multiple args fail to merge.
let config = ConfigBuilder::new()
.config_arg("foo='a'")
.config_arg("foo=['a']")
.build_err();
// This is a little repetitive, but hopefully the user can figure it out.
assert_error(
config.unwrap_err(),
"\
failed to merge --config argument `foo=['a']`
Caused by:
failed to merge key `foo` between --config cli option and --config cli option
Caused by:
failed to merge config value from `--config cli option` into `--config cli option`: \
expected string, but found array",
);
}