1use std::fmt::Write;
7use std::fs::File;
8use std::io::Write as IoWrite;
9
10use super::config::ReportFormat;
11use super::results::TestResults;
12use super::types::TestSuite;
13
14pub fn generate_report(
16 format: &ReportFormat,
17 results: &TestResults,
18 suite: &TestSuite,
19) -> Result<String, String> {
20 match format {
21 ReportFormat::Text => generate_text_report(results),
22 ReportFormat::Json => generate_json_report(results),
23 ReportFormat::Html => generate_html_report(results),
24 ReportFormat::Markdown => generate_markdown_report(results),
25 ReportFormat::Csv => generate_csv_report(results),
26 }
27}
28
29pub fn generate_text_report(results: &TestResults) -> Result<String, String> {
31 let mut report = String::new();
32
33 report.push_str("=== Quantum Optimization Test Report ===\n\n");
34
35 report.push_str(&format!("Total Tests: {}\n", results.summary.total_tests));
36 report.push_str(&format!("Passed: {}\n", results.summary.passed));
37 report.push_str(&format!("Failed: {}\n", results.summary.failed));
38 report.push_str(&format!(
39 "Success Rate: {:.2}%\n",
40 results.summary.success_rate * 100.0
41 ));
42 report.push_str(&format!(
43 "Average Runtime: {:?}\n\n",
44 results.summary.avg_runtime
45 ));
46
47 report.push_str("Quality Metrics:\n");
48 report.push_str(&format!(
49 " Average Quality: {:.4}\n",
50 results.summary.quality_metrics.avg_quality
51 ));
52 report.push_str(&format!(
53 " Best Quality: {:.4}\n",
54 results.summary.quality_metrics.best_quality
55 ));
56 report.push_str(&format!(
57 " Worst Quality: {:.4}\n",
58 results.summary.quality_metrics.worst_quality
59 ));
60 report.push_str(&format!(
61 " Std Dev: {:.4}\n",
62 results.summary.quality_metrics.std_dev
63 ));
64 report.push_str(&format!(
65 " Constraint Satisfaction: {:.2}%\n\n",
66 results.summary.quality_metrics.constraint_satisfaction_rate * 100.0
67 ));
68
69 if !results.failures.is_empty() {
70 report.push_str("Failures:\n");
71 for failure in &results.failures {
72 report.push_str(&format!(
73 " - {} ({:?}): {}\n",
74 failure.test_id, failure.failure_type, failure.message
75 ));
76 }
77 }
78
79 Ok(report)
80}
81
82pub fn generate_json_report(results: &TestResults) -> Result<String, String> {
84 fn write_err(e: std::fmt::Error) -> String {
86 format!("JSON write error: {e}")
87 }
88
89 let mut json = String::new();
90
91 json.push_str("{\n");
93
94 json.push_str(" \"summary\": {\n");
96 writeln!(
97 &mut json,
98 " \"total_tests\": {},",
99 results.summary.total_tests
100 )
101 .map_err(write_err)?;
102 writeln!(&mut json, " \"passed\": {},", results.summary.passed).map_err(write_err)?;
103 writeln!(&mut json, " \"failed\": {},", results.summary.failed).map_err(write_err)?;
104 writeln!(&mut json, " \"skipped\": {},", results.summary.skipped).map_err(write_err)?;
105 writeln!(
106 &mut json,
107 " \"success_rate\": {},",
108 results.summary.success_rate
109 )
110 .map_err(write_err)?;
111 writeln!(
112 &mut json,
113 " \"avg_runtime_ms\": {}",
114 results.summary.avg_runtime.as_millis()
115 )
116 .map_err(write_err)?;
117 json.push_str(" },\n");
118
119 json.push_str(" \"quality_metrics\": {\n");
121 writeln!(
122 &mut json,
123 " \"avg_quality\": {},",
124 results.summary.quality_metrics.avg_quality
125 )
126 .map_err(write_err)?;
127 writeln!(
128 &mut json,
129 " \"best_quality\": {},",
130 results.summary.quality_metrics.best_quality
131 )
132 .map_err(write_err)?;
133 writeln!(
134 &mut json,
135 " \"worst_quality\": {},",
136 results.summary.quality_metrics.worst_quality
137 )
138 .map_err(write_err)?;
139 writeln!(
140 &mut json,
141 " \"std_dev\": {},",
142 results.summary.quality_metrics.std_dev
143 )
144 .map_err(write_err)?;
145 writeln!(
146 &mut json,
147 " \"constraint_satisfaction_rate\": {}",
148 results.summary.quality_metrics.constraint_satisfaction_rate
149 )
150 .map_err(write_err)?;
151 json.push_str(" },\n");
152
153 json.push_str(" \"performance\": {\n");
155 writeln!(
156 &mut json,
157 " \"total_time_ms\": {},",
158 results.performance.runtime_stats.total_time.as_millis()
159 )
160 .map_err(write_err)?;
161 writeln!(
162 &mut json,
163 " \"solving_time_ms\": {},",
164 results.performance.runtime_stats.solving_time.as_millis()
165 )
166 .map_err(write_err)?;
167 writeln!(
168 &mut json,
169 " \"validation_time_ms\": {}",
170 results
171 .performance
172 .runtime_stats
173 .validation_time
174 .as_millis()
175 )
176 .map_err(write_err)?;
177 json.push_str(" },\n");
178
179 json.push_str(" \"test_results\": [\n");
181 for (i, result) in results.test_results.iter().enumerate() {
182 json.push_str(" {\n");
183 writeln!(&mut json, " \"test_id\": \"{}\",", result.test_id).map_err(write_err)?;
184 writeln!(&mut json, " \"sampler\": \"{}\",", result.sampler).map_err(write_err)?;
185 writeln!(
186 &mut json,
187 " \"objective_value\": {},",
188 result.objective_value
189 )
190 .map_err(write_err)?;
191 writeln!(
192 &mut json,
193 " \"constraints_satisfied\": {},",
194 result.constraints_satisfied
195 )
196 .map_err(write_err)?;
197 writeln!(
198 &mut json,
199 " \"runtime_ms\": {},",
200 result.runtime.as_millis()
201 )
202 .map_err(write_err)?;
203 writeln!(
204 &mut json,
205 " \"is_valid\": {}",
206 result.validation.is_valid
207 )
208 .map_err(write_err)?;
209 json.push_str(" }");
210 if i < results.test_results.len() - 1 {
211 json.push(',');
212 }
213 json.push('\n');
214 }
215 json.push_str(" ],\n");
216
217 json.push_str(" \"failures\": [\n");
219 for (i, failure) in results.failures.iter().enumerate() {
220 json.push_str(" {\n");
221 writeln!(&mut json, " \"test_id\": \"{}\",", failure.test_id).map_err(write_err)?;
222 writeln!(
223 &mut json,
224 " \"failure_type\": \"{:?}\",",
225 failure.failure_type
226 )
227 .map_err(write_err)?;
228 writeln!(
229 &mut json,
230 " \"message\": \"{}\"",
231 failure.message.replace('"', "\\\"")
232 )
233 .map_err(write_err)?;
234 json.push_str(" }");
235 if i < results.failures.len() - 1 {
236 json.push(',');
237 }
238 json.push('\n');
239 }
240 json.push_str(" ]\n");
241
242 json.push_str("}\n");
243
244 Ok(json)
245}
246
247pub fn generate_html_report(results: &TestResults) -> Result<String, String> {
249 let mut html = String::new();
250
251 html.push_str("<!DOCTYPE html>\n<html>\n<head>\n");
252 html.push_str("<title>Quantum Optimization Test Report</title>\n");
253 html.push_str(
254 "<style>
255 body { font-family: Arial, sans-serif; margin: 20px; }
256 table { border-collapse: collapse; width: 100%; }
257 th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
258 th { background-color: #f2f2f2; }
259 .passed { color: green; }
260 .failed { color: red; }
261 </style>\n",
262 );
263 html.push_str("</head>\n<body>\n");
264
265 html.push_str("<h1>Quantum Optimization Test Report</h1>\n");
266
267 html.push_str("<h2>Summary</h2>\n");
269 html.push_str("<table>\n");
270 html.push_str(&format!(
271 "<tr><td>Total Tests</td><td>{}</td></tr>\n",
272 results.summary.total_tests
273 ));
274 html.push_str(&format!(
275 "<tr><td>Passed</td><td class='passed'>{}</td></tr>\n",
276 results.summary.passed
277 ));
278 html.push_str(&format!(
279 "<tr><td>Failed</td><td class='failed'>{}</td></tr>\n",
280 results.summary.failed
281 ));
282 html.push_str(&format!(
283 "<tr><td>Success Rate</td><td>{:.2}%</td></tr>\n",
284 results.summary.success_rate * 100.0
285 ));
286 html.push_str("</table>\n");
287
288 html.push_str("</body>\n</html>");
289
290 Ok(html)
291}
292
293pub fn generate_markdown_report(results: &TestResults) -> Result<String, String> {
295 let mut md = String::new();
296
297 md.push_str("# Quantum Optimization Test Report\n\n");
298
299 md.push_str("## Summary\n\n");
300 md.push_str("| Metric | Value |\n");
301 md.push_str("|--------|-------|\n");
302 md.push_str(&format!(
303 "| Total Tests | {} |\n",
304 results.summary.total_tests
305 ));
306 md.push_str(&format!("| Passed | {} |\n", results.summary.passed));
307 md.push_str(&format!("| Failed | {} |\n", results.summary.failed));
308 md.push_str(&format!(
309 "| Success Rate | {:.2}% |\n",
310 results.summary.success_rate * 100.0
311 ));
312 md.push_str(&format!(
313 "| Average Runtime | {:?} |\n\n",
314 results.summary.avg_runtime
315 ));
316
317 md.push_str("## Quality Metrics\n\n");
318 md.push_str(&format!(
319 "- **Average Quality**: {:.4}\n",
320 results.summary.quality_metrics.avg_quality
321 ));
322 md.push_str(&format!(
323 "- **Best Quality**: {:.4}\n",
324 results.summary.quality_metrics.best_quality
325 ));
326 md.push_str(&format!(
327 "- **Worst Quality**: {:.4}\n",
328 results.summary.quality_metrics.worst_quality
329 ));
330 md.push_str(&format!(
331 "- **Standard Deviation**: {:.4}\n",
332 results.summary.quality_metrics.std_dev
333 ));
334 md.push_str(&format!(
335 "- **Constraint Satisfaction Rate**: {:.2}%\n\n",
336 results.summary.quality_metrics.constraint_satisfaction_rate * 100.0
337 ));
338
339 Ok(md)
340}
341
342pub fn generate_csv_report(results: &TestResults) -> Result<String, String> {
344 let mut csv = String::new();
345
346 csv.push_str("test_id,sampler,objective_value,constraints_satisfied,runtime_ms,valid\n");
347
348 for result in &results.test_results {
349 csv.push_str(&format!(
350 "{},{},{},{},{},{}\n",
351 result.test_id,
352 result.sampler,
353 result.objective_value,
354 result.constraints_satisfied,
355 result.runtime.as_millis(),
356 result.validation.is_valid
357 ));
358 }
359
360 Ok(csv)
361}
362
363pub fn export_csv(results: &TestResults, suite: &TestSuite) -> Result<String, String> {
365 let mut csv = String::new();
366 csv.push_str("test_id,problem_type,size,sampler,objective_value,runtime_ms,constraints_satisfied,valid\n");
367
368 for result in &results.test_results {
369 if let Some(test_case) = suite.test_cases.iter().find(|tc| tc.id == result.test_id) {
371 csv.push_str(&format!(
372 "{},{:?},{},{},{},{},{},{}\n",
373 result.test_id,
374 test_case.problem_type,
375 test_case.size,
376 result.sampler,
377 result.objective_value,
378 result.runtime.as_millis(),
379 result.constraints_satisfied,
380 result.validation.is_valid
381 ));
382 }
383 }
384
385 Ok(csv)
386}
387
388pub fn export_xml(results: &TestResults) -> Result<String, String> {
390 let mut xml = String::new();
391 xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
392 xml.push_str("<test_results>\n");
393 xml.push_str(&format!(
394 " <summary total=\"{}\" passed=\"{}\" failed=\"{}\" success_rate=\"{:.2}\"/>\n",
395 results.summary.total_tests,
396 results.summary.passed,
397 results.summary.failed,
398 results.summary.success_rate
399 ));
400
401 xml.push_str(" <tests>\n");
402 for result in &results.test_results {
403 xml.push_str(&format!(
404 " <test id=\"{}\" sampler=\"{}\" objective=\"{}\" runtime_ms=\"{}\" valid=\"{}\"/>\n",
405 result.test_id,
406 result.sampler,
407 result.objective_value,
408 result.runtime.as_millis(),
409 result.validation.is_valid
410 ));
411 }
412 xml.push_str(" </tests>\n");
413 xml.push_str("</test_results>\n");
414
415 Ok(xml)
416}
417
418pub fn save_report(report: &str, filename: &str) -> Result<(), String> {
420 let mut file = File::create(filename).map_err(|e| format!("Failed to create file: {e}"))?;
421 file.write_all(report.as_bytes())
422 .map_err(|e| format!("Failed to write file: {e}"))?;
423 Ok(())
424}