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