From 9a6248258d2435e2e122409acb30a24b290add99 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Apr 2026 10:23:54 +0000 Subject: [PATCH 1/2] fix: correct file-contains check logic (was inverted) The `contains` parameter was passed as `false`, causing file-contains to verify that the string is NOT present instead of verifying it IS. Co-Authored-By: Claude Opus 4.6 --- src/assertions/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assertions/mod.rs b/src/assertions/mod.rs index ca6b225..caa7859 100644 --- a/src/assertions/mod.rs +++ b/src/assertions/mod.rs @@ -87,7 +87,7 @@ impl AssertionChecker { "file-contains" => { let file = check.command.file.as_ref().ok_or("Missing file")?; let contains = check.command.contains.as_ref().ok_or("Missing contains")?; - file::check_file_content(&self.work_dir, file, contains, false) + file::check_file_content(&self.work_dir, file, contains, true) } "log-contains" => { let pattern = check.command.pattern.as_ref().ok_or("Missing pattern")?; From 289d4d1a6b94a7a3eae7ed5daa218fa1f74b431b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Apr 2026 10:26:50 +0000 Subject: [PATCH 2/2] test: add integration test for file-contains via evaluate_check Verify that file-contains correctly checks string presence (not absence) through the full evaluate_check dispatch path. Co-Authored-By: Claude Opus 4.6 --- src/assertions/tests.rs | 48 +++++++++++++++++++++++++++++++++++++++++ src/models/check.rs | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/assertions/tests.rs b/src/assertions/tests.rs index 7623c46..d7638e8 100644 --- a/src/assertions/tests.rs +++ b/src/assertions/tests.rs @@ -3,6 +3,7 @@ #[cfg(test)] mod tests { use crate::assertions::AssertionChecker; + use crate::models::check::CheckData; use std::path::Path; fn create_checker(log_file: &str) -> AssertionChecker { @@ -260,4 +261,51 @@ mod tests { "nonexistent log should produce empty data" ); } + + #[test] + fn test_file_contains_via_evaluate_check() { + let work_dir = tempfile::tempdir().unwrap(); + let test_file = work_dir.path().join("report.md"); + std::fs::write(&test_file, "Screened patents: 42").unwrap(); + + let empty_log = work_dir.path().join("empty.log"); + std::fs::write(&empty_log, "").unwrap(); + + let checker = AssertionChecker::new(&empty_log, work_dir.path(), None); + + let check = crate::models::CheckStep { + name: "contains_patent_data".to_string(), + command: CheckData { + command: "file-contains".to_string(), + file: Some("report.md".to_string()), + contains: Some("Screened patents".to_string()), + ..Default::default() + }, + deny: false, + }; + + let result = checker.evaluate_check(&check); + assert!( + result.is_ok(), + "file-contains should pass when string is present" + ); + + // String not in file should fail + let check_missing = crate::models::CheckStep { + name: "contains_missing".to_string(), + command: CheckData { + command: "file-contains".to_string(), + file: Some("report.md".to_string()), + contains: Some("NOTPRESENT".to_string()), + ..Default::default() + }, + deny: false, + }; + + let result = checker.evaluate_check(&check_missing); + assert!( + result.is_err(), + "file-contains should fail when string is absent" + ); + } } diff --git a/src/models/check.rs b/src/models/check.rs index 4f4dc1b..39c5793 100644 --- a/src/models/check.rs +++ b/src/models/check.rs @@ -13,7 +13,7 @@ pub struct CheckStep { } /// Check data - command type and arguments -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Default, Deserialize, Serialize)] pub struct CheckData { pub command: String, #[serde(default)]