use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::time::{Duration, Instant};
pub mod sectional {
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Section {
CoreIssuance,
Distribution,
DexIntegration,
Governance,
Security,
MemoryOptimization,
}
impl Section {
pub fn as_str(&self) -> &'static str {
match self {
Section::CoreIssuance => "core-issuance",
Section::Distribution => "distribution",
Section::DexIntegration => "dex-integration",
Section::Governance => "governance",
Section::Security => "security",
Section::MemoryOptimization => "memory-optimization",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"core-issuance" => Some(Section::CoreIssuance),
"distribution" => Some(Section::Distribution),
"dex-integration" => Some(Section::DexIntegration),
"governance" => Some(Section::Governance),
"security" => Some(Section::Security),
"memory-optimization" => Some(Section::MemoryOptimization),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct TestResult {
pub section: Section,
pub passed: bool,
pub duration: Duration,
pub memory_usage: Option<usize>,
pub details: HashMap<String, String>,
}
impl TestResult {
pub fn new(section: Section) -> Self {
Self {
section,
passed: false,
duration: Duration::from_secs(0),
memory_usage: None,
details: HashMap::new(),
}
}
pub fn mark_passed(&mut self) {
self.passed = true;
}
pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration;
}
pub fn set_memory_usage(&mut self, bytes: usize) {
self.memory_usage = Some(bytes);
}
pub fn add_detail(&mut self, key: &str, value: String) {
self.details.insert(key.to_string(), value);
}
}
pub fn run_test<F>(section: Section, test_fn: F) -> TestResult
where
F: FnOnce() -> bool,
{
let mut result = TestResult::new(section);
let start = Instant::now();
let passed = test_fn();
result.set_duration(start.elapsed());
if passed {
result.mark_passed();
}
report_test_result(&result);
result
}
pub fn report_test_result(result: &TestResult) {
let reports_dir = Path::new("reports");
if !reports_dir.exists() {
let _ = fs::create_dir_all(reports_dir);
}
let file_path = reports_dir.join(format!("{}_result.txt", result.section.as_str()));
let mut file = match File::create(&file_path) {
Ok(f) => f,
Err(_) => return, };
let _ = writeln!(file, "Section: {}", result.section.as_str());
let _ = writeln!(file, "Passed: {}", result.passed);
let _ = writeln!(file, "Duration: {:?}", result.duration);
if let Some(memory) = result.memory_usage {
let _ = writeln!(file, "Memory usage: {memory} bytes");
}
if !result.details.is_empty() {
let _ = writeln!(file, "\nDetails:");
for (key, value) in &result.details {
let _ = writeln!(file, " {key}: {value}");
}
}
}
pub fn should_test_section(section: Section) -> bool {
if let Ok(filter) = env::var("TEST_SECTION") {
if filter == "all" {
return true;
}
return filter.split(',').any(|s| s.trim() == section.as_str());
}
true
}
#[cfg(feature = "memory_tracking")]
pub fn measure_memory_usage<F, T>(f: F) -> (T, usize)
where
F: FnOnce() -> T,
{
use std::alloc::{GlobalAlloc, System};
use std::mem;
unsafe {
let layout = std::alloc::Layout::new::<u8>();
let _ = System.alloc(layout);
}
let result = f();
let estimate = mem::size_of_val(&result);
(result, estimate)
}
#[cfg(not(feature = "memory_tracking"))]
pub fn measure_memory_usage<F, T>(f: F) -> (T, usize)
where
F: FnOnce() -> T,
{
let result = f();
(result, 0)
}
}
#[macro_export]
macro_rules! sectional_test {
($section:expr, $test_name:ident, $body:block) => {
#[test]
fn $test_name() {
if $crate::sectional_test_utils::sectional::should_test_section($section) {
$crate::sectional_test_utils::sectional::run_test($section, || $body);
}
}
};
}