use langchainrust::{AgentState, GraphBuilder, GraphError, StateGraph, StateUpdate, END, START};
use std::collections::HashMap;
#[test]
fn test_cycle_detection_simple() {
let mut graph: StateGraph<AgentState> = StateGraph::new();
graph.add_node_fn("node1", |state| Ok(StateUpdate::full(state.clone())));
graph.add_node_fn("node2", |state| Ok(StateUpdate::full(state.clone())));
graph.add_edge(START, "node1");
graph.add_edge("node1", "node2");
graph.add_edge("node2", "node1");
let result = graph.compile();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(err, GraphError::InfiniteCycleError(_)));
}
#[test]
fn test_unreachable_node_detection() {
let mut graph: StateGraph<AgentState> = StateGraph::new();
graph.add_node_fn("connected", |state| Ok(StateUpdate::full(state.clone())));
graph.add_node_fn("isolated", |state| Ok(StateUpdate::full(state.clone())));
graph.add_edge(START, "connected");
graph.add_edge("connected", END);
let result = graph.compile();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(err, GraphError::OrphanNodeError(_)));
assert!(err.to_string().contains("isolated"));
}
#[test]
fn test_duplicate_edge_detection() {
let mut graph: StateGraph<AgentState> = StateGraph::new();
graph.add_node_fn("node1", |state| Ok(StateUpdate::full(state.clone())));
graph.add_node_fn("node2", |state| Ok(StateUpdate::full(state.clone())));
graph.add_edge(START, "node1");
graph.add_edge("node1", "node2");
graph.add_edge("node1", "node2"); graph.add_edge("node2", END);
let result = graph.compile();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(err, GraphError::DuplicateEdgeError(_)));
}
#[test]
fn test_conditional_edge_invalid_target() {
let mut graph: StateGraph<AgentState> = StateGraph::new();
graph.add_node_fn("decision", |state| Ok(StateUpdate::full(state.clone())));
graph.add_node_fn("path_a", |state| Ok(StateUpdate::full(state.clone())));
graph.add_edge(START, "decision");
let targets = HashMap::from([
("a".to_string(), "path_a".to_string()),
("b".to_string(), "nonexistent_node".to_string()), ]);
graph.add_conditional_edges("decision", "router", targets, None);
graph.add_edge("path_a", END);
let router = langchainrust::FunctionRouter::new(|_state| "a".to_string());
graph.set_conditional_router("router", router);
let result = graph.compile();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(err, GraphError::ValidationError(_)));
}
#[test]
fn test_edge_targeting_start() {
let mut graph: StateGraph<AgentState> = StateGraph::new();
graph.add_node_fn("loop_node", |state| Ok(StateUpdate::full(state.clone())));
graph.add_edge(START, "loop_node");
graph.add_edge("loop_node", START);
let result = graph.compile();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("START"));
}
#[test]
fn test_valid_graph_compiles() {
let compiled = GraphBuilder::<AgentState>::new()
.add_node_fn("step1", |state| Ok(StateUpdate::full(state.clone())))
.add_node_fn("step2", |state| Ok(StateUpdate::full(state.clone())))
.add_node_fn("step3", |state| Ok(StateUpdate::full(state.clone())))
.add_edge(START, "step1")
.add_edge("step1", "step2")
.add_edge("step2", "step3")
.add_edge("step3", END)
.compile();
assert!(compiled.is_ok());
}