From 21cea28384abcea0e671aade48719fab93376b9a Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 13:54:27 -0800 Subject: [PATCH 1/6] fix: correct typo in example! macro documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed "mainting" to "maintaining" in the doc comment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/compiler/function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/function.rs b/src/compiler/function.rs index 0b416fd74..7ad7a61c3 100644 --- a/src/compiler/function.rs +++ b/src/compiler/function.rs @@ -87,7 +87,7 @@ pub struct Example { /// Macro to create an `Example` with automatic source location tracking /// Accepts fields in any order: title, source, result /// Optional fields added to `Example` shouldn't be required to be added for the macro to work, -/// mainting backwards compatibility +/// maintaining backwards compatibility #[macro_export] macro_rules! example { // Entry point - delegate to internal parser with empty state From 7e9b8ec6682a2a94a452d6dffa43369c7b472232 Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 15:02:51 -0800 Subject: [PATCH 2/6] feat: add comprehensive compile-time tests for example! macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added trybuild-based compile-time tests following TDD principles: Tests added (tests/compiler/function/example/): - Valid usage with trailing commas (pass.rs) - Duplicate field detection (3 tests with .stderr) - Missing field detection (3 tests with .stderr) - Unknown field detection (1 test with .stderr) Macro improvements (src/compiler/function.rs): - Added duplicate field error handling with compile_error! - Enhanced documentation with compile_fail examples - Added test_example_macro_trailing_commas unit test Infrastructure: - Added trybuild dev dependency (Cargo.toml) - Created tests/trybuild.rs test suite with organized structure - Added tests/README.md documenting trybuild workflow Test organization mirrors source structure: src/compiler/function.rs → tests/compiler/function/example/ All tests pass including unit tests, doc tests, and trybuild tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- Cargo.lock | 84 ++++++++++++++++-- Cargo.toml | 1 + src/compiler/function.rs | 86 +++++++++++++++++++ tests/README.md | 46 ++++++++++ .../function/example/duplicate_result.rs | 10 +++ .../function/example/duplicate_result.stderr | 13 +++ .../function/example/duplicate_source.rs | 10 +++ .../function/example/duplicate_source.stderr | 13 +++ .../function/example/duplicate_title.rs | 10 +++ .../function/example/duplicate_title.stderr | 13 +++ .../function/example/missing_result.rs | 8 ++ .../function/example/missing_result.stderr | 16 ++++ .../function/example/missing_source.rs | 8 ++ .../function/example/missing_source.stderr | 16 ++++ .../function/example/missing_title.rs | 8 ++ .../function/example/missing_title.stderr | 16 ++++ tests/compiler/function/example/pass.rs | 9 ++ .../function/example/unknown_field.rs | 10 +++ .../function/example/unknown_field.stderr | 18 ++++ tests/trybuild.rs | 53 ++++++++++++ 20 files changed, 441 insertions(+), 7 deletions(-) create mode 100644 tests/README.md create mode 100644 tests/compiler/function/example/duplicate_result.rs create mode 100644 tests/compiler/function/example/duplicate_result.stderr create mode 100644 tests/compiler/function/example/duplicate_source.rs create mode 100644 tests/compiler/function/example/duplicate_source.stderr create mode 100644 tests/compiler/function/example/duplicate_title.rs create mode 100644 tests/compiler/function/example/duplicate_title.stderr create mode 100644 tests/compiler/function/example/missing_result.rs create mode 100644 tests/compiler/function/example/missing_result.stderr create mode 100644 tests/compiler/function/example/missing_source.rs create mode 100644 tests/compiler/function/example/missing_source.stderr create mode 100644 tests/compiler/function/example/missing_title.rs create mode 100644 tests/compiler/function/example/missing_title.stderr create mode 100644 tests/compiler/function/example/pass.rs create mode 100644 tests/compiler/function/example/unknown_field.rs create mode 100644 tests/compiler/function/example/unknown_field.stderr create mode 100644 tests/trybuild.rs diff --git a/Cargo.lock b/Cargo.lock index 9447fc2fe..4e904f982 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,12 +1336,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" - [[package]] name = "hashbrown" version = "0.16.1" @@ -1647,7 +1641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.16.1", ] [[package]] @@ -3375,6 +3369,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3648,6 +3651,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "target-triple" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" + [[package]] name = "tempfile" version = "3.21.0" @@ -3864,6 +3873,45 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + [[package]] name = "tower" version = "0.5.2" @@ -3998,6 +4046,21 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "trybuild" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e17e807bff86d2a06b52bca4276746584a78375055b6e45843925ce2802b335" +dependencies = [ + "glob", + "serde", + "serde_derive", + "serde_json", + "target-triple", + "termcolor", + "toml", +] + [[package]] name = "twox-hash" version = "2.1.2" @@ -4256,6 +4319,7 @@ dependencies = [ "tokio", "tracing", "tracing-test", + "trybuild", "ua-parser", "unicode-segmentation", "url", @@ -4815,6 +4879,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + [[package]] name = "winsafe" version = "0.0.19" diff --git a/Cargo.toml b/Cargo.toml index dc6f403fd..c37980161 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -263,6 +263,7 @@ regex = { version = "1", default-features = false, features = ["std", "perf", "u paste = { version = "1", default-features = false } proptest = { version = "1" } proptest-derive = { version = "0.6" } +trybuild = "1" [build-dependencies] lalrpop = { version = "0.22", default-features = false } diff --git a/src/compiler/function.rs b/src/compiler/function.rs index 7ad7a61c3..035bcec2f 100644 --- a/src/compiler/function.rs +++ b/src/compiler/function.rs @@ -88,6 +88,54 @@ pub struct Example { /// Accepts fields in any order: title, source, result /// Optional fields added to `Example` shouldn't be required to be added for the macro to work, /// maintaining backwards compatibility +/// +/// # Examples +/// +/// Valid usage: +/// ``` +/// use vrl::example; +/// +/// let ex = example! { +/// title: "test", +/// source: "code", +/// result: Ok("output"), +/// }; +/// ``` +/// +/// Missing required field should fail: +/// ```compile_fail +/// use vrl::example; +/// +/// let ex = example! { +/// title: "test", +/// source: "code", +/// // missing result field +/// }; +/// ``` +/// +/// Duplicate field should fail: +/// ```compile_fail +/// use vrl::example; +/// +/// let ex = example! { +/// title: "test", +/// source: "code", +/// result: Ok("output"), +/// title: "duplicate", +/// }; +/// ``` +/// +/// Unknown field should fail: +/// ```compile_fail +/// use vrl::example; +/// +/// let ex = example! { +/// title: "test", +/// source: "code", +/// result: Ok("output"), +/// unknown_field: "value", +/// }; +/// ``` #[macro_export] macro_rules! example { // Entry point - delegate to internal parser with empty state @@ -97,6 +145,21 @@ macro_rules! example { $crate::example!(@internal [] [] [] [$($field: $value,)*]) }; + // Error: duplicate title field + (@internal [$title:expr] [$($source:tt)*] [$($result:tt)*] [title: $t:expr, $($rest:tt)*]) => { + compile_error!("duplicate 'title' field in example! macro") + }; + + // Error: duplicate source field + (@internal [$($title:tt)*] [$source:expr] [$($result:tt)*] [source: $s:expr, $($rest:tt)*]) => { + compile_error!("duplicate 'source' field in example! macro") + }; + + // Error: duplicate result field + (@internal [$($title:tt)*] [$($source:tt)*] [$result:expr] [result: $r:expr, $($rest:tt)*]) => { + compile_error!("duplicate 'result' field in example! macro") + }; + // Parse title field (@internal [$($title:tt)*] [$($source:tt)*] [$($result:tt)*] [title: $t:expr, $($rest:tt)*]) => { $crate::example!(@internal [$t] [$($source)*] [$($result)*] [$($rest)*]) @@ -714,4 +777,27 @@ mod tests { assert_eq!(ex3.source, "code3"); assert_eq!(ex3.result, Err("error3")); } + + #[test] + fn test_example_macro_trailing_commas() { + // Test with trailing comma + let ex_with_comma = example! { + title: "test", + source: "code", + result: Ok("ok"), + }; + assert_eq!(ex_with_comma.title, "test"); + assert_eq!(ex_with_comma.source, "code"); + assert_eq!(ex_with_comma.result, Ok("ok")); + + // Test without trailing comma + let ex_no_comma = example! { + title: "test", + source: "code", + result: Ok("ok") + }; + assert_eq!(ex_no_comma.title, "test"); + assert_eq!(ex_no_comma.source, "code"); + assert_eq!(ex_no_comma.result, Ok("ok")); + } } diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..de766bbaa --- /dev/null +++ b/tests/README.md @@ -0,0 +1,46 @@ +# VRL Tests + +Some tests are organized to mirror source code structure: +``` +src/compiler/function.rs → tests/compiler/function/*/ +src/parser/lex.rs → tests/parser/lex/*/ +``` + +## Trybuild Tests (Compile-Time) + +Trybuild tests verify code fails to compile with correct error messages. Defined in `tests/trybuild.rs`. + +### Quick Workflow + +1. **Create test file**: `tests/compiler/function/example/my_test.rs` +2. **Run tests**: `cargo test --test trybuild` (creates `wip/my_test.stderr`) +3. **Review error**: `cat wip/my_test.stderr` +4. **Accept (bless)**: `mv wip/my_test.stderr tests/compiler/function/example/` +5. **Add to suite**: Edit `tests/trybuild.rs`, add `t.compile_fail("tests/.../my_test.rs")` +6. **Commit both files**: `.rs` and `.stderr` files together + +### Important: Commit .stderr Files + +**Always commit `.stderr` files** - they define expected error messages and enable regression detection. + +### Update Error Messages + +```bash +TRYBUILD=overwrite cargo test --test trybuild +git diff tests/ # Review changes +``` + +## Commands + +```bash +cargo test # All tests +cargo test --test trybuild # Trybuild only +cargo test --test trybuild compiler_function_example # Specific test +``` + +Note: `trybuild` tests do not show up in code coverage reports. + +## Reference + +- [trybuild docs](https://docs.rs/trybuild/) +- [Rust testing guide](https://doc.rust-lang.org/book/ch11-00-testing.html) diff --git a/tests/compiler/function/example/duplicate_result.rs b/tests/compiler/function/example/duplicate_result.rs new file mode 100644 index 000000000..ae3371651 --- /dev/null +++ b/tests/compiler/function/example/duplicate_result.rs @@ -0,0 +1,10 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + result: Ok("output"), + result: Err("duplicate"), + }; +} diff --git a/tests/compiler/function/example/duplicate_result.stderr b/tests/compiler/function/example/duplicate_result.stderr new file mode 100644 index 000000000..92c8e7e53 --- /dev/null +++ b/tests/compiler/function/example/duplicate_result.stderr @@ -0,0 +1,13 @@ +error: duplicate 'result' field in example! macro + --> tests/compiler/function/example/duplicate_result.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | source: "code", +7 | | result: Ok("output"), +8 | | result: Err("duplicate"), +9 | | }; + | |_____^ + | + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/duplicate_source.rs b/tests/compiler/function/example/duplicate_source.rs new file mode 100644 index 000000000..329503a1c --- /dev/null +++ b/tests/compiler/function/example/duplicate_source.rs @@ -0,0 +1,10 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + result: Ok("output"), + source: "duplicate", + }; +} diff --git a/tests/compiler/function/example/duplicate_source.stderr b/tests/compiler/function/example/duplicate_source.stderr new file mode 100644 index 000000000..a62bcdabe --- /dev/null +++ b/tests/compiler/function/example/duplicate_source.stderr @@ -0,0 +1,13 @@ +error: duplicate 'source' field in example! macro + --> tests/compiler/function/example/duplicate_source.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | source: "code", +7 | | result: Ok("output"), +8 | | source: "duplicate", +9 | | }; + | |_____^ + | + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/duplicate_title.rs b/tests/compiler/function/example/duplicate_title.rs new file mode 100644 index 000000000..910c8de49 --- /dev/null +++ b/tests/compiler/function/example/duplicate_title.rs @@ -0,0 +1,10 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + result: Ok("output"), + title: "duplicate", + }; +} diff --git a/tests/compiler/function/example/duplicate_title.stderr b/tests/compiler/function/example/duplicate_title.stderr new file mode 100644 index 000000000..11fd7abab --- /dev/null +++ b/tests/compiler/function/example/duplicate_title.stderr @@ -0,0 +1,13 @@ +error: duplicate 'title' field in example! macro + --> tests/compiler/function/example/duplicate_title.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | source: "code", +7 | | result: Ok("output"), +8 | | title: "duplicate", +9 | | }; + | |_____^ + | + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/missing_result.rs b/tests/compiler/function/example/missing_result.rs new file mode 100644 index 000000000..48935f123 --- /dev/null +++ b/tests/compiler/function/example/missing_result.rs @@ -0,0 +1,8 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + }; +} diff --git a/tests/compiler/function/example/missing_result.stderr b/tests/compiler/function/example/missing_result.stderr new file mode 100644 index 000000000..ec3c48c88 --- /dev/null +++ b/tests/compiler/function/example/missing_result.stderr @@ -0,0 +1,16 @@ +error: no rules expected `]` + --> tests/compiler/function/example/missing_result.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | source: "code", +7 | | }; + | |_____^ no rules expected this token in macro call + | +note: while trying to match `title` + --> src/compiler/function.rs + | + | (@internal [$title:expr] [$($source:tt)*] [$($result:tt)*] [title: $t:expr, $($rest:tt)*]) => { + | ^^^^^ + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/missing_source.rs b/tests/compiler/function/example/missing_source.rs new file mode 100644 index 000000000..a555d79cb --- /dev/null +++ b/tests/compiler/function/example/missing_source.rs @@ -0,0 +1,8 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + result: Ok("output"), + }; +} diff --git a/tests/compiler/function/example/missing_source.stderr b/tests/compiler/function/example/missing_source.stderr new file mode 100644 index 000000000..cc6ee2528 --- /dev/null +++ b/tests/compiler/function/example/missing_source.stderr @@ -0,0 +1,16 @@ +error: no rules expected `]` + --> tests/compiler/function/example/missing_source.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | result: Ok("output"), +7 | | }; + | |_____^ no rules expected this token in macro call + | +note: while trying to match `title` + --> src/compiler/function.rs + | + | (@internal [$title:expr] [$($source:tt)*] [$($result:tt)*] [title: $t:expr, $($rest:tt)*]) => { + | ^^^^^ + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/missing_title.rs b/tests/compiler/function/example/missing_title.rs new file mode 100644 index 000000000..eae56253d --- /dev/null +++ b/tests/compiler/function/example/missing_title.rs @@ -0,0 +1,8 @@ +use vrl::example; + +fn main() { + let _ex = example! { + source: "code", + result: Ok("output"), + }; +} diff --git a/tests/compiler/function/example/missing_title.stderr b/tests/compiler/function/example/missing_title.stderr new file mode 100644 index 000000000..0bb8b05d0 --- /dev/null +++ b/tests/compiler/function/example/missing_title.stderr @@ -0,0 +1,16 @@ +error: no rules expected `]` + --> tests/compiler/function/example/missing_title.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | source: "code", +6 | | result: Ok("output"), +7 | | }; + | |_____^ no rules expected this token in macro call + | +note: while trying to match `source` + --> src/compiler/function.rs + | + | (@internal [$($title:tt)*] [$source:expr] [$($result:tt)*] [source: $s:expr, $($rest:tt)*]) => { + | ^^^^^^ + = note: this error originates in the macro `$crate::example` which comes from the expansion of the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiler/function/example/pass.rs b/tests/compiler/function/example/pass.rs new file mode 100644 index 000000000..4cc927de3 --- /dev/null +++ b/tests/compiler/function/example/pass.rs @@ -0,0 +1,9 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + result: Ok("output"), + }; +} diff --git a/tests/compiler/function/example/unknown_field.rs b/tests/compiler/function/example/unknown_field.rs new file mode 100644 index 000000000..a4b7f3311 --- /dev/null +++ b/tests/compiler/function/example/unknown_field.rs @@ -0,0 +1,10 @@ +use vrl::example; + +fn main() { + let _ex = example! { + title: "test", + source: "code", + result: Ok("output"), + unknown_field: "value", + }; +} diff --git a/tests/compiler/function/example/unknown_field.stderr b/tests/compiler/function/example/unknown_field.stderr new file mode 100644 index 000000000..8f33b2e35 --- /dev/null +++ b/tests/compiler/function/example/unknown_field.stderr @@ -0,0 +1,18 @@ +error: no rules expected identifier `unknown_field` + --> tests/compiler/function/example/unknown_field.rs:4:15 + | +4 | let _ex = example! { + | _______________^ +5 | | title: "test", +6 | | source: "code", +7 | | result: Ok("output"), +8 | | unknown_field: "value", +9 | | }; + | |_____^ no rules expected this token in macro call + | +note: while trying to match `title` + --> src/compiler/function.rs + | + | (@internal [$title:expr] [$($source:tt)*] [$($result:tt)*] [title: $t:expr, $($rest:tt)*]) => { + | ^^^^^ + = note: this error originates in the macro `example` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/trybuild.rs b/tests/trybuild.rs new file mode 100644 index 000000000..5a32f5ab8 --- /dev/null +++ b/tests/trybuild.rs @@ -0,0 +1,53 @@ +//! Compile-time tests using trybuild. +//! +//! These tests verify that macros and other compile-time constructs correctly +//! reject invalid usage with appropriate error messages. +//! +//! # Organization +//! +//! Test files are organized to mirror the source code structure: +//! - `src/compiler/function.rs` → `tests/compiler/function/*/` +//! - `src/parser/foo.rs` → `tests/parser/foo/*/` +//! +//! # Adding New Tests +//! +//! 1. Create test files in the appropriate directory matching the source structure +//! 2. Add a new test function following the naming pattern: `{module}_{submodule}_{feature}` +//! 3. Use `t.pass()` for tests that should compile successfully +//! 4. Use `t.compile_fail()` for tests that should fail with specific error messages + +/// Tests for the example! macro defined in src/compiler/function.rs +/// +/// The example! macro accepts fields in any order and validates: +/// - All required fields are present (title, source, result) +/// - No duplicate fields +/// - No unknown fields +#[test] +fn compiler_function_example() { + let t = trybuild::TestCases::new(); + + // Valid usage + t.pass("tests/compiler/function/example/pass.rs"); + + // Duplicate field errors + t.compile_fail("tests/compiler/function/example/duplicate_title.rs"); + t.compile_fail("tests/compiler/function/example/duplicate_source.rs"); + t.compile_fail("tests/compiler/function/example/duplicate_result.rs"); + + // Missing field errors + t.compile_fail("tests/compiler/function/example/missing_title.rs"); + t.compile_fail("tests/compiler/function/example/missing_source.rs"); + t.compile_fail("tests/compiler/function/example/missing_result.rs"); + + // Unknown field errors + t.compile_fail("tests/compiler/function/example/unknown_field.rs"); +} + +// Add more test functions here as needed: +// +// #[test] +// fn parser_something() { +// let t = trybuild::TestCases::new(); +// t.pass("tests/parser/something/pass.rs"); +// t.compile_fail("tests/parser/something/fail.rs"); +// } From 1dd10f9894639350bb67265a63af3ce4b512a37d Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 15:09:54 -0800 Subject: [PATCH 3/6] docs: add code coverage documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added COVERAGE.md with quick start guide for running cargo-llvm-cov coverage reports. Includes: - Installation and basic usage commands - HTML report location - Text summary commands - Note about trybuild tests not appearing in coverage - Current project coverage baseline (~74% lines, ~68% functions) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- COVERAGE.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 COVERAGE.md diff --git a/COVERAGE.md b/COVERAGE.md new file mode 100644 index 000000000..4c2678769 --- /dev/null +++ b/COVERAGE.md @@ -0,0 +1,35 @@ +# Code Coverage + +## Quick Start + +```bash +# Install cargo-llvm-cov (first time only) +cargo install cargo-llvm-cov + +# Run coverage and open HTML report +cargo llvm-cov --html --open + +# Run coverage for specific tests +cargo llvm-cov --html --open -- test_name +``` + +## Reports + +HTML report location: `target/llvm-cov/html/index.html` + +## Coverage Summary + +View text summary: +```bash +cargo llvm-cov report --summary-only +``` + +## Notes + +- Trybuild compile-time tests do not appear in coverage reports (they verify compile errors, not runtime behavior) +- Coverage measures runtime test execution only +- Current project coverage: ~74% lines, ~68% functions + +## Reference + +- [cargo-llvm-cov documentation](https://github.com/taiki-e/cargo-llvm-cov) From 45e670bfd0dd5a6da783c8b3c2171a4462232b3e Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 17:27:56 -0800 Subject: [PATCH 4/6] chore: pin trybuild to version 1.0.114 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pin trybuild dev dependency to specific version for reproducible builds. Verified all trybuild tests pass with pinned version. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c37980161..c8f1e5333 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -263,7 +263,7 @@ regex = { version = "1", default-features = false, features = ["std", "perf", "u paste = { version = "1", default-features = false } proptest = { version = "1" } proptest-derive = { version = "0.6" } -trybuild = "1" +trybuild = "1.0.114" [build-dependencies] lalrpop = { version = "0.22", default-features = false } From 8146863e83f36a3f1381d3b95a455c5f002cf0b2 Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 18:34:21 -0800 Subject: [PATCH 5/6] fix: make year-dependent tests work across all years MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced hardcoded year values in test expectations with a {CURRENT_YEAR} placeholder that gets replaced at test runtime with the actual current year. This prevents tests from failing when the year changes. Changes: - Added replace_current_year_placeholder() helper function in test framework - Updated parse_klog and parse_linux_authorization tests to use placeholder - Refactored duplicate code following DRY principles All 801 tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/stdlib/parse_klog.rs | 2 +- src/stdlib/parse_linux_authorization.rs | 2 +- src/test/mod.rs | 11 ++++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/stdlib/parse_klog.rs b/src/stdlib/parse_klog.rs index c1c86768d..841f0b3b5 100644 --- a/src/stdlib/parse_klog.rs +++ b/src/stdlib/parse_klog.rs @@ -89,7 +89,7 @@ impl Function for ParseKlog { "level": "info", "line": 70, "message": "hello from klog", - "timestamp": "2025-05-05T17:59:40.692994Z" + "timestamp": "{CURRENT_YEAR}-05-05T17:59:40.692994Z" }"#}), }] } diff --git a/src/stdlib/parse_linux_authorization.rs b/src/stdlib/parse_linux_authorization.rs index 7caef0574..009d312b5 100644 --- a/src/stdlib/parse_linux_authorization.rs +++ b/src/stdlib/parse_linux_authorization.rs @@ -27,7 +27,7 @@ impl Function for ParseLinuxAuthorization { "hostname": "localhost", "message": "Accepted publickey for eng from 10.1.1.1 port 8888 ssh2: RSA SHA256:foobar", "procid": 1111, - "timestamp": "2025-03-23T01:49:58Z" + "timestamp": "{CURRENT_YEAR}-03-23T01:49:58Z" }"#}), }] } diff --git a/src/test/mod.rs b/src/test/mod.rs index ceab7fdb8..955bd5108 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -208,7 +208,7 @@ fn process_result( let got_value = vrl_value_to_json_value(got); let mut failed = false; - let want = test.result.clone(); + let want = replace_current_year_placeholder(test.result.clone()); let want_value = if want.starts_with("r'") && want.ends_with('\'') { match regex::Regex::new(&want[2..want.len() - 1].replace("\\'", "'")) { Ok(regex) => regex.to_string().into(), @@ -257,7 +257,7 @@ fn process_result( Err(err) => { let mut failed = false; let got = err.to_string().trim().to_owned(); - let want = test.result.clone().trim().to_owned(); + let want = replace_current_year_placeholder(test.result.clone().trim().to_owned()); if (test.result_approx && compare_partial_diagnostic(&got, &want)) || got == want { println!("{}{}", Colour::Green.bold().paint("OK"), timings); @@ -319,7 +319,7 @@ fn process_compilation_diagnostics( let got = formatter.to_string(); let got = got.trim(); - let want = test.result.clone(); + let want = replace_current_year_placeholder(test.result.clone()); let want = want.trim(); if (test.result_approx && compare_partial_diagnostic(got, want)) || got == want { @@ -404,6 +404,11 @@ fn print_result( std::process::exit(code) } +fn replace_current_year_placeholder(input: String) -> String { + let current_year = Utc::now().format("%Y").to_string(); + input.replace("{CURRENT_YEAR}", ¤t_year) +} + fn compare_partial_diagnostic(got: &str, want: &str) -> bool { got.lines() .filter(|line| line.trim().starts_with("error[E")) From b52cd30f3afb0cd90a2680bacd84e2bc2c7b5f3b Mon Sep 17 00:00:00 2001 From: Benson Fung Date: Thu, 15 Jan 2026 18:58:18 -0800 Subject: [PATCH 6/6] chore: update cargo-deny to 0.19.0 to fix CVSS 4.0 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated cargo-deny from version 0.18.3 to 0.19.0 to resolve the "unsupported CVSS version: 4.0" error that occurs when parsing the RustSec advisory database. The fix was introduced in cargo-deny 0.18.6 by updating the rustsec dependency to version 0.31, which includes CVSS 4.0 support. Changes: - Updated cargo-deny version in scripts/check_deny.sh from 0.18.3 to 0.19.0 - Verified all checks pass: advisories, bans, licenses, and sources References: - GitHub Issue: https://github.com/EmbarkStudios/cargo-deny/issues/804 - Fix PR: https://github.com/EmbarkStudios/cargo-deny/pull/805 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- scripts/check_deny.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/check_deny.sh b/scripts/check_deny.sh index 0a5825c22..842a1c8fb 100755 --- a/scripts/check_deny.sh +++ b/scripts/check_deny.sh @@ -1,8 +1,8 @@ #!/bin/bash -if ! cargo install --list | grep -q "cargo-deny v0.18.3"; then +if ! cargo install --list | grep -q "cargo-deny v0.19.0"; then echo "Install cargo-deny" - cargo install cargo-deny --version 0.18.3 --force --locked + cargo install cargo-deny --version 0.19.0 --force --locked fi echo "Check deny"