prosaic_project/
scenario.rs1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Scenario {
8 pub name: String,
9 #[serde(default)]
10 pub description: String,
11 #[serde(default)]
12 pub engine: ScenarioEngineOverride,
13 pub events: Vec<ScenarioEvent>,
14 #[serde(default)]
15 pub expected: Option<Expected>,
16}
17
18#[derive(Debug, Clone, Default, Serialize, Deserialize)]
19#[serde(default)]
20pub struct ScenarioEngineOverride {
21 pub variation: Option<String>,
22 pub language: Option<String>,
23 pub salience_thresholds: Option<crate::manifest::SalienceThresholdsConfig>,
24 pub faithfulness_min: Option<f64>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ScenarioEvent {
29 pub template: String,
30 #[serde(default)]
32 pub context: HashMap<String, toml::Value>,
33 #[serde(default)]
35 pub rst_relation: Option<String>,
36}
37
38#[derive(Debug, Clone, Default, Serialize, Deserialize)]
39#[serde(default)]
40pub struct Expected {
41 pub output: Option<String>,
42 pub faithfulness_min: Option<f64>,
43 pub discourse: Vec<ExpectedDiscourse>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct ExpectedDiscourse {
48 pub event_index: usize,
49 #[serde(default)]
50 pub reference_form: Option<String>,
51 #[serde(default)]
52 pub connective_contains: Option<String>,
53 #[serde(default)]
54 pub transition: Option<String>,
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn parse_minimal_scenario() {
63 let toml_str = r#"
64 name = "smoke"
65 [[events]]
66 template = "code.added"
67 context = { name = "Foo", entity_type = "class" }
68 "#;
69 let s: Scenario = toml::from_str(toml_str).unwrap();
70 assert_eq!(s.name, "smoke");
71 assert_eq!(s.events.len(), 1);
72 assert_eq!(s.events[0].template, "code.added");
73 assert_eq!(
74 s.events[0].context.get("name").unwrap().as_str().unwrap(),
75 "Foo"
76 );
77 }
78
79 #[test]
80 fn parse_full_scenario_with_expectations() {
81 let toml_str = r#"
82 name = "PR 142"
83 description = "auth refactor"
84
85 [engine]
86 variation = "fixed"
87 language = "en"
88 faithfulness_min = 0.9
89
90 [[events]]
91 template = "code.modified"
92 context = { name = "UserService", consumer_count = 6 }
93
94 [[events]]
95 template = "code.moved"
96 context = { name = "UserService" }
97 rst_relation = "elaboration"
98
99 [expected]
100 output = "..."
101 faithfulness_min = 0.85
102
103 [[expected.discourse]]
104 event_index = 1
105 reference_form = "Pronoun"
106
107 [[expected.discourse]]
108 event_index = 1
109 connective_contains = "also"
110 "#;
111 let s: Scenario = toml::from_str(toml_str).unwrap();
112 assert_eq!(s.events.len(), 2);
113 assert_eq!(s.events[1].rst_relation.as_deref(), Some("elaboration"));
114 let exp = s.expected.unwrap();
115 assert_eq!(exp.faithfulness_min, Some(0.85));
116 assert_eq!(exp.discourse.len(), 2);
117 assert_eq!(exp.discourse[0].reference_form.as_deref(), Some("Pronoun"));
118 assert_eq!(
119 exp.discourse[1].connective_contains.as_deref(),
120 Some("also")
121 );
122 }
123
124 #[test]
125 fn parse_array_context_value() {
126 let toml_str = r#"
127 name = "list"
128 [[events]]
129 template = "code.modified"
130 context = { name = "X", consumers = ["a", "b", "c"] }
131 "#;
132 let s: Scenario = toml::from_str(toml_str).unwrap();
133 let arr = s.events[0]
134 .context
135 .get("consumers")
136 .unwrap()
137 .as_array()
138 .unwrap();
139 assert_eq!(arr.len(), 3);
140 assert_eq!(arr[0].as_str().unwrap(), "a");
141 }
142}