pub mod cross_framework;
pub mod memory_leak_detector;
pub mod naming_conventions;
pub mod precision_tracker;
pub use cross_framework::{
CrossFrameworkValidator, Framework, ValidationConfig, ValidationResult, ValidationTestCase,
};
pub use memory_leak_detector::{
CIIntegration, MemoryLeakConfig, MemoryLeakDetector, MemoryLeakReport, ValgrindIntegration,
ValgrindReport,
};
pub use precision_tracker::{
OperationType, PrecisionConfig, PrecisionData, PrecisionStatistics, PrecisionTracker,
PrecisionTrackingError, TimelinePoint, TypeStatistics,
};
pub use naming_conventions::{
ElementType, NamingChecker, NamingCli, NamingConventions, NamingReport, NamingRule,
NamingViolation, ViolationSeverity,
};
pub mod test_utils;
pub use test_utils::{
BenchmarkResult, ErrorTestUtils, PerformanceTestUtils, TensorTestUtils, TestAssertions,
TestConfig, TestResult,
};
#[cfg(test)]
pub use test_utils::property_utils;
#[macro_export]
macro_rules! test_with_memory_tracking {
($test_name:expr, $body:block) => {{
use $crate::testing::MemoryLeakDetector;
let detector = MemoryLeakDetector::new();
let _monitoring = detector.start_monitoring();
#[allow(clippy::redundant_closure_call)]
let result = (|| $body)();
let report = detector.generate_report($test_name);
if report.leaked_bytes > 0 {
panic!(
"Memory leak detected: {} bytes in {} allocations",
report.leaked_bytes, report.active_allocations
);
}
result
}};
}
pub struct IntegrationTestRunner {
detector: MemoryLeakDetector,
reports: Vec<MemoryLeakReport>,
}
impl Default for IntegrationTestRunner {
fn default() -> Self {
Self::new()
}
}
impl IntegrationTestRunner {
pub fn new() -> Self {
Self {
detector: MemoryLeakDetector::new(),
reports: Vec::new(),
}
}
pub fn run_test<F, R>(
&mut self,
test_name: &str,
test_fn: F,
) -> Result<R, Box<dyn std::error::Error>>
where
F: FnOnce(&MemoryLeakDetector) -> Result<R, Box<dyn std::error::Error>>,
{
self.detector.reset();
let result = test_fn(&self.detector)?;
let report = self.detector.generate_report(test_name);
if report.leaked_bytes > 0 {
eprintln!(
"Memory leak in test '{}': {} bytes",
test_name, report.leaked_bytes
);
}
self.reports.push(report);
Ok(result)
}
pub fn get_reports(&self) -> &[MemoryLeakReport] {
&self.reports
}
pub fn generate_ci_reports(&self) -> Result<(), Box<dyn std::error::Error>> {
use std::fs;
let junit_xml = CIIntegration::generate_junit_report(&self.reports);
fs::write("memory_leak_junit.xml", junit_xml)?;
let markdown = CIIntegration::generate_markdown_report(&self.reports);
fs::write("memory_leak_report.md", markdown)?;
let annotations = CIIntegration::generate_github_annotations(&self.reports);
for annotation in annotations {
println!("{}", annotation);
}
Ok(())
}
pub fn has_memory_leaks(&self) -> bool {
self.reports.iter().any(|r| r.leaked_bytes > 0)
}
pub fn get_summary(&self) -> TestSummary {
let total_tests = self.reports.len();
let failed_tests = self.reports.iter().filter(|r| r.leaked_bytes > 0).count();
let total_leaked_bytes: usize = self.reports.iter().map(|r| r.leaked_bytes).sum();
let peak_memory: usize =
self.reports.iter().map(|r| r.peak_memory_usage).max().unwrap_or(0);
TestSummary {
total_tests,
passed_tests: total_tests - failed_tests,
failed_tests,
total_leaked_bytes,
peak_memory_usage: peak_memory,
}
}
}
#[derive(Debug, Clone)]
pub struct TestSummary {
pub total_tests: usize,
pub passed_tests: usize,
pub failed_tests: usize,
pub total_leaked_bytes: usize,
pub peak_memory_usage: usize,
}
impl TestSummary {
pub fn all_passed(&self) -> bool {
self.failed_tests == 0
}
pub fn pass_rate(&self) -> f64 {
if self.total_tests == 0 {
100.0
} else {
(self.passed_tests as f64 / self.total_tests as f64) * 100.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integration_runner() {
let mut runner = IntegrationTestRunner::new();
runner
.run_test("passing_test", |detector| {
let id = detector.record_allocation(1024);
detector.record_deallocation(id);
Ok(())
})
.expect("passing test should succeed");
runner
.run_test("failing_test", |detector| {
detector.record_allocation(2048); Ok(())
})
.expect("failing test should still return Ok");
let summary = runner.get_summary();
assert_eq!(summary.total_tests, 2);
assert_eq!(summary.passed_tests, 1);
assert_eq!(summary.failed_tests, 1);
assert_eq!(summary.total_leaked_bytes, 2048);
assert!(runner.has_memory_leaks());
assert_eq!(summary.pass_rate(), 50.0);
}
#[test]
fn test_memory_tracking_macro() {
let result = test_with_memory_tracking!("macro_test", {
42
});
assert_eq!(result, 42);
}
#[test]
#[should_panic(expected = "Memory leak detected")]
fn test_memory_tracking_macro_with_leak() {
let detector = MemoryLeakDetector::new();
let _monitoring = detector.start_monitoring();
detector.record_allocation(1024);
let report = detector.generate_report("macro_leak_test");
if report.leaked_bytes > 0 {
panic!(
"Memory leak detected: {} bytes in {} allocations",
report.leaked_bytes, report.active_allocations
);
}
}
}