warpdotdev/warp, scoped to crates/fuzzy_match, at 714c51f1e2: the project's own tests caught 5 of 37 planted faults, 32 got through, and corral proved 6 of those missing tests by writing a test and running it.
#[cfg(test)]
mod corral_tests {
use super::super::*;
#[test]
fn test_substring_glob_match_indices_within_bounds() {
let text = "/src/ui/button.rs";
let pattern = "ui/*.rs";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match");
let char_count = text.chars().count();
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {idx} must be within bounds 0..{char_count}"
);
}
assert_eq!(result.matched_indices, vec![5, 6, 7, 14, 15, 16]);
}
#[test]
fn test_substring_glob_match_indices_partial_suffix() {
let text = "/src/ui/button.rs";
let pattern = "ui/*.r";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match");
let char_count = text.chars().count();
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {idx} must be within bounds 0..{char_count}"
);
}
assert_eq!(result.matched_indices, vec![5, 6, 7, 14, 15]);
}
#[test]
fn test_wildcard_matched_indices_strictly_within_character_bounds() {
let cases = [
("xabc", "a?c"),
("hello world", "w?rld"),
("abc", "?b?"),
("foo_test", "t?st"),
];
for (text, pattern) in cases {
let result = match_wildcard_pattern(text, pattern)
.unwrap_or_else(|| panic!("expected match for text='{}', pattern='{}'", text, pattern));
let char_count = text.chars().count();
assert!(
!result.matched_indices.is_empty(),
"matched_indices should not be empty"
);
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {} is out of bounds for text '{}' (length {})",
idx,
text,
char_count
);
}
}
}
#[test]
fn test_wildcard_matched_indices_within_text_bounds() {
let text = "hello_world";
let pattern = "w?rld";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match text");
assert!(!result.matched_indices.is_empty());
let char_count = text.chars().count();
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {} must be strictly within text bounds (char count: {})",
idx,
char_count
);
}
}
#[test]
fn test_wildcard_substring_matched_indices_strictly_within_bounds() {
let test_cases = [
("/src/ui/button.rs", "ui/*.rs"),
("/src/ui/button.rs", "ui/*.r"),
("src/views/modal.tsx", "views/*.tsx"),
];
for (text, pattern) in test_cases {
let result = match_wildcard_pattern(text, pattern)
.unwrap_or_else(|| panic!("expected match for text='{}', pattern='{}'", text, pattern));
let char_count = text.chars().count();
assert!(
!result.matched_indices.is_empty(),
"expected non-empty matched indices for pattern '{}'",
pattern
);
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {} is out of bounds for text '{}' with character count {}",
idx,
text,
char_count
);
assert!(
text.chars().nth(idx).is_some(),
"matched index {} does not correspond to a valid character in text '{}'",
idx,
text
);
}
}
}
#[test]
fn test_wildcard_substring_matched_indices_exact_content() {
let text = "/src/ui/button.rs";
let pattern = "ui/*.rs";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match");
assert_eq!(result.matched_indices, vec![5, 6, 7, 14, 15, 16]);
}
#[test]
fn test_wildcard_prefix_suffix_matched_indices_bounds() {
let text = "/src/ui/button.rs";
let pattern = "ui/*.rs";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match");
let char_count = text.chars().count();
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {} is out of bounds (text length is {} chars)",
idx,
char_count
);
}
assert_eq!(result.matched_indices, vec![5, 6, 7, 14, 15, 16]);
}
#[test]
fn test_wildcard_exact_matched_indices_bounds() {
let text = "dir/file.ext";
let pattern = "dir/*.ext";
let result = match_wildcard_pattern(text, pattern).expect("pattern should match");
let char_count = text.chars().count();
for &idx in &result.matched_indices {
assert!(
idx < char_count,
"matched index {} is out of bounds (text length is {} chars)",
idx,
char_count
);
}
assert_eq!(result.matched_indices, vec![0, 1, 2, 3, 8, 9, 10, 11]);
}
#[test]
fn test_wildcard_pattern_matched_indices_within_text_bounds() {
let text = "src/ui/test.spec.ts";
let pattern = "ui/*.*.ts";
let result = match_wildcard_pattern(text, pattern);
assert!(result.is_some());
let match_result = result.unwrap();
let text_char_count = text.chars().count();
assert!(!match_result.matched_indices.is_empty());
for &idx in &match_result.matched_indices {
assert!(
idx < text_char_count,
"matched index {} must be strictly less than text character length {}",
idx,
text_char_count
);
}
}
#[test]
fn test_wildcard_pattern_complex_suffix_indices_bounds() {
let text = "ui/button.test.rs";
let pattern = "ui/*?*.rs";
let result = match_wildcard_pattern(text, pattern);
assert!(result.is_some());
let match_result = result.unwrap();
let text_char_count = text.chars().count();
for &idx in &match_result.matched_indices {
assert!(
idx < text_char_count,
"matched index {} must be within character bounds (0..{})",
idx,
text_char_count
);
}
}
}
A proven fault was caught by a test corral wrote and ran; an unproven one was not, so it may be a missing test or a fault no test can see.
s0/m6 · line 421 proven
- matched_indices: (start_idx..remaining_char_count).collect(), + matched_indices: (start_idx..=remaining_char_count).collect(),
s0/m8 · line 438 proven
- matched_indices: (0..remaining_text.chars().count()).collect(), + matched_indices: (0..=remaining_text.chars().count()).collect(),
s0/m5 · line 454 proven
+ combined_indices.push(text.chars().count());
s0/m1 · line 457 proven
- combined_indices.push(remaining_start_char + idx); + combined_indices.push(remaining_start_char + idx + 1);
s0/m3 · line 493 proven
- let matched_indices: Vec<usize> = (start_idx..end_idx.min(text_chars.len())).collect(); + let matched_indices: Vec<usize> = (start_idx..=text_chars.len()).collect();
s0/m4 · line 493 proven
- let matched_indices: Vec<usize> = (start_idx..end_idx.min(text_chars.len())).collect(); + let matched_indices: Vec<usize> = (start_idx..end_idx.saturating_add(5)).collect();
s6/m1 · line 68 unproven
- matched_indices: vec![], + matched_indices: vec![usize::MAX],
s1/m2 · line 230 unproven
- let matched_indices: Vec<usize> = (start_char_idx..text_char_count).collect(); + let matched_indices: Vec<usize> = (start_char_idx + 1..=text_char_count).collect();
s1/m1 · line 231 unproven
- let matched_indices: Vec<usize> = (start_char_idx..text_char_count).collect(); + let matched_indices: Vec<usize> = (start_char_idx..=text_char_count).collect();
s1/m3 · line 239 unproven
- if let Some(match_info) = find_partial_suffix_match(text, suffix) {
+ if let Some(mut match_info) = find_partial_suffix_match(text, suffix) {
+ match_info.push(text.chars().count());s1/m4 · line 255 unproven
- let matched_indices: Vec<usize> = (0..prefix_char_count).collect(); + let mut matched_indices: Vec<usize> = (0..prefix_char_count).collect(); + matched_indices.push(text.chars().count());
s1/m5 · line 255 unproven
- let matched_indices: Vec<usize> = (0..prefix_char_count).collect(); + let matched_indices: Vec<usize> = (prefix_char_count..=text.chars().count()).collect();
s1/m6 · line 268 unproven
- if let Some(match_info) = find_substring_glob_match(text, pattern) {
+ if let Some(mut match_info) = find_substring_glob_match(text, pattern) {
+ match_info.push(text.chars().count());s1/m7 · line 276 unproven
- let matched_indices: Vec<usize> = (0..text.chars().count()).collect(); + let matched_indices: Vec<usize> = (0..=text.chars().count()).collect();
s4/m1 · line 337 unproven
- (start_pos..start_pos + partial_chars.len()).collect(); + (start_pos..=start_pos + partial_chars.len()).collect();
s4/m2 · line 337 unproven
- (start_pos..start_pos + partial_chars.len()).collect(); + (start_pos + 1..start_pos + partial_chars.len() + 1).collect();
s4/m3 · line 337 unproven
- (start_pos..start_pos + partial_chars.len()).collect(); + (text_chars.len()..text_chars.len() + partial_chars.len()).collect();
s0/m7 · line 475 unproven
- (start_char_idx..start_char_idx + prefix_char_count).collect(); + (start_char_idx..start_char_idx + prefix_char_count + text.chars().count()).collect();
s0/m2 · line 477 unproven
- (start_char_idx..start_char_idx + prefix_char_count).collect(); + (start_char_idx..=text.chars().count()).collect();
s6/m3 · line 513 unproven
- Some(text_chars.len()) + Some(text_chars.len() + 1)
s2/m1 · line 543 unproven
- return pattern[pattern_idx..].iter().all(|&c| c == '*'); + return true;
s2/m2 · line 551 unproven
- if is_glob_match_chars_recursive(text, pattern, text_idx, pattern_idx + 1) {
+ if is_glob_match_chars_recursive(text, pattern, text_idx + 1, pattern_idx + 1) {s2/m3 · line 555 unproven
- if is_glob_match_chars_recursive(text, pattern, i + 1, pattern_idx + 1) {
+ if is_glob_match_chars_recursive(text, pattern, i + 2, pattern_idx + 1) {s2/m4 · line 563 unproven
- is_glob_match_chars_recursive(text, pattern, text_idx + 1, pattern_idx + 1) + is_glob_match_chars_recursive(text, pattern, text_idx, pattern_idx + 1)
s2/m5 · line 568 unproven
- is_glob_match_chars_recursive(text, pattern, text_idx + 1, pattern_idx + 1) + is_glob_match_chars_recursive(text, pattern, text_idx + 2, pattern_idx + 1)
s3/m1 · line 589 unproven
- return pattern[pattern_idx..].iter().all(|&c| c == b'*'); + return true;
s3/m3 · line 597 unproven
- if is_glob_match_recursive(text, pattern, text_idx, pattern_idx + 1) {
+ if is_glob_match_recursive(text, pattern, text_idx + 1, pattern_idx + 1) {s3/m5 · line 601 unproven
- false + true
s3/m2 · line 609 unproven
- is_glob_match_recursive(text, pattern, text_idx + 1, pattern_idx + 1) + is_glob_match_recursive(text, pattern, text_idx, pattern_idx + 1)
s3/m4 · line 613 unproven
- if text[text_idx].eq_ignore_ascii_case(&c) {
+ if text[text_idx] == c {s5/m2 · line 660 unproven
+ result.matched_indices.push(text.chars().count());
s5/m1 · line 663 unproven
- .retain(|&idx| idx < text.chars().count()); + .retain(|&idx| idx <= text.chars().count());