ralph_core/testing/
scenario.rs1use super::mock_backend::MockBackend;
4use crate::config::RalphConfig;
5use crate::event_reader::Event;
6
7#[derive(Debug)]
9pub struct Scenario {
10 pub name: String,
11 pub config: RalphConfig,
12 pub expected_events: Vec<Event>,
13 pub expected_iterations: usize,
14}
15
16impl Scenario {
17 pub fn new(name: impl Into<String>, config: RalphConfig) -> Self {
19 Self {
20 name: name.into(),
21 config,
22 expected_events: Vec::new(),
23 expected_iterations: 0,
24 }
25 }
26
27 pub fn with_events(mut self, events: Vec<Event>) -> Self {
29 self.expected_events = events;
30 self
31 }
32
33 pub fn with_iterations(mut self, count: usize) -> Self {
35 self.expected_iterations = count;
36 self
37 }
38}
39
40pub struct ScenarioRunner {
42 backend: MockBackend,
43}
44
45impl ScenarioRunner {
46 pub fn new(backend: MockBackend) -> Self {
48 Self { backend }
49 }
50
51 pub fn run(&self, scenario: &Scenario) -> ExecutionTrace {
53 let mut iterations = 0;
54 let events = Vec::new();
55
56 while iterations < scenario.expected_iterations {
58 let prompt = format!("Iteration {}", iterations + 1);
59 let _response = self.backend.execute(&prompt);
60 iterations += 1;
61 }
62
63 ExecutionTrace {
64 iterations,
65 events,
66 final_state: iterations as u32,
67 }
68 }
69}
70
71#[derive(Debug)]
73pub struct ExecutionTrace {
74 pub iterations: usize,
75 pub events: Vec<Event>,
76 pub final_state: u32,
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::config::RalphConfig;
83
84 #[test]
85 fn test_scenario_creation() {
86 let config = RalphConfig::default();
87 let scenario = Scenario::new("test", config).with_iterations(3);
88
89 assert_eq!(scenario.name, "test");
90 assert_eq!(scenario.expected_iterations, 3);
91 }
92
93 #[test]
94 fn test_scenario_runner_executes() {
95 let backend = MockBackend::new(vec!["ok".into()]);
96 let runner = ScenarioRunner::new(backend);
97
98 let config = RalphConfig::default();
99 let scenario = Scenario::new("test", config).with_iterations(1);
100
101 let trace = runner.run(&scenario);
102 assert_eq!(trace.iterations, 1);
103 }
104
105 #[test]
106 fn test_mock_backend_simulates_hat_execution() {
107 let responses = vec![
109 r#"Building feature...
110<event topic="build.done">
111tests: pass
112lint: pass
113typecheck: pass
114audit: pass
115coverage: pass
116</event>"#
117 .to_string(),
118 ];
119
120 let backend = MockBackend::new(responses);
121
122 let output = backend.execute("You are the builder hat. Build feature X.");
124
125 assert!(output.contains("build.done"));
127 assert!(output.contains("tests: pass"));
128
129 assert_eq!(backend.execution_count(), 1);
131 let executions = backend.executions();
132 assert_eq!(
133 executions[0].prompt,
134 "You are the builder hat. Build feature X."
135 );
136 }
137}