use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TestId(String);
impl TestId {
pub fn new(id: impl Into<String>) -> Result<Self, AuditError> {
let id = id.into();
if id.is_empty() {
return Err(AuditError::InvalidTestId("Test ID cannot be empty".into()));
}
if id.contains('\0') {
return Err(AuditError::InvalidTestId(
"Test ID cannot contain null bytes".into(),
));
}
Ok(Self(id))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for TestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for TestId {
type Err = AuditError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum TestType {
Unit,
Integration,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestCase {
pub id: TestId,
pub name: String,
pub file_path: String,
pub test_type: TestType,
pub execution_time_ms: u64,
pub failure_history: Vec<TestFailure>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestFailure {
pub timestamp: DateTime<Utc>,
pub message: String,
pub is_flaky: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MutationResult {
pub mutation_id: String,
pub test_id: TestId,
pub mutant_survived: bool,
pub mutation_type: MutationType,
pub kill_timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MutationType {
BinaryOp,
UnaryOp,
ConstantReplacement,
StatementDeletion,
ReturnValueChange,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum AssertionStrength {
Weak,
Medium,
Strong,
}
impl AssertionStrength {
#[must_use]
pub fn to_score(self) -> f64 {
match self {
Self::Weak => 2.0,
Self::Medium => 5.5,
Self::Strong => 9.0,
}
}
}
#[derive(Debug, Error)]
pub enum AuditError {
#[error("Mutation testing failed: {0}")]
MutationFailed(String),
#[error("Failed to parse assertion: {0}")]
AssertionParseError(String),
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("Invalid test ID: {0}")]
InvalidTestId(String),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
}
pub type AuditResult<T> = Result<T, AuditError>;