punch_runtime/automation/
common.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct WindowInfo {
11 pub title: String,
13 pub app_name: String,
15 pub position: Option<(i32, i32)>,
17 pub size: Option<(u32, u32)>,
19 pub is_minimized: bool,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct UiElement {
26 pub element_id: String,
29 pub role: String,
31 pub label: Option<String>,
33 pub value: Option<String>,
35 pub enabled: bool,
37}
38
39#[derive(Debug, Clone, Default, Serialize, Deserialize)]
41pub struct UiSelector {
42 pub role: Option<String>,
44 pub label: Option<String>,
46 pub value: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct ScreenshotResult {
53 pub png_base64: String,
55 pub width: u32,
57 pub height: u32,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct OcrResult {
64 pub text: String,
66 pub regions: Vec<OcrRegion>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct OcrRegion {
73 pub text: String,
75 pub bounds: Option<(i32, i32, u32, u32)>,
77 pub confidence: f32,
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_window_info_serde_roundtrip() {
87 let info = WindowInfo {
88 title: "My Window".to_string(),
89 app_name: "Safari".to_string(),
90 position: Some((100, 200)),
91 size: Some((1920, 1080)),
92 is_minimized: false,
93 };
94 let json = serde_json::to_string(&info).expect("serialize");
95 let deser: WindowInfo = serde_json::from_str(&json).expect("deserialize");
96 assert_eq!(deser.title, "My Window");
97 assert_eq!(deser.size, Some((1920, 1080)));
98 }
99
100 #[test]
101 fn test_window_info_none_optionals() {
102 let info = WindowInfo {
103 title: String::new(),
104 app_name: "Finder".to_string(),
105 position: None,
106 size: None,
107 is_minimized: true,
108 };
109 let json = serde_json::to_string(&info).expect("serialize");
110 let deser: WindowInfo = serde_json::from_str(&json).expect("deserialize");
111 assert!(deser.position.is_none());
112 assert!(deser.is_minimized);
113 }
114
115 #[test]
116 fn test_ui_element_serde_roundtrip() {
117 let elem = UiElement {
118 element_id: "Safari:button:3".to_string(),
119 role: "button".to_string(),
120 label: Some("Close".to_string()),
121 value: None,
122 enabled: true,
123 };
124 let json = serde_json::to_string(&elem).expect("serialize");
125 let deser: UiElement = serde_json::from_str(&json).expect("deserialize");
126 assert_eq!(deser.element_id, "Safari:button:3");
127 assert_eq!(deser.role, "button");
128 assert!(deser.enabled);
129 }
130
131 #[test]
132 fn test_ui_selector_defaults() {
133 let sel = UiSelector::default();
134 assert!(sel.role.is_none());
135 assert!(sel.label.is_none());
136 assert!(sel.value.is_none());
137 }
138
139 #[test]
140 fn test_screenshot_result_serde() {
141 let result = ScreenshotResult {
142 png_base64: "iVBORw0KGgo=".to_string(),
143 width: 1920,
144 height: 1080,
145 };
146 let json = serde_json::to_string(&result).expect("serialize");
147 let deser: ScreenshotResult = serde_json::from_str(&json).expect("deserialize");
148 assert_eq!(deser.width, 1920);
149 assert_eq!(deser.height, 1080);
150 }
151
152 #[test]
153 fn test_ocr_result_serde() {
154 let result = OcrResult {
155 text: "Hello World".to_string(),
156 regions: vec![OcrRegion {
157 text: "Hello".to_string(),
158 bounds: Some((10, 20, 50, 15)),
159 confidence: 0.95,
160 }],
161 };
162 let json = serde_json::to_string(&result).expect("serialize");
163 let deser: OcrResult = serde_json::from_str(&json).expect("deserialize");
164 assert_eq!(deser.regions.len(), 1);
165 assert!((deser.regions[0].confidence - 0.95).abs() < f32::EPSILON);
166 }
167
168 #[test]
169 fn test_ocr_empty_regions() {
170 let result = OcrResult {
171 text: String::new(),
172 regions: Vec::new(),
173 };
174 let json = serde_json::to_string(&result).expect("serialize");
175 let deser: OcrResult = serde_json::from_str(&json).expect("deserialize");
176 assert!(deser.text.is_empty());
177 assert!(deser.regions.is_empty());
178 }
179
180 #[test]
181 fn test_ocr_region_no_bounds() {
182 let region = OcrRegion {
183 text: "test".to_string(),
184 bounds: None,
185 confidence: 0.5,
186 };
187 let json = serde_json::to_string(®ion).expect("serialize");
188 let deser: OcrRegion = serde_json::from_str(&json).expect("deserialize");
189 assert!(deser.bounds.is_none());
190 }
191}