fluent_test/frontend/
console.rs1use crate::backend::LogicalOp;
2use crate::backend::{Assertion, TestSessionResult};
3use crate::config::Config;
4use colored::*;
5
6pub struct ConsoleRenderer {
8 config: Config,
9}
10
11impl ConsoleRenderer {
12 pub fn new(config: Config) -> Self {
14 Self { config }
15 }
16
17 pub fn render_success(&self, result: &Assertion<()>) -> String {
19 let message = self.build_assertion_message(result);
20
21 if self.config.show_success_details {
22 let prefix = if self.config.use_unicode_symbols { "✓ " } else { "+ " };
23 if self.config.use_colors {
24 return format!("{}{}", prefix.green(), message.green());
25 } else {
26 return format!("{}{}", prefix, message);
27 }
28 } else {
29 return String::new(); }
31 }
32
33 pub fn render_failure(&self, result: &Assertion<()>) -> (String, String) {
35 let message = self.build_assertion_message(result);
36 let details = self.build_failure_details(result);
37
38 let prefix = if self.config.use_unicode_symbols { "✗ " } else { "- " };
39 let header = if self.config.use_colors { format!("{}{}", prefix, message.red().bold()) } else { format!("{}{}", prefix, message) };
40
41 return (header, details);
42 }
43
44 fn build_failure_details(&self, result: &Assertion<()>) -> String {
46 let mut details = String::new();
47
48 for step in &result.steps {
50 let result_symbol = if step.passed { "✓" } else { "✗" };
51 let formatted_sentence = step.sentence.format_with_conjugation(result.expr_str);
53
54 details.push_str(&format!(" {} {}\n", result_symbol, formatted_sentence));
56 }
57
58 return details;
59 }
60
61 fn build_assertion_message(&self, result: &Assertion<()>) -> String {
63 if result.steps.is_empty() {
64 return "No assertions made".to_string();
65 }
66
67 let clean_expr = result.expr_str.trim_start_matches('&');
69
70 if result.steps.len() == 1 {
72 return format!("{} {}", clean_expr, result.steps[0].sentence.format_with_conjugation(result.expr_str));
73 }
74
75 let mut message = format!("{} {}", clean_expr, result.steps[0].sentence.format_with_conjugation(result.expr_str));
77
78 for i in 1..result.steps.len() {
80 let prev = &result.steps[i - 1];
81 let curr = &result.steps[i];
82
83 let op_str = match prev.logical_op {
84 Some(LogicalOp::And) => " AND ",
85 Some(LogicalOp::Or) => " OR ",
86 None => " [MISSING OP] ",
87 };
88
89 message.push_str(&format!("{}{}", op_str, curr.sentence.format_with_conjugation(result.expr_str)));
92 }
93
94 return message;
95 }
96
97 pub fn render_session_summary(&self, result: &TestSessionResult) -> String {
99 let mut output = String::from("\nTest Results:\n");
100
101 let passed_msg = format!("{} passed", result.passed_count);
102 let failed_msg = format!("{} failed", result.failed_count);
103
104 if self.config.use_colors {
105 output.push_str(&format!(
106 " {} / {}\n",
107 if result.passed_count > 0 { passed_msg.green() } else { passed_msg.normal() },
108 if result.failed_count > 0 { failed_msg.red().bold() } else { failed_msg.normal() }
109 ));
110 } else {
111 output.push_str(&format!(" {} / {}\n", passed_msg, failed_msg));
112 }
113
114 if result.failed_count > 0 {
115 output.push_str("\nFailure Details:\n");
116 for (i, failure) in result.failures.iter().enumerate() {
117 let (header, details) = self.render_failure(failure);
118 output.push_str(&format!(" {}. {}\n", i + 1, header));
119
120 for line in details.lines() {
122 output.push_str(&format!(" {}\n", line));
123 }
124 }
125 }
126
127 return output;
128 }
129
130 pub fn print_success(&self, result: &Assertion<()>) {
132 let message = self.render_success(result);
133 if !message.is_empty() {
134 println!("{}", message);
135 }
136 }
137
138 pub fn print_failure(&self, result: &Assertion<()>) {
140 let (header, details) = self.render_failure(result);
141
142 println!("{}", header);
144
145 if self.config.use_colors {
147 for line in details.lines() {
148 if line.contains("✓") {
149 println!("{}", line.green());
150 } else if line.contains("✗") {
151 println!("{}", line.red());
152 } else {
153 println!("{}", line);
154 }
155 }
156 } else {
157 println!("{}", details);
159 }
160 }
161
162 pub fn print_session_summary(&self, result: &TestSessionResult) {
164 println!("{}", self.render_session_summary(result));
165 }
166}