use pattern_core::Pattern;
#[test]
fn test_traverse_result_atomic_ok() {
let p = Pattern::point(10);
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| Ok(v * 2));
assert_eq!(result, Ok(Pattern::point(20)));
}
#[test]
fn test_traverse_result_atomic_err() {
let p = Pattern::point(10);
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| {
if *v > 5 {
Ok(v * 2)
} else {
Err("too small".to_string())
}
});
assert_eq!(result, Ok(Pattern::point(20)));
let p_err = Pattern::point(3);
let result_err: Result<Pattern<i32>, String> = p_err.traverse_result(|v| {
if *v > 5 {
Ok(v * 2)
} else {
Err("too small".to_string())
}
});
assert_eq!(result_err, Err("too small".to_string()));
}
#[test]
fn test_traverse_result_nested_all_ok() {
let p = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| Ok(v * 10));
assert_eq!(
result,
Ok(Pattern::pattern(
10,
vec![Pattern::point(20), Pattern::point(30)]
))
);
}
#[test]
fn test_traverse_result_nested_with_err() {
let p = Pattern::pattern(
10,
vec![Pattern::point(20), Pattern::point(3)], );
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| {
if *v > 5 {
Ok(v * 2)
} else {
Err(format!("value {} too small", v))
}
});
assert_eq!(result, Err("value 3 too small".to_string()));
}
#[test]
fn test_traverse_result_short_circuit() {
use pattern_core::test_utils::helpers::EffectCounter;
let p = Pattern::pattern(
1,
vec![
Pattern::point(2),
Pattern::point(3),
Pattern::point(4), Pattern::point(5),
Pattern::point(6),
],
);
let counter = EffectCounter::new();
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| {
counter.increment();
if *v < 4 {
Ok(v * 10)
} else {
Err(format!("value {} too large", v))
}
});
assert!(result.is_err());
assert_eq!(result, Err("value 4 too large".to_string()));
assert_eq!(counter.count(), 4);
}
#[test]
fn test_traverse_result_root_error_immediate_short_circuit() {
use pattern_core::test_utils::helpers::EffectCounter;
let p = Pattern::pattern(
10, vec![Pattern::point(2), Pattern::point(3)],
);
let counter = EffectCounter::new();
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| {
counter.increment();
if *v < 5 {
Ok(v * 10)
} else {
Err(format!("value {} too large", v))
}
});
assert!(result.is_err());
assert_eq!(result, Err("value 10 too large".to_string()));
assert_eq!(counter.count(), 1);
}
#[test]
fn test_traverse_result_type_change() {
let p = Pattern::pattern("1", vec![Pattern::point("2"), Pattern::point("3")]);
let result: Result<Pattern<i32>, String> =
p.traverse_result(|s| s.parse::<i32>().map_err(|e| format!("parse error: {}", e)));
assert!(result.is_ok());
let pattern = result.unwrap();
assert_eq!(pattern.value, 1);
assert_eq!(pattern.elements[0].value, 2);
assert_eq!(pattern.elements[1].value, 3);
}
#[test]
fn test_traverse_result_type_change_with_error() {
let p = Pattern::pattern("1", vec![Pattern::point("invalid"), Pattern::point("3")]);
let result: Result<Pattern<i32>, String> =
p.traverse_result(|s| s.parse::<i32>().map_err(|e| format!("parse error: {}", e)));
assert!(result.is_err());
assert!(result.unwrap_err().contains("parse error"));
}
#[test]
fn test_traverse_result_deep_nesting() {
let p = Pattern::pattern(
1,
vec![Pattern::pattern(
2,
vec![Pattern::pattern(
3,
vec![Pattern::pattern(4, vec![Pattern::point(5)])],
)],
)],
);
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| Ok(v * 10));
assert!(result.is_ok());
let pattern = result.unwrap();
assert_eq!(pattern.value, 10);
assert_eq!(pattern.elements[0].value, 20);
assert_eq!(pattern.elements[0].elements[0].value, 30);
assert_eq!(pattern.elements[0].elements[0].elements[0].value, 40);
assert_eq!(
pattern.elements[0].elements[0].elements[0].elements[0].value,
50
);
}
#[test]
fn test_traverse_result_deep_nesting_with_error() {
let p = Pattern::pattern(
1,
vec![Pattern::pattern(
2,
vec![Pattern::pattern(
3, vec![Pattern::pattern(4, vec![Pattern::point(5)])],
)],
)],
);
let result: Result<Pattern<i32>, String> = p.traverse_result(|v| {
if *v != 3 {
Ok(v * 10)
} else {
Err("found 3".to_string())
}
});
assert_eq!(result, Err("found 3".to_string()));
}
#[test]
fn sequence_result_all_ok() {
let pattern: Pattern<Result<i32, String>> =
Pattern::pattern(Ok(1), vec![Pattern::point(Ok(2)), Pattern::point(Ok(3))]);
let result = pattern.sequence_result();
assert!(result.is_ok());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 1);
assert_eq!(unwrapped.elements[0].value, 2);
assert_eq!(unwrapped.elements[1].value, 3);
}
#[test]
fn sequence_result_with_err() {
let pattern: Pattern<Result<i32, String>> = Pattern::pattern(
Ok(1),
vec![
Pattern::point(Ok(2)),
Pattern::point(Err("error here".to_string())), Pattern::point(Ok(3)),
],
);
let result = pattern.sequence_result();
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "error here".to_string());
}
#[test]
fn sequence_result_nested_structure() {
let pattern: Pattern<Result<i32, String>> = Pattern::pattern(
Ok(1),
vec![Pattern::pattern(
Ok(2),
vec![Pattern::point(Ok(3)), Pattern::point(Ok(4))],
)],
);
let result = pattern.sequence_result();
assert!(result.is_ok());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 1);
assert_eq!(unwrapped.elements[0].value, 2);
assert_eq!(unwrapped.elements[0].elements[0].value, 3);
assert_eq!(unwrapped.elements[0].elements[1].value, 4);
}
#[test]
fn sequence_result_err_in_root() {
let pattern: Pattern<Result<i32, String>> = Pattern::pattern(
Err("root error".to_string()), vec![Pattern::point(Ok(2)), Pattern::point(Ok(3))],
);
let result = pattern.sequence_result();
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "root error".to_string());
}
#[test]
fn sequence_result_atomic_ok() {
let pattern: Pattern<Result<i32, String>> = Pattern::point(Ok(42));
let result = pattern.sequence_result();
assert!(result.is_ok());
assert_eq!(result.unwrap().value, 42);
}
#[test]
fn sequence_result_atomic_err() {
let pattern: Pattern<Result<i32, String>> = Pattern::point(Err("error".to_string()));
let result = pattern.sequence_result();
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "error".to_string());
}