use crate::error::{CoreError, CoreResult, ErrorContext};
use crate::testing::{TestConfig, TestResult};
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct SecurityTestConfig {
pub max_input_size: usize,
pub malicious_patterns: usize,
pub test_bounds_checking: bool,
pub test_integer_overflow: bool,
pub test_memory_safety: bool,
pub test_dos_simulation: bool,
pub test_timeout: Duration,
}
impl Default for SecurityTestConfig {
fn default() -> Self {
Self {
max_input_size: 1024 * 1024, malicious_patterns: 1000,
test_bounds_checking: true,
test_integer_overflow: true,
test_memory_safety: true,
test_dos_simulation: true,
test_timeout: Duration::from_secs(10),
}
}
}
impl SecurityTestConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_max_input_size(mut self, size: usize) -> Self {
self.max_input_size = size;
self
}
pub fn with_malicious_patterns(mut self, patterns: usize) -> Self {
self.malicious_patterns = patterns;
self
}
pub fn with_bounds_checking(mut self, enabled: bool) -> Self {
self.test_bounds_checking = enabled;
self
}
pub fn with_integer_overflow(mut self, enabled: bool) -> Self {
self.test_integer_overflow = enabled;
self
}
pub fn with_memory_safety(mut self, enabled: bool) -> Self {
self.test_memory_safety = enabled;
self
}
pub fn with_dos_simulation(mut self, enabled: bool) -> Self {
self.test_dos_simulation = enabled;
self
}
pub fn with_test_timeout(mut self, timeout: Duration) -> Self {
self.test_timeout = timeout;
self
}
}
#[derive(Debug, Clone)]
pub struct SecurityTestResult {
pub test_name: String,
pub tests_executed: usize,
pub vulnerabilities_found: usize,
pub duration: Duration,
pub security_issues: Vec<SecurityIssue>,
pub security_level: SecurityLevel,
}
#[derive(Debug, Clone)]
pub struct SecurityIssue {
pub severity: SecuritySeverity,
pub category: SecurityCategory,
pub description: String,
pub trigger_input: String,
pub mitigation: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecuritySeverity {
Critical,
High,
Medium,
Low,
Info,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecurityCategory {
BufferOverflow,
IntegerOverflow,
OutOfBounds,
MemorySafety,
InputValidation,
DenialOfService,
InformationDisclosure,
DependencyVuln,
ConfigSecurity,
ThirdPartyIntegration,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecurityLevel {
Insecure,
Vulnerable,
Weak,
Secure,
Hardened,
}
pub struct InputValidationTester {
config: SecurityTestConfig,
}
impl InputValidationTester {
pub fn new(config: SecurityTestConfig) -> Self {
Self { config }
}
pub fn test_malicious_inputs<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
where
F: Fn(&[u8]) -> CoreResult<()>,
{
let start_time = Instant::now();
let mut result = SecurityTestResult {
test_name: "malicious_input_validation".to_string(),
tests_executed: 0,
vulnerabilities_found: 0,
duration: Duration::from_secs(0),
security_issues: Vec::new(),
security_level: SecurityLevel::Secure,
};
let patterns = self.generate_malicious_patterns();
for (i, pattern) in patterns.iter().enumerate() {
result.tests_executed += 1;
let test_start = Instant::now();
let test_result =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| testfunction(pattern)));
let test_duration = test_start.elapsed();
match test_result {
Ok(Ok(())) => {
}
Ok(Err(_)) => {
}
Err(_) => {
result.vulnerabilities_found += 1;
result.security_issues.push(SecurityIssue {
severity: SecuritySeverity::High,
category: SecurityCategory::InputValidation,
description: "Function panicked on malicious input".to_string(),
trigger_input: format!("{:?}", (i, pattern)),
mitigation: Some(
"Add proper input validation and error handling".to_string(),
),
});
}
}
if test_duration > self.config.test_timeout {
result.vulnerabilities_found += 1;
result.security_issues.push(SecurityIssue {
severity: SecuritySeverity::Medium,
category: SecurityCategory::DenialOfService,
description: format!("{:?}", test_duration),
trigger_input: format!("{:?}", (i, pattern)),
mitigation: Some("Add input size limits and timeouts".to_string()),
});
}
}
result.duration = start_time.elapsed();
result.security_level = self.assess_security_level(&result.security_issues);
Ok(result)
}
pub fn test_bounds_checking<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
where
F: Fn(usize, usize) -> CoreResult<()>,
{
let start_time = Instant::now();
let mut result = SecurityTestResult {
test_name: "bounds_checking".to_string(),
tests_executed: 0,
vulnerabilities_found: 0,
duration: Duration::from_secs(0),
security_issues: Vec::new(),
security_level: SecurityLevel::Secure,
};
let test_cases = vec![
(0, 0), (0, 1), (1, 0), (usize::MAX, 1), (1, usize::MAX), (usize::MAX, usize::MAX), (usize::MAX - 1, 2), ];
for (start, length) in test_cases {
result.tests_executed += 1;
let test_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
testfunction(start, length)
}));
match test_result {
Ok(Ok(())) => {
if start.saturating_add(length) < start {
result.vulnerabilities_found += 1;
result.security_issues.push(SecurityIssue {
severity: SecuritySeverity::High,
category: SecurityCategory::IntegerOverflow,
description: "Integer overflow not detected".to_string(),
trigger_input: format!("{:?}", (start, length)),
mitigation: Some(
"Add overflow checks in bounds validation".to_string(),
),
});
}
}
Ok(Err(_)) => {
}
Err(_) => {
result.vulnerabilities_found += 1;
result.security_issues.push(SecurityIssue {
severity: SecuritySeverity::Critical,
category: SecurityCategory::OutOfBounds,
description: "Function panicked on bounds check".to_string(),
trigger_input: format!("{:?}", (start, length)),
mitigation: Some("Implement safe bounds checking".to_string()),
});
}
}
}
result.duration = start_time.elapsed();
result.security_level = self.assess_security_level(&result.security_issues);
Ok(result)
}
#[allow(clippy::vec_init_then_push)]
fn generate_malicious_patterns(&self) -> Vec<Vec<u8>> {
let mut patterns = Vec::new();
patterns.push(vec![]);
patterns.push(vec![0xAA; self.config.max_input_size]);
patterns.push(vec![0x00; 100]);
patterns.push(vec![0xFF; 100]);
for size in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] {
if size <= self.config.max_input_size {
patterns.push(vec![0x41; size]); patterns.push(vec![0x90; size]); }
}
patterns.push(b"%s%s%s%s%s%s%s%s%s%s".to_vec());
patterns.push(b"%x%x%x%x%x%x%x%x%x%x".to_vec());
patterns.push(b"%n%n%n%n%n%n%n%n%n%n".to_vec());
patterns.push(b"' OR '1'='1".to_vec());
patterns.push(b"'; DROP TABLE users; --".to_vec());
patterns.push(b"../../../etc/passwd".to_vec());
patterns.push(b"..\\..\\..\\windows\\system32\\config\\sam".to_vec());
patterns.push(vec![0xC0, 0x80]); patterns.push(vec![0xED, 0xA0, 0x80]); patterns.push(vec![0xFF, 0xFE]);
patterns.truncate(self.config.malicious_patterns);
patterns
}
fn assess_security_level(&self, issues: &[SecurityIssue]) -> SecurityLevel {
let critical_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::Critical)
.count();
let high_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::High)
.count();
let medium_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::Medium)
.count();
if critical_count > 0 {
SecurityLevel::Insecure
} else if high_count > 2 {
SecurityLevel::Vulnerable
} else if high_count > 0 || medium_count > 5 {
SecurityLevel::Weak
} else if medium_count > 0 {
SecurityLevel::Secure
} else {
SecurityLevel::Hardened
}
}
}
pub struct MemorySafetyTester {
#[allow(dead_code)]
config: SecurityTestConfig,
}
impl MemorySafetyTester {
pub fn new(config: SecurityTestConfig) -> Self {
Self { config }
}
pub fn test_memory_leaks<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
where
F: Fn() -> CoreResult<()>,
{
let start_time = Instant::now();
let mut result = SecurityTestResult {
test_name: "memory_leak_detection".to_string(),
tests_executed: 0,
vulnerabilities_found: 0,
duration: Duration::from_secs(0),
security_issues: Vec::new(),
security_level: SecurityLevel::Secure,
};
let initial_memory = self.get_memory_usage();
for i in 0..100 {
result.tests_executed += 1;
match testfunction() {
Ok(()) => {}
Err(_) => {
}
}
if i % 10 == 0 {
if let Ok(current_memory) = self.get_memory_usage() {
if let Ok(initial) = initial_memory {
let memory_growth = current_memory.saturating_sub(initial);
if memory_growth > 10 * 1024 * 1024 {
result.vulnerabilities_found += 1;
result.security_issues.push(SecurityIssue {
severity: SecuritySeverity::Medium,
category: SecurityCategory::MemorySafety,
description: format!(
"Potential memory leak detected: {} MB growth",
memory_growth / (1024 * 1024)
),
trigger_input: format!("After {} iterations", i),
mitigation: Some(
"Review memory management and cleanup".to_string(),
),
});
break; }
}
}
}
}
result.duration = start_time.elapsed();
result.security_level = self.assess_security_level(&result.security_issues);
Ok(result)
}
pub fn test_use_after_free(&self) -> CoreResult<SecurityTestResult> {
let start_time = Instant::now();
let result = SecurityTestResult {
test_name: "use_after_free_detection".to_string(),
tests_executed: 1,
vulnerabilities_found: 0,
duration: start_time.elapsed(),
security_issues: vec![SecurityIssue {
severity: SecuritySeverity::Info,
category: SecurityCategory::MemorySafety,
description: "Rust's ownership system prevents use-after-free vulnerabilities"
.to_string(),
trigger_input: "N/A".to_string(),
mitigation: Some("Continue using Rust's safe memory management".to_string()),
}],
security_level: SecurityLevel::Hardened,
};
Ok(result)
}
fn get_memory_usage(&self) -> CoreResult<usize> {
#[cfg(target_os = "linux")]
{
use std::fs;
let status = fs::read_to_string("/proc/self/status").map_err(|e| {
CoreError::IoError(ErrorContext::new(format!(
"Failed to read memory status: {}",
e
)))
})?;
for line in status.lines() {
if line.starts_with("VmRSS:") {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2 {
let kb: usize = parts[1].parse().map_err(|e| {
CoreError::ValidationError(crate::error::ErrorContext::new(format!(
"Failed to parse memory: {}",
e
)))
})?;
return Ok(kb * 1024);
}
}
}
}
Ok(0)
}
fn assess_security_level(&self, issues: &[SecurityIssue]) -> SecurityLevel {
let critical_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::Critical)
.count();
let high_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::High)
.count();
let medium_count = issues
.iter()
.filter(|i| i.severity == SecuritySeverity::Medium)
.count();
if critical_count > 0 {
SecurityLevel::Insecure
} else if high_count > 0 {
SecurityLevel::Vulnerable
} else if medium_count > 2 {
SecurityLevel::Weak
} else if medium_count > 0 {
SecurityLevel::Secure
} else {
SecurityLevel::Hardened
}
}
}
pub struct VulnerabilityAssessment {
config: SecurityTestConfig,
}
impl VulnerabilityAssessment {
pub fn new(config: SecurityTestConfig) -> Self {
Self { config }
}
pub fn perform_security_audit(&self) -> CoreResult<SecurityAuditReport> {
let start_time = Instant::now();
let mut report = SecurityAuditReport {
audit_timestamp: std::time::SystemTime::now(),
total_tests: 0,
passed_tests: 0,
failed_tests: 0,
vulnerabilities: Vec::new(),
recommendations: Vec::new(),
overall_score: 0.0,
security_level: SecurityLevel::Secure,
duration: Duration::from_secs(0),
};
self.scan_dependencies(&mut report)?;
self.analyzecode_security(&mut report)?;
self.check_configuration_security(&mut report)?;
self.assess_third_party_security(&mut report)?;
report.duration = start_time.elapsed();
report.overall_score = self.calculate_security_score(&report);
report.security_level = self.determine_security_level(report.overall_score);
Ok(report)
}
fn scan_dependencies(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
report.total_tests += 1;
let vulnerable_deps = self.check_vulnerable_dependencies()?;
if vulnerable_deps.is_empty() {
report.passed_tests += 1;
} else {
report.failed_tests += 1;
for dep in vulnerable_deps {
report.vulnerabilities.push(SecurityVulnerability {
id: dep.name.to_string(),
severity: SecuritySeverity::High,
category: SecurityCategory::DependencyVuln,
title: dep.name.to_string(),
description: dep.description,
affected_component: dep.name.clone(),
cve_id: dep.cve_id,
mitigation: format!("{}, {}", dep.name, dep.fixed_version),
});
}
}
Ok(())
}
fn analyzecode_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
report.total_tests += 1;
let security_issues = self.perform_static_analysis()?;
if security_issues.is_empty() {
report.passed_tests += 1;
} else {
report.failed_tests += 1;
for issue in security_issues {
report.vulnerabilities.push(issue);
}
}
Ok(())
}
fn check_configuration_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
report.total_tests += 1;
let config_issues = self.audit_configuration()?;
if config_issues.is_empty() {
report.passed_tests += 1;
report
.recommendations
.push("Configuration security: PASS".to_string());
} else {
report.failed_tests += 1;
for issue in config_issues {
report.vulnerabilities.push(issue);
}
}
Ok(())
}
fn assess_third_party_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
report.total_tests += 1;
let integration_issues = self.check_third_party_integrations()?;
if integration_issues.is_empty() {
report.passed_tests += 1;
report
.recommendations
.push("Third-party integrations: SECURE".to_string());
} else {
report.failed_tests += 1;
for issue in integration_issues {
report.vulnerabilities.push(issue);
}
}
Ok(())
}
fn check_vulnerable_dependencies(&self) -> CoreResult<Vec<VulnerableDependency>> {
Ok(vec![])
}
fn perform_static_analysis(&self) -> CoreResult<Vec<SecurityVulnerability>> {
let vulnerabilities = vec![SecurityVulnerability {
id: "SAFE-001".to_string(),
severity: SecuritySeverity::Info,
category: SecurityCategory::MemorySafety,
title: "Memory Safety Analysis".to_string(),
description: "Rust's type system prevents most memory safety vulnerabilities"
.to_string(),
affected_component: "core".to_string(),
cve_id: None,
mitigation: "Continue using Rust's safe abstractions".to_string(),
}];
Ok(vulnerabilities)
}
fn audit_configuration(&self) -> CoreResult<Vec<SecurityVulnerability>> {
let issues = Vec::new();
Ok(issues)
}
fn check_third_party_integrations(&self) -> CoreResult<Vec<SecurityVulnerability>> {
let issues = Vec::new();
Ok(issues)
}
fn calculate_security_score(&self, report: &SecurityAuditReport) -> f64 {
if report.total_tests == 0 {
return 0.0;
}
let base_score = (report.passed_tests as f64 / report.total_tests as f64) * 100.0;
let mut penalty = 0.0;
for vuln in &report.vulnerabilities {
match vuln.severity {
SecuritySeverity::Critical => penalty += 25.0,
SecuritySeverity::High => penalty += 15.0,
SecuritySeverity::Medium => penalty += 8.0,
SecuritySeverity::Low => penalty += 3.0,
SecuritySeverity::Info => penalty += 0.0,
}
}
(base_score - penalty).max(0.0)
}
fn determine_security_level(&self, score: f64) -> SecurityLevel {
match score {
s if s >= 95.0 => SecurityLevel::Hardened,
s if s >= 85.0 => SecurityLevel::Secure,
s if s >= 70.0 => SecurityLevel::Weak,
s if s >= 50.0 => SecurityLevel::Vulnerable,
_ => SecurityLevel::Insecure,
}
}
}
#[derive(Debug, Clone)]
pub struct SecurityAuditReport {
pub audit_timestamp: std::time::SystemTime,
pub total_tests: usize,
pub passed_tests: usize,
pub failed_tests: usize,
pub vulnerabilities: Vec<SecurityVulnerability>,
pub recommendations: Vec<String>,
pub overall_score: f64,
pub security_level: SecurityLevel,
pub duration: Duration,
}
#[derive(Debug, Clone)]
pub struct SecurityVulnerability {
pub id: String,
pub severity: SecuritySeverity,
pub category: SecurityCategory,
pub title: String,
pub description: String,
pub affected_component: String,
pub cve_id: Option<String>,
pub mitigation: String,
}
#[derive(Debug, Clone)]
pub struct VulnerableDependency {
pub name: String,
pub current_version: String,
pub fixed_version: String,
pub description: String,
pub cve_id: Option<String>,
}
pub struct SecurityTestUtils;
impl SecurityTestUtils {
pub fn create_security_test_suite(name: &str, config: TestConfig) -> crate::testing::TestSuite {
let mut suite = crate::testing::TestSuite::new(name, config);
let security_config = SecurityTestConfig::default()
.with_malicious_patterns(100)
.with_max_input_size(1024);
let security_config_1 = security_config.clone();
suite.add_test("malicious_input_validation", move |_runner| {
let tester = InputValidationTester::new(security_config_1.clone());
let result = tester.test_malicious_inputs(|input| {
if input.len() > 1000 {
Err(CoreError::ValidationError(crate::error::ErrorContext::new(
"Input too large",
)))
} else if input.is_empty() {
Err(CoreError::ValidationError(crate::error::ErrorContext::new(
"Input cannot be empty",
)))
} else {
Ok(())
}
})?;
if result.security_level == SecurityLevel::Insecure {
return Ok(TestResult::failure(
result.duration,
result.tests_executed,
format!(
"Critical security vulnerabilities found: {}",
result.vulnerabilities_found
),
));
}
Ok(TestResult::success(result.duration, result.tests_executed))
});
let security_config_2 = security_config.clone();
suite.add_test("bounds_checking", move |_runner| {
let tester = InputValidationTester::new(security_config_2.clone());
let result = tester.test_bounds_checking(|start, length| {
let end = start.checked_add(length).ok_or_else(|| {
CoreError::ValidationError(crate::error::ErrorContext::new(
"Integer overflow in bounds calculation",
))
})?;
if end > 1000 {
Err(CoreError::ValidationError(crate::error::ErrorContext::new(
"Bounds exceed maximum allowed",
)))
} else {
Ok(())
}
})?;
if result.security_level == SecurityLevel::Insecure
|| result.security_level == SecurityLevel::Vulnerable
{
return Ok(TestResult::failure(
result.duration,
result.tests_executed,
format!(
"Bounds checking vulnerabilities found: {}",
result.vulnerabilities_found
),
));
}
Ok(TestResult::success(result.duration, result.tests_executed))
});
let security_config_3 = security_config.clone();
suite.add_test("memory_safety", move |_runner| {
let tester = MemorySafetyTester::new(security_config_3.clone());
let result = tester.test_memory_leaks(|| {
let data = vec![0u8; 1000];
Ok(())
})?;
if result.vulnerabilities_found > 0 {
return Ok(TestResult::failure(
result.duration,
result.tests_executed,
format!(
"Memory safety issues found: {}",
result.vulnerabilities_found
),
));
}
Ok(TestResult::success(result.duration, result.tests_executed))
});
let security_config_clone2 = security_config.clone();
suite.add_test("use_after_free", move |_runner| {
let tester = MemorySafetyTester::new(security_config_clone2.clone());
let result = tester.test_use_after_free()?;
Ok(TestResult::success(result.duration, result.tests_executed))
});
let security_config_clone3 = security_config.clone();
suite.add_test("vulnerability_assessment", move |_runner| {
let assessment = VulnerabilityAssessment::new(security_config_clone3.clone());
let report = assessment.perform_security_audit()?;
if report.security_level == SecurityLevel::Insecure
|| report.security_level == SecurityLevel::Vulnerable
{
return Ok(TestResult::failure(
report.duration,
report.total_tests,
format!(
"Security audit failed: {} vulnerabilities found, score: {:.1}",
report.vulnerabilities.len(),
report.overall_score
),
));
}
Ok(TestResult::success(report.duration, report.total_tests))
});
suite
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_security_config() {
let config = SecurityTestConfig::new()
.with_max_input_size(2048)
.with_malicious_patterns(500)
.with_bounds_checking(true)
.with_memory_safety(false);
assert_eq!(config.max_input_size, 2048);
assert_eq!(config.malicious_patterns, 500);
assert!(config.test_bounds_checking);
assert!(!config.test_memory_safety);
}
#[test]
fn test_security_severity() {
assert_eq!(SecuritySeverity::Critical, SecuritySeverity::Critical);
assert_ne!(SecuritySeverity::Critical, SecuritySeverity::High);
}
#[test]
fn test_security_level_assessment() {
let tester = InputValidationTester::new(SecurityTestConfig::default());
let level = tester.assess_security_level(&[]);
assert_eq!(level, SecurityLevel::Hardened);
let critical_issue = SecurityIssue {
severity: SecuritySeverity::Critical,
category: SecurityCategory::BufferOverflow,
description: "Test issue".to_string(),
trigger_input: "test".to_string(),
mitigation: None,
};
let level = tester.assess_security_level(&[critical_issue]);
assert_eq!(level, SecurityLevel::Insecure);
}
#[test]
fn test_malicious_pattern_generation() {
let tester =
InputValidationTester::new(SecurityTestConfig::default().with_malicious_patterns(10));
let patterns = tester.generate_malicious_patterns();
assert_eq!(patterns.len(), 10);
assert!(patterns.iter().any(|p| p.is_empty())); }
#[test]
fn test_vulnerability_assessment() {
let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
let report = assessment
.perform_security_audit()
.expect("Operation failed");
assert!(report.total_tests > 0);
assert!(report.passed_tests > 0);
assert!(report.overall_score >= 0.0);
assert!(report.overall_score <= 100.0);
}
#[test]
fn test_security_score_calculation() {
let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
let report = SecurityAuditReport {
audit_timestamp: std::time::SystemTime::now(),
total_tests: 10,
passed_tests: 10,
failed_tests: 0,
vulnerabilities: vec![],
recommendations: vec![],
overall_score: 0.0,
security_level: SecurityLevel::Secure,
duration: Duration::from_secs(1),
};
let score = assessment.calculate_security_score(&report);
assert_eq!(score, 100.0);
let report_with_critical = SecurityAuditReport {
audit_timestamp: std::time::SystemTime::now(),
total_tests: 10,
passed_tests: 9,
failed_tests: 1,
vulnerabilities: vec![SecurityVulnerability {
id: "TEST-001".to_string(),
severity: SecuritySeverity::Critical,
category: SecurityCategory::MemorySafety,
title: "Test vulnerability".to_string(),
description: "Test description".to_string(),
affected_component: "test".to_string(),
cve_id: None,
mitigation: "Test mitigation".to_string(),
}],
recommendations: vec![],
overall_score: 0.0,
security_level: SecurityLevel::Secure,
duration: Duration::from_secs(1),
};
let score_with_critical = assessment.calculate_security_score(&report_with_critical);
assert!(score_with_critical < 100.0);
assert!(score_with_critical >= 0.0);
}
#[test]
fn test_security_level_determination() {
let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
assert_eq!(
assessment.determine_security_level(100.0),
SecurityLevel::Hardened
);
assert_eq!(
assessment.determine_security_level(90.0),
SecurityLevel::Secure
);
assert_eq!(
assessment.determine_security_level(75.0),
SecurityLevel::Weak
);
assert_eq!(
assessment.determine_security_level(60.0),
SecurityLevel::Vulnerable
);
assert_eq!(
assessment.determine_security_level(30.0),
SecurityLevel::Insecure
);
}
}