use super::state::{AnalysisPhase, AnalysisState};
pub fn can_start_call_graph(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::Initialized) && state.results.metrics.is_some()
}
pub fn can_start_coverage(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::CallGraphComplete)
&& state.results.call_graph.is_some()
&& state.config.coverage_file.is_some()
}
pub fn can_skip_coverage(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::CallGraphComplete) && state.config.coverage_file.is_none()
}
pub fn can_start_purity(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::CoverageComplete) && state.results.call_graph.is_some()
}
pub fn can_start_context(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::PurityComplete)
&& state.results.enriched_metrics.is_some()
&& state.config.enable_context
}
pub fn can_skip_context(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::PurityComplete) && !state.config.enable_context
}
pub fn can_start_scoring(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::ContextComplete)
&& state.results.call_graph.is_some()
&& state.results.enriched_metrics.is_some()
}
pub fn can_start_filtering(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::ScoringComplete)
&& state.results.unified_analysis.is_some()
}
pub fn can_complete(state: &AnalysisState) -> bool {
matches!(state.phase, AnalysisPhase::FilteringInProgress)
&& state.results.unified_analysis.is_some()
}
pub fn is_valid_checkpoint(state: &AnalysisState) -> bool {
match state.phase {
AnalysisPhase::Initialized => true,
AnalysisPhase::CallGraphBuilding => state.results.metrics.is_some(),
AnalysisPhase::CallGraphComplete => {
state.results.metrics.is_some() && state.results.call_graph.is_some()
}
AnalysisPhase::CoverageLoading => {
state.results.metrics.is_some() && state.results.call_graph.is_some()
}
AnalysisPhase::CoverageComplete => {
state.results.metrics.is_some() && state.results.call_graph.is_some()
}
AnalysisPhase::PurityAnalyzing => {
state.results.metrics.is_some() && state.results.call_graph.is_some()
}
AnalysisPhase::PurityComplete => {
state.results.metrics.is_some()
&& state.results.call_graph.is_some()
&& state.results.enriched_metrics.is_some()
}
AnalysisPhase::ContextLoading | AnalysisPhase::ContextComplete => {
state.results.metrics.is_some()
&& state.results.call_graph.is_some()
&& state.results.enriched_metrics.is_some()
}
AnalysisPhase::ScoringInProgress | AnalysisPhase::ScoringComplete => {
state.results.metrics.is_some()
&& state.results.call_graph.is_some()
&& state.results.enriched_metrics.is_some()
}
AnalysisPhase::FilteringInProgress => {
state.results.metrics.is_some()
&& state.results.call_graph.is_some()
&& state.results.enriched_metrics.is_some()
&& state.results.unified_analysis.is_some()
}
AnalysisPhase::Complete => state.results.unified_analysis.is_some(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::analysis::workflow::state::AnalysisConfig;
use crate::core::FunctionMetrics;
use crate::priority::call_graph::CallGraph;
use std::path::PathBuf;
fn create_test_state() -> AnalysisState {
AnalysisState::new(AnalysisConfig::default())
}
fn create_test_metrics() -> Vec<FunctionMetrics> {
vec![FunctionMetrics::new(
"test_fn".to_string(),
PathBuf::from("test.rs"),
1,
)]
}
#[test]
fn test_can_start_call_graph_requires_metrics() {
let mut state = create_test_state();
assert!(!can_start_call_graph(&state));
state.results.metrics = Some(create_test_metrics());
assert!(can_start_call_graph(&state));
}
#[test]
fn test_can_start_call_graph_requires_initialized_phase() {
let mut state = create_test_state();
state.results.metrics = Some(create_test_metrics());
assert!(can_start_call_graph(&state));
state.phase = AnalysisPhase::CallGraphComplete;
assert!(!can_start_call_graph(&state));
}
#[test]
fn test_can_start_coverage_requires_config() {
let mut state = create_test_state();
state.phase = AnalysisPhase::CallGraphComplete;
state.results.call_graph = Some(CallGraph::new());
assert!(!can_start_coverage(&state));
assert!(can_skip_coverage(&state));
state.config.coverage_file = Some(PathBuf::from("coverage.lcov"));
assert!(can_start_coverage(&state));
assert!(!can_skip_coverage(&state));
}
#[test]
fn test_can_start_coverage_requires_call_graph() {
let mut state = create_test_state();
state.phase = AnalysisPhase::CallGraphComplete;
state.config.coverage_file = Some(PathBuf::from("coverage.lcov"));
assert!(!can_start_coverage(&state));
state.results.call_graph = Some(CallGraph::new());
assert!(can_start_coverage(&state));
}
#[test]
fn test_can_start_purity_requires_call_graph() {
let mut state = create_test_state();
state.phase = AnalysisPhase::CoverageComplete;
assert!(!can_start_purity(&state));
state.results.call_graph = Some(CallGraph::new());
assert!(can_start_purity(&state));
}
#[test]
fn test_can_start_purity_requires_coverage_complete_phase() {
let mut state = create_test_state();
state.results.call_graph = Some(CallGraph::new());
state.phase = AnalysisPhase::CallGraphComplete;
assert!(!can_start_purity(&state));
state.phase = AnalysisPhase::CoverageComplete;
assert!(can_start_purity(&state));
}
#[test]
fn test_can_start_context_requires_enable_flag() {
let mut state = create_test_state();
state.phase = AnalysisPhase::PurityComplete;
state.results.enriched_metrics = Some(create_test_metrics());
assert!(!can_start_context(&state));
assert!(can_skip_context(&state));
state.config.enable_context = true;
assert!(can_start_context(&state));
assert!(!can_skip_context(&state));
}
#[test]
fn test_can_start_scoring_requires_all_dependencies() {
let mut state = create_test_state();
state.phase = AnalysisPhase::ContextComplete;
assert!(!can_start_scoring(&state));
state.results.call_graph = Some(CallGraph::new());
assert!(!can_start_scoring(&state));
state.results.enriched_metrics = Some(create_test_metrics());
assert!(can_start_scoring(&state));
}
#[test]
fn test_guards_are_pure() {
let state = create_test_state();
let r1 = can_start_call_graph(&state);
let r2 = can_start_call_graph(&state);
assert_eq!(r1, r2, "Guards must be pure - same input, same output");
}
#[test]
fn test_guards_do_not_modify_state() {
let state = create_test_state();
let initial_phase = state.phase;
let _ = can_start_call_graph(&state);
let _ = can_start_coverage(&state);
let _ = can_skip_coverage(&state);
let _ = can_start_purity(&state);
let _ = can_start_context(&state);
let _ = can_skip_context(&state);
let _ = can_start_scoring(&state);
let _ = can_start_filtering(&state);
let _ = can_complete(&state);
assert_eq!(state.phase, initial_phase);
}
#[test]
fn test_is_valid_checkpoint_initialized() {
let state = create_test_state();
assert!(is_valid_checkpoint(&state));
}
#[test]
fn test_is_valid_checkpoint_call_graph_complete() {
let mut state = create_test_state();
state.phase = AnalysisPhase::CallGraphComplete;
assert!(!is_valid_checkpoint(&state));
state.results.metrics = Some(create_test_metrics());
state.results.call_graph = Some(CallGraph::new());
assert!(is_valid_checkpoint(&state));
}
#[test]
fn test_is_valid_checkpoint_complete() {
let mut state = create_test_state();
state.phase = AnalysisPhase::Complete;
assert!(!is_valid_checkpoint(&state));
state.results.unified_analysis =
Some(crate::priority::UnifiedAnalysis::new(CallGraph::new()));
assert!(is_valid_checkpoint(&state));
}
}