build(rust): vendor googletest crate
This commit was merged in pull request #76.
This commit is contained in:
1 parent
a6fe84190e
commit
6887b104d6
576 files changed
+284290
-2
No files matched your search
+333
@@ -0,0 +1,333 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//! The components required to implement matchers.
|
||||
|
||||
use crate::description::Description;
|
||||
use crate::internal::test_outcome::TestAssertionFailure;
|
||||
use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
|
||||
use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
|
||||
pub use googletest_macro::MatcherBase;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// An interface for checking an arbitrary condition on a datum.
|
||||
///
|
||||
/// This trait is automatically implemented for a reference of any type
|
||||
/// implementing `Matcher`. This simplifies reusing a matcher in different
|
||||
/// assertions.
|
||||
///
|
||||
/// It is also implemented for tuple of `Matcher`. If `MatcherT: Matcher<T>` and
|
||||
/// `MatcherU: Matcher<U>`, then `(MatcherT, MatcherU): Matcher<(T, U)>`, and so
|
||||
/// on, up to 12 elements. Tuples longer than that do not automatically inherit
|
||||
/// the `Debug` trait from their members, so are generally not well-supported;
|
||||
/// see [Rust by Example](https://doc.rust-lang.org/rust-by-example/primitives/tuples.html#tuples).
|
||||
// `ActualT` requires `Copy` so that `actual` could be passed to `matches` and
|
||||
// if it fails passed to `explain_match`. We can relax this constraint later by
|
||||
// requiring only `Clone`.
|
||||
pub trait Matcher<ActualT: Debug + Copy>: MatcherBase {
|
||||
/// Returns whether the condition matches the datum `actual`.
|
||||
///
|
||||
/// The trait implementation defines what it means to "match". Often the
|
||||
/// matching condition is based on data stored in the matcher. For example,
|
||||
/// `eq` matches when its stored expected value is equal (in the sense of
|
||||
/// the `==` operator) to the value `actual`.
|
||||
fn matches(&self, actual: ActualT) -> MatcherResult;
|
||||
|
||||
/// Returns a description of `self` according to the supplied matching
|
||||
/// sense: a positive description if `sense` is `Match`, and a negative
|
||||
/// description if it's `NoMatch`.
|
||||
///
|
||||
/// The function should print a verb phrase that describes the property a
|
||||
/// value matching, respectively not matching, this matcher should have.
|
||||
/// The subject of the verb phrase is the value being matched.
|
||||
///
|
||||
/// The output appears next to `Expected` in an assertion failure message.
|
||||
/// For example:
|
||||
///
|
||||
/// ```text
|
||||
/// Value of: ...
|
||||
/// Expected: is equal to 7
|
||||
/// ^^^^^^^^^^^^^
|
||||
/// Actual: ...
|
||||
/// ```
|
||||
///
|
||||
/// When the matcher contains one or more inner matchers, the implementation
|
||||
/// should invoke [`Self::describe`] on the inner matchers to complete the
|
||||
/// description. It should place the inner description at a point where a
|
||||
/// verb phrase would fit. For example, the matcher
|
||||
/// [`some`][crate::matchers::some] implements `describe` as follows:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn describe(&self, sense: MatcherResult) -> Description {
|
||||
/// match sense {
|
||||
/// MatcherResult::Match => {
|
||||
/// Description::new()
|
||||
/// .text("has a value which")
|
||||
/// .nested(self.inner.describe(MatcherResult::Match))
|
||||
/// // Inner matcher: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// }
|
||||
/// MatcherResult::NoMatch => {
|
||||
/// Description::new()
|
||||
/// .text("is None or has a value which")
|
||||
/// .nested(self.inner.describe(MatcherResult::NoMatch))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The output expectation differs from that of
|
||||
/// [`explain_match`][Self::explain_match] in that it is a verb phrase
|
||||
/// (beginning with a verb like "is") rather than a relative clause
|
||||
/// (beginning with "which" or "whose"). This difference is because the
|
||||
/// output of `explain_match` is always used adjectivally to describe the
|
||||
/// actual value, while `describe` is used in contexts where a relative
|
||||
/// clause would not make sense.
|
||||
fn describe(&self, sense: MatcherResult) -> Description;
|
||||
|
||||
/// Prepares a [`String`] describing how the expected value
|
||||
/// encoded in this instance matches or does not match the given value
|
||||
/// `actual`.
|
||||
///
|
||||
/// This should be in the form of a relative clause, i.e. something starting
|
||||
/// with a relative pronoun such as "which" or "whose". It will appear next
|
||||
/// to the actual value in an assertion failure. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// Value of: ...
|
||||
/// Expected: ...
|
||||
/// Actual: ["Something"], which does not contain "Something else"
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation relies on [`describe`][Self::describe]. Thus
|
||||
/// it does not make any use of the actual value itself, but rather only
|
||||
/// whether the value is matched.
|
||||
///
|
||||
/// Override the default implementation to provide additional context on why
|
||||
/// a particular value matched or did not match. For example, the
|
||||
/// [`container_eq`][crate::matchers::container_eq] matcher displays
|
||||
/// information on which elements of the actual value were not present in
|
||||
/// the expected value and vice versa.
|
||||
///
|
||||
/// This implementation should be overridden in any matcher which contains
|
||||
/// one or more inner matchers. The implementation should invoke
|
||||
/// `explain_match` on the inner matchers, so that the generated match
|
||||
/// explanation also reflects their implementation. Without this, the match
|
||||
/// explanation of the inner matchers will not be able to make use of the
|
||||
/// actual value at all.
|
||||
///
|
||||
/// For example, the `explain_match` implementation of the matcher
|
||||
/// [`points_to`][crate::matchers::points_to] defers immediately to the
|
||||
/// inner matcher and appears as follows:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn explain_match(&self, actual: &ActualT) -> Description {
|
||||
/// self.expected.explain_match(*actual)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The matcher can also provide some additional context before deferring to
|
||||
/// an inner matcher. In that case it should invoke `explain_match` on the
|
||||
/// inner matcher at a point where a relative clause would fit. For example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn explain_match(&self, actual: ActualT) -> Description {
|
||||
/// Description::new()
|
||||
/// .text("which points to a value")
|
||||
/// .nested(self.expected.explain_match(*actual))
|
||||
/// }
|
||||
/// ```
|
||||
fn explain_match(&self, actual: ActualT) -> Description {
|
||||
format!("which {}", self.describe(self.matches(actual))).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Base trait for matchers. Any type implementing `Matcher` must implement
|
||||
/// `MatcherBase`, but that should be done through the `#[derive(MatcherBase)]`
|
||||
/// macro.
|
||||
// The `and` and `or` functions cannot be part of the `Matcher` trait since it
|
||||
// can be implemented multiple times for a given matcher type. Consider that
|
||||
// `and` and `or` are part of the `Matcher` trait and `MyMatcher` implements
|
||||
// both `Matcher<A>` and `Matcher<B>`. Then `MyMatcher{...}.and(...)` can be
|
||||
// either:
|
||||
// * `Matcher::<A>::and(MyMatcher{...}, ...)` or
|
||||
// * `Matcher::<B>::and(MyMatcher{...}, ...)`.
|
||||
// Moving the `and` and `or` functions in a non-generic trait removes this
|
||||
// confusion by making `and` and `or` unique for a given type.
|
||||
pub trait MatcherBase {
|
||||
/// Constructs a matcher that matches both `self` and `right`.
|
||||
///
|
||||
/// ```
|
||||
/// # use googletest::prelude::*;
|
||||
/// # fn should_pass() -> Result<()> {
|
||||
/// verify_that!("A string", starts_with("A").and(ends_with("string")))?; // Passes
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # fn should_fail_1() -> Result<()> {
|
||||
/// verify_that!("A string", starts_with("Another").and(ends_with("string")))?; // Fails
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # fn should_fail_2() -> Result<()> {
|
||||
/// verify_that!("A string", starts_with("A").and(ends_with("non-string")))?; // Fails
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # should_pass().unwrap();
|
||||
/// # should_fail_1().unwrap_err();
|
||||
/// # should_fail_2().unwrap_err();
|
||||
/// ```
|
||||
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
|
||||
// visibility of ConjunctionMatcher once impl in return position in trait
|
||||
// methods is stable.
|
||||
fn and<Right>(self, right: Right) -> ConjunctionMatcher<Self, Right>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
ConjunctionMatcher::new(self, right)
|
||||
}
|
||||
|
||||
/// Constructs a matcher that matches when at least one of `self` or `right`
|
||||
/// matches the input.
|
||||
///
|
||||
/// ```
|
||||
/// # use googletest::prelude::*;
|
||||
/// # fn should_pass() -> Result<()> {
|
||||
/// verify_that!(10, eq(2).or(ge(5)))?; // Passes
|
||||
/// verify_that!(10, eq(2).or(eq(5)).or(ge(9)))?; // Passes
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # fn should_fail() -> Result<()> {
|
||||
/// verify_that!(10, eq(2).or(ge(15)))?; // Fails
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # should_pass().unwrap();
|
||||
/// # should_fail().unwrap_err();
|
||||
/// ```
|
||||
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
|
||||
// visibility of DisjunctionMatcher once impl in return position in trait
|
||||
// methods is stable.
|
||||
fn or<Right>(self, right: Right) -> DisjunctionMatcher<Self, Right>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
DisjunctionMatcher::new(self, right)
|
||||
}
|
||||
}
|
||||
|
||||
/// Any actual value whose debug length is greater than this value will be
|
||||
/// pretty-printed. Otherwise, it will have normal debug output formatting.
|
||||
const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
|
||||
|
||||
/// Constructs a [`TestAssertionFailure`] reporting that the given `matcher`
|
||||
/// does not match the value `actual`.
|
||||
///
|
||||
/// The parameter `actual_expr` contains the expression which was evaluated to
|
||||
/// obtain `actual`.
|
||||
#[track_caller]
|
||||
pub(crate) fn create_assertion_failure<T: Debug + Copy>(
|
||||
matcher: &impl Matcher<T>,
|
||||
actual: T,
|
||||
actual_expr: &'static str,
|
||||
) -> TestAssertionFailure {
|
||||
let actual_formatted = format!("{actual:?}");
|
||||
let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
|
||||
format!("{actual:#?}")
|
||||
} else {
|
||||
actual_formatted
|
||||
};
|
||||
TestAssertionFailure::create(format!(
|
||||
"\
|
||||
Value of: {actual_expr}
|
||||
Expected: {}
|
||||
Actual: {actual_formatted},
|
||||
{}",
|
||||
matcher.describe(MatcherResult::Match),
|
||||
matcher.explain_match(actual).indent(),
|
||||
))
|
||||
}
|
||||
|
||||
/// The result of applying a [`Matcher`] on an actual value.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum MatcherResult {
|
||||
/// The actual value matches according to the [`Matcher`] definition.
|
||||
Match,
|
||||
/// The actual value does not match according to the [`Matcher`] definition.
|
||||
NoMatch,
|
||||
}
|
||||
|
||||
impl From<bool> for MatcherResult {
|
||||
fn from(b: bool) -> Self {
|
||||
if b {
|
||||
MatcherResult::Match
|
||||
} else {
|
||||
MatcherResult::NoMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MatcherResult> for bool {
|
||||
fn from(matcher_result: MatcherResult) -> Self {
|
||||
matcher_result.is_match()
|
||||
}
|
||||
}
|
||||
|
||||
impl MatcherResult {
|
||||
/// Returns `true` if `self` is [`MatcherResult::Match`], otherwise
|
||||
/// `false`.
|
||||
pub fn is_match(self) -> bool {
|
||||
matches!(self, MatcherResult::Match)
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is [`MatcherResult::NoMatch`], otherwise
|
||||
/// `false`.
|
||||
pub fn is_no_match(self) -> bool {
|
||||
matches!(self, MatcherResult::NoMatch)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: ?Sized + MatcherBase> MatcherBase for &M {}
|
||||
|
||||
impl<T: Debug + Copy, M: Matcher<T>> Matcher<T> for &M {
|
||||
fn matches(&self, actual: T) -> MatcherResult {
|
||||
(*self).matches(actual)
|
||||
}
|
||||
|
||||
fn describe(&self, matcher_result: MatcherResult) -> Description {
|
||||
(*self).describe(matcher_result)
|
||||
}
|
||||
|
||||
fn explain_match(&self, actual: T) -> Description {
|
||||
(*self).explain_match(actual)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::prelude::*;
|
||||
use crate::Result;
|
||||
|
||||
#[test]
|
||||
fn ref_matchers_can_be_reused() -> Result<()> {
|
||||
let matcher = eq(1);
|
||||
|
||||
verify_that!(1, &matcher)?;
|
||||
verify_that!(1, &matcher)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ref_matchers_as_inner_matcher() -> Result<()> {
|
||||
let matcher = gt(1);
|
||||
|
||||
verify_that!([2, 3, 4, 5], [&matcher, &matcher, &matcher, &matcher])
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user