|  | #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__ |