| #ifndef GOOGLE_PROTOBUF_CONFORMANCE_TESTEE_H__ | 
 | #define GOOGLE_PROTOBUF_CONFORMANCE_TESTEE_H__ | 
 |  | 
 | #include <string> | 
 | #include <utility> | 
 |  | 
 | #include "absl/container/flat_hash_set.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "binary_wireformat.h" | 
 | #include "conformance/conformance.pb.h" | 
 | #include "test_runner.h" | 
 | #include "google/protobuf/descriptor.h" | 
 |  | 
 | // This file defines the APIs used by conformance tests to interact with | 
 | // testees.  The structure of these APIs are intentionally decoupled from the | 
 | // runner/testee protocol (which are used to implement them), in order to | 
 | // maximize their flexibility in tests. | 
 | // | 
 | // Tests should not ever need to name any of these types directly, but will | 
 | // obtain a Test object pointing to the global testee and pass the final | 
 | // TestResult to one of our matchers. | 
 | // | 
 | // Example: | 
 | // | 
 | // EXPECT_THAT(RequiredTest() | 
 | //                .ParseBinary(Wire(LengthPrefixedField(1, "foo")) | 
 | //                .SerializeText({.print_unknown_fields = true}), | 
 | //             ParsedPayload(EqualsProto("pb(1: "foo")pb"))); | 
 |  | 
 | // TODO Possible future APIs to expand conformance coverage: | 
 | // - Add ClearUnknownFields() to InMemoryMessage | 
 | // - Add MergeFrom() method to InMemoryMessage to merge raw binary | 
 | // - Remove && qualifiers on Parse* and add InMemoryMessage::Merge that merges | 
 | //   two parsed messages | 
 | // - Add ConstructEmpty methods on Test | 
 | // - Add reflection methods to InMemoryMessage (e.g. Get/Set/Add, and a Has that | 
 | //   returns TestResult) | 
 | // - Add a SerializeIntoMemory method that allows further action on the results | 
 | //   of serialization instead of immediately returning it | 
 | namespace google { | 
 | namespace protobuf { | 
 | namespace conformance { | 
 | namespace internal { | 
 |  | 
 | // The strictness of a test.  Required tests will fail the test suite if they | 
 | // fail.  Recommended tests will not fail the test suite if they fail, but will | 
 | // be reported as a warning. | 
 | enum class TestStrictness { | 
 |   kRequired = 0, | 
 |   kRecommended = 1, | 
 | }; | 
 |  | 
 | // The final result of a conformance test, to be processed by a matcher. | 
 | class TestResult { | 
 |  public: | 
 |   // The name of the test that was run, useful for failure matching and | 
 |   // reporting. | 
 |   absl::string_view name() const { return test_name_; } | 
 |  | 
 |   // The strictness of the test. | 
 |   TestStrictness strictness() const { return strictness_; } | 
 |  | 
 |   // The type of the message that was tested, needed for parsing. | 
 |   const Descriptor* type() const { return type_; } | 
 |  | 
 |   // The format of the output that was requested. | 
 |   ::conformance::WireFormat format() const { return format_; } | 
 |  | 
 |   // The conformance response that was returned from the testee.  This will | 
 |   // contain either the resulting payload or an error message. | 
 |   const ::conformance::ConformanceResponse& response() const { | 
 |     return response_; | 
 |   } | 
 |  | 
 |  private: | 
 |   TestResult(absl::string_view test_name, TestStrictness strictness, | 
 |              const Descriptor* type, ::conformance::WireFormat format, | 
 |              ::conformance::ConformanceResponse response) | 
 |       : test_name_(test_name), | 
 |         strictness_(strictness), | 
 |         type_(type), | 
 |         format_(format), | 
 |         response_(std::move(response)) {} | 
 |   friend class InMemoryMessage; | 
 |  | 
 |   std::string test_name_; | 
 |   TestStrictness strictness_; | 
 |   const Descriptor* type_; | 
 |   ::conformance::WireFormat format_; | 
 |   ::conformance::ConformanceResponse response_; | 
 | }; | 
 |  | 
 | // Options for serializing text format. | 
 | struct TextSerializationOptions { | 
 |   bool print_unknown_fields = false; | 
 | }; | 
 |  | 
 | // This class represents a message held in memory by the testee that can be | 
 | // manipulated in various ways. | 
 | class InMemoryMessage { | 
 |  public: | 
 |   ~InMemoryMessage() = default; | 
 |  | 
 |   // Serialize the message back in any of our supported formats.  These all | 
 |   // consume the message. | 
 |   TestResult SerializeBinary() &&; | 
 |   TestResult SerializeText(TextSerializationOptions options = {}) &&; | 
 |   TestResult SerializeJson() &&; | 
 |  | 
 |  private: | 
 |   InMemoryMessage(class Testee* testee, absl::string_view name, | 
 |                   TestStrictness strictness, const Descriptor* type, | 
 |                   ::conformance::ConformanceRequest request) | 
 |       : testee_(testee), | 
 |         name_(name), | 
 |         strictness_(strictness), | 
 |         type_(type), | 
 |         request_(std::move(request)) {} | 
 |   friend class Test; | 
 |  | 
 |   TestResult SerializeImpl(::conformance::WireFormat format); | 
 |  | 
 |   class Testee* testee_; | 
 |   std::string name_; | 
 |   TestStrictness strictness_; | 
 |   const Descriptor* type_; | 
 |   ::conformance::ConformanceRequest request_; | 
 | }; | 
 |  | 
 | // Options for parsing JSON. | 
 | struct JsonParseOptions { | 
 |   bool ignore_unknown_fields = false; | 
 | }; | 
 |  | 
 | // This class represents a single test case representing some interaction with | 
 | // the testee.  The end result of a test should be a single TestResult. | 
 | class Test { | 
 |  public: | 
 |   ~Test() = default; | 
 |  | 
 |   // Parse the message from one of our supported formats into an in-memory | 
 |   // message for further processing. | 
 |   InMemoryMessage ParseBinary(const Descriptor* type, Wire input) &&; | 
 |   InMemoryMessage ParseText(const Descriptor* type, absl::string_view input) &&; | 
 |   InMemoryMessage ParseJson(const Descriptor* type, absl::string_view input, | 
 |                             JsonParseOptions options = {}) &&; | 
 |  | 
 |  private: | 
 |   Test(class Testee* testee, absl::string_view name, TestStrictness strictness) | 
 |       : testee_(testee), name_(name), strictness_(strictness) {} | 
 |   friend class Testee; | 
 |  | 
 |   class Testee* testee_; | 
 |   std::string name_; | 
 |   TestStrictness strictness_; | 
 | }; | 
 |  | 
 | // This class represents an abstraction of the testee.  It is used to | 
 | // create Test objects that can be used to interact further for testing. | 
 | class Testee { | 
 |  public: | 
 |   explicit Testee(ConformanceTestRunner* runner) : runner_(runner) {} | 
 |  | 
 |   Test CreateTest(absl::string_view name, TestStrictness strictness) { | 
 |     return Test(this, name, strictness); | 
 |   } | 
 |  | 
 |  private: | 
 |   ::conformance::ConformanceResponse Run( | 
 |       absl::string_view test_name, | 
 |       const ::conformance::ConformanceRequest& request); | 
 |   friend class InMemoryMessage; | 
 |  | 
 |   ConformanceTestRunner* runner_; | 
 |  | 
 |   absl::flat_hash_set<std::string> test_names_ran_; | 
 | }; | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace conformance | 
 | }  // namespace protobuf | 
 | }  // namespace google | 
 |  | 
 | #endif  // GOOGLE_PROTOBUF_CONFORMANCE_TESTEE_H__ |