Skip to content

Commit c075e18

Browse files
ethanpailesBurntSushi
ethanpailes
authored andcommitted
regex/literal: add quickcheck property for Boyer-Moore
If you just generate two random strings, the odds are very high that the shorter one won't be a substring of the longer one once they reach any substantial length. This means that the existing quickcheck cases were probably just testing the negative cases. The exception would be the two cases that append the needle to the haystack, but those only test behavior at the ends. This patch adds a better quickcheck case that can test a needle anywhere in the haystack. Fixes #446
1 parent 4ce1115 commit c075e18

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

src/literals.rs

+42-4
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ mod tests {
927927
let haystack = vec![91];
928928
let needle = vec![91];
929929

930-
let naive_offset = naive_find(needle, haystack.as_slice()).unwrap();
930+
let naive_offset = naive_find(&needle, &haystack).unwrap();
931931
assert_eq!(0, naive_offset);
932932
}
933933

@@ -981,12 +981,12 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
981981

982982
use quickcheck::TestResult;
983983

984-
fn naive_find(needle: Vec<u8>, haystack: &[u8]) -> Option<usize> {
984+
fn naive_find(needle: &[u8], haystack: &[u8]) -> Option<usize> {
985985
assert!(needle.len() <= haystack.len());
986986

987987
for i in 0..(haystack.len() - (needle.len() - 1)) {
988988
if haystack[i] == needle[0]
989-
&& &haystack[i..(i+needle.len())] == needle.as_slice() {
989+
&& &haystack[i..(i+needle.len())] == needle {
990990
return Some(i)
991991
}
992992
}
@@ -1008,7 +1008,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10081008

10091009
let searcher = BoyerMooreSearch::new(needle.clone());
10101010
TestResult::from_bool(
1011-
searcher.find(haystack) == naive_find(needle, haystack))
1011+
searcher.find(haystack) == naive_find(&needle, haystack))
10121012
}
10131013

10141014
fn qc_bm_equals_single(pile1: Vec<u8>, pile2: Vec<u8>) -> TestResult {
@@ -1063,6 +1063,44 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10631063
.unwrap_or(false))
10641064
}
10651065

1066+
// qc_equals_* is only testing the negative case as @burntsushi
1067+
// pointed out in https://github.com/rust-lang/regex/issues/446.
1068+
// This quickcheck prop represents an effort to force testing of
1069+
// the positive case. qc_bm_finds_first and qc_bm_finds_trailing_needle
1070+
// already check some of the positive cases, but they don't cover
1071+
// cases where the needle is in the middle of haystack. This prop
1072+
// fills that hole.
1073+
fn qc_bm_finds_subslice(
1074+
haystack: Vec<u8>,
1075+
needle_start: usize,
1076+
needle_length: usize
1077+
) -> TestResult {
1078+
if haystack.len() == 0 {
1079+
return TestResult::discard();
1080+
}
1081+
1082+
let needle_start = needle_start % haystack.len();
1083+
let needle_length = needle_length % (haystack.len() - needle_start);
1084+
1085+
if needle_length == 0 {
1086+
return TestResult::discard();
1087+
}
1088+
1089+
let needle = &haystack[needle_start..(needle_start + needle_length)];
1090+
1091+
let bm_searcher = BoyerMooreSearch::new(needle.to_vec());
1092+
1093+
let start = naive_find(&needle, &haystack);
1094+
match start {
1095+
None => TestResult::from_bool(false),
1096+
Some(nf_start) =>
1097+
TestResult::from_bool(
1098+
nf_start <= needle_start
1099+
&& bm_searcher.find(&haystack) == start
1100+
)
1101+
}
1102+
}
1103+
10661104
fn qc_bm_finds_first(needle: Vec<u8>) -> TestResult {
10671105
if needle.len() == 0 {
10681106
return TestResult::discard();

0 commit comments

Comments
 (0)