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 #include <vector> 44 45 #include <google/protobuf/descriptor.h> 46 #include <google/protobuf/wire_format_lite.h> 47 #include <google/protobuf/util/type_resolver.h> 48 #include "conformance.pb.h" 49 50 namespace conformance { 51 class ConformanceRequest; 52 class ConformanceResponse; 53 } // namespace conformance 54 55 namespace protobuf_test_messages { 56 namespace proto3 { 57 class TestAllTypesProto3; 58 } // namespace proto3 59 } // namespace protobuf_test_messages 60 61 namespace google { 62 namespace protobuf { 63 64 class ConformanceTestSuite; 65 66 class ConformanceTestRunner { 67 public: ~ConformanceTestRunner()68 virtual ~ConformanceTestRunner() {} 69 70 // Call to run a single conformance test. 71 // 72 // "input" is a serialized conformance.ConformanceRequest. 73 // "output" should be set to a serialized conformance.ConformanceResponse. 74 // 75 // If there is any error in running the test itself, set "runtime_error" in 76 // the response. 77 virtual void RunTest(const std::string& test_name, 78 const std::string& input, 79 std::string* output) = 0; 80 }; 81 82 // Test runner that spawns the process being tested and communicates with it 83 // over a pipe. 84 class ForkPipeRunner : public ConformanceTestRunner { 85 public: 86 // Note: Run() doesn't take ownership of the pointers inside suites. 87 static int Run(int argc, char *argv[], 88 const std::vector<ConformanceTestSuite*>& suites); 89 ForkPipeRunner(const std::string & executable,const std::vector<std::string> & executable_args)90 ForkPipeRunner(const std::string& executable, 91 const std::vector<std::string>& executable_args) 92 : child_pid_(-1), 93 executable_(executable), 94 executable_args_(executable_args) {} 95 ForkPipeRunner(const std::string & executable)96 explicit ForkPipeRunner(const std::string& executable) 97 : child_pid_(-1), executable_(executable) {} 98 ~ForkPipeRunner()99 virtual ~ForkPipeRunner() {} 100 101 void RunTest(const std::string& test_name, 102 const std::string& request, 103 std::string* response); 104 105 private: 106 void SpawnTestProgram(); 107 108 void CheckedWrite(int fd, const void *buf, size_t len); 109 bool TryRead(int fd, void *buf, size_t len); 110 void CheckedRead(int fd, void *buf, size_t len); 111 112 int write_fd_; 113 int read_fd_; 114 pid_t child_pid_; 115 std::string executable_; 116 const std::vector<std::string> executable_args_; 117 std::string current_test_name_; 118 }; 119 120 // Class representing the test suite itself. To run it, implement your own 121 // class derived from ConformanceTestRunner, class derived from 122 // ConformanceTestSuite and then write code like: 123 // 124 // class MyConformanceTestSuite : public ConformanceTestSuite { 125 // public: 126 // void RunSuiteImpl() { 127 // // INSERT ACTURAL TESTS. 128 // } 129 // }; 130 // 131 // class MyConformanceTestRunner : public ConformanceTestRunner { 132 // public: 133 // static int Run(int argc, char *argv[], 134 // ConformanceTestSuite* suite); 135 // 136 // private: 137 // virtual void RunTest(...) { 138 // // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE. 139 // } 140 // }; 141 // 142 // int main() { 143 // MyConformanceTestSuite suite; 144 // MyConformanceTestRunner::Run(argc, argv, &suite); 145 // } 146 // 147 class ConformanceTestSuite { 148 public: ConformanceTestSuite()149 ConformanceTestSuite() 150 : verbose_(false), 151 enforce_recommended_(false), 152 failure_list_flag_name_("--failure_list") {} ~ConformanceTestSuite()153 virtual ~ConformanceTestSuite() {} 154 SetVerbose(bool verbose)155 void SetVerbose(bool verbose) { verbose_ = verbose; } 156 157 // Whether to require the testee to pass RECOMMENDED tests. By default failing 158 // a RECOMMENDED test case will not fail the entire suite but will only 159 // generated a warning. If this flag is set to true, RECOMMENDED tests will 160 // be treated the same way as REQUIRED tests and failing a RECOMMENDED test 161 // case will cause the entire test suite to fail as well. An implementation 162 // can enable this if it wants to be strictly conforming to protobuf spec. 163 // See the comments about ConformanceLevel below to learn more about the 164 // difference between REQUIRED and RECOMMENDED test cases. SetEnforceRecommended(bool value)165 void SetEnforceRecommended(bool value) { 166 enforce_recommended_ = value; 167 } 168 169 // Gets the flag name to the failure list file. 170 // By default, this would return --failure_list GetFailureListFlagName()171 std::string GetFailureListFlagName() { return failure_list_flag_name_; } 172 SetFailureListFlagName(const std::string & failure_list_flag_name)173 void SetFailureListFlagName(const std::string& failure_list_flag_name) { 174 failure_list_flag_name_ = failure_list_flag_name; 175 } 176 177 // Run all the conformance tests against the given test runner. 178 // Test output will be stored in "output". 179 // 180 // Returns true if the set of failing tests was exactly the same as the 181 // failure list. 182 // The filename here is *only* used to create/format useful error messages for 183 // how to update the failure list. We do NOT read this file at all. 184 bool RunSuite(ConformanceTestRunner* runner, std::string* output, 185 const std::string& filename, 186 conformance::FailureSet* failure_list); 187 188 protected: 189 // Test cases are classified into a few categories: 190 // REQUIRED: the test case must be passed for an implementation to be 191 // interoperable with other implementations. For example, a 192 // parser implementation must accept both packed and unpacked 193 // form of repeated primitive fields. 194 // RECOMMENDED: the test case is not required for the implementation to 195 // be interoperable with other implementations, but is 196 // recommended for best performance and compatibility. For 197 // example, a proto3 serializer should serialize repeated 198 // primitive fields in packed form, but an implementation 199 // failing to do so will still be able to communicate with 200 // other implementations. 201 enum ConformanceLevel { 202 REQUIRED = 0, 203 RECOMMENDED = 1, 204 }; 205 206 class ConformanceRequestSetting { 207 public: 208 ConformanceRequestSetting(ConformanceLevel level, 209 conformance::WireFormat input_format, 210 conformance::WireFormat output_format, 211 conformance::TestCategory test_category, 212 const Message& prototype_message, 213 const std::string& test_name, 214 const std::string& input); ~ConformanceRequestSetting()215 virtual ~ConformanceRequestSetting() {} 216 217 std::unique_ptr<Message> NewTestMessage() const; 218 219 std::string GetTestName() const; 220 GetRequest()221 const conformance::ConformanceRequest& GetRequest() const { 222 return request_; 223 } 224 GetLevel()225 const ConformanceLevel GetLevel() const { 226 return level_; 227 } 228 229 std::string ConformanceLevelToString(ConformanceLevel level) const; 230 SetPrintUnknownFields(bool print_unknown_fields)231 void SetPrintUnknownFields(bool print_unknown_fields) { 232 request_.set_print_unknown_fields(true); 233 } 234 SetPrototypeMessageForCompare(const Message & message)235 void SetPrototypeMessageForCompare(const Message& message) { 236 prototype_message_for_compare_.reset(message.New()); 237 } 238 239 protected: 240 virtual std::string InputFormatString(conformance::WireFormat format) const; 241 virtual std::string OutputFormatString( 242 conformance::WireFormat format) const; 243 conformance::ConformanceRequest request_; 244 245 private: 246 ConformanceLevel level_; 247 ::conformance::WireFormat input_format_; 248 ::conformance::WireFormat output_format_; 249 const Message& prototype_message_; 250 std::unique_ptr<Message> prototype_message_for_compare_; 251 std::string test_name_; 252 }; 253 254 bool CheckSetEmpty(const std::set<std::string>& set_to_check, 255 const std::string& write_to_file, const std::string& msg); 256 std::string WireFormatToString(conformance::WireFormat wire_format); 257 258 // Parse payload in the response to the given message. Returns true on 259 // success. 260 virtual bool ParseResponse( 261 const conformance::ConformanceResponse& response, 262 const ConformanceRequestSetting& setting, 263 Message* test_message) = 0; 264 265 void VerifyResponse(const ConformanceRequestSetting& setting, 266 const std::string& equivalent_wire_format, 267 const conformance::ConformanceResponse& response, 268 bool need_report_success, bool require_same_wire_format); 269 270 void ReportSuccess(const std::string& test_name); 271 void ReportFailure(const std::string& test_name, ConformanceLevel level, 272 const conformance::ConformanceRequest& request, 273 const conformance::ConformanceResponse& response, 274 const char* fmt, ...); 275 void ReportSkip(const std::string& test_name, 276 const conformance::ConformanceRequest& request, 277 const conformance::ConformanceResponse& response); 278 279 void RunValidInputTest(const ConformanceRequestSetting& setting, 280 const std::string& equivalent_text_format); 281 void RunValidBinaryInputTest(const ConformanceRequestSetting& setting, 282 const std::string& equivalent_wire_format, 283 bool require_same_wire_format = false); 284 285 void RunTest(const std::string& test_name, 286 const conformance::ConformanceRequest& request, 287 conformance::ConformanceResponse* response); 288 289 void AddExpectedFailedTest(const std::string& test_name); 290 291 virtual void RunSuiteImpl() = 0; 292 293 ConformanceTestRunner* runner_; 294 int successes_; 295 int expected_failures_; 296 bool verbose_; 297 bool enforce_recommended_; 298 std::string output_; 299 std::string failure_list_flag_name_; 300 std::string failure_list_filename_; 301 302 // The set of test names that are expected to fail in this run, but haven't 303 // failed yet. 304 std::set<std::string> expected_to_fail_; 305 306 // The set of test names that have been run. Used to ensure that there are no 307 // duplicate names in the suite. 308 std::set<std::string> test_names_; 309 310 // The set of tests that failed, but weren't expected to. 311 std::set<std::string> unexpected_failing_tests_; 312 313 // The set of tests that succeeded, but weren't expected to. 314 std::set<std::string> unexpected_succeeding_tests_; 315 316 // The set of tests that the testee opted out of; 317 std::set<std::string> skipped_; 318 }; 319 320 } // namespace protobuf 321 } // namespace google 322 323 #endif // CONFORMANCE_CONFORMANCE_TEST_H 324