| // Protocol Buffers - Google's data interchange format |
| // Copyright 2026 Google LLC. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd |
| |
| // gMock matchers for conformance TestResults. |
| // |
| // Every conformance test ends in one EXPECT_THAT. Its matcher is Yields() |
| // wrapped around one of the leaf matchers defined here: |
| // |
| // EXPECT_THAT( |
| // Testee() |
| // .ParseBinary(TestAllTypesProto2::descriptor(), input) |
| // .SerializeBinary(), |
| // Yields(WhenParsed(EqualsTextProto(R"pb(optional_int32: 1)pb")))); |
| // |
| // The leaf matchers (WhenParsed, RawPayload, IsParseError, ...) only look at |
| // the TestResult, so they compose with other gMock matchers: |
| // Yields(AnyOf(IsParseError(), WhenParsed(m))) works as expected. |
| // EqualsTextProto() and EqualsBinaryProto() match a `const Message&` and are |
| // meant to be used inside WhenParsed(). |
| // |
| // Yields() is the one matcher that talks to the global ResultLedger. It |
| // records the outcome of the test and turns the failure list into the gtest |
| // verdict: |
| // |
| // - A failure that is in the failure list passes. A listed test that |
| // succeeds fails. |
| // - A failure of a test above the enforcement level is tolerated unless |
| // the test is listed. kP0 failures always count (see TestPriority). |
| // - A test the testee skipped passes unless it is listed. The ResultLedger |
| // counts it in ListedSkips(). |
| // |
| // The failure messages of the leaf matchers end up in failure lists, so each |
| // matcher documents its message and keeps it stable. Messages that come from |
| // an inner matcher use gMock's wording, which can change between versions. |
| // Failure list entries for those should only use a prefix of the message (see |
| // ResultLedger::ReportFailure()). |
| // |
| // This file also defines PrintTo() for TestResult, which gtest uses to print a |
| // result when a matcher on it fails. |
| |
| #ifndef GOOGLE_PROTOBUF_CONFORMANCE_MATCHERS_H__ |
| #define GOOGLE_PROTOBUF_CONFORMANCE_MATCHERS_H__ |
| |
| #include <ostream> |
| #include <utility> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include "absl/base/nullability.h" |
| #include "absl/strings/string_view.h" |
| #include "conformance/binary_wireformat.h" |
| #include "conformance/testee.h" |
| #include "google/protobuf/descriptor.h" |
| #include "google/protobuf/message.h" |
| |
| namespace google { |
| namespace protobuf { |
| namespace conformance { |
| namespace internal { |
| |
| // Prints a TestResult in gtest failure output. The output has the test's |
| // priority and name and a short form of the response. Long payloads are |
| // truncated. Binary payloads are also decoded as the test's message type. |
| // Declared in TestResult's namespace so that gtest finds it through ADL. It |
| // lives with the matchers because their failures are where results get |
| // printed. |
| void PrintTo(const TestResult& result, std::ostream* absl_nonnull os); |
| |
| // Implements WhenParsed() and WhenParsedAs() below. The payload is |
| // decoded as `type_override` if it is non-null, and as the test's message type |
| // otherwise. |
| testing::Matcher<const TestResult&> MakeWhenParsedMatcher( |
| testing::Matcher<const Message&> m, |
| const Descriptor* absl_nullable type_override = nullptr); |
| |
| // Implements Yields(): see the function below for the semantics. |
| testing::Matcher<const TestResult&> MakeYieldsMatcher( |
| testing::Matcher<const TestResult&> inner); |
| |
| } // namespace internal |
| |
| // Matches a result whose payload, decoded as the test's message type, matches |
| // `m`. The payload is decoded from binary or text output. `m` is any matcher |
| // on `const Message&`, usually EqualsTextProto() or EqualsBinaryProto(). |
| // |
| // EXPECT_THAT( |
| // Testee().ParseBinary(type, input).SerializeBinary(), |
| // Yields(WhenParsed(EqualsTextProto(R"pb(optional_int32: 1)pb")))); |
| // |
| // A payload that can't be decoded fails with "<format> output we received |
| // from test was unparseable." Otherwise the failure message comes from `m`. |
| // JSON output can't be decoded yet (b/410122158) and fails with a message |
| // saying so. Use RawPayload() for it. |
| template <typename M> |
| testing::Matcher<const internal::TestResult&> WhenParsed(M m) { |
| return internal::MakeWhenParsedMatcher( |
| testing::SafeMatcherCast<const Message&>(std::move(m))); |
| } |
| |
| // Like WhenParsed(), but decodes the payload as the generated type `T` |
| // instead of the message type the test was run against. Use it when the |
| // testee serializes unknown fields that a richer "shadow" type such as |
| // UnknownToTestAllTypes can decode: |
| // |
| // EXPECT_THAT(Testee("Foo").ParseBinary(type, input).SerializeBinary(), |
| // Yields(WhenParsedAs<UnknownToTestAllTypes>( |
| // EqualsBinaryProto(input)))); |
| // |
| // Failure messages are the same as WhenParsed()'s. |
| template <typename T, typename M> |
| testing::Matcher<const internal::TestResult&> WhenParsedAs(M m) { |
| return internal::MakeWhenParsedMatcher( |
| testing::SafeMatcherCast<const Message&>(std::move(m)), T::descriptor()); |
| } |
| |
| // Matches a result whose raw payload is exactly `bytes`, whatever the output |
| // format. |
| // |
| // EXPECT_THAT(Testee().ParseBinary(type, input).SerializeBinary(), |
| // Yields(RawPayload(input))); |
| // |
| // A mismatch fails with "Output was not equivalent to reference message: |
| // Expect: <octal>, but got: <octal>". A response that isn't a payload of the |
| // requested format fails with a fixed message for that case. That covers no |
| // result, an error, a skipped test and the wrong output format. A PROTOBUF |
| // payload must also be parseable as the test's message type. Otherwise it |
| // fails with "Protobuf output we received from test was unparseable." |
| testing::Matcher<const internal::TestResult&> RawPayload(Wire bytes); |
| |
| // Matches a message equivalent to `text`, parsed as the actual message's type. |
| // Messages are compared with MessageDifferencer, with NaN equal to NaN. |
| // |
| // EXPECT_THAT( |
| // Testee().ParseBinary(type, input).SerializeBinary(), |
| // Yields(WhenParsed(EqualsTextProto(R"pb(optional_int32: 1)pb")))); |
| testing::Matcher<const Message&> EqualsTextProto(absl::string_view text); |
| |
| // Like EqualsTextProto(), but the expected message is the binary serialization |
| // `bytes`. It takes a Wire rather than a string so that NUL bytes survive. |
| // Messages are compared with MessageDifferencer, with NaN equal to NaN. |
| // |
| // EXPECT_THAT(Testee().ParseBinary(type, input).SerializeBinary(), |
| // Yields(WhenParsed(EqualsBinaryProto(VarintField(1, 1))))); |
| testing::Matcher<const Message&> EqualsBinaryProto(Wire bytes); |
| |
| // TODO: b/410122158 - Add JSON matchers once JSON support is migrated. |
| |
| // Matches a response that reports a parse error. |
| // |
| // EXPECT_THAT(Testee().ParseBinary(type, Wire("\x08")).SerializeBinary(), |
| // Yields(IsParseError())); |
| // |
| // Any other response fails with "Should have failed to parse, but didn't." A |
| // runtime error fails with "Should have failed to parse, but raised an error |
| // instead." |
| testing::Matcher<const internal::TestResult&> IsParseError(); |
| |
| // Matches a response that reports a serialize error. |
| // |
| // EXPECT_THAT(Testee().ParseBinary(type, input).SerializeJson(), |
| // Yields(IsSerializeError())); |
| // |
| // Any other response fails like it does for IsParseError(), with the |
| // corresponding "Should have failed to serialize, ..." messages. |
| testing::Matcher<const internal::TestResult&> IsSerializeError(); |
| |
| // Wraps the matcher of every conformance test's EXPECT_THAT. |
| // |
| // EXPECT_THAT(Testee().ParseBinary(type, input).SerializeBinary(), |
| // Yields(WhenParsed(EqualsBinaryProto(input)))); |
| // |
| // Yields() evaluates `inner` against the TestResult, reports the outcome to |
| // the global ResultLedger and applies the failure list and priority rules |
| // described at the top of this file. Its verdict is not simply `inner`'s: an |
| // expected failure passes and an unexpected success fails. Do not wrap |
| // Yields() in Not() or other combinators. Compose `inner` instead. |
| // |
| // Each test may be checked exactly once. The first evaluation reports the |
| // result to the ResultLedger, which remembers the test's name. gtest |
| // evaluates a failing matcher a second time to explain the failure; Yields() |
| // replays its own failed verdict for that. Any other check of a result the |
| // ResultLedger has already heard about fails with "already checked". |
| template <typename M> |
| testing::Matcher<const internal::TestResult&> Yields(M inner) { |
| return internal::MakeYieldsMatcher( |
| testing::SafeMatcherCast<const internal::TestResult&>(std::move(inner))); |
| } |
| |
| } // namespace conformance |
| } // namespace protobuf |
| } // namespace google |
| |
| #endif // GOOGLE_PROTOBUF_CONFORMANCE_MATCHERS_H__ |