toster 0.1.0

A simple-as-toast tester for C++ solutions to competitive programming exercises
use std::cmp::max;
use colored::Colorize;
use comfy_table::ContentArrangement::Dynamic;
use comfy_table::{Attribute, Cell, Color, Table};
use terminal_size::{Height, Width};

pub enum TestResult {
	Correct {
		test_name: String
	},
	Incorrect {
		test_name: String,
		correct_answer: String,
		incorrect_answer: String
	},
	Error {
		test_name: String,
		error_message: String
	}
}

impl TestResult {
	pub fn to_string(&self) -> String {
		let mut result: String = String::new();

		match self {
			TestResult::Correct {test_name} => {
				result.push_str(&format!("{}", format!("Test {}:\n", test_name).bold()));
				result.push_str(&format!("{}", "Timed out".red()));
			}
			TestResult::Incorrect {test_name, correct_answer, incorrect_answer} => {
				result.push_str(&format!("{}", format!("Test {}:\n", test_name).bold()));

				let split_correct = correct_answer.split("\n").collect::<Vec<_>>();
				let split_incorrect = incorrect_answer.split("\n").collect::<Vec<_>>();

				if max(split_correct.len(), split_incorrect.len()) > 100 {
					result.push_str(&format!("{}", "Result too large to show".red()));
				}
				else {
					let (Width(w), Height(_)) = terminal_size::terminal_size().unwrap_or((Width(40), Height(0)));

					let mut table = Table::new();
					table.set_content_arrangement(Dynamic).set_width(w).set_header(vec![
						Cell::new("Output file").add_attribute(Attribute::Bold).fg(Color::Green),
						Cell::new("Your program's output").add_attribute(Attribute::Bold).fg(Color::Red)
					]);

					for i in 0..max(split_correct.len(), split_incorrect.len()) {
						let file_segment = if split_correct.len() > i { split_correct[i] } else { "" };
						let out_segment = if split_incorrect.len() > i { split_incorrect[i] } else { "" };

						if file_segment != out_segment {
							table.add_row(vec![
								Cell::new(file_segment).fg(Color::Green),
								Cell::new(out_segment).fg(Color::Red)
							]);
						}
						else {
							table.add_row(vec![file_segment, out_segment]);
						}
					}

					result.push_str(&table.to_string());
				}
			}
			TestResult::Error { test_name, error_message } => {
				result.push_str(&format!("{}", format!("Test {}:\n", test_name).bold()));
				result.push_str(&format!("{}", error_message.red()));
			}
		}

		return result;
	}
}