• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 
32 // This file defines a protocol for running the conformance test suite
33 // in-process.  In other words, the suite itself will run in the same process as
34 // the code under test.
35 //
36 // For pros and cons of this approach, please see conformance.proto.
37 
38 #ifndef CONFORMANCE_CONFORMANCE_TEST_H
39 #define CONFORMANCE_CONFORMANCE_TEST_H
40 
41 #include <functional>
42 #include <string>
43 
44 #include <google/protobuf/descriptor.h>
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/util/type_resolver.h>
47 #include <google/protobuf/wire_format_lite.h>
48 
49 #include "conformance.pb.h"
50 
51 namespace conformance {
52 class ConformanceRequest;
53 class ConformanceResponse;
54 }  // namespace conformance
55 
56 namespace protobuf_test_messages {
57 namespace proto3 {
58 class TestAllTypesProto3;
59 }  // namespace proto3
60 }  // namespace protobuf_test_messages
61 
62 namespace google {
63 namespace protobuf {
64 
65 class ConformanceTestSuite;
66 
67 class ConformanceTestRunner {
68  public:
~ConformanceTestRunner()69   virtual ~ConformanceTestRunner() {}
70 
71   // Call to run a single conformance test.
72   //
73   // "input" is a serialized conformance.ConformanceRequest.
74   // "output" should be set to a serialized conformance.ConformanceResponse.
75   //
76   // If there is any error in running the test itself, set "runtime_error" in
77   // the response.
78   virtual void RunTest(const std::string& test_name,
79                        const std::string& input,
80                        std::string* output) = 0;
81 };
82 
83 // Test runner that spawns the process being tested and communicates with it
84 // over a pipe.
85 class ForkPipeRunner : public ConformanceTestRunner {
86  public:
87   // Note: Run() doesn't take ownership of the pointers inside suites.
88   static int Run(int argc, char *argv[],
89                  const std::vector<ConformanceTestSuite*>& suites);
90 
ForkPipeRunner(const std::string & executable)91   ForkPipeRunner(const std::string &executable)
92       : child_pid_(-1), executable_(executable) {}
93 
~ForkPipeRunner()94   virtual ~ForkPipeRunner() {}
95 
96   void RunTest(const std::string& test_name,
97                const std::string& request,
98                std::string* response);
99 
100  private:
101   void SpawnTestProgram();
102 
103   void CheckedWrite(int fd, const void *buf, size_t len);
104   bool TryRead(int fd, void *buf, size_t len);
105   void CheckedRead(int fd, void *buf, size_t len);
106 
107   int write_fd_;
108   int read_fd_;
109   pid_t child_pid_;
110   std::string executable_;
111   std::string current_test_name_;
112 };
113 
114 // Class representing the test suite itself.  To run it, implement your own
115 // class derived from ConformanceTestRunner, class derived from
116 // ConformanceTestSuite and then write code like:
117 //
118 //    class MyConformanceTestSuite : public ConformanceTestSuite {
119 //     public:
120 //      void RunSuiteImpl() {
121 //        // INSERT ACTURAL TESTS.
122 //      }
123 //    };
124 //
125 //    class MyConformanceTestRunner : public ConformanceTestRunner {
126 //     public:
127 //      static int Run(int argc, char *argv[],
128 //                 ConformanceTestSuite* suite);
129 //
130 //     private:
131 //      virtual void RunTest(...) {
132 //        // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE.
133 //      }
134 //    };
135 //
136 //    int main() {
137 //      MyConformanceTestSuite suite;
138 //      MyConformanceTestRunner::Run(argc, argv, &suite);
139 //    }
140 //
141 class ConformanceTestSuite {
142  public:
ConformanceTestSuite()143   ConformanceTestSuite()
144       : verbose_(false),
145         enforce_recommended_(false),
146         failure_list_flag_name_("--failure_list") {}
~ConformanceTestSuite()147   virtual ~ConformanceTestSuite() {}
148 
SetVerbose(bool verbose)149   void SetVerbose(bool verbose) { verbose_ = verbose; }
150 
151   // Whether to require the testee to pass RECOMMENDED tests. By default failing
152   // a RECOMMENDED test case will not fail the entire suite but will only
153   // generated a warning. If this flag is set to true, RECOMMENDED tests will
154   // be treated the same way as REQUIRED tests and failing a RECOMMENDED test
155   // case will cause the entire test suite to fail as well. An implementation
156   // can enable this if it wants to be strictly conforming to protobuf spec.
157   // See the comments about ConformanceLevel below to learn more about the
158   // difference between REQUIRED and RECOMMENDED test cases.
SetEnforceRecommended(bool value)159   void SetEnforceRecommended(bool value) {
160     enforce_recommended_ = value;
161   }
162 
163   // Gets the flag name to the failure list file.
164   // By default, this would return --failure_list
GetFailureListFlagName()165   string GetFailureListFlagName() {
166     return failure_list_flag_name_;
167   }
168 
SetFailureListFlagName(const std::string & failure_list_flag_name)169   void SetFailureListFlagName(const std::string& failure_list_flag_name) {
170     failure_list_flag_name_ = failure_list_flag_name;
171   }
172 
173   // Run all the conformance tests against the given test runner.
174   // Test output will be stored in "output".
175   //
176   // Returns true if the set of failing tests was exactly the same as the
177   // failure list.
178   // The filename here is *only* used to create/format useful error messages for
179   // how to update the failure list.  We do NOT read this file at all.
180   bool RunSuite(ConformanceTestRunner* runner, std::string* output,
181                 const std::string& filename,
182                 conformance::FailureSet* failure_list);
183 
184  protected:
185   // Test cases are classified into a few categories:
186   //   REQUIRED: the test case must be passed for an implementation to be
187   //             interoperable with other implementations. For example, a
188   //             parser implementaiton must accept both packed and unpacked
189   //             form of repeated primitive fields.
190   //   RECOMMENDED: the test case is not required for the implementation to
191   //                be interoperable with other implementations, but is
192   //                recommended for best performance and compatibility. For
193   //                example, a proto3 serializer should serialize repeated
194   //                primitive fields in packed form, but an implementation
195   //                failing to do so will still be able to communicate with
196   //                other implementations.
197   enum ConformanceLevel {
198     REQUIRED = 0,
199     RECOMMENDED = 1,
200   };
201 
202   class ConformanceRequestSetting {
203    public:
204     ConformanceRequestSetting(
205         ConformanceLevel level,
206         conformance::WireFormat input_format,
207         conformance::WireFormat output_format,
208         conformance::TestCategory test_category,
209         const Message& prototype_message,
210         const string& test_name, const string& input);
~ConformanceRequestSetting()211     virtual ~ConformanceRequestSetting() {}
212 
213     Message* GetTestMessage() const;
214 
215     string GetTestName() const;
216 
GetRequest()217     const conformance::ConformanceRequest& GetRequest() const {
218       return request_;
219     }
220 
GetLevel()221     const ConformanceLevel GetLevel() const {
222       return level_;
223     }
224 
225     string ConformanceLevelToString(ConformanceLevel level) const;
226 
SetPrintUnknownFields(bool print_unknown_fields)227     void SetPrintUnknownFields(bool print_unknown_fields) {
228       request_.set_print_unknown_fields(true);
229     }
230 
SetPrototypeMessageForCompare(const Message & message)231     void SetPrototypeMessageForCompare(const Message& message) {
232       prototype_message_for_compare_.reset(message.New());
233     }
234 
235    protected:
236     virtual string InputFormatString(conformance::WireFormat format) const;
237     virtual string OutputFormatString(conformance::WireFormat format) const;
238     conformance::ConformanceRequest request_;
239 
240    private:
241     ConformanceLevel level_;
242     ::conformance::WireFormat input_format_;
243     ::conformance::WireFormat output_format_;
244     const Message& prototype_message_;
245     std::unique_ptr<Message> prototype_message_for_compare_;
246     string test_name_;
247   };
248 
249   bool CheckSetEmpty(const std::set<string>& set_to_check,
250                      const std::string& write_to_file, const std::string& msg);
251   string WireFormatToString(conformance::WireFormat wire_format);
252 
253   // Parse payload in the response to the given message. Returns true on
254   // success.
255   virtual bool ParseResponse(
256       const conformance::ConformanceResponse& response,
257       const ConformanceRequestSetting& setting,
258       Message* test_message) = 0;
259 
260   void VerifyResponse(
261       const ConformanceRequestSetting& setting,
262       const string& equivalent_wire_format,
263       const conformance::ConformanceResponse& response,
264       bool need_report_success);
265 
266   void ReportSuccess(const std::string& test_name);
267   void ReportFailure(const string& test_name,
268                      ConformanceLevel level,
269                      const conformance::ConformanceRequest& request,
270                      const conformance::ConformanceResponse& response,
271                      const char* fmt, ...);
272   void ReportSkip(const string& test_name,
273                   const conformance::ConformanceRequest& request,
274                   const conformance::ConformanceResponse& response);
275 
276   void RunValidInputTest(const ConformanceRequestSetting& setting,
277                          const string& equivalent_text_format);
278   void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
279                                const string& equivalent_wire_format);
280 
281   void RunTest(const std::string& test_name,
282                const conformance::ConformanceRequest& request,
283                conformance::ConformanceResponse* response);
284 
285   void AddExpectedFailedTest(const std::string& test_name);
286 
287   virtual void RunSuiteImpl() = 0;
288 
289   ConformanceTestRunner* runner_;
290   int successes_;
291   int expected_failures_;
292   bool verbose_;
293   bool enforce_recommended_;
294   std::string output_;
295   std::string failure_list_flag_name_;
296   std::string failure_list_filename_;
297 
298   // The set of test names that are expected to fail in this run, but haven't
299   // failed yet.
300   std::set<std::string> expected_to_fail_;
301 
302   // The set of test names that have been run.  Used to ensure that there are no
303   // duplicate names in the suite.
304   std::set<std::string> test_names_;
305 
306   // The set of tests that failed, but weren't expected to.
307   std::set<std::string> unexpected_failing_tests_;
308 
309   // The set of tests that succeeded, but weren't expected to.
310   std::set<std::string> unexpected_succeeding_tests_;
311 
312   // The set of tests that the testee opted out of;
313   std::set<std::string> skipped_;
314 };
315 
316 }  // namespace protobuf
317 }  // namespace google
318 
319 #endif  // CONFORMANCE_CONFORMANCE_TEST_H
320