use serde::{Deserialize, Serialize};
use anyhow::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReportFormat {
Json,
Markdown,
Html,
Csv,
}
impl Default for ReportFormat {
fn default() -> Self {
ReportFormat::Json
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DetailLevel {
Summary,
Standard,
Detailed,
Comprehensive,
}
impl Default for DetailLevel {
fn default() -> Self {
DetailLevel::Standard
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportingConfig {
pub output_formats: Vec<ReportFormat>,
pub detail_level: DetailLevel,
pub include_statistical_details: bool,
pub include_attestation_details: bool,
pub generate_executive_summary: bool,
pub include_visualizations: bool,
pub include_charts: bool,
pub retention_days: u64,
}
impl Default for ReportingConfig {
fn default() -> Self {
Self {
output_formats: vec![ReportFormat::Json],
detail_level: DetailLevel::Standard,
include_statistical_details: false,
include_attestation_details: false,
generate_executive_summary: false,
include_visualizations: false,
include_charts: false,
retention_days: 30,
}
}
}
pub struct ReportGenerator {
config: ReportingConfig,
}
impl ReportGenerator {
pub fn new(config: ReportingConfig) -> Self {
Self { config }
}
pub async fn generate_comprehensive_report(&self) -> Result<Report> {
Ok(Report {
report_id: "comprehensive-report".to_string(),
timestamp: chrono::Utc::now(),
sections: vec![],
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Report {
pub report_id: String,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub sections: Vec<ReportSection>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSection {
pub title: String,
pub content: String,
pub metrics: std::collections::HashMap<String, serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reporting_config_default() {
let config = ReportingConfig::default();
assert_eq!(config.output_formats.len(), 1);
assert!(matches!(config.output_formats[0], ReportFormat::Json));
assert!(!config.include_charts);
assert_eq!(config.retention_days, 30);
}
#[test]
fn test_report_generator_creation() {
let config = ReportingConfig::default();
let generator = ReportGenerator::new(config);
assert_eq!(generator.config.output_formats.len(), 1);
assert!(matches!(generator.config.output_formats[0], ReportFormat::Json));
}
#[tokio::test]
async fn test_comprehensive_report_generation() {
let config = ReportingConfig::default();
let generator = ReportGenerator::new(config);
let result = generator.generate_comprehensive_report().await;
assert!(result.is_ok());
let report = result.unwrap();
assert_eq!(report.report_id, "comprehensive-report");
assert!(report.sections.is_empty());
}
#[test]
fn test_report_section_creation() {
let mut metrics = std::collections::HashMap::new();
metrics.insert("test_metric".to_string(), serde_json::Value::Number(serde_json::Number::from(42)));
let section = ReportSection {
title: "Test Section".to_string(),
content: "Test content".to_string(),
metrics,
};
assert_eq!(section.title, "Test Section");
assert_eq!(section.content, "Test content");
assert_eq!(section.metrics.len(), 1);
}
#[test]
fn test_report_creation() {
let report = Report {
report_id: "test-report".to_string(),
timestamp: chrono::Utc::now(),
sections: vec![],
};
assert_eq!(report.report_id, "test-report");
assert!(report.sections.is_empty());
}
#[test]
fn test_custom_reporting_config() {
let config = ReportingConfig {
output_formats: vec![ReportFormat::Html, ReportFormat::Markdown],
detail_level: DetailLevel::Comprehensive,
include_statistical_details: true,
include_attestation_details: true,
generate_executive_summary: true,
include_visualizations: true,
include_charts: true,
retention_days: 90,
};
assert_eq!(config.output_formats.len(), 2);
assert!(matches!(config.output_formats[0], ReportFormat::Html));
assert!(matches!(config.output_formats[1], ReportFormat::Markdown));
assert!(matches!(config.detail_level, DetailLevel::Comprehensive));
assert!(config.include_charts);
assert_eq!(config.retention_days, 90);
}
}