use super::*;
use crate::snippets::types::{SnippetMetadata, SourceOrigin};
use crate::snippets::validators::SnippetValidator;
use tracing_test::traced_test;
struct CappedValidator {
language: crate::snippets::types::Language,
ceiling: ValidationLevel,
}
impl SnippetValidator for CappedValidator {
fn language(&self) -> crate::snippets::types::Language {
self.language
}
fn is_available(&self) -> bool {
true
}
fn validate(
&self,
_snippet: &Snippet,
_level: ValidationLevel,
_timeout_secs: u64,
) -> Result<(SnippetStatus, Option<String>)> {
Ok((SnippetStatus::Pass, None))
}
fn max_level(&self) -> ValidationLevel {
self.ceiling
}
}
fn network_snippet() -> Snippet {
Snippet {
id: None,
path: "example.md".into(),
language: crate::snippets::types::Language::Rust,
title: None,
code: "fn main() {}".into(),
start_line: 1,
block_index: 0,
annotation: None,
metadata: SnippetMetadata {
side_effect: Some(SideEffectClass::Network),
..SnippetMetadata::default()
},
source_origin: SourceOrigin {
path: "example.md".into(),
line: 1,
block_index: 0,
},
}
}
#[traced_test]
#[test]
fn non_batching_validator_skips_the_batch_log_and_uses_the_fallback_log() {
let mut registry = ValidatorRegistry::new();
registry.register(Box::new(CappedValidator {
language: crate::snippets::types::Language::Rust,
ceiling: ValidationLevel::Run,
}));
let config = RunnerConfig {
level: ValidationLevel::Syntax,
parallelism: 1,
cache_dir: None,
allowed_side_effects: vec![SideEffectClass::Network],
..RunnerConfig::default()
};
let summary =
run_validation(&[network_snippet(), network_snippet()], ®istry, &config).expect("validation completes");
assert_eq!(summary.passed, 2);
assert!(!logs_contain("Starting batched snippet validation"));
assert!(logs_contain("Starting per-snippet validation"));
assert!(logs_contain("Finished per-snippet validation"));
}
struct DecliningBatchValidator;
impl SnippetValidator for DecliningBatchValidator {
fn language(&self) -> crate::snippets::types::Language {
crate::snippets::types::Language::Rust
}
fn is_available(&self) -> bool {
true
}
fn validate(
&self,
_snippet: &Snippet,
_level: ValidationLevel,
_timeout_secs: u64,
) -> Result<(SnippetStatus, Option<String>)> {
Ok((SnippetStatus::Pass, None))
}
fn validate_batch_in_session(
&self,
_snippets: &[&Snippet],
_level: ValidationLevel,
_timeout_secs: u64,
_session: Option<&crate::snippets::session::ValidationSession>,
) -> Option<Result<Vec<(SnippetStatus, Option<String>)>>> {
None
}
fn max_level(&self) -> ValidationLevel {
ValidationLevel::Run
}
fn supports_batching(&self) -> bool {
true
}
}
#[traced_test]
#[test]
fn batching_validator_that_declines_a_group_logs_the_fallback_explicitly() {
let mut registry = ValidatorRegistry::new();
registry.register(Box::new(DecliningBatchValidator));
let config = RunnerConfig {
level: ValidationLevel::Syntax,
parallelism: 1,
cache_dir: None,
allowed_side_effects: vec![SideEffectClass::Network],
..RunnerConfig::default()
};
let summary = run_validation(&[network_snippet()], ®istry, &config).expect("validation completes");
assert_eq!(summary.results[0].status, SnippetStatus::Pass);
assert!(logs_contain("Starting batched snippet validation"));
assert!(logs_contain(
"Batch validation declined for this group; falling back to per-snippet validation"
));
assert!(logs_contain("Starting per-snippet validation"));
}