diff --git a/Cargo.lock b/Cargo.lock index 3f45b87ecc5..b4b80f50394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -568,16 +568,16 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "config" -version = "0.15.16" +version = "0.15.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49" +checksum = "180e549344080374f9b32ed41bf3b6b57885ff6a289367b3dbc10eea8acc1918" dependencies = [ "indexmap 2.11.4", "pathdiff", "ron", "serde_core", "serde_json", - "toml 0.9.0", + "toml 0.9.8", "winnow", ] @@ -3683,12 +3683,12 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.0" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap 2.11.4", - "serde", + "serde_core", "serde_spanned 1.0.3", "toml_datetime 0.7.3", "toml_parser", diff --git a/Cargo.toml b/Cargo.toml index 59059c65482..31426f56097 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ cfg-if = "1.0.3" color-eyre = "0.6.5" # config's "preserve_order" feature is needed for preserving the order of # setup scripts in .config/nextest.toml. -config = { version = "0.15.16", default-features = false, features = [ +config = { version = "0.15.18", default-features = false, features = [ "toml", "preserve_order", ] } diff --git a/nextest-runner/src/config/elements/archive.rs b/nextest-runner/src/config/elements/archive.rs index 7f9896b4d54..e638440f49e 100644 --- a/nextest-runner/src/config/elements/archive.rs +++ b/nextest-runner/src/config/elements/archive.rs @@ -352,6 +352,7 @@ mod tests { [profile.default] archive.include = { path = "foo", relative-to = "target" } "#}, + ConfigErrorKind::Message, r"invalid type: map, expected a sequence" ; "missing list")] #[test_case( @@ -361,7 +362,8 @@ mod tests { { path = "foo" } ] "#}, - r"missing field `relative-to`" + ConfigErrorKind::NotFound, + r#"profile.default.archive.include[0]relative-to"# ; "missing relative-to")] #[test_case( indoc!{r#" @@ -370,6 +372,7 @@ mod tests { { path = "bar", relative-to = "unknown" } ] "#}, + ConfigErrorKind::Message, r"enum ArchiveRelativeTo does not have variant constructor unknown" ; "invalid relative-to")] #[test_case( @@ -379,6 +382,7 @@ mod tests { { path = "bar", relative-to = "target", depth = -1 } ] "#}, + ConfigErrorKind::Message, r#"invalid value: integer `-1`, expected a non-negative integer or "infinite""# ; "negative depth")] #[test_case( @@ -388,6 +392,7 @@ mod tests { { path = "foo/../bar", relative-to = "target" } ] "#}, + ConfigErrorKind::Message, r#"invalid value: string "foo/../bar", expected a relative path with no parent components"# ; "parent component")] #[test_case( @@ -397,6 +402,7 @@ mod tests { { path = "/foo/bar", relative-to = "target" } ] "#}, + ConfigErrorKind::Message, r#"invalid value: string "/foo/bar", expected a relative path with no parent components"# ; "absolute path")] #[test_case( @@ -406,6 +412,7 @@ mod tests { { path = "foo", relative-to = "target", on-missing = "unknown" } ] "#}, + ConfigErrorKind::Message, r#"invalid value: string "unknown", expected a string: "ignore", "warn", or "error""# ; "invalid on-missing")] #[test_case( @@ -415,9 +422,14 @@ mod tests { { path = "foo", relative-to = "target", on-missing = 42 } ] "#}, + ConfigErrorKind::Message, r#"invalid type: integer `42`, expected a string: "ignore", "warn", or "error""# ; "invalid on-missing type")] - fn parse_invalid(config_contents: &str, expected_message: &str) { + fn parse_invalid( + config_contents: &str, + expected_kind: ConfigErrorKind, + expected_message: &str, + ) { let workspace_dir = tempdir().unwrap(); let graph = temp_workspace(&workspace_dir, config_contents); @@ -434,14 +446,18 @@ mod tests { .expect_err("config expected to be invalid"); let message = match config_err.kind() { - ConfigParseErrorKind::DeserializeError(path_error) => match path_error.inner() { - ConfigError::Message(message) => message, - other => { - panic!( - "for config error {config_err:?}, expected ConfigError::Message for inner error {other:?}" - ); + ConfigParseErrorKind::DeserializeError(path_error) => { + match (path_error.inner(), expected_kind) { + (ConfigError::NotFound(message), ConfigErrorKind::NotFound) => message, + (ConfigError::Message(message), ConfigErrorKind::Message) => message, + (other, expected) => { + panic!( + "for config error {config_err:?}, expected \ + ConfigErrorKind::{expected:?} for inner error {other:?}" + ); + } } - }, + } other => { panic!( "for config error {other:?}, expected ConfigParseErrorKind::DeserializeError" diff --git a/nextest-runner/src/config/elements/leak_timeout.rs b/nextest-runner/src/config/elements/leak_timeout.rs index 5914b5acdba..d979c4a3761 100644 --- a/nextest-runner/src/config/elements/leak_timeout.rs +++ b/nextest-runner/src/config/elements/leak_timeout.rs @@ -151,7 +151,7 @@ mod tests { [profile.ci] leak-timeout = { result = "fail" } "#}, - Err("original: missing field `period`"), + Err(r#"original: missing configuration field "profile.ci.leak-timeout.period""#), None ; "partial leak-timeout table should error" diff --git a/nextest-runner/src/config/elements/max_fail.rs b/nextest-runner/src/config/elements/max_fail.rs index b1761b1fb79..df735b4539a 100644 --- a/nextest-runner/src/config/elements/max_fail.rs +++ b/nextest-runner/src/config/elements/max_fail.rs @@ -319,7 +319,7 @@ mod tests { [profile.custom] fail-fast = { invalid-key = 1 } "#}, - "profile.custom.fail-fast: missing field `max-fail`" + r#"profile.custom.fail-fast: missing configuration field "profile.custom.fail-fast.max-fail""# ; "invalid map key" )] #[test_case( diff --git a/nextest-runner/src/config/elements/retry_policy.rs b/nextest-runner/src/config/elements/retry_policy.rs index d12691d25fd..a91fb10e9b0 100644 --- a/nextest-runner/src/config/elements/retry_policy.rs +++ b/nextest-runner/src/config/elements/retry_policy.rs @@ -300,6 +300,7 @@ mod tests { [profile.default] retries = { backoff = "foo" } "#}, + ConfigErrorKind::Message, "unknown variant `foo`, expected `fixed` or `exponential`" ; "invalid value for backoff")] #[test_case( @@ -307,13 +308,15 @@ mod tests { [profile.default] retries = { backoff = "fixed" } "#}, - "missing field `count`" + ConfigErrorKind::NotFound, + "profile.default.retries.count" ; "fixed specified without count")] #[test_case( indoc!{r#" [profile.default] retries = { backoff = "fixed", count = 1, delay = "foobar" } "#}, + ConfigErrorKind::Message, "invalid value: string \"foobar\", expected a duration" ; "delay is not a valid duration")] #[test_case( @@ -321,6 +324,7 @@ mod tests { [profile.default] retries = { backoff = "fixed", count = 1, jitter = true } "#}, + ConfigErrorKind::Message, "`jitter` cannot be true if `delay` isn't specified or is zero" ; "jitter specified without delay")] #[test_case( @@ -328,6 +332,7 @@ mod tests { [profile.default] retries = { backoff = "fixed", count = 1, max-delay = "10s" } "#}, + ConfigErrorKind::Message, "unknown field `max-delay`, expected one of `count`, `delay`, `jitter`" ; "max-delay is incompatible with fixed backoff")] #[test_case( @@ -335,20 +340,23 @@ mod tests { [profile.default] retries = { backoff = "exponential", count = 1 } "#}, - "missing field `delay`" + ConfigErrorKind::NotFound, + "profile.default.retries.delay" ; "exponential backoff must specify delay")] #[test_case( indoc!{r#" [profile.default] retries = { backoff = "exponential", delay = "1s" } "#}, - "missing field `count`" + ConfigErrorKind::NotFound, + "profile.default.retries.count" ; "exponential backoff must specify count")] #[test_case( indoc!{r#" [profile.default] retries = { backoff = "exponential", count = 0, delay = "1s" } "#}, + ConfigErrorKind::Message, "`count` cannot be zero with exponential backoff" ; "exponential backoff must have a non-zero count")] #[test_case( @@ -356,6 +364,7 @@ mod tests { [profile.default] retries = { backoff = "exponential", count = 1, delay = "0s" } "#}, + ConfigErrorKind::Message, "`delay` cannot be zero with exponential backoff" ; "exponential backoff must have a non-zero delay")] #[test_case( @@ -363,6 +372,7 @@ mod tests { [profile.default] retries = { backoff = "exponential", count = 1, delay = "1s", max-delay = "0s" } "#}, + ConfigErrorKind::Message, "`max-delay` cannot be zero with exponential backoff" ; "exponential backoff must have a non-zero max delay")] #[test_case( @@ -370,9 +380,14 @@ mod tests { [profile.default] retries = { backoff = "exponential", count = 1, delay = "4s", max-delay = "2s", jitter = true } "#}, + ConfigErrorKind::Message, "`max-delay` cannot be less than delay" ; "max-delay greater than delay")] - fn parse_retries_invalid(config_contents: &str, expected_message: &str) { + fn parse_retries_invalid( + config_contents: &str, + expected_kind: ConfigErrorKind, + expected_message: &str, + ) { let workspace_dir = tempdir().unwrap(); let graph = temp_workspace(&workspace_dir, config_contents); @@ -388,14 +403,18 @@ mod tests { .expect_err("config expected to be invalid"); let message = match config_err.kind() { - ConfigParseErrorKind::DeserializeError(path_error) => match path_error.inner() { - ConfigError::Message(message) => message, - other => { - panic!( - "for config error {config_err:?}, expected ConfigError::Message for inner error {other:?}" - ); + ConfigParseErrorKind::DeserializeError(path_error) => { + match (path_error.inner(), expected_kind) { + (ConfigError::Message(message), ConfigErrorKind::Message) => message, + (ConfigError::NotFound(message), ConfigErrorKind::NotFound) => message, + (other, expected) => { + panic!( + "for config error {config_err:?}, expected \ + ConfigErrorKind::{expected:?} for inner error {other:?}" + ); + } } - }, + } other => { panic!( "for config error {other:?}, expected ConfigParseErrorKind::DeserializeError" diff --git a/nextest-runner/src/config/elements/slow_timeout.rs b/nextest-runner/src/config/elements/slow_timeout.rs index fd00bcb76f9..03e04b98931 100644 --- a/nextest-runner/src/config/elements/slow_timeout.rs +++ b/nextest-runner/src/config/elements/slow_timeout.rs @@ -169,7 +169,7 @@ mod tests { [profile.ci] slow-timeout = { terminate-after = 3 } "#}, - Err("original: missing field `period`"), + Err("original: missing configuration field \"profile.ci.slow-timeout.period\""), None ; "partial slow-timeout table should error" diff --git a/nextest-runner/src/config/scripts/imp.rs b/nextest-runner/src/config/scripts/imp.rs index 90241d20044..29777384ac2 100644 --- a/nextest-runner/src/config/scripts/imp.rs +++ b/nextest-runner/src/config/scripts/imp.rs @@ -1200,7 +1200,7 @@ mod tests { indoc! {r#" [scripts.setup.foo] "#}, - "scripts.setup.foo: missing field `command`" + r#"scripts.setup.foo: missing configuration field "scripts.setup.foo.command""# ; "missing command" )] @@ -1227,7 +1227,7 @@ mod tests { [scripts.setup.foo] command = { relative-to = "target" } "#}, - "missing field `command-line`" + r#"missing configuration field "scripts.setup.foo.command.command-line""# ; "missing command-line in table" )] diff --git a/nextest-runner/src/config/utils/test_helpers.rs b/nextest-runner/src/config/utils/test_helpers.rs index b5c118577fc..32e3ba91ab1 100644 --- a/nextest-runner/src/config/utils/test_helpers.rs +++ b/nextest-runner/src/config/utils/test_helpers.rs @@ -56,6 +56,12 @@ pub(in crate::config) struct BinaryQueryCreator<'a> { platform: BuildPlatform, } +#[derive(Clone, Copy, Debug)] +pub(in crate::config) enum ConfigErrorKind { + NotFound, + Message, +} + impl BinaryQueryCreator<'_> { pub(in crate::config) fn to_query(&self) -> BinaryQuery<'_> { BinaryQuery {