Skip to content

Commit fbba28e

Browse files
committed
Added smoke tests for new methods.
Fixed bug in existing StrSearcher impl
1 parent c29559d commit fbba28e

File tree

2 files changed

+160
-22
lines changed

2 files changed

+160
-22
lines changed

src/libcollectionstest/str.rs

+137-12
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,31 @@ mod pattern {
17201720
if rev {
17211721
v.reverse();
17221722
}
1723+
1724+
let mut first_index = 0;
1725+
let mut err = None;
1726+
1727+
for (i, e) in right.iter().enumerate() {
1728+
match *e {
1729+
Match(a, b) | Reject(a, b)
1730+
if a <= b && a == first_index => {
1731+
first_index = b;
1732+
}
1733+
_ => {
1734+
err = Some(i);
1735+
break;
1736+
}
1737+
}
1738+
}
1739+
1740+
if let Some(err) = err {
1741+
panic!("Input skipped range at {}", err);
1742+
}
1743+
1744+
if first_index != haystack.len() {
1745+
panic!("Did not cover whole input");
1746+
}
1747+
17231748
assert_eq!(v, right);
17241749
}
17251750

@@ -1731,25 +1756,35 @@ mod pattern {
17311756
Reject(6, 7),
17321757
]);
17331758
make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [
1734-
Match(0, 0),
1735-
Match(1, 1),
1736-
Match(2, 2),
1737-
Match(3, 3),
1738-
Match(4, 4),
1739-
Match(5, 5),
1740-
Match(6, 6),
1741-
Match(7, 7),
1759+
Match (0, 0),
1760+
Reject(0, 1),
1761+
Match (1, 1),
1762+
Reject(1, 2),
1763+
Match (2, 2),
1764+
Reject(2, 3),
1765+
Match (3, 3),
1766+
Reject(3, 4),
1767+
Match (4, 4),
1768+
Reject(4, 5),
1769+
Match (5, 5),
1770+
Reject(5, 6),
1771+
Match (6, 6),
1772+
Reject(6, 7),
1773+
Match (7, 7),
17421774
]);
17431775
make_test!(str_searcher_mulibyte_haystack, " ", "├──", [
17441776
Reject(0, 3),
17451777
Reject(3, 6),
17461778
Reject(6, 9),
17471779
]);
17481780
make_test!(str_searcher_empty_needle_mulibyte_haystack, "", "├──", [
1749-
Match(0, 0),
1750-
Match(3, 3),
1751-
Match(6, 6),
1752-
Match(9, 9),
1781+
Match (0, 0),
1782+
Reject(0, 3),
1783+
Match (3, 3),
1784+
Reject(3, 6),
1785+
Match (6, 6),
1786+
Reject(6, 9),
1787+
Match (9, 9),
17531788
]);
17541789
make_test!(str_searcher_empty_needle_empty_haystack, "", "", [
17551790
Match(0, 0),
@@ -1778,6 +1813,96 @@ mod pattern {
17781813

17791814
}
17801815

1816+
macro_rules! generate_iterator_test {
1817+
{
1818+
$name:ident {
1819+
$(
1820+
($($arg:expr),*) -> [$($t:tt)*];
1821+
)*
1822+
}
1823+
with $fwd:expr, $bwd:expr;
1824+
} => {
1825+
#[test]
1826+
fn $name() {
1827+
$(
1828+
{
1829+
let res = vec![$($t)*];
1830+
1831+
let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
1832+
assert_eq!(fwd_vec, res);
1833+
1834+
let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect();
1835+
bwd_vec.reverse();
1836+
assert_eq!(bwd_vec, res);
1837+
}
1838+
)*
1839+
}
1840+
};
1841+
{
1842+
$name:ident {
1843+
$(
1844+
($($arg:expr),*) -> [$($t:tt)*];
1845+
)*
1846+
}
1847+
with $fwd:expr;
1848+
} => {
1849+
#[test]
1850+
fn $name() {
1851+
$(
1852+
{
1853+
let res = vec![$($t)*];
1854+
1855+
let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
1856+
assert_eq!(fwd_vec, res);
1857+
}
1858+
)*
1859+
}
1860+
}
1861+
}
1862+
1863+
generate_iterator_test! {
1864+
double_ended_split {
1865+
("foo.bar.baz", '.') -> ["foo", "bar", "baz"];
1866+
("foo::bar::baz", "::") -> ["foo", "bar", "baz"];
1867+
}
1868+
with str::split, str::rsplit;
1869+
}
1870+
1871+
generate_iterator_test! {
1872+
double_ended_split_terminator {
1873+
("foo;bar;baz;", ';') -> ["foo", "bar", "baz"];
1874+
}
1875+
with str::split_terminator, str::rsplit_terminator;
1876+
}
1877+
1878+
generate_iterator_test! {
1879+
double_ended_matches {
1880+
("a1b2c3", char::is_numeric) -> ["1", "2", "3"];
1881+
}
1882+
with str::matches, str::rmatches;
1883+
}
1884+
1885+
generate_iterator_test! {
1886+
double_ended_match_indices {
1887+
("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)];
1888+
}
1889+
with str::match_indices, str::rmatch_indices;
1890+
}
1891+
1892+
generate_iterator_test! {
1893+
not_double_ended_splitn {
1894+
("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"];
1895+
}
1896+
with str::splitn;
1897+
}
1898+
1899+
generate_iterator_test! {
1900+
not_double_ended_rsplitn {
1901+
("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"];
1902+
}
1903+
with str::rsplitn;
1904+
}
1905+
17811906
mod bench {
17821907
use test::{Bencher, black_box};
17831908

src/libcore/str/pattern.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,14 @@ pub struct StrSearcher<'a, 'b> {
351351
needle: &'b str,
352352
start: usize,
353353
end: usize,
354-
done: bool,
354+
state: State,
355+
}
356+
357+
#[derive(Clone, PartialEq)]
358+
enum State { Done, NotDone, Reject(usize, usize) }
359+
impl State {
360+
#[inline] fn done(&self) -> bool { *self == State::Done }
361+
#[inline] fn take(&mut self) -> State { ::mem::replace(self, State::NotDone) }
355362
}
356363

357364
/// Non-allocating substring search.
@@ -368,7 +375,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
368375
needle: self,
369376
start: 0,
370377
end: haystack.len(),
371-
done: false,
378+
state: State::NotDone,
372379
}
373380
}
374381
}
@@ -385,8 +392,9 @@ unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> {
385392
|m: &mut StrSearcher| {
386393
// Forward step for empty needle
387394
let current_start = m.start;
388-
if !m.done {
395+
if !m.state.done() {
389396
m.start = m.haystack.char_range_at(current_start).next;
397+
m.state = State::Reject(current_start, m.start);
390398
}
391399
SearchStep::Match(current_start, current_start)
392400
},
@@ -415,8 +423,9 @@ unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
415423
|m: &mut StrSearcher| {
416424
// Backward step for empty needle
417425
let current_end = m.end;
418-
if !m.done {
426+
if !m.state.done() {
419427
m.end = m.haystack.char_range_at_reverse(current_end).next;
428+
m.state = State::Reject(m.end, current_end);
420429
}
421430
SearchStep::Match(current_end, current_end)
422431
},
@@ -446,23 +455,27 @@ fn str_search_step<F, G>(mut m: &mut StrSearcher,
446455
where F: FnOnce(&mut StrSearcher) -> SearchStep,
447456
G: FnOnce(&mut StrSearcher) -> SearchStep
448457
{
449-
if m.done {
458+
if m.state.done() {
450459
SearchStep::Done
451460
} else if m.needle.len() == 0 && m.start <= m.end {
452461
// Case for needle == ""
453-
if m.start == m.end {
454-
m.done = true;
462+
if let State::Reject(a, b) = m.state.take() {
463+
SearchStep::Reject(a, b)
464+
} else {
465+
if m.start == m.end {
466+
m.state = State::Done;
467+
}
468+
empty_needle_step(&mut m)
455469
}
456-
empty_needle_step(&mut m)
457470
} else if m.start + m.needle.len() <= m.end {
458471
// Case for needle != ""
459472
nonempty_needle_step(&mut m)
460473
} else if m.start < m.end {
461474
// Remaining slice shorter than needle, reject it
462-
m.done = true;
475+
m.state = State::Done;
463476
SearchStep::Reject(m.start, m.end)
464477
} else {
465-
m.done = true;
478+
m.state = State::Done;
466479
SearchStep::Done
467480
}
468481
}

0 commit comments

Comments
 (0)