use std::sync::Arc;
use super::*;
#[test]
fn test_planning_phase_started_sets_planning_phase() {
let state = create_test_state();
let new_state = reduce(state, PipelineEvent::planning_phase_started());
assert_eq!(new_state.phase, PipelinePhase::Planning);
}
#[test]
fn test_planning_phase_completed_transitions_to_development() {
let state = create_state_in_phase(PipelinePhase::Planning);
let new_state = reduce(state, PipelineEvent::planning_phase_completed());
assert_eq!(new_state.phase, PipelinePhase::Development);
}
#[test]
fn test_planning_prompt_prepared_sets_iteration() {
let state = create_test_state();
let new_state = reduce(state, PipelineEvent::planning_prompt_prepared(1));
assert_eq!(new_state.planning_prompt_prepared_iteration, Some(1));
}
#[test]
fn test_plan_generation_completed_transitions_to_development() {
let state = create_state_in_phase(PipelinePhase::Planning);
let new_state = reduce(state, PipelineEvent::plan_generation_completed(1, true));
assert_eq!(new_state.phase, PipelinePhase::Development);
}
#[test]
fn test_planning_output_validation_failed_increments_attempt() {
let state = create_state_in_phase(PipelinePhase::Planning);
assert_eq!(state.continuation.invalid_output_attempts, 0);
let new_state = reduce(
state,
PipelineEvent::planning_output_validation_failed(1, 0),
);
assert_eq!(new_state.continuation.invalid_output_attempts, 1);
assert_eq!(new_state.phase, PipelinePhase::Planning);
assert_eq!(new_state.iteration, 1);
}
#[test]
fn test_planning_output_validation_failed_stays_in_planning_phase() {
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.iteration = 1;
let new_state = reduce(
state,
PipelineEvent::planning_output_validation_failed(1, 0),
);
assert_eq!(new_state.phase, PipelinePhase::Planning);
}
#[test]
fn test_planning_output_validation_failed_switches_agent_at_max_attempts() {
use crate::reducer::state::ContinuationState;
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.iteration = 1;
state.continuation = ContinuationState {
same_agent_retry_count: 1,
same_agent_retry_pending: true,
same_agent_retry_reason: Some(crate::reducer::state::SameAgentRetryReason::Timeout),
xsd_retry_count: 1,
max_xsd_retry_count: 2,
..ContinuationState::new()
};
state.agent_chain.agents = Arc::from(vec!["agent1".to_string(), "agent2".to_string()]);
state.agent_chain.current_agent_index = 0;
let new_state = reduce(
state,
PipelineEvent::planning_output_validation_failed(1, 0),
);
assert_eq!(new_state.agent_chain.current_agent_index, 1);
assert_eq!(new_state.continuation.invalid_output_attempts, 0);
assert_eq!(
new_state.continuation.same_agent_retry_count, 0,
"Same-agent retry budget must not carry across agents"
);
assert!(
!new_state.continuation.same_agent_retry_pending,
"Same-agent retry pending must be cleared when switching agents"
);
assert!(
new_state.continuation.same_agent_retry_reason.is_none(),
"Same-agent retry reason must be cleared when switching agents"
);
assert_eq!(new_state.phase, PipelinePhase::Planning);
}
#[test]
fn test_planning_output_validation_failed_preserves_iteration() {
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.iteration = 3;
let new_state = reduce(
state,
PipelineEvent::planning_output_validation_failed(3, 1),
);
assert_eq!(new_state.iteration, 3);
}
#[test]
fn test_planning_output_validation_failed_multiple_attempts_before_switch() {
use crate::reducer::state::ContinuationState;
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.continuation = ContinuationState {
max_xsd_retry_count: 3,
..ContinuationState::new()
};
state.agent_chain.agents = Arc::from(vec!["agent1".to_string(), "agent2".to_string()]);
state.agent_chain.current_agent_index = 0;
let state = reduce(
state,
PipelineEvent::planning_output_validation_failed(1, 0),
);
assert_eq!(state.agent_chain.current_agent_index, 0);
assert_eq!(state.continuation.invalid_output_attempts, 1);
let state = reduce(
state,
PipelineEvent::planning_output_validation_failed(1, 1),
);
assert_eq!(state.agent_chain.current_agent_index, 0);
assert_eq!(state.continuation.invalid_output_attempts, 2);
}
#[test]
fn test_planning_phase_started_resets_invalid_output_attempts() {
let mut state = create_state_in_phase(PipelinePhase::Development);
state.continuation.invalid_output_attempts = 3;
let new_state = reduce(state, PipelineEvent::planning_phase_started());
assert_eq!(new_state.continuation.invalid_output_attempts, 0);
assert_eq!(new_state.phase, PipelinePhase::Planning);
}
#[test]
fn test_planning_phase_completed_resets_invalid_output_attempts() {
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.continuation.invalid_output_attempts = 2;
let new_state = reduce(state, PipelineEvent::planning_phase_completed());
assert_eq!(new_state.continuation.invalid_output_attempts, 0);
assert_eq!(new_state.phase, PipelinePhase::Development);
}
#[test]
fn test_plan_generation_completed_valid_resets_invalid_output_attempts() {
let mut state = create_state_in_phase(PipelinePhase::Planning);
state.continuation.invalid_output_attempts = 1;
let new_state = reduce(state, PipelineEvent::plan_generation_completed(1, true));
assert_eq!(new_state.continuation.invalid_output_attempts, 0);
assert_eq!(new_state.phase, PipelinePhase::Development);
}