use pattern_core::Pattern;
#[test]
fn map_then_traverse_option() {
let pattern = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result = pattern
.map(|v| format!("{}", v * 2))
.traverse_option(|s| s.parse::<i32>().ok());
assert!(result.is_some());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 2);
assert_eq!(unwrapped.elements[0].value, 4);
assert_eq!(unwrapped.elements[1].value, 6);
}
#[test]
fn map_then_traverse_result() {
let pattern = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result: Result<Pattern<i32>, String> = pattern
.map(|v| format!("{}", v * 10))
.traverse_result(|s| s.parse::<i32>().map_err(|e| format!("parse error: {}", e)));
assert!(result.is_ok());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 10);
assert_eq!(unwrapped.elements[0].value, 20);
assert_eq!(unwrapped.elements[1].value, 30);
}
#[test]
fn traverse_then_map() {
let pattern = Pattern::pattern("1", vec![Pattern::point("2"), Pattern::point("3")]);
let result = pattern
.traverse_option(|s| s.parse::<i32>().ok())
.map(|p| p.map(|v| v * 100));
assert!(result.is_some());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 100);
assert_eq!(unwrapped.elements[0].value, 200);
assert_eq!(unwrapped.elements[1].value, 300);
}
#[test]
fn traverse_option_then_fold() {
let pattern = Pattern::pattern("1", vec![Pattern::point("2"), Pattern::point("3")]);
let result = pattern
.traverse_option(|s| s.parse::<i32>().ok())
.map(|p| p.fold(0, |acc, v| acc + v));
assert_eq!(result, Some(6)); }
#[test]
fn traverse_result_then_fold() {
let pattern = Pattern::pattern("1", vec![Pattern::point("2"), Pattern::point("3")]);
let result: Result<i32, String> = pattern
.traverse_result(|s| s.parse::<i32>().map_err(|e| format!("error: {}", e)))
.map(|p| p.fold(0, |acc, v| acc + v));
assert!(result.is_ok());
assert_eq!(result.unwrap(), 6); }
#[test]
fn traverse_error_prevents_fold() {
let pattern = Pattern::pattern("1", vec![Pattern::point("invalid"), Pattern::point("3")]);
let result: Result<i32, String> = pattern
.traverse_result(|s| s.parse::<i32>().map_err(|e| format!("error: {}", e)))
.map(|p| p.fold(0, |acc, v| acc + v));
assert!(result.is_err());
}
#[test]
fn full_pipeline_map_traverse_fold() {
let pattern = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result = pattern
.map(|v| format!("{}", v * 10)) .traverse_option(|s| {
s.parse::<i32>().ok().filter(|&n| n > 0) })
.map(|p| p.fold(1, |acc, v| acc * v));
assert_eq!(result, Some(6000)); }
#[test]
fn full_pipeline_with_validation_error() {
let pattern = Pattern::pattern(-1, vec![Pattern::point(2), Pattern::point(3)]);
let result = pattern
.map(|v| v * 10)
.traverse_result(|&v| {
if v > 0 {
Ok(v)
} else {
Err(format!("negative value: {}", v))
}
})
.map(|p| p.fold(0, |acc, v| acc + v));
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "negative value: -10");
}
#[test]
fn map_then_validate_all() {
let pattern = Pattern::pattern(1, vec![Pattern::point(-2), Pattern::point(3)]);
let result: Result<Pattern<i32>, Vec<String>> = pattern.map(|v| v * 10).validate_all(|&v| {
if v > 0 {
Ok(v)
} else {
Err(format!("negative: {}", v))
}
});
assert!(result.is_err());
let errors = result.unwrap_err();
assert_eq!(errors.len(), 1);
assert!(errors[0].contains("negative: -20"));
}
#[test]
fn validate_all_then_fold() {
let pattern = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result: Result<i32, Vec<String>> = pattern
.validate_all(|&v| {
if v > 0 {
Ok(v * 10)
} else {
Err(format!("negative: {}", v))
}
})
.map(|p| p.fold(0, |acc, v| acc + v));
assert!(result.is_ok());
assert_eq!(result.unwrap(), 60); }
#[test]
fn map_to_option_then_sequence() {
let pattern = Pattern::pattern(1, vec![Pattern::point(2), Pattern::point(3)]);
let result = pattern
.map(|&v| if v > 0 { Some(v * 10) } else { None })
.sequence_option();
assert!(result.is_some());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 10);
assert_eq!(unwrapped.elements[0].value, 20);
}
#[test]
fn sequence_result_then_fold() {
let pattern: Pattern<Result<i32, String>> =
Pattern::pattern(Ok(10), vec![Pattern::point(Ok(20)), Pattern::point(Ok(30))]);
let result: Result<i32, String> = pattern
.sequence_result()
.map(|p| p.fold(0, |acc, v| acc + v));
assert!(result.is_ok());
assert_eq!(result.unwrap(), 60);
}
#[test]
fn nested_map_traverse_composition() {
let pattern = Pattern::pattern(
1,
vec![
Pattern::pattern(2, vec![Pattern::point(3)]),
Pattern::point(4),
],
);
let result = pattern
.map(|v| v * 2) .map(|v| format!("{}", v)) .traverse_option(|s| s.parse::<i32>().ok()) .map(|p| p.map(|v| v + 1));
assert!(result.is_some());
let unwrapped = result.unwrap();
assert_eq!(unwrapped.value, 3); assert_eq!(unwrapped.elements[0].value, 5); assert_eq!(unwrapped.elements[0].elements[0].value, 7); assert_eq!(unwrapped.elements[1].value, 9); }