1use crate::backend::{Assertion, TestSessionResult};
2use crate::config::Config;
3use crate::events::{AssertionEvent, EventEmitter, on_failure, on_success};
4use crate::frontend::ConsoleRenderer;
5use once_cell::sync::Lazy;
6use std::cell::RefCell;
7use std::collections::HashSet;
8use std::sync::RwLock;
9
10pub(crate) static GLOBAL_CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| RwLock::new(Config::new()));
11
12thread_local! {
13 static TEST_SESSION: RefCell<TestSessionResult> = RefCell::new(TestSessionResult::default());
14 static REPORTED_MESSAGES: RefCell<HashSet<String>> = RefCell::new(HashSet::new());
16 static DEDUPLICATE_ENABLED: RefCell<bool> = const { RefCell::new(true) };
18 static SILENT_MODE: RefCell<bool> = const { RefCell::new(false) };
20}
21
22pub struct Reporter;
23
24impl Reporter {
25 pub fn init() {
27 on_success(|result| {
29 Self::handle_success_event(result);
30 });
31
32 on_failure(|result| {
34 Self::handle_failure_event(result);
35 });
36 }
37
38 fn handle_success_event(result: Assertion<()>) {
40 TEST_SESSION.with(|session| {
41 let mut session = session.borrow_mut();
42 session.passed_count += 1;
43 });
44
45 let silent = SILENT_MODE.with(|silent| *silent.borrow());
47 if silent {
48 return;
49 }
50
51 let should_report = DEDUPLICATE_ENABLED.with(|enabled| {
53 if !*enabled.borrow() {
54 return true;
56 }
57
58 REPORTED_MESSAGES.with(|msgs| {
60 let key = format!("{:?}", result);
61 let mut messages = msgs.borrow_mut();
62 if !messages.contains(&key) {
63 messages.insert(key);
64 true
65 } else {
66 false
67 }
68 })
69 });
70
71 if should_report {
72 let config = GLOBAL_CONFIG.read().unwrap();
73 let renderer = ConsoleRenderer::new(Config {
74 use_colors: config.use_colors,
75 use_unicode_symbols: config.use_unicode_symbols,
76 show_success_details: config.show_success_details,
77 enhanced_output: config.enhanced_output,
78 });
79 renderer.print_success(&result);
80 }
81 }
82
83 fn handle_failure_event(result: Assertion<()>) {
85 TEST_SESSION.with(|session| {
86 let mut session = session.borrow_mut();
87 session.failed_count += 1;
88 session.failures.push(result.clone());
89 });
90
91 let silent = SILENT_MODE.with(|silent| *silent.borrow());
93 if silent {
94 return;
95 }
96
97 let should_report = DEDUPLICATE_ENABLED.with(|enabled| {
99 if !*enabled.borrow() {
100 return true;
102 }
103
104 let key = format!("{:?}", result);
106 REPORTED_MESSAGES.with(|msgs| {
107 let mut messages = msgs.borrow_mut();
108 if !messages.contains(&key) {
109 messages.insert(key);
110 true
111 } else {
112 false
113 }
114 })
115 });
116
117 if should_report {
118 let config = GLOBAL_CONFIG.read().unwrap();
119 let renderer = ConsoleRenderer::new(Config {
120 use_colors: config.use_colors,
121 use_unicode_symbols: config.use_unicode_symbols,
122 show_success_details: config.show_success_details,
123 enhanced_output: config.enhanced_output,
124 });
125 renderer.print_failure(&result);
126 }
127 }
128
129 pub fn reset_message_cache() {
131 REPORTED_MESSAGES.with(|msgs| {
132 msgs.borrow_mut().clear();
133 });
134 }
135
136 pub fn enable_deduplication() {
138 DEDUPLICATE_ENABLED.with(|enabled| {
139 *enabled.borrow_mut() = true;
140 });
141 }
142
143 pub fn disable_deduplication() {
145 DEDUPLICATE_ENABLED.with(|enabled| {
146 *enabled.borrow_mut() = false;
147 });
148 }
149
150 pub fn enable_silent_mode() {
152 SILENT_MODE.with(|silent| {
153 *silent.borrow_mut() = true;
154 });
155 }
156
157 pub fn disable_silent_mode() {
159 SILENT_MODE.with(|silent| {
160 *silent.borrow_mut() = false;
161 });
162 }
163
164 pub fn summarize() {
165 TEST_SESSION.with(|session| {
166 let session = session.borrow();
167 let config = GLOBAL_CONFIG.read().unwrap();
168 let renderer = ConsoleRenderer::new(Config {
169 use_colors: config.use_colors,
170 use_unicode_symbols: config.use_unicode_symbols,
171 show_success_details: config.show_success_details,
172 enhanced_output: config.enhanced_output,
173 });
174 renderer.print_session_summary(&session);
175 });
176
177 EventEmitter::emit(AssertionEvent::SessionCompleted);
179
180 Self::reset_message_cache();
182
183 Self::enable_deduplication();
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::backend::assertions::AssertionStep;
192 use crate::backend::assertions::sentence::AssertionSentence;
193
194 fn create_test_assertion(passed: bool) -> Assertion<()> {
196 let mut assertion = Assertion::new((), "test_value");
198
199 assertion.steps.push(AssertionStep {
201 sentence: AssertionSentence::new("be", if passed { "correct" } else { "incorrect" }),
202 passed,
203 logical_op: None,
204 });
205
206 assertion.is_final = false;
208
209 assertion
210 }
211
212 fn record_failure(assertion: Assertion<()>) {
215 TEST_SESSION.with(|session| {
216 let mut session = session.borrow_mut();
217 session.failed_count += 1;
218 session.failures.push(assertion);
219 });
220 }
221
222 #[test]
223 fn test_reporter_deduplication_flags() {
224 Reporter::enable_deduplication();
226 DEDUPLICATE_ENABLED.with(|enabled| {
227 assert_eq!(*enabled.borrow(), true);
228 });
229
230 Reporter::disable_deduplication();
231 DEDUPLICATE_ENABLED.with(|enabled| {
232 assert_eq!(*enabled.borrow(), false);
233 });
234
235 Reporter::enable_deduplication();
237 }
238
239 #[test]
240 fn test_reporter_silent_mode() {
241 Reporter::enable_silent_mode();
243 SILENT_MODE.with(|silent| {
244 assert_eq!(*silent.borrow(), true);
245 });
246
247 Reporter::disable_silent_mode();
248 SILENT_MODE.with(|silent| {
249 assert_eq!(*silent.borrow(), false);
250 });
251 }
252
253 #[test]
254 fn test_reporter_message_cache() {
255 REPORTED_MESSAGES.with(|msgs| {
257 msgs.borrow_mut().insert("test_message".to_string());
258 });
259
260 REPORTED_MESSAGES.with(|msgs| {
262 assert!(msgs.borrow().contains("test_message"));
263 });
264
265 Reporter::reset_message_cache();
267
268 REPORTED_MESSAGES.with(|msgs| {
270 assert!(!msgs.borrow().contains("test_message"));
271 });
272 }
273
274 #[test]
275 fn test_handle_success_event() {
276 TEST_SESSION.with(|session| {
278 *session.borrow_mut() = TestSessionResult::default();
279 });
280
281 Reporter::disable_deduplication();
283
284 let assertion = create_test_assertion(true);
286 Reporter::handle_success_event(assertion);
287
288 TEST_SESSION.with(|session| {
290 let session = session.borrow();
291 assert_eq!(session.passed_count, 1);
292 assert_eq!(session.failed_count, 0);
293 assert_eq!(session.failures.len(), 0);
294 });
295
296 Reporter::enable_deduplication();
298 Reporter::reset_message_cache();
299 }
300
301 #[test]
302 fn test_session_tracking() {
303 TEST_SESSION.with(|session| {
305 *session.borrow_mut() = TestSessionResult::default();
306 });
307
308 let assertion = create_test_assertion(false);
310
311 record_failure(assertion.clone());
313
314 TEST_SESSION.with(|session| {
316 let session = session.borrow();
317 assert_eq!(session.passed_count, 0);
318 assert_eq!(session.failed_count, 1);
319 assert_eq!(session.failures.len(), 1);
320
321 if !session.failures.is_empty() {
323 let first_failure = &session.failures[0];
324 assert_eq!(first_failure.expr_str, assertion.expr_str);
325 assert_eq!(first_failure.steps.len(), assertion.steps.len());
326 assert_eq!(first_failure.steps[0].passed, assertion.steps[0].passed);
327 }
328 });
329
330 TEST_SESSION.with(|session| {
332 *session.borrow_mut() = TestSessionResult::default();
333 });
334 }
335
336 #[test]
337 fn test_silent_mode() {
338 Reporter::enable_silent_mode();
340
341 SILENT_MODE.with(|silent| {
343 assert_eq!(*silent.borrow(), true);
344 });
345
346 TEST_SESSION.with(|session| {
349 *session.borrow_mut() = TestSessionResult::default();
350 });
351
352 Reporter::handle_success_event(create_test_assertion(true));
354
355 TEST_SESSION.with(|session| {
357 let session = session.borrow();
358 assert_eq!(session.passed_count, 1);
359 });
360
361 Reporter::disable_silent_mode();
363
364 SILENT_MODE.with(|silent| {
366 assert_eq!(*silent.borrow(), false);
367 });
368
369 TEST_SESSION.with(|session| {
371 *session.borrow_mut() = TestSessionResult::default();
372 });
373 }
374
375 #[test]
376 fn test_deduplication() {
377 Reporter::enable_deduplication();
379 Reporter::reset_message_cache();
380
381 TEST_SESSION.with(|session| {
383 *session.borrow_mut() = TestSessionResult::default();
384 });
385
386 let assertion = create_test_assertion(true);
388
389 Reporter::handle_success_event(assertion.clone());
391 Reporter::handle_success_event(assertion);
392
393 REPORTED_MESSAGES.with(|msgs| {
395 assert_eq!(msgs.borrow().len(), 1);
396 });
397
398 TEST_SESSION.with(|session| {
400 let session = session.borrow();
401 assert_eq!(session.passed_count, 2);
402 });
403
404 Reporter::reset_message_cache();
406 }
407}