Skip to content

Commit 3e4015f

Browse files
hovinenbcopybara-github
authored andcommitted
Add to the matcher pointwise! support for matching against (dereferenced) slices.
This requires eliminating the dependency on the trait HasSize, which does not support slices. PiperOrigin-RevId: 515602080
1 parent 733063b commit 3e4015f

File tree

1 file changed

+39
-28
lines changed

1 file changed

+39
-28
lines changed

googletest/src/matchers/pointwise_matcher.rs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,16 @@ macro_rules! pointwise {
7272
pub mod internal {
7373
#[cfg(not(google3))]
7474
use crate as googletest;
75+
#[cfg(not(google3))]
76+
use crate::matchers::zipped_iterator::zip;
7577
#[cfg(google3)]
7678
use description::Description;
7779
use googletest::matcher::{MatchExplanation, Matcher, MatcherResult};
7880
#[cfg(not(google3))]
7981
use googletest::matchers::description::Description;
80-
#[cfg(not(google3))]
81-
use googletest::matchers::has_size::HasSize;
82-
#[cfg(google3)]
83-
use has_size::HasSize;
8482
use std::fmt::Debug;
83+
#[cfg(google3)]
84+
use zipped_iterator::zip;
8585

8686
/// This struct is meant to be used only through the `pointwise` macro.
8787
///
@@ -97,48 +97,52 @@ pub mod internal {
9797
}
9898
}
9999

100-
impl<T: Debug, MatcherT: Matcher<T>, ContainerT: ?Sized + HasSize + Debug> Matcher<ContainerT>
100+
impl<T: Debug, MatcherT: Matcher<T>, ContainerT: ?Sized + Debug> Matcher<ContainerT>
101101
for PointwiseMatcher<MatcherT>
102102
where
103103
for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
104104
{
105105
fn matches(&self, actual: &ContainerT) -> MatcherResult {
106-
if actual.size() != self.matchers.len() {
107-
return MatcherResult::DoesNotMatch;
108-
}
109-
for (element, matcher) in actual.into_iter().zip(&self.matchers) {
106+
let mut zipped_iterator = zip(actual.into_iter(), self.matchers.iter());
107+
for (element, matcher) in zipped_iterator.by_ref() {
110108
if matches!(matcher.matches(element), MatcherResult::DoesNotMatch) {
111109
return MatcherResult::DoesNotMatch;
112110
}
113111
}
114-
MatcherResult::Matches
112+
if zipped_iterator.has_size_mismatch() {
113+
MatcherResult::DoesNotMatch
114+
} else {
115+
MatcherResult::Matches
116+
}
115117
}
116118

117119
fn explain_match(&self, actual: &ContainerT) -> MatchExplanation {
118-
if actual.size() != self.matchers.len() {
119-
return MatchExplanation::create(format!(
120-
"which has size {} (expected {})",
121-
actual.size(),
122-
self.matchers.len()
123-
));
124-
}
125-
126120
// TODO(b/260819741) This code duplicates elements_are_matcher.rs. Consider
127121
// extract as a separate library. (or implement pointwise! with
128122
// elements_are)
129-
let mismatches = actual
130-
.into_iter()
131-
.zip(self.matchers.iter())
132-
.enumerate()
133-
.filter(|&(_, (a, e))| matches!(e.matches(a), MatcherResult::DoesNotMatch))
134-
.map(|(idx, (a, e))| format!("element #{idx} is {a:#?}, {}", e.explain_match(a)))
135-
.collect::<Description>();
123+
let actual_iterator = actual.into_iter();
124+
let mut zipped_iterator = zip(actual_iterator, self.matchers.iter());
125+
let mut mismatches = Vec::new();
126+
for (idx, (a, e)) in zipped_iterator.by_ref().enumerate() {
127+
if matches!(e.matches(a), MatcherResult::DoesNotMatch) {
128+
mismatches.push(format!("element #{idx} is {a:?}, {}", e.explain_match(a)));
129+
}
130+
}
136131
if mismatches.is_empty() {
137-
MatchExplanation::create("which matches all elements".to_string())
132+
if !zipped_iterator.has_size_mismatch() {
133+
MatchExplanation::create("which matches all elements".to_string())
134+
} else {
135+
MatchExplanation::create(format!(
136+
"which has size {} (expected {})",
137+
zipped_iterator.left_size(),
138+
self.matchers.len()
139+
))
140+
}
138141
} else if mismatches.len() == 1 {
139-
MatchExplanation::create(format!("where {mismatches}"))
142+
MatchExplanation::create(format!("where {}", mismatches[0]))
140143
} else {
141-
MatchExplanation::create(format!("where:\n{}", mismatches.indent().bullet_list()))
144+
let mismatches = mismatches.into_iter().collect::<Description>();
145+
MatchExplanation::create(format!("where:\n{}", mismatches.bullet_list().indent()))
142146
}
143147
}
144148

@@ -185,6 +189,13 @@ mod tests {
185189
verify_that!(value, pointwise!(lt, [2, 3]))
186190
}
187191

192+
#[google_test]
193+
fn pointwise_matches_two_element_slice() -> Result<()> {
194+
let value = vec![1, 2];
195+
let slice = value.as_slice();
196+
verify_that!(*slice, pointwise!(lt, [2, 3]))
197+
}
198+
188199
#[google_test]
189200
fn pointwise_does_not_match_value_of_wrong_length() -> Result<()> {
190201
let value = vec![1];

0 commit comments

Comments
 (0)