use crate::prelude::*;
use colored::Colorize;
use std::any::Any;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt::Debug;
use std::fmt::Display;
#[derive(Clone, Debug)]
pub struct TestDefinition {
pub name: String,
pub description: String,
pub points: f64,
pub is_visible: bool,
}
pub trait ExerciseDef: Sync + Send + Any {
fn description(&self) -> &str;
fn get_generator_src(&self) -> &str;
fn list(&self) -> Vec<TestDefinition>;
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct ExerciseResult {
pub tests: HashMap<String, TestResult>,
}
impl Display for ExerciseResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let _ = writeln!(f, "ExerciseResult:");
let mut v: Vec<(String, TestResult)> = self
.tests
.iter()
.map(|(x, y)| (x.clone(), y.clone()))
.collect();
v.sort_by(|x, y| {
let cmp = x.1.cmp(&y.1);
if cmp.is_ne() {
return cmp;
}
x.0.cmp(&x.0)
});
for (name, result) in v {
if let CompilationResult::Error(x) = result.compiled {
let _ = write!(
f,
" {}: {} {}",
name.green(),
"Compilation Error:".red(),
x
);
} else if let RunResult::Error(x) = result.runned {
let _ = write!(f, " {}: {} {}", name.green(), "Run Error:".red(), x);
} else {
let _ = write!(f, " {}: {}", name, result);
}
}
write!(f, "")
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct TestResult {
pub compiled: CompilationResult,
pub runned: RunResult,
pub points_given: f64,
}
impl Eq for TestResult {}
impl Ord for TestResult {
fn cmp(&self, other: &Self) -> Ordering {
let cmp = self.compiled.cmp(&other.compiled);
if cmp.is_ne() {
return cmp;
}
let cmp = self.runned.cmp(&other.runned);
if cmp.is_ne() {
return cmp;
}
self.points_given.total_cmp(&other.points_given)
}
}
impl PartialOrd for TestResult {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Display for TestResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"TestResult({}, {:<16}, points: {:.2})",
self.compiled,
self.runned.to_string(),
self.points_given
)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CompilationResult {
Built,
Error(String),
#[default]
NotBuilt,
}
impl Ord for CompilationResult {
fn cmp(&self, other: &Self) -> Ordering {
use CompilationResult::*;
use Ordering::*;
match (self, other) {
(Built, Built) => Equal,
(Built, _) => Less,
(Error(_), Built) => Greater,
(Error(x), Error(y)) => x.cmp(y),
(Error(_), NotBuilt) => Less,
(NotBuilt, NotBuilt) => Equal,
(NotBuilt, _) => Greater,
}
}
}
impl PartialOrd for CompilationResult {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Display for CompilationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompilationResult::Built => write!(f, "{}", "Built".green()),
CompilationResult::Error(_) => write!(f, "{}", "Error".red()),
CompilationResult::NotBuilt => write!(f, "{}", "Not built".yellow()),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RunResult {
Ok,
Error(String),
#[default]
NotRun,
}
impl Ord for RunResult {
fn cmp(&self, other: &Self) -> Ordering {
use Ordering::*;
use RunResult::*;
match (self, other) {
(Ok, Ok) => Equal,
(Ok, _) => Less,
(Error(_), Ok) => Greater,
(Error(x), Error(y)) => x.cmp(y),
(Error(_), NotRun) => Less,
(NotRun, NotRun) => Equal,
(NotRun, _) => Greater,
}
}
}
impl PartialOrd for RunResult {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Display for RunResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RunResult::Ok => write!(f, "{}", "Ok".green()),
RunResult::Error(_) => write!(f, "{}", "Error".red()),
RunResult::NotRun => write!(f, "{}", "Not run".yellow()),
}
}
}