build(rust): vendor googletest crate

This commit was merged in pull request #76.
This commit is contained in:
alexion committed 2026-09-19 14:53:22 -04:00
1 parent a6fe84190e
commit 6887b104d6
576 files changed
+284290 -2

No files matched your search

@@ -0,0 +1,155 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn matches_any_value_when_list_is_empty() -> Result<()> {
verify_that!((), all!())
}
#[test]
fn matches_value_with_single_matching_component() -> Result<()> {
verify_that!(123, all!(eq(123)))
}
#[test]
fn does_not_match_value_with_single_non_matching_component() -> Result<()> {
verify_that!(123, not(all!(eq(456))))
}
#[test]
fn matches_value_with_two_matching_components() -> Result<()> {
verify_that!("A string", all!(starts_with("A"), ends_with("string")))
}
#[test]
fn does_not_match_value_with_one_non_matching_component_among_two_components() -> Result<()> {
verify_that!(123, not(all!(eq(123), eq(456))))
}
#[test]
fn supports_trailing_comma() -> Result<()> {
verify_that!(
"An important string",
all!(starts_with("An"), contains_substring("important"), ends_with("string"),)
)
}
#[test]
fn admits_matchers_without_static_lifetime() -> Result<()> {
#[derive(Debug, PartialEq)]
struct AStruct(i32);
let expected_value = AStruct(123);
verify_that!(AStruct(123), all![eq(&expected_value)])
}
#[test]
fn mismatch_description_two_failed_matchers() -> Result<()> {
verify_that!(
all!(starts_with("One"), starts_with("Two")).explain_match("Three"),
displays_as(eq("* which does not start with \"One\"\n* which does not start with \"Two\""))
)
}
#[test]
fn mismatch_description_empty_matcher() -> Result<()> {
verify_that!(all!().explain_match("Three"), displays_as(eq("which is anything")))
}
#[test]
fn all_multiple_failed_assertions() -> Result<()> {
let result = verify_that!(4, all![eq(1), eq(2), eq(3)]);
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: 4
Expected: has all the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: 4,
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_all_is_inside_some() -> Result<()> {
let value = Some(4);
let result = verify_that!(value, some(all![eq(1), eq(2), eq(3)]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: value
Expected: has a value which has all the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: Some(4),
which has a value
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_all_is_inside_ok() -> Result<()> {
let value: std::result::Result<i32, std::io::Error> = Ok(4);
let result = verify_that!(value, ok(all![eq(&1), eq(&2), eq(&3)]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: value
Expected: is a success containing a value, which has all the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: Ok(4),
which is a success
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_all_is_inside_err() -> Result<()> {
let value: std::result::Result<(), &'static str> = Err("An error");
let result = verify_that!(value, err(all![starts_with("Not"), ends_with("problem")]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
r#"
Value of: value
Expected: is an error which has all the following properties:
* starts with prefix "Not"
* ends with suffix "problem"
Actual: Err("An error"),
which is an error
* which does not start with "Not"
* which does not end with "problem""#
))))
)
}
@@ -0,0 +1,145 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn matches_value_with_single_matching_component() -> Result<()> {
verify_that!(123, any!(eq(123)))
}
#[test]
fn does_not_match_value_with_single_non_matching_component() -> Result<()> {
verify_that!(123, not(any!(eq(456))))
}
#[test]
fn matches_value_with_first_of_two_matching_components() -> Result<()> {
verify_that!("A string", any!(starts_with("A"), starts_with("string")))
}
#[test]
fn matches_value_with_second_of_two_matching_components() -> Result<()> {
verify_that!("A string", any!(starts_with("string"), starts_with("A")))
}
#[test]
fn supports_trailing_comma() -> Result<()> {
verify_that!(
"An important string",
any!(starts_with("An"), contains_substring("important"), ends_with("string"),)
)
}
#[test]
fn admits_matchers_without_static_lifetime() -> Result<()> {
#[derive(Debug, PartialEq)]
struct AStruct(i32);
let expected_value = AStruct(123);
verify_that!(AStruct(123), any![eq(&expected_value)])
}
#[test]
fn mismatch_description_two_failed_matchers() -> Result<()> {
verify_that!(
any!(starts_with("One"), starts_with("Two")).explain_match("Three"),
displays_as(eq("* which does not start with \"One\"\n* which does not start with \"Two\""))
)
}
#[test]
fn all_multiple_failed_assertions() -> Result<()> {
let result = verify_that!(4, any![eq(1), eq(2), eq(3)]);
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: 4
Expected: has at least one of the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: 4,
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_any_is_inside_some() -> Result<()> {
let value = Some(4);
let result = verify_that!(value, some(any![eq(1), eq(2), eq(3)]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: value
Expected: has a value which has at least one of the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: Some(4),
which has a value
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_any_is_inside_ok() -> Result<()> {
let value: std::result::Result<i32, std::io::Error> = Ok(4);
let result = verify_that!(value, ok(any![eq(&1), eq(&2), eq(&3)]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: value
Expected: is a success containing a value, which has at least one of the following properties:
* is equal to 1
* is equal to 2
* is equal to 3
Actual: Ok(4),
which is a success
* which isn't equal to 1
* which isn't equal to 2
* which isn't equal to 3"
))))
)
}
#[test]
fn formats_error_message_correctly_when_any_is_inside_err() -> Result<()> {
let value: std::result::Result<(), &'static str> = Err("An error");
let result = verify_that!(value, err(any![starts_with("Not"), ends_with("problem")]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
r#"
Value of: value
Expected: is an error which has at least one of the following properties:
* starts with prefix "Not"
* ends with suffix "problem"
Actual: Err("An error"),
which is an error
* which does not start with "Not"
* which does not end with "problem""#
))))
)
}
@@ -0,0 +1,428 @@
mod verify_pred {
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn supports_function_call_with_non_debug_types() -> Result<()> {
// Non-Debug - cannot be printed.
struct Apple;
fn f(_a: &Apple, _b: u32, _c: u32) -> bool {
false
}
fn g(_a: u32) -> u32 {
5
}
let a = &Apple;
let res = verify_pred!(f(a, g(g(3)), 1 + 2));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
f(a, g(g(3)), 1 + 2) was false with
a does not implement Debug,
g(g(3)) = 5,
1 + 2 = 3,
at"
})))
)
}
#[test]
fn supports_trailing_comma() -> Result<()> {
verify_that!(verify_pred!(false,), err(anything()))
}
#[test]
fn supports_non_function() -> Result<()> {
verify_pred!(true)?;
verify_that!(verify_pred!(false), err(anything()))
}
#[test]
fn does_not_print_literals() -> Result<()> {
trait Foo {
fn f(&self, _a: u32, _b: i32, _c: u32, _d: &str) -> bool {
false
}
}
impl Foo for i32 {}
let res = verify_pred!(0.f(1, 2_i32.abs(), 1 + 2, "hello"));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {r#"
0.f(1, 2_i32.abs(), 1 + 2, "hello") was false with
2_i32.abs() = 2,
1 + 2 = 3,
at"#
})))
)
}
#[test]
fn supports_chained_field_access_and_method_calls_with_non_debug_types() -> Result<()> {
// Non-Debug
struct Apple {
b: Banana,
}
#[derive(Debug)]
struct Banana;
impl Banana {
fn c(&self, _c: &Cherry, _d: u32) -> bool {
false
}
}
// Non-Debug - cannot be printed.
struct Cherry;
let a = Apple { b: Banana };
let c = &Cherry;
let d = 3;
let res = verify_pred!(a.b.c(c, d));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
a.b.c(c, d) was false with
a does not implement Debug,
a.b = Banana,
c does not implement Debug,
d = 3,
at"
})))
)
}
#[test]
fn evaluates_functions_and_arguments_exactly_once() -> Result<()> {
let mut a = 0;
let mut foo = |_b: u32| {
a += 1;
false
};
let mut b = 0;
let mut bar = || {
b += 10;
b
};
let res = verify_pred!(foo(bar()));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
foo(bar()) was false with
bar() = 10,
at"
})))
)?;
verify_that!((a, b), eq((1, 10)))
}
#[test]
fn evaluates_methods_and_arguments_exactly_once() -> Result<()> {
struct Apple(u32);
impl Apple {
fn c(&mut self, _b: bool) -> bool {
self.0 += 1;
false
}
}
let mut a = Apple(0);
let mut b = Apple(10);
let res = verify_pred!(a.c(b.c(false)));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
a.c(b.c(false)) was false with
a does not implement Debug,
b.c(false) = false,
at"
})))
)?;
verify_that!((a.0, b.0), eq((1, 11)))
}
#[test]
fn supports_chained_method_calls() -> Result<()> {
#[derive(Debug)]
struct Apple;
impl Apple {
fn b(&self, _b: u32) -> Banana {
Banana
}
}
// Non-Debug: not printed on error.
struct Banana;
impl Banana {
fn c(&self, _c0: u32, _c1: Cherry) -> bool {
false
}
}
// Non-Debug: not printed on error.
#[derive(Copy, Clone)]
struct Cherry;
let a = Apple;
let v = 10;
let res = verify_pred!(a.b(v).c(11, Cherry));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
a.b(v).c(11, Cherry) was false with
a = Apple,
v = 10,
a.b(v) does not implement Debug,
Cherry does not implement Debug,
at"
})))
)
}
#[test]
fn prints_consumed_values() -> Result<()> {
// Non-Debug
struct Apple;
impl Apple {
fn b(self) -> Banana {
Banana
}
}
#[derive(Debug)]
struct Banana;
impl Banana {
fn c(self) -> bool {
false
}
}
let a = Apple;
let res = verify_pred!(a.b().c());
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
a.b().c() was false with
a does not implement Debug,
a.b() = Banana,
at"
})))
)
}
#[test]
fn works_with_realistic_example_with_consumed_intermediate_values() -> Result<()> {
let res =
verify_pred!(vec![1, 2].into_iter().map(|x| x * 2).collect::<Vec<_>>().is_empty());
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > >
().is_empty() was false with
vec! [1, 2] = [1, 2],
vec! [1, 2].into_iter() = IntoIter([1, 2]),
| x | x * 2 does not implement Debug,
vec! [1, 2].into_iter().map(| x | x * 2) = Map { iter: IntoIter([1, 2]) },
vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > > () = [2, 4],
at"
})))
)
}
#[test]
fn values_should_be_accessible_after_test() -> Result<()> {
// Not `Copy` and should not be consumed by the generated test code.
#[derive(Debug)]
struct Apple;
impl Apple {
fn b(&self, _c: &mut u32) -> bool {
false
}
}
let mut c = 0;
let a = Apple;
let res = verify_pred!(a.b(&mut c));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
a.b(& mut c) was false with
a = Apple,
& mut c = 0,
at"
})))
)?;
// `a` and `&mut c` should still be accessible after the test despite not being
// `Copy`.
let _ = a.b(&mut c);
Ok(())
}
#[test]
fn prints_values_for_mutating_expressions() -> Result<()> {
let mut a = 1;
let mut b = 2;
let mut c = 0;
trait Mutator {
fn mutate_and_false(&mut self, b: &mut u32) -> bool;
}
impl Mutator for u32 {
fn mutate_and_false(&mut self, b: &mut u32) -> bool {
*self += 10;
*b += 20;
false
}
}
// Macro to to avoid the inconsistency in how `;` and `&mut` are printed between
// Rust versions when printing out the stringified version of the block.
macro_rules! block_a {
() => {{
c += 10;
&mut a
}};
}
macro_rules! block_b {
() => {{
c += 100;
&mut b
}};
}
let res = verify_pred! { block_a!().mutate_and_false(block_b!()) };
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
block_a! ().mutate_and_false(block_b! ()) was false with
block_a! () = 1,
block_b! () = 2,
at"
})))
)?;
verify_that!((a, b, c), eq((11, 22, 110)))
}
#[test]
fn values_can_be_insulated_with_parens() -> Result<()> {
// Not `Copy` and has a consuming method.
struct Apple;
impl Apple {
fn b(self) -> Banana {
Banana
}
}
#[derive(Debug)]
struct Banana;
impl Banana {
fn c(&self) -> bool {
false
}
}
let a = Apple;
let res = verify_pred!({ a.b() }.c());
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
{ a.b() }.c() was false with
{ a.b() } = Banana,
at"
})))
)
}
#[test]
fn binary_operator() -> Result<()> {
// Add chaining and function calls.
fn f(x: u32) -> u32 {
x + 1
}
#[derive(Debug)]
struct Apple;
impl Apple {
fn b(&self, y: u32) -> u32 {
y + 10
}
}
let a = Apple;
let x = 1;
let y = 2;
let res = verify_pred!(f(x) - 1 == a.b(y + 1) + f(y));
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
f(x) - 1 == a.b(y + 1) + f(y) was false with
x = 1,
f(x) = 2,
f(x) - 1 = 1,
a = Apple,
y + 1 = 3,
a.b(y + 1) = 13,
y = 2,
f(y) = 3,
a.b(y + 1) + f(y) = 16,
at"
})))
)
}
#[rustversion::before(1.77)]
#[test]
fn unary_operator() -> Result<()> {
#[derive(Debug)]
struct Apple;
impl Apple {
fn b(&self, _b: u32, _c: i32) -> i32 {
0
}
}
let a = Apple;
let b = 1;
let res = verify_pred!(!a.b(b, -1) == !-2);
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
! a.b(b, - 1) ==! - 2 was false with
a = Apple,
b = 1,
a.b(b, - 1) = 0,
! a.b(b, - 1) = -1,
! - 2 = 1,
at"
})))
)
}
#[rustversion::since(1.77)]
#[test]
fn unary_operator() -> Result<()> {
#[derive(Debug)]
struct Apple;
impl Apple {
fn b(&self, _b: u32, _c: i32) -> i32 {
0
}
}
let a = Apple;
let b = 1;
let res = verify_pred!(!a.b(b, -1) == !-2);
verify_that!(
res,
err(displays_as(contains_substring(indoc! {"
! a.b(b, - 1) == ! - 2 was false with
a = Apple,
b = 1,
a.b(b, - 1) = 0,
! a.b(b, - 1) = -1,
! - 2 = 1,
at"
})))
)
}
}
@@ -0,0 +1,50 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use std::fmt::{Display, Write};
// Make a long text with each element of the iterator on one line.
// `collection` must contains at least one element.
fn build_text<T: Display>(mut collection: impl Iterator<Item = T>) -> String {
let mut text = String::new();
write!(&mut text, "{}", collection.next().expect("Provided collection without elements"))
.unwrap();
for item in collection {
write!(&mut text, "\n{item}").unwrap();
}
text
}
#[test]
fn colors_appear_when_no_color_is_no_set_and_force_color_is_set() -> googletest::Result<()> {
std::env::remove_var("NO_COLOR");
std::env::set_var("FORCE_COLOR", "1");
let result = verify_that!(build_text(1..50), eq(&build_text(1..51)));
verify_that!(
result,
err(displays_as(contains_substring(
"
Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):
1
2
\x1B[3m<---- 45 common lines omitted ---->\x1B[0m
48
49
+\x1B[1;32m50\x1B[0m"
)))
)
}
@@ -0,0 +1,187 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
#[test]
fn all_matcher_works_as_inner_matcher() -> Result<()> {
let value = vec![1];
verify_that!(value, contains_each![all!(gt(&0), lt(&2))])
}
#[test]
fn matches_pattern_works_as_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct AStruct(i32);
verify_that!(vec![AStruct(123)], contains_each![matches_pattern!(&AStruct(eq(123)))])
}
#[test]
fn matches_pattern_works_with_property_as_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct AStruct(i32);
impl AStruct {
fn get_value(&self) -> i32 {
self.0
}
}
verify_that!(
vec![AStruct(123)],
contains_each![matches_pattern!(&AStruct {
get_value(): eq(123)
})]
)
}
#[test]
fn contains_each_works_as_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct AStruct(Vec<i32>);
verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref contains_each![eq(&123)])))
}
#[test]
fn pointwise_works_as_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct AStruct(Vec<i32>);
verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref pointwise!(eq, [&123]))))
}
#[test]
fn elements_are_works_as_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct AStruct(Vec<i32>);
verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref elements_are![eq(&123)])))
}
#[test]
fn tuple_works_as_inner_matcher() -> Result<()> {
verify_that!(vec![(123,)], elements_are![(eq(&123),)])
}
#[test]
fn matches_struct_with_method_returning_option_of_non_copy_value() -> Result<()> {
#[derive(Debug)]
struct AnInnerStruct;
#[derive(Debug)]
struct AStruct;
impl AStruct {
fn get_value(&self) -> Option<AnInnerStruct> {
Some(AnInnerStruct)
}
}
verify_that!(
AStruct,
matches_pattern!(&AStruct {
get_value(): ref some(matches_pattern!(&AnInnerStruct))
})
)
}
#[test]
fn matches_struct_with_method_returning_option_of_non_copy_enum() -> Result<()> {
#[derive(Debug)]
enum AnInnerStruct {
ThisCase,
#[allow(unused)]
ThatCase,
}
#[derive(Debug)]
struct AStruct;
impl AStruct {
fn get_value(&self) -> Option<AnInnerStruct> {
Some(AnInnerStruct::ThisCase)
}
}
verify_that!(
AStruct,
matches_pattern!(&AStruct {
get_value(): ref some(matches_pattern!(&AnInnerStruct::ThisCase))
})
)
}
#[test]
fn matches_struct_with_method_returning_option_ref_binding_mode() -> Result<()> {
#[derive(Debug)]
struct AnInnerStruct;
#[derive(Debug)]
struct AStruct;
impl AStruct {
fn get_value(&self) -> Option<AnInnerStruct> {
Some(AnInnerStruct)
}
}
verify_that!(
AStruct,
matches_pattern!(AStruct {
get_value(): some(matches_pattern!(AnInnerStruct))
})
)
}
#[test]
fn matches_struct_with_method_returning_option_enum_ref_binding_mode() -> Result<()> {
#[derive(Debug)]
enum AnInnerStruct {
ThisCase,
#[allow(unused)]
ThatCase,
}
#[derive(Debug)]
struct AStruct;
impl AStruct {
fn get_value(&self) -> Option<AnInnerStruct> {
Some(AnInnerStruct::ThisCase)
}
}
verify_that!(
AStruct,
matches_pattern!(AStruct {
get_value(): some(matches_pattern!(AnInnerStruct::ThisCase))
})
)
}
#[test]
fn matches_struct_with_property_against_predicate() -> Result<()> {
#[derive(Debug)]
enum AnInnerStruct {
ThisCase,
#[allow(unused)]
ThatCase,
}
#[derive(Debug)]
struct AStruct;
impl AStruct {
fn get_value(&self) -> AnInnerStruct {
AnInnerStruct::ThisCase
}
}
verify_that!(
AStruct,
matches_pattern!(AStruct {
get_value(): predicate(|_: &_| true)
})
)
}
@@ -0,0 +1,147 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn elements_are_matches_vector() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, elements_are![eq(&1), eq(&2), eq(&3)])
}
#[test]
fn elements_are_matches_slice() -> Result<()> {
let value = vec![1, 2, 3];
let slice = value.as_slice();
verify_that!(slice, elements_are![eq(&1), eq(&2), eq(&3)])
}
#[test]
fn elements_are_matches_array() -> Result<()> {
verify_that!([1, 2, 3], elements_are![eq(1), eq(2), eq(3)])
}
#[test]
fn elements_are_supports_trailing_comma() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, elements_are![eq(&1), eq(&2), eq(&3),])
}
#[test]
fn elements_are_returns_no_match_when_expected_and_actual_sizes_differ() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, not(elements_are![eq(&1), eq(&2), eq(&3)]))
}
#[test]
fn elements_are_admits_matchers_without_static_lifetime() -> Result<()> {
#[derive(Debug, PartialEq)]
struct AStruct(i32);
let expected_value = AStruct(123);
verify_that!(vec![AStruct(123)], elements_are![eq(&expected_value)])
}
#[test]
fn elements_are_matches_iterator_returning_by_value() -> Result<()> {
#[derive(Debug, Copy, Clone)]
struct Countdown(i32);
impl Iterator for Countdown {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
0 => None,
x => {
self.0 -= 1;
Some(x)
}
}
}
}
verify_that!(Countdown(3), elements_are![eq(3), eq(2), eq(1)])
}
#[test]
fn elements_are_produces_correct_failure_message() -> Result<()> {
let result = verify_that!(vec![1, 4, 3], elements_are![eq(&1), eq(&2), eq(&3)]);
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 4, 3]
Expected: has elements:
0. is equal to 1
1. is equal to 2
2. is equal to 3
Actual: [1, 4, 3],
where element #1 is 4, which isn't equal to 2"
))))
)
}
#[test]
fn elements_are_produces_correct_failure_message_nested() -> Result<()> {
let result = verify_that!(
vec![vec![0, 1], vec![1, 2]],
elements_are![elements_are![eq(&1), eq(&2)], elements_are![eq(&2), eq(&3)]]
);
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Expected: has elements:
0. has elements:
0. is equal to 1
1. is equal to 2
1. has elements:
0. is equal to 2
1. is equal to 3
Actual: [[0, 1], [1, 2]],
where:
* element #0 is [0, 1], where:
* element #0 is 0, which isn't equal to 1
* element #1 is 1, which isn't equal to 2
* element #1 is [1, 2], where:
* element #0 is 1, which isn't equal to 2
* element #1 is 2, which isn't equal to 3"
))))
)
}
#[test]
fn elements_are_explain_match_wrong_size() -> Result<()> {
let matcher = elements_are![eq(&1)];
verify_that!(matcher.explain_match(&vec![1, 2]), displays_as(eq("whose size is 2")))
}
fn create_matcher<'a>() -> impl Matcher<&'a Vec<i32>> {
elements_are![eq(&1)]
}
#[test]
fn elements_are_works_when_matcher_is_created_in_subroutine() -> Result<()> {
verify_that!(vec![1], create_matcher())
}
#[test]
fn elements_are_implicitly_called() -> Result<()> {
verify_that!(vec![1, 2, 3], [eq(&1), eq(&2), eq(&3)])
}
#[test]
fn elements_are_with_auto_eq() -> Result<()> {
verify_that!(vec![1, 2, 3], [&1, &2, lt(&43)])
}
@@ -0,0 +1,315 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::matcher::MatcherResult;
use googletest::prelude::*;
use googletest::Result;
#[derive(Debug)]
struct IntField {
int: i32,
}
#[test]
fn field_matches_integer_field() -> Result<()> {
verify_that!(IntField { int: 32 }, field!(&IntField.int, eq(32)))
}
#[derive(Debug)]
struct StringField {
strink: String,
}
#[test]
fn field_matches_string_field() -> Result<()> {
verify_that!(
StringField { strink: "yes".to_string() },
field!(&StringField.strink, ref eq("yes"))
)
}
#[test]
fn field_error_message_shows_field_name_and_inner_matcher() -> Result<()> {
let matcher = field!(&IntField.int, eq(31));
verify_that!(
matcher.describe(MatcherResult::Match),
displays_as(eq("has field `int`, which is equal to 31"))
)
}
mod sub {
#[derive(Debug)]
pub struct SubStruct {
pub field: i32,
}
}
#[test]
fn struct_in_other_module_matches() -> Result<()> {
verify_that!(sub::SubStruct { field: 32 }, field!(&sub::SubStruct.field, eq(32)))
}
#[derive(Debug)]
struct Tuple(i32, #[allow(unused)] String);
#[test]
fn tuple_matches_with_index() -> Result<()> {
verify_that!(Tuple(32, "yes".to_string()), field!(&Tuple.0, eq(32)))
}
#[test]
fn matches_enum_value() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
AValue(u32),
}
let value = AnEnum::AValue(123);
verify_that!(value, field!(&AnEnum::AValue.0, eq(123)))
}
#[test]
fn shows_correct_failure_message_for_wrong_struct_entry() -> Result<()> {
#[derive(Debug)]
struct AStruct {
a: Vec<u32>,
}
let value = AStruct { a: vec![1] };
let arr: [u32; 0] = [];
let result = verify_that!(value, field!(&AStruct.a, ref container_eq(arr)));
verify_that!(
result,
err(displays_as(contains_substring(
"which has field `a`, which contains the unexpected element 1"
)))
)
}
#[test]
fn does_not_match_enum_value_with_wrong_enum_variant() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(dead_code)] // This variant is intentionally unused.
AValue(u32),
AnotherValue,
}
let value = AnEnum::AnotherValue;
verify_that!(&value, not(field!(&AnEnum::AValue.0, eq(123))))
}
#[test]
fn shows_correct_failure_message_for_wrong_enum_value() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(dead_code)] // This variant is intentionally unused.
AValue {
a: u32,
},
AnotherValue,
}
let value = AnEnum::AnotherValue;
let result = verify_that!(value, field!(&AnEnum::AValue.a, eq(123)));
verify_that!(
result,
err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`")))
)
}
#[test]
fn shows_correct_failure_message_for_wrong_enum_value_with_tuple_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(dead_code)] // This variant is intentionally unused.
AValue(u32),
#[allow(unused)]
AnotherValue(u32),
}
let value = AnEnum::AnotherValue(123);
let result = verify_that!(value, field!(&AnEnum::AValue.0, eq(123)));
verify_that!(
result,
err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`")))
)
}
#[test]
fn shows_correct_failure_message_for_wrong_enum_value_with_named_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(dead_code)] // This variant is intentionally unused.
AValue(u32),
AnotherValue {
#[allow(unused)]
a: u32,
},
}
let value = AnEnum::AnotherValue { a: 123 };
let result = verify_that!(value, field!(&AnEnum::AValue.0, eq(123)));
verify_that!(
result,
err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`")))
)
}
#[test]
fn matches_struct_like_enum_value() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
AValue { a_field: u32 },
}
let value = AnEnum::AValue { a_field: 123 };
verify_that!(value, field!(&AnEnum::AValue.a_field, eq(123)))
}
#[test]
fn matches_struct_copy_to_copy() -> Result<()> {
#[derive(Debug, Clone, Copy)]
struct Strukt {
a_field: i32,
}
verify_that!(Strukt { a_field: 32 }, field!(Strukt.a_field, eq(32)))
}
#[test]
fn matches_struct_ref_to_copy() -> Result<()> {
#[derive(Debug)]
struct Strukt {
a_field: i32,
}
verify_that!(Strukt { a_field: 32 }, field!(&Strukt.a_field, eq(32)))
}
#[test]
fn matches_struct_ref_to_ref() -> Result<()> {
#[derive(Debug)]
struct Strukt {
a_field: String,
}
verify_that!(Strukt { a_field: "32".into() }, field!(&Strukt.a_field, ref eq("32")))
}
#[test]
fn matches_struct_copy_to_ref() -> Result<()> {
// It is not possible to have a copy struct with non-copy field. Hence, this
// test case is not necessary.
Ok(())
}
#[test]
fn matches_struct_ref_to_ref_binding_mode() -> Result<()> {
#[derive(Debug)]
struct Strukt {
a_field: String,
}
verify_that!(Strukt { a_field: "32".into() }, field!(Strukt.a_field, eq("32")))
}
#[test]
fn matches_struct_with_auto_eq() -> Result<()> {
#[derive(Debug)]
struct Strukt {
a_field: String,
}
verify_that!(Strukt { a_field: "32".into() }, field!(Strukt.a_field, "32"))
}
#[test]
fn matches_enum_with_auto_eq() -> Result<()> {
#[derive(Debug)]
enum Enum {
Str(String),
#[allow(unused)]
Int(i32),
}
verify_that!(Enum::Str("32".into()), field!(Enum::Str.0, "32"))
}
#[test]
fn matches_enum_with_auto_eq_with_wrapper() -> Result<()> {
#[derive(Debug)]
struct Wrapper<I> {
wrapped: I,
}
verify_that!(
Wrapper { wrapped: Wrapper { wrapped: 23 } },
field!(Wrapper.wrapped, field!(Wrapper.wrapped, &23))
)
}
#[test]
fn supports_fully_qualified_struct_path() -> Result<()> {
// Ensure that the macro expands to the fully-qualified struct path.
mod googletest {}
let value = ::googletest::internal::test_data::TestStruct { value: 10 };
verify_that!(value, field!(&::googletest::internal::test_data::TestStruct.value, ref eq(&10)))?;
verify_that!(value, field!(&::googletest::internal::test_data::TestStruct.value, eq(10)))?;
verify_that!(value, field!(::googletest::internal::test_data::TestStruct.value, eq(&10)))?;
Ok(())
}
#[test]
fn supports_generic_struct() -> Result<()> {
#[derive(Debug)]
struct Struct<S, T> {
#[allow(dead_code)] // The property1 field is used only for adding the type parameter.
property1: S,
property2: T,
}
let value = Struct { property1: 1, property2: 10 };
verify_that!(&value, field!(&Struct::<i32, u32>.property2, ref eq(&10)))?;
verify_that!(value, field!(&Struct::<i32, u32>.property2, eq(10)))?;
verify_that!(value, field!(Struct::<i32, u32>.property2, eq(&10)))?;
Ok(())
}
#[test]
fn supports_fully_qualified_generic_struct() -> Result<()> {
// Ensure that the macro expands to the fully-qualified struct path.
mod googletest {}
let value = ::googletest::internal::test_data::GenericTestStruct { value: 10 };
verify_that!(
&value,
field!(&::googletest::internal::test_data::GenericTestStruct::<i32>.value, ref eq(&10))
)?;
verify_that!(
value,
field!(&::googletest::internal::test_data::GenericTestStruct::<i32>.value, eq(10))
)?;
verify_that!(
value,
field!(::googletest::internal::test_data::GenericTestStruct::<i32>.value, eq(&10))
)?;
Ok(())
}
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod write_expr_value {
use googletest::prelude::*;
// Converts the formatting call to a `String` for testing.
macro_rules! write_expr_value {
($expr_str:expr, $expr: expr $(,)?) => {{
let mut s = String::new();
::googletest::fmt::internal::__googletest__write_expr_value!(s, $expr_str, $expr);
s
}};
}
#[test]
fn test_with_debug_value_references() -> googletest::Result<()> {
#[derive(Debug)]
struct Foo;
let mut val = Foo;
verify_that!(write_expr_value!("val", val), eq("\n val = Foo,"))?;
verify_that!(write_expr_value!("val", &val), eq("\n val = Foo,"))?;
verify_that!(write_expr_value!("val", &&val), eq("\n val = Foo,"))?;
verify_that!(write_expr_value!("val", &mut val), eq("\n val = Foo,"))?;
verify_that!(write_expr_value!("val", &mut &mut val), eq("\n val = Foo,"))?;
Ok(())
}
#[test]
fn test_with_non_debug_value_references() -> googletest::Result<()> {
struct Foo;
let mut val = Foo;
verify_that!(write_expr_value!("val", val), eq("\n val does not implement Debug,"))?;
verify_that!(write_expr_value!("val", &val), eq("\n val does not implement Debug,"))?;
verify_that!(write_expr_value!("val", &&val), eq("\n val does not implement Debug,"))?;
verify_that!(write_expr_value!("val", &mut val), eq("\n val does not implement Debug,"))?;
verify_that!(
write_expr_value!("val", &mut &mut val),
eq("\n val does not implement Debug,")
)?;
Ok(())
}
}
@@ -0,0 +1,469 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn matches_enum_without_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A,
}
let actual = AnEnum::A;
verify_that!(actual, matches_pattern!(&AnEnum::A))?;
verify_that!(actual, matches_pattern!(&AnEnum::A,))
}
#[test]
fn matches_enum_without_field_ref_binding_mode() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A,
}
let actual = AnEnum::A;
verify_that!(actual, matches_pattern!(AnEnum::A))?;
verify_that!(actual, matches_pattern!(AnEnum::A,))
}
#[test]
fn matches_enum_without_field_copy() -> Result<()> {
#[derive(Debug, Clone, Copy)]
enum AnEnum {
A,
}
let actual = AnEnum::A;
verify_that!(actual, matches_pattern!(AnEnum::A))?;
verify_that!(actual, matches_pattern!(AnEnum::A,))
}
#[test]
fn generates_correct_failure_output_when_enum_variant_without_field_is_not_matched() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(unused)]
A,
B,
}
let actual = AnEnum::B;
let result = verify_that!(actual, matches_pattern!(&AnEnum::A));
const EXPECTED: &str = "is not & AnEnum :: A";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn generates_correct_failure_output_when_enum_variant_without_field_is_matched() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A,
}
let actual = AnEnum::A;
let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A)));
const EXPECTED: &str = "is & AnEnum :: A";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn has_meaningful_assertion_failure_message_when_wrong_enum_variant_is_used() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(unused)]
A(u32),
#[allow(unused)]
B(u32),
}
let actual = AnEnum::A(123);
let result = verify_that!(actual, matches_pattern!(&AnEnum::B(eq(123))));
verify_that!(
result,
err(displays_as(contains_substring(indoc! {"
Actual: A(123),
which has the wrong enum variant `A`
"
})))
)
}
#[test]
fn matches_enum_struct_non_exhaustive() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a_field: u32, another_field: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a_field: 123, another_field: 234 };
verify_that!(actual, matches_pattern!(&AnEnum::Variant1 { a_field: eq(123), .. }))
}
#[test]
fn matches_enum_struct_with_all_non_exhaustive_fields() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
verify_that!(actual, matches_pattern!(&AnEnum::Variant1 { .. }))
}
#[test]
fn has_failure_when_wrong_enum_struct_variant_is_matched_with_all_non_exhaustive_fields(
) -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant2 { .. }));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant2 { .. }
Actual: Variant1 { a: 123, b: 234 },
which is not & AnEnum :: Variant2 { .. }
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn matches_enum_struct_with_all_wildcard_fields() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
verify_that!(actual, matches_pattern!(&AnEnum::Variant1 { a: _, b: _ }))
}
#[test]
fn has_failure_when_wrong_enum_struct_variant_is_matched_with_all_wildcard_fields() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant2 { c: _, d: _ }));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant2 { c : _, d : _, }
Actual: Variant1 { a: 123, b: 234 },
which is not & AnEnum :: Variant2 { c : _, d : _, }
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn matches_enum_struct_non_exhaustive_with_wildcard_fields() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
verify_that!(actual, matches_pattern!(&AnEnum::Variant1 { a: _, .. }))
}
#[test]
fn has_failure_when_wrong_enum_struct_variant_is_matched_non_exhaustive_with_wildcard_fields(
) -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a: u32, b: u32 },
Variant2 { c: u32, d: u32 },
}
let actual: AnEnum = AnEnum::Variant1 { a: 123, b: 234 };
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant2 { c: _, .. }));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant2 { c : _, .. }
Actual: Variant1 { a: 123, b: 234 },
which is not & AnEnum :: Variant2 { c : _, .. }
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn matches_enum_struct_exhaustive_with_multiple_variants() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1 { a_field: u32 },
Variant2,
}
let actual: AnEnum = AnEnum::Variant1 { a_field: 123 };
verify_that!(actual, matches_pattern!(&AnEnum::Variant1 { a_field: eq(123) }))
}
#[test]
fn matches_match_pattern_literal() -> Result<()> {
let actual = false;
#[allow(clippy::redundant_pattern_matching)]
verify_that!(actual, matches_pattern!(false))?;
#[allow(clippy::redundant_pattern_matching)]
verify_that!(actual, matches_pattern!(false,))?;
let actual = 1;
verify_that!(actual, matches_pattern!(1))?;
verify_that!(actual, matches_pattern!(1,))?;
let actual = "test";
verify_that!(actual, matches_pattern!(&"test"))?;
verify_that!(actual, matches_pattern!(&"test",))
}
#[test]
fn has_failure_when_wrong_enum_variant_is_matched_non_exhaustively() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant2;
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant1(..)));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant1(..)
Actual: Variant2,
which is not & AnEnum :: Variant1(..)
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn has_failure_when_wrong_enum_variant_is_matched_with_underscore() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant2;
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant1(_)));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant1(_)
Actual: Variant2,
which is not & AnEnum :: Variant1(_)
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn has_failure_when_wrong_enum_variant_is_matched_with_value() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant2;
let result = verify_that!(actual, matches_pattern!(&AnEnum::Variant1(123)));
const EXPECTED: &str = indoc!(
"
Expected: is & AnEnum :: Variant1 which has field `0`, which is equal to 123
Actual: Variant2,
which has the wrong enum variant `Variant2`
"
);
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn matches_enum_struct_field_with_mutliple_variants() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant2;
verify_that!(actual, matches_pattern!(&AnEnum::Variant2))
}
#[test]
fn matches_enum_struct_field_with_multiple_variants_non_exhaustive() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant1(123);
verify_that!(actual, matches_pattern!(&AnEnum::Variant1(..)))
}
#[test]
fn matches_enum_struct_field_with_multiple_variants_with_wildcard() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
enum AnEnum {
Variant1(i8),
Variant2,
}
let actual: AnEnum = AnEnum::Variant1(123);
verify_that!(actual, matches_pattern!(&AnEnum::Variant1(_)))
}
#[test]
fn matches_enum_with_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A(u32),
}
let actual = AnEnum::A(123);
verify_that!(actual, matches_pattern!(&AnEnum::A(eq(123))))
}
#[test]
fn does_not_match_wrong_enum_value() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
#[allow(unused)]
A(u32),
B,
}
let actual = AnEnum::B;
verify_that!(actual, not(matches_pattern!(&AnEnum::A(eq(123)))))
}
#[test]
fn includes_enum_variant_in_description_with_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A(u32),
}
let actual = AnEnum::A(123);
let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234))));
const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `0`";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn includes_enum_variant_in_negative_description_with_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A(u32),
}
let actual = AnEnum::A(123);
let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A(eq(123)))));
const EXPECTED: &str = "Expected: is not & AnEnum :: A which has field `0`, which is equal to";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn includes_enum_variant_in_description_with_two_fields() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A(u32, u32),
}
let actual = AnEnum::A(123, 234);
let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234))));
const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn includes_enum_variant_in_description_with_three_fields() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A(u32, u32, u32),
}
let actual = AnEnum::A(123, 234, 345);
let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234), eq(345))));
const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn includes_enum_variant_in_description_with_named_field() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A { field: u32 },
}
let actual = AnEnum::A { field: 123 };
let result = verify_that!(actual, matches_pattern!(&AnEnum::A { field: eq(234) }));
const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `field`";
verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
}
#[test]
fn includes_enum_variant_in_description_with_two_named_fields() -> Result<()> {
#[derive(Debug)]
enum AnEnum {
A { field: u32, another_field: u32 },
}
let actual = AnEnum::A { field: 123, another_field: 234 };
let result = verify_that!(
actual,
matches_pattern!(&AnEnum::A { field: eq(234), another_field: eq(234) })
);
const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
verify_that!(&result, err(displays_as(contains_substring(EXPECTED))))
}
@@ -0,0 +1,234 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
#[test]
fn matches_struct_with_a_method_taking_enum_value_parameter_followed_by_field() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
}
impl AStruct {
fn get_field(&self, _value: AnEnum) -> u32 {
self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2 };
verify_that!(
actual,
matches_pattern!(&AStruct { get_field(AnEnum::AVariant): eq(1), another_field: eq(2), .. })
)
}
#[test]
fn matches_struct_with_a_method_taking_enum_value_param_ret_ref_followed_by_field() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
}
impl AStruct {
fn get_field_ref(&self, _value: AnEnum) -> &u32 {
&self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2 };
verify_that!(
actual,
matches_pattern!(&AStruct {
get_field_ref(AnEnum::AVariant): eq(&1),
another_field: eq(2),
..
})
)
}
#[test]
fn matches_struct_with_field_followed_by_method_taking_enum_value_param() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
}
impl AStruct {
fn get_field(&self, _value: AnEnum) -> u32 {
self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2 };
verify_that!(
actual,
matches_pattern!(&AStruct {
another_field: eq(2),
get_field(AnEnum::AVariant): eq(1),
..
})
)
}
#[test]
fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
}
impl AStruct {
fn get_field_ref(&self, _value: AnEnum) -> &u32 {
&self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2 };
verify_that!(
actual,
matches_pattern!(&AStruct {
another_field: eq(2),
get_field_ref(AnEnum::AVariant): eq(&1),
..
})
)
}
#[test]
fn matches_struct_with_field_followed_by_method_taking_enum_value_param_followed_by_field(
) -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
a_third_field: u32,
}
impl AStruct {
fn get_field(&self, _value: AnEnum) -> u32 {
self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2, a_third_field: 3 };
verify_that!(
actual,
matches_pattern!(&AStruct {
another_field: eq(2),
get_field(AnEnum::AVariant): eq(1),
a_third_field: eq(3),
..
})
)
}
#[test]
fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_followed_by_field(
) -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
another_field: u32,
a_third_field: u32,
}
impl AStruct {
fn get_field_ref(&self, _value: AnEnum) -> &u32 {
&self.a_field
}
}
let actual = AStruct { a_field: 1, another_field: 2, a_third_field: 3 };
verify_that!(
actual,
matches_pattern!(&AStruct {
another_field: eq(2),
get_field_ref(AnEnum::AVariant): eq(&1),
a_third_field: eq(3),
..
})
)
}
#[test]
fn matches_struct_with_a_method_returning_reference_taking_enum_value_parameter() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
}
impl AStruct {
fn get_field_ref(&self, _value: AnEnum) -> &u32 {
&self.a_field
}
}
let actual = AStruct { a_field: 1 };
verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(AnEnum::AVariant): eq(&1) }))
}
#[test]
fn matches_struct_with_a_method_taking_enum_value_parameter() -> Result<()> {
enum AnEnum {
AVariant,
}
#[derive(Debug)]
struct AStruct {
a_field: u32,
}
impl AStruct {
fn get_a_field(&self, _value: AnEnum) -> u32 {
self.a_field
}
}
let actual = AStruct { a_field: 1 };
verify_that!(actual, matches_pattern!(&AStruct { get_a_field(AnEnum::AVariant): eq(1) }))
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,237 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
#[test]
fn matches_tuple_struct_containing_single_field() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32);
let actual = AStruct(123);
verify_that!(actual, matches_pattern!(&AStruct(eq(123))))
}
#[test]
fn matches_tuple_struct_containing_two_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32);
let actual = AStruct(123, 234);
verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234))))
}
#[test]
fn matches_tuple_struct_containing_three_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32);
let actual = AStruct(123, 234, 345);
verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345))))
}
#[test]
fn matches_tuple_struct_containing_four_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456);
verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456))))
}
#[test]
fn matches_tuple_struct_containing_five_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567);
verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567))))
}
#[test]
fn matches_tuple_struct_containing_six_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678);
verify_that!(
actual,
matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678)))
)
}
#[test]
fn matches_tuple_struct_containing_seven_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678, 789);
verify_that!(
actual,
matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678), eq(789)))
)
}
#[test]
fn matches_tuple_struct_containing_eight_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678, 789, 890);
verify_that!(
actual,
matches_pattern!(&AStruct(
eq(123),
eq(234),
eq(345),
eq(456),
eq(567),
eq(678),
eq(789),
eq(890)
))
)
}
#[test]
fn matches_tuple_struct_containing_nine_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678, 789, 890, 901);
verify_that!(
actual,
matches_pattern!(&AStruct(
eq(123),
eq(234),
eq(345),
eq(456),
eq(567),
eq(678),
eq(789),
eq(890),
eq(901)
))
)
}
#[test]
fn matches_tuple_struct_containing_ten_fields() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678, 789, 890, 901, 12);
verify_that!(
actual,
matches_pattern!(&AStruct(
eq(123),
eq(234),
eq(345),
eq(456),
eq(567),
eq(678),
eq(789),
eq(890),
eq(901),
eq(12)
))
)
}
#[test]
fn matches_tuple_struct_containing_ten_fields_by_ref() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32);
let actual = AStruct(123, 234, 345, 456, 567, 678, 789, 890, 901, 12);
verify_that!(
actual,
matches_pattern!(&AStruct(
ref eq(&123),
ref eq(&234),
ref eq(&345),
ref eq(&456),
ref eq(&567),
ref eq(&678),
ref eq(&789),
ref eq(&890),
ref eq(&901),
ref eq(&12)
))
)
}
#[test]
fn matches_tuple_struct_with_trailing_comma() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32);
let actual = AStruct(123);
verify_that!(
actual,
matches_pattern!(&AStruct(
eq(123), // Keep the trailing comma, block reformatting
))
)
}
#[test]
fn matches_tuple_struct_with_two_fields_and_trailing_comma() -> Result<()> {
#[derive(Debug)]
struct AStruct(u32, u32);
let actual = AStruct(123, 234);
verify_that!(
actual,
matches_pattern!(&AStruct(
eq(123),
eq(234), // Keep the trailing comma, block reformatting
))
)
}
#[test]
fn matches_tuple_struct_with_interleaved_underscore() -> Result<()> {
#[derive(Debug)]
struct NonCopy;
#[derive(Debug)]
struct AStruct(u32, NonCopy, u32);
let actual = AStruct(1, NonCopy, 3);
verify_that!(actual, matches_pattern!(&AStruct(eq(1), _, eq(3))))?;
verify_that!(actual, matches_pattern!(AStruct(eq(&1), _, eq(&3))))
}
#[test]
fn matches_tuple_struct_non_exhaustive() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
struct AStruct(i32, u32);
let actual = AStruct(1, 3);
verify_that!(actual, matches_pattern!(&AStruct(_, ..)))?;
verify_that!(actual, matches_pattern!(AStruct(_, ..)))
}
#[test]
fn matches_generic_tuple_struct_exhaustively() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
struct AStruct<T>(T, u32);
let actual = AStruct(1, 3);
verify_that!(actual, matches_pattern!(&AStruct(_, _)))?;
verify_that!(actual, matches_pattern!(AStruct(_, _)))
}
@@ -0,0 +1,50 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use std::fmt::{Display, Write};
// Make a long text with each element of the iterator on one line.
// `collection` must contains at least one element.
fn build_text<T: Display>(mut collection: impl Iterator<Item = T>) -> String {
let mut text = String::new();
write!(&mut text, "{}", collection.next().expect("Provided collection without elements"))
.unwrap();
for item in collection {
write!(&mut text, "\n{item}").unwrap();
}
text
}
#[test]
fn colors_suppressed_when_both_no_color_and_force_color_are_set() -> googletest::Result<()> {
std::env::set_var("NO_COLOR", "1");
std::env::set_var("FORCE_COLOR", "1");
let result = verify_that!(build_text(1..50), eq(&build_text(1..51)));
verify_that!(
result,
err(displays_as(contains_substring(
"
Difference(-actual / +expected):
1
2
<---- 45 common lines omitted ---->
48
49
+50"
)))
)
}
@@ -0,0 +1,37 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_std]
/// A simple, no_std function.
fn no_std_identity(value: u32) -> u32 {
value
}
#[cfg(test)]
mod tests {
use super::*;
use googletest::prelude::*;
#[gtest]
fn no_std_verify() -> Result<()> {
verify_eq!(no_std_identity(42), 42)?;
Ok(())
}
#[gtest]
fn no_std_expect() {
expect_eq!(no_std_identity(214), 214)
}
}
@@ -0,0 +1,191 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn pointwise_matches_single_element() -> Result<()> {
let value = vec![1];
verify_that!(value, pointwise!(lt, vec![&2]))
}
#[test]
fn pointwise_matches_two_elements() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, pointwise!(|x| points_to(lt(x)), vec![2, 3]))
}
#[test]
fn pointwise_matches_iterator_returning_by_value() -> Result<()> {
#[derive(Clone, Copy, Debug)]
struct Countdown(i32);
impl Iterator for Countdown {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
0 => None,
x => {
self.0 -= 1;
Some(x)
}
}
}
}
verify_that!(Countdown(3), pointwise!(eq, vec![3, 2, 1]))
}
#[test]
fn pointwise_matches_two_elements_with_array() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, pointwise!(lt, [&2, &3]))
}
#[test]
fn pointwise_matches_two_element_slice() -> Result<()> {
let value = vec![1, 2];
let slice = value.as_slice();
verify_that!(slice, pointwise!(lt, [&2, &3]))
}
#[test]
fn pointwise_does_not_match_value_of_wrong_length() -> Result<()> {
let value = vec![1];
verify_that!(value, not(pointwise!(lt, vec![&2, &3])))
}
#[test]
fn pointwise_does_not_match_value_not_matching_in_first_position() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, not(pointwise!(lt, vec![&1, &3])))
}
#[test]
fn pointwise_does_not_match_value_not_matching_in_second_position() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, not(pointwise!(lt, vec![&2, &2])))
}
#[test]
fn pointwise_allows_qualified_matcher_name() -> Result<()> {
mod submodule {
pub(super) use super::lt;
}
let value = vec![1];
verify_that!(value, pointwise!(submodule::lt, vec![&2]))
}
#[test]
fn pointwise_returns_mismatch_when_actual_value_has_wrong_length() -> Result<()> {
let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![&1, &2]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 2, 3]
Expected: has elements satisfying respectively:
0. is equal to 1
1. is equal to 2
Actual: [1, 2, 3],
which has size 3 (expected 2)
"
))))
)
}
#[test]
fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_first_item() -> Result<()> {
let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![&2, &2, &3]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 2, 3]
Expected: has elements satisfying respectively:
0. is equal to 2
1. is equal to 2
2. is equal to 3
Actual: [1, 2, 3],
where element #0 is 1, which isn't equal to 2
"
))))
)
}
#[test]
fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_second_item() -> Result<()> {
let result = verify_that!(vec![1, 2, 3], pointwise!(eq, &vec![1, 3, 3]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 2, 3]
Expected: has elements satisfying respectively:
0. is equal to 1
1. is equal to 3
2. is equal to 3
Actual: [1, 2, 3],
where element #1 is 2, which isn't equal to 3
"
))))
)
}
#[test]
fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_first_and_second_items(
) -> Result<()> {
let result = verify_that!(vec![1, 2, 3], pointwise!(eq, &vec![2, 3, 3]));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 2, 3]
Expected: has elements satisfying respectively:
0. is equal to 2
1. is equal to 3
2. is equal to 3
Actual: [1, 2, 3],
where:
* element #0 is 1, which isn't equal to 2
* element #1 is 2, which isn't equal to 3"
))))
)
}
#[test]
fn pointwise_matches_single_element_with_lambda_expression_with_extra_value() -> Result<()> {
let value = [1.00001f32];
verify_that!(value, pointwise!(|v| near(v, 0.0001), vec![1.0]))
}
#[test]
fn pointwise_matches_single_element_with_two_containers() -> Result<()> {
let value = [1.00001f32];
verify_that!(value, pointwise!(near, vec![1.0], vec![0.0001]))
}
#[test]
fn pointwise_matches_single_element_with_three_containers() -> Result<()> {
let value = [1.00001f32];
verify_that!(
value,
pointwise!(|v, t, u| near(v, t + u), vec![1.0f32], vec![0.0001f32], vec![0.5f32])
)
}
@@ -0,0 +1,396 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::matcher::MatcherResult;
use googletest::prelude::*;
use googletest::Result;
#[derive(Debug)]
struct SomeStruct {
a_property: u32,
}
impl SomeStruct {
fn get_property(&self) -> u32 {
self.a_property
}
fn get_property_ref(&self) -> &u32 {
&self.a_property
}
fn add_product_to_field(&self, a: u32, b: u32) -> u32 {
self.a_property + a * b
}
fn get_property_ref_with_params(&self, _a: u32, _b: u32) -> &u32 {
&self.a_property
}
fn generic_method<U, V>(&self, _a: U, _b: V) -> u32 {
self.a_property
}
fn generic_method_ref<U, V>(&self, _a: U, _b: V) -> &u32 {
&self.a_property
}
}
#[test]
fn matches_struct_with_matching_property() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.get_property(), eq(10)))
}
#[test]
fn matches_struct_with_matching_property_with_parameters() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.add_product_to_field(2, 3), eq(16)))
}
#[test]
fn matches_struct_with_matching_property_with_parameters_with_trailing_comma() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.add_product_to_field(2, 3,), eq(16)))
}
#[test]
fn matches_struct_with_matching_property_ref() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.get_property_ref(), eq(&10)))
}
#[test]
fn matches_struct_with_matching_string_reference_property() -> Result<()> {
#[derive(Debug)]
struct StructWithString {
property: String,
}
impl StructWithString {
fn get_property_ref(&self) -> &String {
&self.property
}
}
let value = StructWithString { property: "Something".into() };
verify_that!(value, property!(&StructWithString.get_property_ref(), eq("Something")))
}
#[test]
fn matches_struct_with_matching_slice_property() -> Result<()> {
#[derive(Debug)]
struct StructWithVec {
property: Vec<u32>,
}
impl StructWithVec {
fn get_property_ref(&self) -> &[u32] {
&self.property
}
}
let value = StructWithVec { property: vec![1, 2, 3] };
verify_that!(value, property!(&StructWithVec.get_property_ref(), eq([1, 2, 3])))
}
#[test]
fn matches_struct_with_matching_property_ref_with_parameters() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.get_property_ref_with_params(2, 3), eq(&10)))
}
#[test]
fn matches_struct_with_matching_property_ref_with_parameters_and_trailing_comma() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(&SomeStruct.get_property_ref_with_params(2, 3,), eq(&10)))
}
#[test]
fn does_not_match_struct_with_non_matching_property() -> Result<()> {
let value = SomeStruct { a_property: 2 };
verify_that!(value, not(property!(&SomeStruct.get_property(), eq(1))))
}
#[test]
fn supports_fully_qualified_struct_path() -> Result<()> {
// Ensure that the macro expands to the fully-qualified struct path.
mod googletest {}
let value = ::googletest::internal::test_data::TestStruct { value: 10 };
verify_that!(
value,
property!(::googletest::internal::test_data::TestStruct.get_value(), eq(&10))
)?;
verify_that!(
value,
property!(&::googletest::internal::test_data::TestStruct.get_value(), eq(10))
)?;
verify_that!(
value,
property!(&::googletest::internal::test_data::TestStruct.get_value(), ref eq(&10))
)?;
Ok(())
}
#[test]
fn supports_generic_struct_matches() -> Result<()> {
#[derive(Debug)]
struct GenericStruct<S, T> {
#[allow(dead_code)] // The property1 field is used only for adding the type parameter.
property1: S,
property2: T,
}
impl<S, T: Copy> GenericStruct<S, T> {
fn get_property(&self) -> T {
self.property2
}
fn get_property_ref(&self) -> &T {
&self.property2
}
}
let value = GenericStruct { property1: 1, property2: 10 };
verify_that!(value, property!(GenericStruct::<i32, u32>.get_property(), eq(&10)))?;
verify_that!(value, property!(&GenericStruct::<i32, u32>.get_property(), eq(10)))?;
verify_that!(value, property!(&GenericStruct::<i32, u32>.get_property(), ref eq(&10)))?;
verify_that!(value, property!(&GenericStruct::<i32, u32>.get_property_ref(), eq(&10)))?;
verify_that!(value, property!(&GenericStruct::<i32, u32>.get_property_ref(), ref eq(&&10)))?;
Ok(())
}
#[test]
fn supports_generic_method_matches() -> Result<()> {
let value = SomeStruct { a_property: 10 };
verify_that!(value, property!(SomeStruct.generic_method::<i32, i16>(1, 2), eq(&10)))?;
verify_that!(value, property!(&SomeStruct.generic_method::<i32, i16>(1, 2), eq(10)))?;
verify_that!(value, property!(&SomeStruct.generic_method::<i32, i16>(1, 2), ref eq(&10)))?;
verify_that!(value, property!(&SomeStruct.generic_method_ref::<i32, i16>(1, 2), eq(&10)))?;
verify_that!(value, property!(&SomeStruct.generic_method_ref::<i32, i16>(1, 2), ref eq(&&10)))?;
Ok(())
}
#[test]
fn supports_fully_qualified_generic_struct_path() -> Result<()> {
// Ensure that the macro expands to the fully-qualified struct path.
mod googletest {}
let value = ::googletest::internal::test_data::GenericTestStruct { value: 1 };
verify_that!(
value,
property!(
::googletest::internal::test_data::GenericTestStruct::<i32>.get_value::<i16>(10),
eq(&10)
)
)?;
verify_that!(
value,
property!(
&::googletest::internal::test_data::GenericTestStruct::<i32>.get_value::<i16>(10),
eq(10)
)
)?;
verify_that!(
value,
property!(
&::googletest::internal::test_data::GenericTestStruct::<i32>.get_value::<i16>(10),
ref eq(&10))
)?;
Ok(())
}
#[test]
fn describes_itself_in_matching_case() -> Result<()> {
verify_that!(
property!(&SomeStruct.get_property(), eq(1)).describe(MatcherResult::Match),
displays_as(eq("has property `get_property()`, which is equal to 1"))
)
}
#[test]
fn describes_itself_in_not_matching_case() -> Result<()> {
verify_that!(
property!(&SomeStruct.get_property(), eq(1)).describe(MatcherResult::NoMatch),
displays_as(eq("has property `get_property()`, which isn't equal to 1"))
)
}
#[test]
fn explains_mismatch_referencing_explanation_of_inner_matcher() -> Result<()> {
#[derive(Debug)]
struct SomeStruct;
impl SomeStruct {
fn get_a_collection(&self) -> Vec<u32> {
vec![]
}
}
let value = SomeStruct;
let result =
verify_that!(value, property!(&SomeStruct.get_a_collection(), ref container_eq([1])));
verify_that!(
result,
err(displays_as(contains_substring(
"whose property `get_a_collection()` is `[]`, which is missing the element 1"
)))
)
}
#[test]
fn explains_mismatch_referencing_explanation_of_inner_matcher_binding_mode() -> Result<()> {
#[derive(Debug)]
struct SomeStruct;
impl SomeStruct {
fn get_a_collection(&self) -> Vec<u32> {
vec![]
}
}
let result =
verify_that!(SomeStruct, property!(SomeStruct.get_a_collection(), container_eq([1])));
verify_that!(
result,
err(displays_as(contains_substring(
"whose property `get_a_collection()` is `[]`, which is missing the element 1"
)))
)
}
#[test]
fn describes_itself_in_matching_case_for_ref() -> Result<()> {
verify_that!(
property!(&SomeStruct.get_property_ref(), eq(&1)).describe(MatcherResult::Match),
displays_as(eq("has property `get_property_ref()`, which is equal to 1"))
)
}
#[test]
fn describes_itself_in_not_matching_case_for_ref() -> Result<()> {
verify_that!(
property!(&SomeStruct.get_property_ref(), eq(&1)).describe(MatcherResult::NoMatch),
displays_as(eq("has property `get_property_ref()`, which isn't equal to 1"))
)
}
#[test]
fn explains_mismatch_referencing_explanation_of_inner_matcher_for_ref() -> Result<()> {
static EMPTY_COLLECTION: Vec<u32> = vec![];
#[derive(Debug)]
struct SomeStruct;
impl SomeStruct {
fn get_a_collection_ref(&self) -> &[u32] {
&EMPTY_COLLECTION
}
}
let value = SomeStruct;
let result =
verify_that!(value, property!(&SomeStruct.get_a_collection_ref(), container_eq([1])));
verify_that!(
result,
err(displays_as(contains_substring(
"whose property `get_a_collection_ref()` is `[]`, which is missing the element 1"
)))
)
}
#[test]
fn matches_copy_to_copy() -> Result<()> {
#[derive(Debug, Clone, Copy)]
struct Struct;
impl Struct {
fn property(self) -> i32 {
32
}
}
verify_that!(Struct, property!(Struct.property(), eq(32)))
}
#[test]
fn matches_copy_to_ref() -> Result<()> {
#[derive(Debug, Clone, Copy)]
struct Struct;
impl Struct {
fn property(self) -> String {
"something".into()
}
}
verify_that!(Struct, property!(Struct.property(), ref eq("something")))
}
#[test]
fn matches_copy_but_by_ref() -> Result<()> {
#[derive(Debug, Clone, Copy)]
struct Struct;
impl Struct {
fn property(&self) -> String {
"something".into()
}
}
verify_that!(&Struct, property!(&Struct.property(), ref eq("something")))
}
#[test]
fn matches_ref_to_ref() -> Result<()> {
#[derive(Debug)]
struct Struct;
impl Struct {
fn property(&self) -> String {
"something".into()
}
}
verify_that!(Struct, property!(&Struct.property(), ref eq("something")))
}
#[test]
fn matches_ref_to_copy() -> Result<()> {
#[derive(Debug)]
struct Struct;
impl Struct {
fn property(&self) -> i32 {
32
}
}
verify_that!(Struct, property!(&Struct.property(), eq(32)))
}
#[test]
fn matches_ref_to_ref_with_binding_mode() -> Result<()> {
#[derive(Debug)]
struct Struct;
impl Struct {
fn property(&self) -> String {
"something".into()
}
}
verify_that!(Struct, property!(Struct.property(), eq("something")))
}
#[test]
fn matches_property_auto_eq() -> Result<()> {
#[derive(Debug)]
struct Struct;
impl Struct {
fn property(&self) -> String {
"something".into()
}
}
verify_that!(Struct, property!(Struct.property(), "something"))
}
@@ -0,0 +1,30 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg(feature = "proptest")]
use googletest::prelude::*;
use proptest::test_runner::{Config, TestRunner};
#[test]
fn numbers_are_greater_than_zero() -> Result<()> {
let mut runner = TestRunner::new(Config::default());
runner.run(&(1..100i32), |v| Ok(verify_that!(v, gt(0))?)).or_fail()
}
#[test]
fn strings_are_nonempty() -> Result<()> {
let mut runner = TestRunner::new(Config::default());
runner.run(&"[a-zA-Z0-9]+", |v| Ok(verify_that!(v, not(eq("")))?)).or_fail()
}
@@ -0,0 +1,51 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[derive(Debug)]
struct ArenaHolder<'a, T: ?Sized> {
value: &'a T,
}
impl<'a, T: PartialEq + ?Sized> PartialEq<T> for ArenaHolder<'a, T> {
fn eq(&self, other: &T) -> bool {
self.value == other
}
}
struct Strukt {
a_field: String,
}
impl<'a> ArenaHolder<'a, Strukt> {
fn get_a_field(&self) -> ArenaHolder<'_, str> {
ArenaHolder { value: &self.value.a_field }
}
}
#[cfg(test)]
mod tests {
use super::*;
use googletest::prelude::*;
#[gtest]
fn test() {
let arena = [Strukt { a_field: "hello".into() }];
let holder = ArenaHolder { value: &arena[0] };
let inner_holder = holder.get_a_field();
expect_that!(inner_holder, eq("hello"));
}
}
@@ -0,0 +1,3 @@
Google Test trace:
scoped_trace_panic_test.rs:24: Inner trace
scoped_trace_panic_test.rs:22: Outer trace
@@ -0,0 +1,27 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::internal::test_outcome::TestOutcome;
use googletest::prelude::*;
fn main() {
// Initialize the panic hook to capture and print scoped traces on panic.
TestOutcome::init_current_test_outcome();
scoped_trace!("Outer trace");
{
scoped_trace!("Inner trace");
panic!("Intentional panic");
}
}
@@ -0,0 +1,17 @@
#!/bin/bash
# fail on error
set -e
# Read binary path from argument
BINARY_PATH="$1"
if [ -z "$BINARY_PATH" ]; then
echo "Usage: $0 <binary_path>"
exit 1
fi
# Run the binary, capture output, and process with sed
# We ignore the failure of the binary as per the original genrule (|| true)
( "${BINARY_PATH}" 2>&1 || true ) | \
sed -n -e '/^Google Test trace:/p' -e '/^ .*trace/p' | \
sed 's#^.*scoped_trace_panic_test.rs# scoped_trace_panic_test.rs#g'
@@ -0,0 +1,46 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(test)]
mod tests {
use googletest::internal::scoped_trace::get_scoped_traces;
use googletest::prelude::*;
#[gtest]
fn test_scoped_trace_non_fatal() -> googletest::Result<()> {
let result = {
scoped_trace!("First trace");
verify_eq!(1, 2)
};
verify_that!(result, err(displays_as(contains_substring("First trace"))))?;
verify_that!(result, err(displays_as(contains_substring("Google Test trace:"))))
}
#[gtest]
fn test_scoped_trace_nesting() {
scoped_trace!("Outer trace");
{
scoped_trace!("Inner trace");
let traces = get_scoped_traces();
assert_eq!(traces.len(), 2);
assert_eq!(traces[0].message, "Outer trace");
assert_eq!(traces[1].message, "Inner trace");
}
let traces = get_scoped_traces();
assert_eq!(traces.len(), 1);
assert_eq!(traces[0].message, "Outer trace");
}
}
@@ -0,0 +1,265 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::matcher::MatcherResult;
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
#[test]
fn empty_matcher_matches_empty_tuple() -> Result<()> {
verify_that!((), ())
}
#[test]
fn empty_matcher_matches_empty_tuple_reference() -> Result<()> {
let a_ok: std::result::Result<(), String> = Ok(()); // Non copy
verify_that!(a_ok, ok(()))
}
#[test]
fn singleton_matcher_matches_matching_singleton_tuple() -> Result<()> {
verify_that!((123,), (eq(123),))
}
#[test]
fn singleton_matcher_does_not_match_non_matching_singleton_tuple() -> Result<()> {
verify_that!((123,), not((eq(456),)))
}
#[test]
fn pair_matcher_matches_matching_pair_tuple() -> Result<()> {
verify_that!((123, 456), (eq(123), eq(456)))
}
#[test]
fn pair_matcher_matches_matching_pair_tuple_with_different_types() -> Result<()> {
verify_that!((123, "A string"), (eq(123), eq("A string")))
}
#[test]
fn pair_matcher_with_trailing_comma_matches_matching_pair_tuple() -> Result<()> {
verify_that!((123, 456), (eq(123), eq(456),))
}
#[test]
fn tuple_matcher_matches_matching_3_tuple() -> Result<()> {
verify_that!((1, 2, 3), (eq(1), eq(2), eq(3)))
}
#[test]
fn tuple_matcher_matches_matching_4_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4), (eq(1), eq(2), eq(3), eq(4)))
}
#[test]
fn tuple_matcher_matches_matching_5_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5), (eq(1), eq(2), eq(3), eq(4), eq(5)))
}
#[test]
fn tuple_matcher_matches_matching_6_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5, 6), (eq(1), eq(2), eq(3), eq(4), eq(5), eq(6)))
}
#[test]
fn tuple_matcher_matches_matching_7_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5, 6, 7), (eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7)))
}
#[test]
fn tuple_matcher_matches_matching_8_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5, 6, 7, 8), (eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8)))
}
#[test]
fn tuple_matcher_matches_matching_9_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9))
)
}
#[test]
fn tuple_matcher_matches_matching_10_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10))
)
}
#[test]
fn tuple_matcher_matches_matching_11_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10), eq(11))
)
}
#[test]
fn tuple_matcher_matches_matching_12_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10), eq(11), eq(12))
)
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_3_tuple() -> Result<()> {
verify_that!((1, 2, 3), (eq(1), eq(2), eq(3),))
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_4_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4), (eq(1), eq(2), eq(3), eq(4),))
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_5_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5), (eq(1), eq(2), eq(3), eq(4), eq(5),))
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_6_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5, 6), (eq(1), eq(2), eq(3), eq(4), eq(5), eq(6),))
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_7_tuple() -> Result<()> {
verify_that!((1, 2, 3, 4, 5, 6, 7), (eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7),))
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_8_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8),)
)
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_9_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9),)
)
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_10_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10),)
)
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_11_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10), eq(11),)
)
}
#[test]
fn tuple_matcher_with_trailing_comma_matches_matching_12_tuple() -> Result<()> {
verify_that!(
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
(eq(1), eq(2), eq(3), eq(4), eq(5), eq(6), eq(7), eq(8), eq(9), eq(10), eq(11), eq(12),)
)
}
#[test]
fn tuple_matcher_1_has_correct_description_for_match() -> Result<()> {
verify_that!(
Matcher::<(i32,)>::describe(&(eq(1),), MatcherResult::Match),
displays_as(eq(indoc!(
"
is a tuple whose values respectively match:
is equal to 1"
)))
)
}
#[test]
fn tuple_matcher_1_has_correct_description_for_mismatch() -> Result<()> {
verify_that!(
Matcher::<(i32,)>::describe(&(eq(1),), MatcherResult::NoMatch),
displays_as(eq(indoc!(
"
is a tuple whose values do not respectively match:
is equal to 1"
)))
)
}
#[test]
fn tuple_matcher_2_has_correct_description_for_match() -> Result<()> {
verify_that!(
Matcher::<(i32, i32)>::describe(&(eq(1), eq(2)), MatcherResult::Match),
displays_as(eq(indoc!(
"
is a tuple whose values respectively match:
is equal to 1
is equal to 2"
)))
)
}
#[test]
fn tuple_matcher_2_has_correct_description_for_mismatch() -> Result<()> {
verify_that!(
Matcher::<(i32, i32)>::describe(&(eq(1), eq(2)), MatcherResult::NoMatch),
displays_as(eq(indoc!(
"
is a tuple whose values do not respectively match:
is equal to 1
is equal to 2"
)))
)
}
#[test]
fn describe_match_shows_which_tuple_element_did_not_match() -> Result<()> {
verify_that!(
(eq(1), eq(2)).explain_match((1, 3)),
displays_as(eq(indoc!(
"
which
is a tuple whose values do not respectively match:
is equal to 1
is equal to 2
Element #1 is 3,
which isn't equal to 2"
)))
)
}
#[test]
fn describe_match_shows_which_two_tuple_elements_did_not_match() -> Result<()> {
verify_that!(
(eq(1), eq(2)).explain_match((2, 3)),
displays_as(eq(indoc!(
"
which
is a tuple whose values do not respectively match:
is equal to 1
is equal to 2
Element #0 is 2,
which isn't equal to 1
Element #1 is 3,
which isn't equal to 2"
)))
)
}
@@ -0,0 +1,466 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use googletest::prelude::*;
use googletest::Result;
use indoc::indoc;
use std::collections::HashMap;
#[test]
fn unordered_elements_are_matches_empty_vector() -> Result<()> {
let value: Vec<u32> = vec![];
verify_that!(value, unordered_elements_are![])
}
#[test]
fn unordered_elements_are_matches_empty_vector_with_trailing_comma() -> Result<()> {
let value: Vec<u32> = vec![];
verify_that!(value, unordered_elements_are![,])
}
#[test]
fn unordered_elements_are_matches_vector() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, unordered_elements_are![eq(&1), eq(&2), eq(&3)])
}
#[test]
fn unordered_elements_are_matches_iterator_returning_by_value() -> Result<()> {
#[derive(Debug, Copy, Clone)]
struct Countdown(i32);
impl Iterator for Countdown {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
0 => None,
x => {
self.0 -= 1;
Some(x)
}
}
}
}
verify_that!(Countdown(3), unordered_elements_are![eq(1), eq(2), eq(3)])
}
#[test]
fn unordered_elements_are_omitted() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, {eq(&3), eq(&2), eq(&1)})
}
#[test]
fn unordered_elements_are_matches_slice() -> Result<()> {
let value = vec![1, 2, 3];
let slice = value.as_slice();
verify_that!(slice, unordered_elements_are![eq(&1), eq(&2), eq(&3)])
}
#[test]
fn unordered_elements_are_matches_hash_map() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
verify_that!(
value,
unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three"))]
)
}
#[test]
fn unordered_elements_are_matches_hash_map_with_trailing_comma() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
verify_that!(
value,
unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")),]
)
}
#[test]
fn unordered_elements_are_does_not_match_hash_map_with_wrong_key() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (4, "Three")]);
verify_that!(
value,
not(unordered_elements_are![
(eq(&2), eq(&"Two")),
(eq(&1), eq(&"One")),
(eq(&3), eq(&"Three"))
])
)
}
#[test]
fn unordered_elements_are_does_not_match_hash_map_with_wrong_value() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Four")]);
verify_that!(
value,
not(unordered_elements_are![
(eq(&2), eq(&"Two")),
(eq(&1), eq(&"One")),
(eq(&3), eq(&"Three"))
])
)
}
#[test]
fn unordered_elements_are_does_not_match_hash_map_missing_element() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
verify_that!(
value,
not(unordered_elements_are![
(eq(&2), eq(&"Two")),
(eq(&1), eq(&"One")),
(eq(&3), eq(&"Three"))
])
)
}
#[test]
fn unordered_elements_are_does_not_match_hash_map_with_extra_element() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
verify_that!(value, not(unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One"))]))
}
#[test]
fn unordered_elements_are_does_not_match_hash_map_with_mismatched_key_and_value() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Three"), (3, "Two")]);
verify_that!(
value,
not(unordered_elements_are![
(eq(&2), eq(&"Two")),
(eq(&1), eq(&"One")),
(eq(&3), eq(&"Three"))
])
)
}
#[test]
fn unordered_elements_are_matches_vector_with_trailing_comma() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, unordered_elements_are![eq(&1), eq(&2), eq(&3),])
}
#[test]
fn unordered_elements_are_matches_size() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, not(unordered_elements_are![eq(&1), eq(&2), eq(&3)]))
}
#[test]
fn unordered_elements_are_admits_matchers_without_static_lifetime() -> Result<()> {
#[derive(Debug, PartialEq)]
struct AStruct(i32);
let expected_value = AStruct(123);
verify_that!(vec![AStruct(123)], unordered_elements_are![eq(&expected_value)])
}
#[test]
fn unordered_elements_are_with_map_admits_matchers_without_static_lifetime() -> Result<()> {
#[derive(Debug, PartialEq)]
struct AStruct(i32);
let expected_value = AStruct(123);
verify_that!(
HashMap::from([(1, AStruct(123))]),
unordered_elements_are![(eq(&1), eq(&expected_value))]
)
}
#[test]
fn unordered_elements_are_description_mismatch() -> Result<()> {
let result = verify_that!(vec![1, 4, 3], unordered_elements_are![eq(&1), eq(&2), eq(&3)]);
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 4, 3]
Expected: contains elements matching in any order:
0. is equal to 1
1. is equal to 2
2. is equal to 3
Actual: [1, 4, 3],
whose element #1 does not match any expected elements and no elements match the expected element #1"
))))
)
}
#[test]
fn unordered_elements_are_matches_unordered() -> Result<()> {
let value = vec![1, 2];
verify_that!(value, unordered_elements_are![eq(&2), eq(&1)])
}
#[test]
fn unordered_elements_are_matches_unordered_with_repetition() -> Result<()> {
let value = vec![1, 2, 1, 2, 1];
verify_that!(value, unordered_elements_are![eq(&1), eq(&1), eq(&1), eq(&2), eq(&2)])
}
#[test]
fn unordered_elements_are_explains_mismatch_due_to_wrong_size() -> Result<()> {
let matcher = unordered_elements_are![eq(&2), eq(&3), eq(&4)];
verify_that!(
matcher.explain_match(&vec![2, 3]),
displays_as(eq("which has size 2 (expected 3)"))
)
}
#[test]
fn unordered_elements_are_description_no_full_match() -> Result<()> {
let matcher = unordered_elements_are![eq(&1), eq(&2), eq(&2)];
verify_that!(
matcher.explain_match(&vec![1, 1, 2]),
displays_as(eq(indoc!(
"
which does not have a perfect match with the expected elements. The best match found was:
Actual element 1 at index 0 matched expected element `is equal to 1` at index 0.
Actual element 2 at index 2 matched expected element `is equal to 2` at index 1.
Actual element 1 at index 1 did not match any remaining expected element.
Expected element `is equal to 2` at index 2 did not match any remaining actual element."
)))
)
}
#[test]
fn unordered_elements_are_unmatchable_expected_description_mismatch() -> Result<()> {
let matcher = unordered_elements_are![eq(&1), eq(&2), eq(&3)];
verify_that!(
matcher.explain_match(&vec![1, 1, 3]),
displays_as(eq("which has no element matching the expected element #1"))
)
}
#[test]
fn unordered_elements_are_unmatchable_actual_description_mismatch() -> Result<()> {
let matcher = unordered_elements_are![eq(&1), eq(&1), eq(&3)];
verify_that!(
matcher.explain_match(&vec![1, 2, 3]),
displays_as(eq("whose element #1 does not match any expected elements"))
)
}
fn create_matcher<'a>() -> impl Matcher<&'a Vec<i32>> {
unordered_elements_are![eq(&1)]
}
#[test]
fn unordered_elements_are_works_when_matcher_is_created_in_subroutine() -> Result<()> {
verify_that!(vec![1], create_matcher())
}
fn create_matcher_for_map<'a>() -> impl Matcher<&'a HashMap<i32, i32>> {
unordered_elements_are![(eq(&1), eq(&1))]
}
#[test]
fn unordered_elements_are_works_when_matcher_for_maps_is_created_in_subroutine() -> Result<()> {
verify_that!(HashMap::from([(1, 1)]), create_matcher_for_map())
}
#[test]
fn contains_each_matches_when_one_to_one_correspondence_present() -> Result<()> {
verify_that!(vec![2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4)))
}
#[test]
fn contains_each_supports_trailing_comma() -> Result<()> {
verify_that!(vec![2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4),))
}
#[test]
fn contains_each_matches_hash_map() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
verify_that!(value, contains_each![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One"))])
}
#[test]
fn contains_each_matches_hash_map_with_trailing_comma() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
verify_that!(value, contains_each![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")),])
}
#[test]
fn contains_each_matches_when_no_matchers_present() -> Result<()> {
verify_that!(vec![2, 3, 4], contains_each!())
}
#[test]
fn contains_each_matches_when_no_matchers_present_and_trailing_comma() -> Result<()> {
verify_that!(vec![2, 3, 4], contains_each!(,))
}
#[test]
fn contains_each_matches_when_list_is_empty_and_no_matchers_present() -> Result<()> {
verify_that!(Vec::<u32>::new(), contains_each!())
}
#[test]
fn contains_each_matches_when_excess_elements_present() -> Result<()> {
verify_that!(vec![1, 2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4)))
}
#[test]
fn contains_each_does_not_match_when_matchers_are_unmatched() -> Result<()> {
verify_that!(vec![1, 2, 3], not(contains_each!(eq(&2), eq(&3), eq(&4))))
}
#[test]
fn contains_each_explains_mismatch_due_to_wrong_size() -> Result<()> {
let matcher = contains_each![eq(&2), eq(&3), eq(&4)];
verify_that!(
matcher.explain_match(&vec![2, 3]),
displays_as(eq("which has size 2 (expected at least 3)"))
)
}
#[test]
fn contains_each_explains_missing_element_in_mismatch() -> Result<()> {
let matcher = contains_each![eq(&2), eq(&3), eq(&4)];
verify_that!(
matcher.explain_match(&vec![1, 2, 3]),
displays_as(eq("which has no element matching the expected element #2"))
)
}
#[test]
fn contains_each_explains_missing_elements_in_mismatch() -> Result<()> {
let matcher = contains_each![eq(&2), eq(&3), eq(&4), eq(&5)];
verify_that!(
matcher.explain_match(&vec![0, 1, 2, 3]),
displays_as(eq("which has no elements matching the expected elements #2, #3"))
)
}
#[test]
fn contains_each_explains_mismatch_due_to_no_graph_matching_found() -> Result<()> {
let matcher = contains_each![ge(&2), ge(&2)];
verify_that!(
matcher .explain_match(&vec![1, 2]),
displays_as(eq(indoc!(
"
which does not have a superset match with the expected elements. The best match found was:
Actual element 2 at index 1 matched expected element `is greater than or equal to 2` at index 0.
Actual element 1 at index 0 did not match any remaining expected element.
Expected element `is greater than or equal to 2` at index 1 did not match any remaining actual element."))
))
}
#[test]
fn is_contained_in_matches_with_empty_vector() -> Result<()> {
let value: Vec<u32> = vec![];
verify_that!(value, is_contained_in!())
}
#[test]
fn is_contained_in_matches_with_empty_vector_and_trailing_comma() -> Result<()> {
let value: Vec<u32> = vec![];
verify_that!(value, is_contained_in!(,))
}
#[test]
fn is_contained_in_matches_when_one_to_one_correspondence_present() -> Result<()> {
verify_that!(vec![2, 3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4)))
}
#[test]
fn is_contained_supports_trailing_comma() -> Result<()> {
verify_that!(vec![2, 3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4),))
}
#[test]
fn is_contained_in_matches_hash_map() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
verify_that!(
value,
is_contained_in![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three"))]
)
}
#[test]
fn is_contained_in_matches_hash_map_with_trailing_comma() -> Result<()> {
let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
verify_that!(
value,
is_contained_in![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")),]
)
}
#[test]
fn is_contained_in_matches_when_container_is_empty() -> Result<()> {
verify_that!(vec![1; 0], is_contained_in!(eq(&2), eq(&3), eq(&4)))
}
#[test]
fn is_contained_in_matches_when_excess_matchers_present() -> Result<()> {
verify_that!(vec![3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4)))
}
#[test]
fn is_contained_in_does_not_match_when_elements_are_unmatched() -> Result<()> {
verify_that!(vec![1, 2, 3], not(is_contained_in!(eq(&2), eq(&3), eq(&4))))
}
#[test]
fn is_contained_in_explains_mismatch_due_to_wrong_size() -> Result<()> {
let matcher = is_contained_in![eq(&2), eq(&3)];
verify_that!(
matcher.explain_match(&vec![2, 3, 4]),
displays_as(eq("which has size 3 (expected at most 2)"))
)
}
#[test]
fn is_contained_in_explains_missing_element_in_mismatch() -> Result<()> {
let matcher = is_contained_in![eq(&2), eq(&3), eq(&4)];
verify_that!(
matcher.explain_match(&vec![1, 2, 3]),
displays_as(eq("whose element #0 does not match any expected elements"))
)
}
#[test]
fn is_contained_in_explains_missing_elements_in_mismatch() -> Result<()> {
let matcher = is_contained_in![eq(&2), eq(&3), eq(&4), eq(&5)];
verify_that!(
matcher.explain_match(&vec![0, 1, 2, 3]),
displays_as(eq("whose elements #0, #1 do not match any expected elements"))
)
}
#[test]
fn is_contained_in_explains_mismatch_due_to_no_graph_matching_found() -> Result<()> {
let matcher = is_contained_in![ge(&1), ge(&3)];
verify_that!(
matcher.explain_match(&vec![1, 2]),
displays_as(eq(indoc!(
"
which does not have a subset match with the expected elements. The best match found was:
Actual element 1 at index 0 matched expected element `is greater than or equal to 1` at index 0.
Actual element 2 at index 1 did not match any remaining expected element.
Expected element `is greater than or equal to 3` at index 1 did not match any remaining actual element."))
))
}
#[test]
fn unordered_elements_are_with_auto_eq() -> Result<()> {
verify_that!(vec![3, 4, 2], unordered_elements_are![&2, &3, &4])
}
#[test]
fn contains_each_with_auto_eq() -> Result<()> {
verify_that!(vec![3, 4, 2], contains_each![&2, &4])
}
#[test]
fn is_contained_in_with_auto_eq() -> Result<()> {
verify_that!(vec![3, 4, 2], is_contained_in![&1, &2, &3, &4])
}