use crate::bootstrap::*;
use std::collections::HashSet;
#[test]
fn bootstrap_patterns_returns_25_patterns() {
let patterns = get_bootstrap_patterns();
assert_eq!(patterns.len(), 25);
}
#[test]
fn bootstrap_patterns_all_fields_non_empty() {
for p in get_bootstrap_patterns() {
assert!(!p.error_code.is_empty(), "error_code empty for: {}", p.description);
assert!(!p.fix_diff.is_empty(), "fix_diff empty for: {}", p.description);
assert!(!p.decision.is_empty(), "decision empty for: {}", p.description);
assert!(!p.description.is_empty(), "description empty");
}
}
#[test]
fn pattern_idx_0_type_coercion_int_cast() {
let p = &get_bootstrap_patterns()[0];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "type_coercion");
assert!(p.fix_diff.contains("as i32"), "fix_diff: {}", p.fix_diff);
assert!(p.description.contains("explicit type cast"), "desc: {}", p.description);
}
#[test]
fn pattern_idx_1_pointer_to_mut_reference() {
let p = &get_bootstrap_patterns()[1];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "pointer_to_reference");
assert!(p.fix_diff.contains("*mut i32"));
assert!(p.fix_diff.contains("&mut i32"));
assert!(p.description.contains("mutable reference"));
}
#[test]
fn pattern_idx_2_pointer_to_immut_reference() {
let p = &get_bootstrap_patterns()[2];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "pointer_to_reference");
assert!(p.fix_diff.contains("*const i32"));
assert!(p.fix_diff.contains("&i32"));
assert!(p.description.contains("immutable reference"));
}
#[test]
fn pattern_idx_3_mutable_reference_swap() {
let p = &get_bootstrap_patterns()[3];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "mutable_reference");
assert!(p.fix_diff.contains("&mut x"), "fix_diff: {}", p.fix_diff);
assert!(p.fix_diff.contains("&mut y"), "fix_diff: {}", p.fix_diff);
}
#[test]
fn pattern_idx_4_exit_type_coercion() {
let p = &get_bootstrap_patterns()[4];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "type_coercion");
assert!(p.fix_diff.contains("std::process::exit"));
assert!(p.fix_diff.contains("as i32"));
}
#[test]
fn pattern_idx_5_unsafe_deref_write() {
let p = &get_bootstrap_patterns()[5];
assert_eq!(p.error_code, "E0133");
assert_eq!(p.decision, "unsafe_deref");
assert!(p.fix_diff.contains("*ptr = value"));
assert!(p.fix_diff.contains("unsafe"));
assert!(p.description.contains("dereference"));
}
#[test]
fn pattern_idx_6_unsafe_deref_read() {
let p = &get_bootstrap_patterns()[6];
assert_eq!(p.error_code, "E0133");
assert_eq!(p.decision, "unsafe_deref");
assert!(p.fix_diff.contains("let x = *ptr"));
assert!(p.fix_diff.contains("unsafe"));
assert!(p.description.contains("pointer read"));
}
#[test]
fn pattern_idx_7_unsafe_extern_call() {
let p = &get_bootstrap_patterns()[7];
assert_eq!(p.error_code, "E0133");
assert_eq!(p.decision, "unsafe_extern");
assert!(p.fix_diff.contains("extern_fn()"));
assert!(p.fix_diff.contains("unsafe"));
assert!(p.description.contains("extern function"));
}
#[test]
fn pattern_idx_8_clone_before_move() {
let p = &get_bootstrap_patterns()[8];
assert_eq!(p.error_code, "E0382");
assert_eq!(p.decision, "clone_before_move");
assert!(p.fix_diff.contains("value.clone()"));
assert!(p.description.contains("Clone"));
}
#[test]
fn pattern_idx_9_borrow_instead_of_move() {
let p = &get_bootstrap_patterns()[9];
assert_eq!(p.error_code, "E0382");
assert_eq!(p.decision, "borrow_instead_of_move");
assert!(p.fix_diff.contains("let y = &x"));
assert!(p.description.contains("Borrow"));
}
#[test]
fn pattern_idx_10_borrow_parameter() {
let p = &get_bootstrap_patterns()[10];
assert_eq!(p.error_code, "E0382");
assert_eq!(p.decision, "borrow_parameter");
assert!(p.fix_diff.contains("fn take(s: &String)"));
assert!(p.description.contains("borrow"));
}
#[test]
fn pattern_idx_11_sequential_mutable_borrow() {
let p = &get_bootstrap_patterns()[11];
assert_eq!(p.error_code, "E0499");
assert_eq!(p.decision, "sequential_mutable_borrow");
assert!(p.fix_diff.contains("drop(a)"));
assert!(p.description.contains("End first mutable borrow"));
}
#[test]
fn pattern_idx_12_use_stdlib_swap() {
let p = &get_bootstrap_patterns()[12];
assert_eq!(p.error_code, "E0499");
assert_eq!(p.decision, "use_stdlib_method");
assert!(p.fix_diff.contains("arr.swap(i, j)"));
assert!(p.description.contains("stdlib"));
}
#[test]
fn pattern_idx_13_reorder_borrow() {
let p = &get_bootstrap_patterns()[13];
assert_eq!(p.error_code, "E0506");
assert_eq!(p.decision, "reorder_borrow");
assert!(p.fix_diff.contains("x = 5"));
assert!(p.description.contains("Reorder"));
}
#[test]
fn pattern_idx_14_extend_lifetime() {
let p = &get_bootstrap_patterns()[14];
assert_eq!(p.error_code, "E0597");
assert_eq!(p.decision, "extend_lifetime");
assert!(p.fix_diff.contains("let x = 5"));
assert!(p.description.contains("outer scope"));
}
#[test]
fn pattern_idx_15_return_owned_e0597() {
let p = &get_bootstrap_patterns()[15];
assert_eq!(p.error_code, "E0597");
assert_eq!(p.decision, "return_owned");
assert!(p.fix_diff.contains("-> i32"));
assert!(p.description.contains("owned value"));
}
#[test]
fn pattern_idx_16_return_owned_e0515() {
let p = &get_bootstrap_patterns()[16];
assert_eq!(p.error_code, "E0515");
assert_eq!(p.decision, "return_owned");
assert!(p.fix_diff.contains("-> Vec<i32>"));
assert!(p.description.contains("owned value"));
}
#[test]
fn pattern_idx_17_clone_return() {
let p = &get_bootstrap_patterns()[17];
assert_eq!(p.error_code, "E0515");
assert_eq!(p.decision, "clone_return");
assert!(p.fix_diff.contains("local.clone()"));
assert!(p.description.contains("Clone"));
}
#[test]
fn pattern_idx_18_array_to_slice() {
let p = &get_bootstrap_patterns()[18];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "array_to_slice");
assert!(p.fix_diff.contains("&[i32]"));
assert!(p.description.contains("slice"));
}
#[test]
fn pattern_idx_19_bounds_checked_access() {
let p = &get_bootstrap_patterns()[19];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "bounds_checked_access");
assert!(p.fix_diff.contains("arr.get(i)"));
assert!(p.fix_diff.contains("unwrap_or(0)"));
assert!(p.description.contains("bounds check"));
}
#[test]
fn pattern_idx_20_safe_pointer_arithmetic() {
let p = &get_bootstrap_patterns()[20];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "safe_pointer_arithmetic");
assert!(p.fix_diff.contains("wrapping_add(offset)"));
assert!(p.description.contains("safe pointer arithmetic"));
}
#[test]
fn pattern_idx_21_malloc_to_box() {
let p = &get_bootstrap_patterns()[21];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "malloc_to_box");
assert!(p.fix_diff.contains("malloc"));
assert!(p.fix_diff.contains("Box::new(value)"));
assert!(p.description.contains("Box"));
}
#[test]
fn pattern_idx_22_malloc_array_to_vec() {
let p = &get_bootstrap_patterns()[22];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "malloc_array_to_vec");
assert!(p.fix_diff.contains("Vec::with_capacity(n)"));
assert!(p.description.contains("Vec"));
}
#[test]
fn pattern_idx_23_arrow_to_dot() {
let p = &get_bootstrap_patterns()[23];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "arrow_to_dot");
assert!(p.fix_diff.contains("p->field"));
assert!(p.fix_diff.contains("p.field"));
assert!(p.description.contains("arrow"));
}
#[test]
fn pattern_idx_24_nullable_to_option() {
let p = &get_bootstrap_patterns()[24];
assert_eq!(p.error_code, "E0308");
assert_eq!(p.decision, "nullable_to_option");
assert!(p.fix_diff.contains("Option<Box<Node>>"));
assert!(p.description.contains("Option"));
}
#[test]
fn error_codes_e0308_has_12_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0308")
.count();
assert_eq!(count, 12);
}
#[test]
fn error_codes_e0133_has_3_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0133")
.count();
assert_eq!(count, 3);
}
#[test]
fn error_codes_e0382_has_3_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0382")
.count();
assert_eq!(count, 3);
}
#[test]
fn error_codes_e0499_has_2_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0499")
.count();
assert_eq!(count, 2);
}
#[test]
fn error_codes_e0506_has_1_pattern() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0506")
.count();
assert_eq!(count, 1);
}
#[test]
fn error_codes_e0597_has_2_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0597")
.count();
assert_eq!(count, 2);
}
#[test]
fn error_codes_e0515_has_2_patterns() {
let count = get_bootstrap_patterns()
.iter()
.filter(|p| p.error_code == "E0515")
.count();
assert_eq!(count, 2);
}
#[test]
fn all_21_decision_types_present() {
let patterns = get_bootstrap_patterns();
let decisions: HashSet<&str> = patterns.iter().map(|p| p.decision).collect();
assert_eq!(decisions.len(), 21);
let expected = [
"type_coercion",
"pointer_to_reference",
"mutable_reference",
"unsafe_deref",
"unsafe_extern",
"clone_before_move",
"borrow_instead_of_move",
"borrow_parameter",
"sequential_mutable_borrow",
"use_stdlib_method",
"reorder_borrow",
"extend_lifetime",
"return_owned",
"clone_return",
"array_to_slice",
"bounds_checked_access",
"safe_pointer_arithmetic",
"malloc_to_box",
"malloc_array_to_vec",
"arrow_to_dot",
"nullable_to_option",
];
for d in &expected {
assert!(decisions.contains(d), "Missing decision type: {}", d);
}
}
#[test]
fn all_fix_diffs_contain_both_minus_and_plus() {
for p in get_bootstrap_patterns() {
assert!(
p.fix_diff.contains('-') && p.fix_diff.contains('+'),
"Pattern '{}' fix_diff missing - or +: {}",
p.decision,
p.fix_diff
);
}
}
#[test]
fn all_error_codes_are_exxxx_format() {
for p in get_bootstrap_patterns() {
assert!(p.error_code.starts_with('E'), "error_code should start with E: {}", p.error_code);
assert_eq!(p.error_code.len(), 5, "error_code should be 5 chars: {}", p.error_code);
assert!(
p.error_code[1..].chars().all(|c| c.is_ascii_digit()),
"error_code digits: {}",
p.error_code
);
}
}
#[test]
fn all_decisions_are_snake_case() {
for p in get_bootstrap_patterns() {
assert!(
p.decision.chars().all(|c| c.is_lowercase() || c == '_'),
"decision not snake_case: {}",
p.decision
);
}
}
#[test]
fn all_descriptions_start_with_uppercase() {
for p in get_bootstrap_patterns() {
let first = p.description.chars().next().unwrap();
assert!(first.is_uppercase(), "description should start uppercase: {}", p.description);
}
}
#[test]
fn bootstrap_pattern_clone_preserves_fields() {
let patterns = get_bootstrap_patterns();
for p in &patterns {
let cloned = p.clone();
assert_eq!(cloned.error_code, p.error_code);
assert_eq!(cloned.fix_diff, p.fix_diff);
assert_eq!(cloned.decision, p.decision);
assert_eq!(cloned.description, p.description);
}
}
#[test]
fn bootstrap_pattern_debug_contains_struct_name() {
let patterns = get_bootstrap_patterns();
let debug = format!("{:?}", patterns[0]);
assert!(debug.contains("BootstrapPattern"));
}
#[test]
fn stats_from_patterns_total() {
let stats = BootstrapStats::from_patterns();
assert_eq!(stats.total_patterns, 25);
}
#[test]
fn stats_from_patterns_error_code_map() {
let stats = BootstrapStats::from_patterns();
assert_eq!(stats.by_error_code.len(), 7);
assert_eq!(*stats.by_error_code.get("E0308").unwrap(), 12);
assert_eq!(*stats.by_error_code.get("E0133").unwrap(), 3);
assert_eq!(*stats.by_error_code.get("E0382").unwrap(), 3);
assert_eq!(*stats.by_error_code.get("E0499").unwrap(), 2);
assert_eq!(*stats.by_error_code.get("E0506").unwrap(), 1);
assert_eq!(*stats.by_error_code.get("E0597").unwrap(), 2);
assert_eq!(*stats.by_error_code.get("E0515").unwrap(), 2);
}
#[test]
fn stats_from_patterns_decision_map() {
let stats = BootstrapStats::from_patterns();
assert_eq!(stats.by_decision.len(), 21);
assert_eq!(*stats.by_decision.get("type_coercion").unwrap(), 2);
assert_eq!(*stats.by_decision.get("pointer_to_reference").unwrap(), 2);
assert_eq!(*stats.by_decision.get("unsafe_deref").unwrap(), 2);
assert_eq!(*stats.by_decision.get("return_owned").unwrap(), 2);
assert_eq!(*stats.by_decision.get("mutable_reference").unwrap(), 1);
assert_eq!(*stats.by_decision.get("unsafe_extern").unwrap(), 1);
assert_eq!(*stats.by_decision.get("clone_before_move").unwrap(), 1);
assert_eq!(*stats.by_decision.get("borrow_instead_of_move").unwrap(), 1);
assert_eq!(*stats.by_decision.get("borrow_parameter").unwrap(), 1);
assert_eq!(*stats.by_decision.get("sequential_mutable_borrow").unwrap(), 1);
assert_eq!(*stats.by_decision.get("use_stdlib_method").unwrap(), 1);
assert_eq!(*stats.by_decision.get("reorder_borrow").unwrap(), 1);
assert_eq!(*stats.by_decision.get("extend_lifetime").unwrap(), 1);
assert_eq!(*stats.by_decision.get("clone_return").unwrap(), 1);
assert_eq!(*stats.by_decision.get("array_to_slice").unwrap(), 1);
assert_eq!(*stats.by_decision.get("bounds_checked_access").unwrap(), 1);
assert_eq!(*stats.by_decision.get("safe_pointer_arithmetic").unwrap(), 1);
assert_eq!(*stats.by_decision.get("malloc_to_box").unwrap(), 1);
assert_eq!(*stats.by_decision.get("malloc_array_to_vec").unwrap(), 1);
assert_eq!(*stats.by_decision.get("arrow_to_dot").unwrap(), 1);
assert_eq!(*stats.by_decision.get("nullable_to_option").unwrap(), 1);
}
#[test]
fn stats_default_is_empty() {
let stats = BootstrapStats::default();
assert_eq!(stats.total_patterns, 0);
assert!(stats.by_error_code.is_empty());
assert!(stats.by_decision.is_empty());
}
#[test]
fn stats_debug_format() {
let stats = BootstrapStats::from_patterns();
let debug = format!("{:?}", stats);
assert!(debug.contains("BootstrapStats"));
assert!(debug.contains("total_patterns"));
assert!(debug.contains("by_error_code"));
assert!(debug.contains("by_decision"));
}
#[test]
fn stats_pretty_contains_header() {
let stats = BootstrapStats::from_patterns();
let pretty = stats.to_string_pretty();
assert!(pretty.contains("Bootstrap Patterns: 25"));
assert!(pretty.contains("By Error Code:"));
assert!(pretty.contains("By Decision Type:"));
}
#[test]
fn stats_pretty_contains_all_error_codes_with_counts() {
let stats = BootstrapStats::from_patterns();
let pretty = stats.to_string_pretty();
assert!(pretty.contains("E0308: 12"));
assert!(pretty.contains("E0133: 3"));
assert!(pretty.contains("E0382: 3"));
assert!(pretty.contains("E0499: 2"));
assert!(pretty.contains("E0506: 1"));
assert!(pretty.contains("E0597: 2"));
assert!(pretty.contains("E0515: 2"));
}
#[test]
fn stats_pretty_error_codes_sorted_alphabetically() {
let stats = BootstrapStats::from_patterns();
let pretty = stats.to_string_pretty();
let pos_e0133 = pretty.find("E0133").unwrap();
let pos_e0308 = pretty.find("E0308").unwrap();
let pos_e0382 = pretty.find("E0382").unwrap();
let pos_e0499 = pretty.find("E0499").unwrap();
let pos_e0506 = pretty.find("E0506").unwrap();
let pos_e0515 = pretty.find("E0515").unwrap();
let pos_e0597 = pretty.find("E0597").unwrap();
assert!(pos_e0133 < pos_e0308);
assert!(pos_e0308 < pos_e0382);
assert!(pos_e0382 < pos_e0499);
assert!(pos_e0499 < pos_e0506);
assert!(pos_e0506 < pos_e0515);
assert!(pos_e0515 < pos_e0597);
}
#[test]
fn stats_pretty_decisions_sorted_by_count_desc() {
let stats = BootstrapStats::from_patterns();
let pretty = stats.to_string_pretty();
let decision_section = pretty.find("By Decision Type:").unwrap();
let tail = &pretty[decision_section..];
let pos_type_coercion = tail.find("type_coercion").unwrap();
let pos_nullable = tail.find("nullable_to_option").unwrap();
assert!(
pos_type_coercion < pos_nullable,
"type_coercion (2) should appear before nullable_to_option (1)"
);
}
#[test]
fn c_specific_array_pointer_patterns_have_correct_content() {
let patterns = get_bootstrap_patterns();
let array_patterns: Vec<_> = patterns
.iter()
.filter(|p| {
p.decision == "array_to_slice"
|| p.decision == "bounds_checked_access"
|| p.decision == "safe_pointer_arithmetic"
})
.collect();
assert_eq!(array_patterns.len(), 3);
assert!(array_patterns.iter().all(|p| p.error_code == "E0308"));
}
#[test]
fn c_specific_malloc_free_patterns_have_correct_content() {
let patterns = get_bootstrap_patterns();
let malloc_patterns: Vec<_> = patterns
.iter()
.filter(|p| p.decision == "malloc_to_box" || p.decision == "malloc_array_to_vec")
.collect();
assert_eq!(malloc_patterns.len(), 2);
assert!(malloc_patterns.iter().all(|p| p.error_code == "E0308"));
assert!(malloc_patterns.iter().any(|p| p.fix_diff.contains("Box::new")));
assert!(malloc_patterns.iter().any(|p| p.fix_diff.contains("Vec::with_capacity")));
}
#[test]
fn c_specific_struct_patterns_have_correct_content() {
let patterns = get_bootstrap_patterns();
let struct_patterns: Vec<_> = patterns
.iter()
.filter(|p| p.decision == "arrow_to_dot" || p.decision == "nullable_to_option")
.collect();
assert_eq!(struct_patterns.len(), 2);
assert!(struct_patterns.iter().all(|p| p.error_code == "E0308"));
}
#[test]
fn e0133_unsafe_patterns_all_mention_unsafe_in_diff() {
let patterns = get_bootstrap_patterns();
let unsafe_patterns: Vec<_> = patterns
.iter()
.filter(|p| p.error_code == "E0133")
.collect();
for p in &unsafe_patterns {
assert!(
p.fix_diff.contains("unsafe"),
"E0133 pattern should mention 'unsafe': {}",
p.description
);
}
}
#[test]
fn e0382_ownership_patterns_cover_all_strategies() {
let patterns = get_bootstrap_patterns();
let e0382: Vec<_> = patterns
.iter()
.filter(|p| p.error_code == "E0382")
.collect();
let decisions: HashSet<&str> = e0382.iter().map(|p| p.decision).collect();
assert!(decisions.contains("clone_before_move"));
assert!(decisions.contains("borrow_instead_of_move"));
assert!(decisions.contains("borrow_parameter"));
}
#[test]
fn e0499_borrow_patterns_cover_both_strategies() {
let patterns = get_bootstrap_patterns();
let e0499: Vec<_> = patterns
.iter()
.filter(|p| p.error_code == "E0499")
.collect();
let decisions: HashSet<&str> = e0499.iter().map(|p| p.decision).collect();
assert!(decisions.contains("sequential_mutable_borrow"));
assert!(decisions.contains("use_stdlib_method"));
}
#[test]
fn iterate_all_patterns_collect_all_fields() {
let patterns = get_bootstrap_patterns();
let mut error_codes = Vec::with_capacity(25);
let mut fix_diffs = Vec::with_capacity(25);
let mut decisions = Vec::with_capacity(25);
let mut descriptions = Vec::with_capacity(25);
for p in &patterns {
error_codes.push(p.error_code);
fix_diffs.push(p.fix_diff);
decisions.push(p.decision);
descriptions.push(p.description);
}
assert_eq!(error_codes.len(), 25);
assert_eq!(fix_diffs.len(), 25);
assert_eq!(decisions.len(), 25);
assert_eq!(descriptions.len(), 25);
let total_chars: usize = error_codes.iter().map(|s| s.len()).sum::<usize>()
+ fix_diffs.iter().map(|s| s.len()).sum::<usize>()
+ decisions.iter().map(|s| s.len()).sum::<usize>()
+ descriptions.iter().map(|s| s.len()).sum::<usize>();
assert!(total_chars > 500, "Should have substantial combined content");
}
#[test]
fn no_duplicate_decision_description_pairs() {
let patterns = get_bootstrap_patterns();
let pairs: HashSet<_> = patterns
.iter()
.map(|p| (p.decision, p.description))
.collect();
assert_eq!(
pairs.len(),
patterns.len(),
"Each pattern should have unique (decision, description) pair"
);
}
#[test]
fn no_duplicate_fix_diffs() {
let patterns = get_bootstrap_patterns();
let diffs: HashSet<_> = patterns.iter().map(|p| p.fix_diff).collect();
assert_eq!(
diffs.len(),
patterns.len(),
"Each pattern should have a unique fix_diff"
);
}