use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum TraceSignificance {
Trace = 0,
Low = 1,
Medium = 2,
High = 3,
Critical = 4,
}
impl TraceSignificance {
#[must_use]
pub const fn is_default_visible(self) -> bool {
matches!(self, Self::High | Self::Critical)
}
#[must_use]
pub const fn is_verbose_visible(self) -> bool {
matches!(self, Self::Medium | Self::High | Self::Critical)
}
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Trace => "TRACE",
Self::Low => "LOW",
Self::Medium => "MEDIUM",
Self::High => "HIGH",
Self::Critical => "CRITICAL",
}
}
#[must_use]
pub const fn ansi_color(self) -> &'static str {
match self {
Self::Critical => "\x1b[1;31m", Self::High => "\x1b[33m", Self::Medium => "\x1b[36m", Self::Low => "\x1b[2;37m", Self::Trace => "\x1b[90m", }
}
#[must_use]
pub const fn ansi_reset() -> &'static str {
"\x1b[0m"
}
}
impl Default for TraceSignificance {
fn default() -> Self {
Self::Medium
}
}
impl std::fmt::Display for TraceSignificance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.label())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trace_001_a_001_significance_ordering() {
assert!(TraceSignificance::Critical > TraceSignificance::High);
assert!(TraceSignificance::High > TraceSignificance::Medium);
assert!(TraceSignificance::Medium > TraceSignificance::Low);
assert!(TraceSignificance::Low > TraceSignificance::Trace);
}
#[test]
fn test_trace_001_a_002_default_visibility() {
assert!(TraceSignificance::Critical.is_default_visible());
assert!(TraceSignificance::High.is_default_visible());
assert!(!TraceSignificance::Medium.is_default_visible());
assert!(!TraceSignificance::Low.is_default_visible());
assert!(!TraceSignificance::Trace.is_default_visible());
}
#[test]
fn test_trace_001_a_003_verbose_visibility() {
assert!(TraceSignificance::Critical.is_verbose_visible());
assert!(TraceSignificance::High.is_verbose_visible());
assert!(TraceSignificance::Medium.is_verbose_visible());
assert!(!TraceSignificance::Low.is_verbose_visible());
assert!(!TraceSignificance::Trace.is_verbose_visible());
}
#[test]
fn test_trace_001_a_004_labels() {
assert_eq!(TraceSignificance::Critical.label(), "CRITICAL");
assert_eq!(TraceSignificance::High.label(), "HIGH");
assert_eq!(TraceSignificance::Medium.label(), "MEDIUM");
assert_eq!(TraceSignificance::Low.label(), "LOW");
assert_eq!(TraceSignificance::Trace.label(), "TRACE");
}
#[test]
fn test_trace_001_a_005_ansi_colors() {
assert!(!TraceSignificance::Critical.ansi_color().is_empty());
assert!(!TraceSignificance::High.ansi_color().is_empty());
assert!(!TraceSignificance::ansi_reset().is_empty());
}
#[test]
fn test_trace_001_a_006_default() {
assert_eq!(TraceSignificance::default(), TraceSignificance::Medium);
}
#[test]
fn test_trace_001_a_007_display() {
assert_eq!(format!("{}", TraceSignificance::Critical), "CRITICAL");
assert_eq!(format!("{}", TraceSignificance::High), "HIGH");
}
#[test]
fn test_trace_001_a_008_serialization() {
let sig = TraceSignificance::Critical;
let json = serde_json::to_string(&sig).expect("Serialization failed");
let deserialized: TraceSignificance =
serde_json::from_str(&json).expect("Deserialization failed");
assert_eq!(sig, deserialized);
}
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_trace_001_a_higher_more_visible(
sig_low in prop::sample::select(vec![
TraceSignificance::Trace,
TraceSignificance::Low,
]),
sig_high in prop::sample::select(vec![
TraceSignificance::High,
TraceSignificance::Critical,
]),
) {
assert!(sig_high.is_default_visible() || sig_high.is_verbose_visible());
assert!(!sig_low.is_default_visible());
}
}
proptest! {
#[test]
fn prop_trace_001_a_critical_always_visible(_any in 0..100u32) {
assert!(TraceSignificance::Critical.is_default_visible());
assert!(TraceSignificance::Critical.is_verbose_visible());
}
}
proptest! {
#[test]
fn prop_trace_001_a_ordering_transitive(
a in prop::sample::select(vec![
TraceSignificance::Trace,
TraceSignificance::Low,
TraceSignificance::Medium,
]),
b in prop::sample::select(vec![
TraceSignificance::Medium,
TraceSignificance::High,
]),
c in prop::sample::select(vec![
TraceSignificance::High,
TraceSignificance::Critical,
]),
) {
if a < b && b < c {
prop_assert!(a < c);
}
}
}
}
}