Skip to content

Commit 9c5e28a

Browse files
hovinenbcopybara-github
authored andcommitted
Support HashMap and similar types in the macros contains_each! and is_contained_in!.
This extends the functionality just introduced to `unordered_elements_are!` to the other two macros in the same module. This also adds explicit macro rules for empty arguments, which might not otherwise work properly with the new macro rules. PiperOrigin-RevId: 523633992
1 parent 2fb2002 commit 9c5e28a

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

googletest/src/matchers/unordered_elements_are_matcher.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ macro_rules! unordered_elements_are {
127127
/// The actual value must be a container implementing [`IntoIterator`]. This
128128
/// includes standard containers, slices (when dereferenced) and arrays.
129129
///
130+
/// This can also match against [`HashMap`][std::collections::HashMap] and
131+
/// similar collections. The arguments are a sequence of pairs of matchers
132+
/// corresponding to the keys and their respective values.
133+
///
134+
/// ```
135+
/// let value: HashMap<u32, &'static str> =
136+
/// HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
137+
/// verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One"))])
138+
/// ```
139+
///
130140
/// This matcher does not support matching directly against an [`Iterator`]. To
131141
/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
132142
///
@@ -151,6 +161,31 @@ macro_rules! unordered_elements_are {
151161
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
152162
#[macro_export]
153163
macro_rules! contains_each {
164+
($(,)?) => {{
165+
#[cfg(google3)]
166+
use $crate::internal::{UnorderedElementsAreMatcher, Requirements};
167+
#[cfg(not(google3))]
168+
use $crate::matchers::unordered_elements_are_matcher::internal::{
169+
UnorderedElementsAreMatcher, Requirements
170+
};
171+
UnorderedElementsAreMatcher::new([], Requirements::Superset)
172+
}};
173+
174+
// TODO: Consider an alternative map-like syntax here similar to that used in
175+
// https://crates.io/crates/maplit.
176+
($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
177+
#[cfg(google3)]
178+
use $crate::internal::{UnorderedElementsOfMapAreMatcher, Requirements};
179+
#[cfg(not(google3))]
180+
use $crate::matchers::unordered_elements_are_matcher::internal::{
181+
UnorderedElementsOfMapAreMatcher, Requirements
182+
};
183+
UnorderedElementsOfMapAreMatcher::new(
184+
[$((&$key_matcher, &$value_matcher)),*],
185+
Requirements::Superset
186+
)
187+
}};
188+
154189
($($matcher:expr),* $(,)?) => {{
155190
#[cfg(google3)]
156191
use $crate::internal::{UnorderedElementsAreMatcher, Requirements};
@@ -185,6 +220,18 @@ macro_rules! contains_each {
185220
/// The actual value must be a container implementing [`IntoIterator`]. This
186221
/// includes standard containers, slices (when dereferenced) and arrays.
187222
///
223+
/// This can also match against [`HashMap`][std::collections::HashMap] and
224+
/// similar collections. The arguments are a sequence of pairs of matchers
225+
/// corresponding to the keys and their respective values.
226+
///
227+
/// ```
228+
/// let value: HashMap<u32, &'static str> = HashMap::from_iter([(1, "One"), (2, "Two")]);
229+
/// verify_that!(
230+
/// value,
231+
/// is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
232+
/// )
233+
/// ```
234+
///
188235
/// This matcher does not support matching directly against an [`Iterator`]. To
189236
/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
190237
///
@@ -209,6 +256,31 @@ macro_rules! contains_each {
209256
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
210257
#[macro_export]
211258
macro_rules! is_contained_in {
259+
($(,)?) => {{
260+
#[cfg(google3)]
261+
use $crate::internal::{UnorderedElementsAreMatcher, Requirements};
262+
#[cfg(not(google3))]
263+
use $crate::matchers::unordered_elements_are_matcher::internal::{
264+
UnorderedElementsAreMatcher, Requirements
265+
};
266+
UnorderedElementsAreMatcher::new([], Requirements::Subset)
267+
}};
268+
269+
// TODO: Consider an alternative map-like syntax here similar to that used in
270+
// https://crates.io/crates/maplit.
271+
($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
272+
#[cfg(google3)]
273+
use $crate::internal::{UnorderedElementsOfMapAreMatcher, Requirements};
274+
#[cfg(not(google3))]
275+
use $crate::matchers::unordered_elements_are_matcher::internal::{
276+
UnorderedElementsOfMapAreMatcher, Requirements
277+
};
278+
UnorderedElementsOfMapAreMatcher::new(
279+
[$((&$key_matcher, &$value_matcher)),*],
280+
Requirements::Subset
281+
)
282+
}};
283+
212284
($($matcher:expr),* $(,)?) => {{
213285
#[cfg(google3)]
214286
use $crate::internal::{UnorderedElementsAreMatcher, Requirements};

googletest/tests/unordered_elements_are_matcher_test.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ use matchers::{
2626
use matchers::{contains_each, is_contained_in, unordered_elements_are};
2727
use std::collections::HashMap;
2828

29+
#[google_test]
30+
fn unordered_elements_are_matches_empty_vector() -> Result<()> {
31+
let value: Vec<u32> = vec![];
32+
verify_that!(value, unordered_elements_are![])
33+
}
34+
35+
#[google_test]
36+
fn unordered_elements_are_matches_empty_vector_with_trailing_comma() -> Result<()> {
37+
let value: Vec<u32> = vec![];
38+
verify_that!(value, unordered_elements_are![,])
39+
}
40+
2941
#[google_test]
3042
fn unordered_elements_are_matches_vector() -> Result<()> {
3143
let value = vec![1, 2, 3];
@@ -250,11 +262,35 @@ fn contains_each_supports_trailing_comma() -> Result<()> {
250262
verify_that!(vec![2, 3, 4], contains_each!(eq(2), eq(3), eq(4),))
251263
}
252264

265+
#[google_test]
266+
fn contains_each_matches_hash_map() -> Result<()> {
267+
let value: HashMap<u32, &'static str> =
268+
HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
269+
verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One"))])
270+
}
271+
272+
#[google_test]
273+
fn contains_each_matches_hash_map_with_trailing_comma() -> Result<()> {
274+
let value: HashMap<u32, &'static str> =
275+
HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
276+
verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One")),])
277+
}
278+
253279
#[google_test]
254280
fn contains_each_matches_when_no_matchers_present() -> Result<()> {
255281
verify_that!(vec![2, 3, 4], contains_each!())
256282
}
257283

284+
#[google_test]
285+
fn contains_each_matches_when_no_matchers_present_and_trailing_comma() -> Result<()> {
286+
verify_that!(vec![2, 3, 4], contains_each!(,))
287+
}
288+
289+
#[google_test]
290+
fn contains_each_matches_when_list_is_empty_and_no_matchers_present() -> Result<()> {
291+
verify_that!(Vec::<u32>::new(), contains_each!())
292+
}
293+
258294
#[google_test]
259295
fn contains_each_matches_when_excess_elements_present() -> Result<()> {
260296
verify_that!(vec![1, 2, 3, 4], contains_each!(eq(2), eq(3), eq(4)))
@@ -302,6 +338,18 @@ fn contains_each_explains_mismatch_due_to_no_graph_matching_found() -> Result<()
302338
))
303339
}
304340

341+
#[google_test]
342+
fn is_contained_in_matches_with_empty_vector() -> Result<()> {
343+
let value: Vec<u32> = vec![];
344+
verify_that!(value, is_contained_in!())
345+
}
346+
347+
#[google_test]
348+
fn is_contained_in_matches_with_empty_vector_and_trailing_comma() -> Result<()> {
349+
let value: Vec<u32> = vec![];
350+
verify_that!(value, is_contained_in!(,))
351+
}
352+
305353
#[google_test]
306354
fn is_contained_in_matches_when_one_to_one_correspondence_present() -> Result<()> {
307355
verify_that!(vec![2, 3, 4], is_contained_in!(eq(2), eq(3), eq(4)))
@@ -312,6 +360,24 @@ fn is_contained_supports_trailing_comma() -> Result<()> {
312360
verify_that!(vec![2, 3, 4], is_contained_in!(eq(2), eq(3), eq(4),))
313361
}
314362

363+
#[google_test]
364+
fn is_contained_in_matches_hash_map() -> Result<()> {
365+
let value: HashMap<u32, &'static str> = HashMap::from_iter([(1, "One"), (2, "Two")]);
366+
verify_that!(
367+
value,
368+
is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
369+
)
370+
}
371+
372+
#[google_test]
373+
fn is_contained_in_matches_hash_map_with_trailing_comma() -> Result<()> {
374+
let value: HashMap<u32, &'static str> = HashMap::from_iter([(1, "One"), (2, "Two")]);
375+
verify_that!(
376+
value,
377+
is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three")),]
378+
)
379+
}
380+
315381
#[google_test]
316382
fn is_contained_in_matches_when_container_is_empty() -> Result<()> {
317383
verify_that!(vec![], is_contained_in!(eq(2), eq(3), eq(4)))

0 commit comments

Comments
 (0)