//! Tests for config settings.
use std::borrow::Borrow;
-use std::collections;
+use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::io;
use std::os;
use cargo::core::{enable_nightly_features, Shell};
use cargo::util::config::{self, Config, SslVersionConfig};
use cargo::util::toml::{self, VecStringOrBool as VSOB};
+use cargo::CargoResult;
use cargo_test_support::{paths, project, t};
use serde::Deserialize;
+/// Helper for constructing a `Config` object.
+pub struct ConfigBuilder {
+ env: HashMap<String, String>,
+ unstable: Vec<String>,
+}
+
+impl ConfigBuilder {
+ pub fn new() -> ConfigBuilder {
+ ConfigBuilder {
+ env: HashMap::new(),
+ unstable: Vec::new(),
+ }
+ }
+
+ /// Passes a `-Z` flag.
+ pub fn unstable_flag(&mut self, s: impl Into<String>) -> &mut Self {
+ self.unstable.push(s.into());
+ self
+ }
+
+ /// Sets an environment variable.
+ pub fn env(&mut self, key: impl Into<String>, val: impl Into<String>) -> &mut Self {
+ self.env.insert(key.into(), val.into());
+ self
+ }
+
+ /// Creates the `Config`.
+ pub fn build(&self) -> Config {
+ self.build_err().unwrap()
+ }
+
+ /// Creates the `Config`, returning a Result.
+ pub fn build_err(&self) -> CargoResult<Config> {
+ if !self.unstable.is_empty() {
+ // This is unfortunately global. Some day that should be fixed.
+ enable_nightly_features();
+ }
+ let output = Box::new(fs::File::create(paths::root().join("shell.out")).unwrap());
+ let shell = Shell::from_write(output);
+ let cwd = paths::root();
+ let homedir = paths::home();
+ let mut config = Config::new(shell, cwd, homedir);
+ config.set_env(self.env.clone());
+ config.configure(0, None, None, false, false, false, &None, &self.unstable)?;
+ Ok(config)
+ }
+}
+
+fn new_config() -> Config {
+ ConfigBuilder::new().build()
+}
+
fn lines_match(a: &str, b: &str) -> bool {
// Perform a small amount of normalization for filesystem paths before we
// send this to the `lines_match` function.
p.cargo("build").env("CARGO_BUILD_JOBS", "100").run();
}
-fn write_config(config: &str) {
+pub fn write_config(config: &str) {
let path = paths::root().join(".cargo/config");
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, config).unwrap();
t!(symlink_file(&toml_path, &symlink_path));
}
-fn new_config(env: &[(&str, &str)]) -> Config {
- enable_nightly_features(); // -Z advanced-env
- let output = Box::new(fs::File::create(paths::root().join("shell.out")).unwrap());
- let shell = Shell::from_write(output);
- let cwd = paths::root();
- let homedir = paths::home();
- let env = env
- .iter()
- .map(|(k, v)| (k.to_string(), v.to_string()))
- .collect();
- let mut config = Config::new(shell, cwd, homedir);
- config.set_env(env);
- config
- .configure(
- 0,
- None,
- None,
- false,
- false,
- false,
- &None,
- &["advanced-env".into()],
- )
- .unwrap();
- config
-}
-
fn assert_error<E: Borrow<failure::Error>>(error: E, msgs: &str) {
let causes = error
.borrow()
",
);
- let config = new_config(&[]);
+ let config = new_config();
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct S {
}
let s: S = config.get("S").unwrap();
assert_eq!(s, S { f1: Some(123) });
- let config = new_config(&[("CARGO_S_F1", "456")]);
+ let config = ConfigBuilder::new().env("CARGO_S_F1", "456").build();
let s: S = config.get("S").unwrap();
assert_eq!(s, S { f1: Some(456) });
}
",
);
- let config = new_config(&[]);
+ let config = new_config();
assert_eq!(config.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
}
symlink_config_to_config_toml();
- let config = new_config(&[]);
+ let config = new_config();
assert_eq!(config.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
",
);
- let config = new_config(&[]);
+ let config = new_config();
// It should use the value from the one without the extension for
// backwards compatibility.
",
);
- let config = new_config(&[("CARGO_S_UNUSED2", "1"), ("CARGO_S2_UNUSED", "2")]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_S_UNUSED2", "1")
+ .env("CARGO_S2_UNUSED", "2")
+ .build();
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct S {
",
);
- let config = new_config(&[
- ("CARGO_PROFILE_DEV_CODEGEN_UNITS", "5"),
- ("CARGO_PROFILE_DEV_BUILD_OVERRIDE_CODEGEN_UNITS", "11"),
- ("CARGO_PROFILE_DEV_PACKAGE_env_CODEGEN_UNITS", "13"),
- ("CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL", "2"),
- ]);
+ let config = ConfigBuilder::new()
+ .unstable_flag("advanced-env")
+ .env("CARGO_PROFILE_DEV_CODEGEN_UNITS", "5")
+ .env("CARGO_PROFILE_DEV_BUILD_OVERRIDE_CODEGEN_UNITS", "11")
+ .env("CARGO_PROFILE_DEV_PACKAGE_env_CODEGEN_UNITS", "13")
+ .env("CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL", "2")
+ .build();
// TODO: don't use actual `tomlprofile`.
let p: toml::TomlProfile = config.get("profile.dev").unwrap();
- let mut packages = collections::BTreeMap::new();
+ let mut packages = BTreeMap::new();
let key = toml::ProfilePackageSpec::Spec(::cargo::core::PackageIdSpec::parse("bar").unwrap());
let o_profile = toml::TomlProfile {
opt_level: Some(toml::TomlOptLevel("2".to_string())),
",
);
- let config = new_config(&[
- ("CARGO_ENVB", "false"),
- ("CARGO_C", "['d']"),
- ("CARGO_ENVL", "['a', 'b']"),
- ]);
+ let config = ConfigBuilder::new()
+ .unstable_flag("advanced-env")
+ .env("CARGO_ENVB", "false")
+ .env("CARGO_C", "['d']")
+ .env("CARGO_ENVL", "['a', 'b']")
+ .build();
let a = config.get::<VSOB>("a").unwrap();
match a {
",
);
- let config = new_config(&[]);
+ let config = new_config();
assert_error(
config.get::<toml::TomlProfile>("profile.dev").unwrap_err(),
must be an integer, `z`, or `s`, but found: foo",
);
- let config = new_config(&[("CARGO_PROFILE_DEV_OPT_LEVEL", "asdf")]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_PROFILE_DEV_OPT_LEVEL", "asdf")
+ .build();
assert_error(
config.get::<toml::TomlProfile>("profile.dev").unwrap_err(),
",
);
- let config = new_config(&[
- ("CARGO_NEST_foo_f2", "3"),
- ("CARGO_NESTE_foo_f1", "1"),
- ("CARGO_NESTE_foo_f2", "3"),
- ("CARGO_NESTE_bar_asdf", "3"),
- ]);
+ let config = ConfigBuilder::new()
+ .unstable_flag("advanced-env")
+ .env("CARGO_NEST_foo_f2", "3")
+ .env("CARGO_NESTE_foo_f1", "1")
+ .env("CARGO_NESTE_foo_f2", "3")
+ .env("CARGO_NESTE_bar_asdf", "3")
+ .build();
- type Nested = collections::HashMap<String, collections::HashMap<String, u8>>;
+ type Nested = HashMap<String, HashMap<String, u8>>;
let n: Nested = config.get("nest").unwrap();
- let mut expected = collections::HashMap::new();
- let mut foo = collections::HashMap::new();
+ let mut expected = HashMap::new();
+ let mut foo = HashMap::new();
foo.insert("f1".to_string(), 1);
foo.insert("f2".to_string(), 3);
expected.insert("foo".to_string(), foo);
- let mut bar = collections::HashMap::new();
+ let mut bar = HashMap::new();
bar.insert("asdf".to_string(), 3);
expected.insert("bar".to_string(), bar);
assert_eq!(n, expected);
",
);
- let config = new_config(&[("CARGO_E_S", "asdf"), ("CARGO_E_BIG", "123456789")]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_E_S", "asdf")
+ .env("CARGO_E_BIG", "123456789")
+ .build();
assert_error(
config.get::<i64>("foo").unwrap_err(),
"missing config key `foo`",
",
);
- let config = new_config(&[("CARGO_BAR_ASDF", "3")]);
+ let config = ConfigBuilder::new().env("CARGO_BAR_ASDF", "3").build();
assert_eq!(config.get::<Option<i32>>("a").unwrap(), None);
assert_eq!(config.get::<Option<i32>>("a.b").unwrap(), None);
#[cargo_test]
fn config_bad_toml() {
write_config("asdf");
- let config = new_config(&[]);
+ let config = new_config();
assert_error(
config.get::<i32>("foo").unwrap_err(),
"\
type L = Vec<String>;
- let config = new_config(&[
- ("CARGO_L4", "['three', 'four']"),
- ("CARGO_L5", "['a']"),
- ("CARGO_ENV_EMPTY", "[]"),
- ("CARGO_ENV_BLANK", ""),
- ("CARGO_ENV_NUM", "1"),
- ("CARGO_ENV_NUM_LIST", "[1]"),
- ("CARGO_ENV_TEXT", "asdf"),
- ("CARGO_LEPAIR", "['a', 'b']"),
- ("CARGO_NESTED2_L", "['z']"),
- ("CARGO_NESTEDE_L", "['env']"),
- ("CARGO_BAD_ENV", "[zzz]"),
- ]);
+ let config = ConfigBuilder::new()
+ .unstable_flag("advanced-env")
+ .env("CARGO_L4", "['three', 'four']")
+ .env("CARGO_L5", "['a']")
+ .env("CARGO_ENV_EMPTY", "[]")
+ .env("CARGO_ENV_BLANK", "")
+ .env("CARGO_ENV_NUM", "1")
+ .env("CARGO_ENV_NUM_LIST", "[1]")
+ .env("CARGO_ENV_TEXT", "asdf")
+ .env("CARGO_LEPAIR", "['a', 'b']")
+ .env("CARGO_NESTED2_L", "['z']")
+ .env("CARGO_NESTEDE_L", "['env']")
+ .env("CARGO_BAD_ENV", "[zzz]")
+ .build();
assert_eq!(config.get::<L>("unset").unwrap(), vec![] as Vec<String>);
assert_eq!(config.get::<L>("l1").unwrap(), vec![] as Vec<String>);
",
);
- let config = new_config(&[("CARGO_NSE", "987"), ("CARGO_NS2", "654")]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_NSE", "987")
+ .env("CARGO_NS2", "654")
+ .build();
#[derive(Debug, Deserialize, Eq, PartialEq)]
#[serde(transparent)]
paths::home().display(),
));
- let config = new_config(&[("CARGO_EPATH", "a/b"), ("CARGO_P3", "d/e")]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_EPATH", "a/b")
+ .env("CARGO_P3", "d/e")
+ .build();
assert_eq!(
config
",
);
- let config = new_config(&[
- ("CARGO_EPOS", "123456789"),
- ("CARGO_ENEG", "-1"),
- ("CARGO_EI64MAX", "9223372036854775807"),
- ]);
+ let config = ConfigBuilder::new()
+ .env("CARGO_EPOS", "123456789")
+ .env("CARGO_ENEG", "-1")
+ .env("CARGO_EI64MAX", "9223372036854775807")
+ .build();
assert_eq!(
config.get::<u64>("i64max").unwrap(),
",
);
- let config = new_config(&[]);
+ let config = new_config();
assert!(config
.get::<Option<SslVersionConfig>>("http.ssl-version")
",
);
- let config = new_config(&[]);
+ let config = new_config();
let a = config
.get::<Option<SslVersionConfig>>("http.ssl-version")
",
);
- let config = new_config(&[]);
+ let config = new_config();
let a = config
.get::<Option<SslVersionConfig>>("http.ssl-version")
",
);
- let config = new_config(&[]);
+ let config = new_config();
+
+ assert_error(
+ config
+ .get::<SslVersionConfig>("http.ssl-version")
+ .unwrap_err(),
+ "\
+could not load Cargo configuration
+
+Caused by:
+ could not parse TOML configuration in `[..]/.cargo/config`
- assert!(config.get::<SslVersionConfig>("http.ssl-version").is_err());
+Caused by:
+ could not parse input as TOML
+
+Caused by:
+ dotted key attempted to extend non-table type at line 2 column 15",
+ );
assert!(config
.get::<Option<SslVersionConfig>>("http.ssl-version")
.unwrap()