ralph_core/testing/
scenario.rs1use crate::config::RalphConfig;
4use crate::event_reader::Event;
5use super::mock_backend::MockBackend;
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)
88 .with_iterations(3);
89
90 assert_eq!(scenario.name, "test");
91 assert_eq!(scenario.expected_iterations, 3);
92 }
93
94 #[test]
95 fn test_scenario_runner_executes() {
96 let backend = MockBackend::new(vec!["ok".into()]);
97 let runner = ScenarioRunner::new(backend);
98
99 let config = RalphConfig::default();
100 let scenario = Scenario::new("test", config).with_iterations(1);
101
102 let trace = runner.run(&scenario);
103 assert_eq!(trace.iterations, 1);
104 }
105
106 #[test]
107 fn test_mock_backend_simulates_hat_execution() {
108 let responses = vec![
110 r#"Building feature...
111<event topic="build.done">
112tests: pass
113lint: pass
114typecheck: pass
115</event>"#.to_string(),
116 ];
117
118 let backend = MockBackend::new(responses);
119
120 let output = backend.execute("You are the builder hat. Build feature X.");
122
123 assert!(output.contains("build.done"));
125 assert!(output.contains("tests: pass"));
126
127 assert_eq!(backend.execution_count(), 1);
129 let executions = backend.executions();
130 assert_eq!(executions[0].prompt, "You are the builder hat. Build feature X.");
131 }
132}