#![cfg_attr(coverage_nightly, coverage(off))]
use super::types::WasmComplexity;
use crate::models::unified_ast::{AstDag, NodeKey};
use anyhow::Result;
#[derive(Debug, Clone)]
pub struct MemoryCostModel {
pub load_cost: f64,
pub store_cost: f64,
pub grow_cost: f64,
}
impl Default for MemoryCostModel {
fn default() -> Self {
Self {
load_cost: 3.0,
store_cost: 5.0,
grow_cost: 100.0,
}
}
}
pub struct WasmComplexityAnalyzer {
_max_complexity: usize,
}
impl WasmComplexityAnalyzer {
#[must_use]
pub fn new() -> Self {
Self {
_max_complexity: 100,
}
}
pub fn analyze_ast(&self, _ast: &AstDag) -> Result<WasmComplexity> {
Ok(WasmComplexity {
cyclomatic: 5,
cognitive: 5,
memory_pressure: 1.0,
hot_path_score: 10.0,
estimated_gas: 5000.0,
indirect_call_overhead: 1.0,
max_loop_depth: 1,
})
}
pub fn analyze_function(&self, _dag: &AstDag, _func_id: NodeKey) -> WasmComplexity {
let cyclomatic = 1; let max_depth = 0u32;
WasmComplexity {
cyclomatic,
cognitive: cyclomatic,
memory_pressure: cyclomatic as f32 * 0.1,
hot_path_score: cyclomatic as f32,
estimated_gas: f64::from(cyclomatic) * 1000.0,
indirect_call_overhead: 1.0,
max_loop_depth: max_depth,
}
}
pub fn analyze_text(&self, content: &str) -> Result<WasmComplexity> {
let line_count = content.lines().count();
let function_count = content.matches("func").count();
let complexity_score = (function_count * 2) + (line_count / 10);
Ok(WasmComplexity {
cyclomatic: complexity_score as u32,
cognitive: complexity_score as u32,
memory_pressure: line_count as f32 * 0.1,
hot_path_score: complexity_score as f32,
estimated_gas: complexity_score as f64 * 1000.0,
indirect_call_overhead: 1.0,
max_loop_depth: 1,
})
}
}
impl Default for WasmComplexityAnalyzer {
fn default() -> Self {
Self::new()
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_complexity_analyzer_new() {
let analyzer = WasmComplexityAnalyzer::new();
assert!(analyzer._max_complexity == 100);
}
#[test]
fn test_complexity_analyzer_default() {
let analyzer = WasmComplexityAnalyzer::default();
assert!(analyzer._max_complexity == 100);
}
#[test]
fn test_complexity_analyzer() {
let analyzer = WasmComplexityAnalyzer::new();
let content = "(module (func $test (result i32) i32.const 42))";
let complexity = analyzer.analyze_text(content).unwrap();
assert!(complexity.cyclomatic > 0);
assert!(complexity.cognitive > 0);
}
#[test]
fn test_analyze_text_empty() {
let analyzer = WasmComplexityAnalyzer::new();
let complexity = analyzer.analyze_text("").unwrap();
assert_eq!(complexity.cyclomatic, 0);
assert_eq!(complexity.cognitive, 0);
}
#[test]
fn test_analyze_text_with_multiple_functions() {
let analyzer = WasmComplexityAnalyzer::new();
let content = "(module (func $a) (func $b) (func $c))";
let complexity = analyzer.analyze_text(content).unwrap();
assert!(complexity.cyclomatic >= 6);
}
#[test]
fn test_memory_cost_model_default() {
let model = MemoryCostModel::default();
assert_eq!(model.load_cost, 3.0);
assert_eq!(model.store_cost, 5.0);
assert_eq!(model.grow_cost, 100.0);
}
#[test]
fn test_memory_cost_model_clone() {
let model = MemoryCostModel::default();
let cloned = model.clone();
assert_eq!(model.load_cost, cloned.load_cost);
assert_eq!(model.store_cost, cloned.store_cost);
assert_eq!(model.grow_cost, cloned.grow_cost);
}
#[test]
fn test_memory_cost_model_debug() {
let model = MemoryCostModel::default();
let debug_str = format!("{:?}", model);
assert!(debug_str.contains("MemoryCostModel"));
}
#[test]
fn test_analyze_ast() {
let analyzer = WasmComplexityAnalyzer::new();
let dag = AstDag::new();
let complexity = analyzer.analyze_ast(&dag).unwrap();
assert_eq!(complexity.cyclomatic, 5);
assert_eq!(complexity.cognitive, 5);
}
#[test]
fn test_analyze_function() {
let analyzer = WasmComplexityAnalyzer::new();
let dag = AstDag::new();
let func_id: NodeKey = 0;
let complexity = analyzer.analyze_function(&dag, func_id);
assert_eq!(complexity.cyclomatic, 1);
assert_eq!(complexity.cognitive, 1);
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}