blob: 5782789dfdd147e91b2a22282b0f9388f5f9a9f9 [file] [log] [blame]
Josh Haberman35a1cc72015-04-01 17:23:48 -07001// 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#include <errno.h>
32#include <stdarg.h>
33#include <unistd.h>
34
Yilun Chong020a24d2017-06-29 11:33:22 -070035#include <google/protobuf/message.h>
Yilun Chongcb95a7f2019-01-11 11:40:52 -080036#include <google/protobuf/text_format.h>
Josh Habermanb0500b32015-07-10 16:36:59 -070037#include <google/protobuf/util/json_util.h>
38#include <google/protobuf/util/type_resolver_util.h>
Joshua Haberman5c028d62020-11-20 10:44:58 -080039#include <google/protobuf/stubs/status.h>
Rafi Kamal58d44202019-11-11 17:06:56 -080040#include "conformance.pb.h"
41#include <google/protobuf/test_messages_proto2.pb.h>
42#include <google/protobuf/test_messages_proto3.pb.h>
43#include <google/protobuf/stubs/status.h>
Josh Haberman35a1cc72015-04-01 17:23:48 -070044
Josh Haberman35a1cc72015-04-01 17:23:48 -070045using conformance::ConformanceRequest;
46using conformance::ConformanceResponse;
Josh Habermanb0500b32015-07-10 16:36:59 -070047using google::protobuf::Descriptor;
48using google::protobuf::DescriptorPool;
Yilun Chong020a24d2017-06-29 11:33:22 -070049using google::protobuf::Message;
Yilun Chong3adb0542017-06-30 17:22:32 -070050using google::protobuf::MessageFactory;
Yilun Chongcb95a7f2019-01-11 11:40:52 -080051using google::protobuf::TextFormat;
Josh Habermanb0500b32015-07-10 16:36:59 -070052using google::protobuf::util::BinaryToJsonString;
Feng Xiao6bbe1972018-08-08 17:00:41 -070053using google::protobuf::util::JsonParseOptions;
Josh Habermanb0500b32015-07-10 16:36:59 -070054using google::protobuf::util::JsonToBinaryString;
55using google::protobuf::util::NewTypeResolverForDescriptorPool;
Josh Habermanb0500b32015-07-10 16:36:59 -070056using google::protobuf::util::TypeResolver;
Yilun Chongcb95a7f2019-01-11 11:40:52 -080057using protobuf_test_messages::proto3::TestAllTypesProto3;
Joshua Haberman9df42752021-02-26 10:37:37 -080058using protobuf_test_messages::proto2::TestAllTypesProto2;
Josh Habermanb0500b32015-07-10 16:36:59 -070059using std::string;
60
61static const char kTypeUrlPrefix[] = "type.googleapis.com";
62
Yilun Chong0adb74c2019-01-08 15:06:30 -080063const char* kFailures[] = {
Yilun Chong0adb74c2019-01-08 15:06:30 -080064};
65
Josh Habermanb0500b32015-07-10 16:36:59 -070066static string GetTypeUrl(const Descriptor* message) {
67 return string(kTypeUrlPrefix) + "/" + message->full_name();
68}
Josh Haberman35a1cc72015-04-01 17:23:48 -070069
70int test_count = 0;
71bool verbose = false;
Josh Habermanb0500b32015-07-10 16:36:59 -070072TypeResolver* type_resolver;
73string* type_url;
74
Rafi Kamal58d44202019-11-11 17:06:56 -080075namespace google {
76namespace protobuf {
77
78using util::Status;
Josh Haberman35a1cc72015-04-01 17:23:48 -070079
80bool CheckedRead(int fd, void *buf, size_t len) {
81 size_t ofs = 0;
82 while (len > 0) {
83 ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
84
85 if (bytes_read == 0) return false;
86
87 if (bytes_read < 0) {
Rafi Kamal58d44202019-11-11 17:06:56 -080088 GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
Josh Haberman35a1cc72015-04-01 17:23:48 -070089 }
90
91 len -= bytes_read;
92 ofs += bytes_read;
93 }
94
95 return true;
96}
97
98void CheckedWrite(int fd, const void *buf, size_t len) {
99 if (write(fd, buf, len) != len) {
100 GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
101 }
102}
103
104void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
Yilun Chong020a24d2017-06-29 11:33:22 -0700105 Message *test_message;
Joshua Haberman9df42752021-02-26 10:37:37 -0800106 google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
107 google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
Yilun Chong3adb0542017-06-30 17:22:32 -0700108 const Descriptor *descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(
109 request.message_type());
110 if (!descriptor) {
111 GOOGLE_LOG(FATAL) << "No such message type: " << request.message_type();
Yilun Chong020a24d2017-06-29 11:33:22 -0700112 }
Yilun Chong3adb0542017-06-30 17:22:32 -0700113 test_message = MessageFactory::generated_factory()->GetPrototype(descriptor)->New();
Josh Haberman35a1cc72015-04-01 17:23:48 -0700114
115 switch (request.payload_case()) {
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700116 case ConformanceRequest::kProtobufPayload: {
Yilun Chong020a24d2017-06-29 11:33:22 -0700117 if (!test_message->ParseFromString(request.protobuf_payload())) {
118 // Getting parse details would involve something like:
119 // http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
120 response->set_parse_error("Parse error (no more details available).");
121 return;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700122 }
123 break;
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700124 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700125
Josh Habermanb0500b32015-07-10 16:36:59 -0700126 case ConformanceRequest::kJsonPayload: {
127 string proto_binary;
Feng Xiao6bbe1972018-08-08 17:00:41 -0700128 JsonParseOptions options;
129 options.ignore_unknown_fields =
130 (request.test_category() ==
131 conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
Joshua Haberman5c028d62020-11-20 10:44:58 -0800132 util::Status status =
133 JsonToBinaryString(type_resolver, *type_url, request.json_payload(),
134 &proto_binary, options);
Josh Habermanb0500b32015-07-10 16:36:59 -0700135 if (!status.ok()) {
136 response->set_parse_error(string("Parse error: ") +
Yannic Bonenbergeraa5cb982021-03-10 10:05:31 +0100137 std::string(status.message()));
Josh Habermanb0500b32015-07-10 16:36:59 -0700138 return;
139 }
140
Yilun Chong020a24d2017-06-29 11:33:22 -0700141 if (!test_message->ParseFromString(proto_binary)) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800142 response->set_runtime_error(
143 "Parsing JSON generates invalid proto output.");
144 return;
145 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700146 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700147 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700148
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800149 case ConformanceRequest::kTextPayload: {
150 if (!TextFormat::ParseFromString(request.text_payload(), test_message)) {
151 response->set_parse_error("Parse error");
152 return;
153 }
154 break;
155 }
156
Josh Haberman35a1cc72015-04-01 17:23:48 -0700157 case ConformanceRequest::PAYLOAD_NOT_SET:
158 GOOGLE_LOG(FATAL) << "Request didn't have payload.";
159 break;
Paul Yangcecba292018-12-14 16:05:03 -0800160
161 default:
Rafi Kamal58d44202019-11-11 17:06:56 -0800162 GOOGLE_LOG(FATAL) << "unknown payload type: " << request.payload_case();
Paul Yangcecba292018-12-14 16:05:03 -0800163 break;
Josh Haberman35a1cc72015-04-01 17:23:48 -0700164 }
165
Yilun Chong0adb74c2019-01-08 15:06:30 -0800166 conformance::FailureSet failures;
167 if (descriptor == failures.GetDescriptor()) {
168 for (const char* s : kFailures) failures.add_failure(s);
169 test_message = &failures;
170 }
171
Josh Habermanb0500b32015-07-10 16:36:59 -0700172 switch (request.requested_output_format()) {
173 case conformance::UNSPECIFIED:
Josh Haberman35a1cc72015-04-01 17:23:48 -0700174 GOOGLE_LOG(FATAL) << "Unspecified output format";
175 break;
176
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700177 case conformance::PROTOBUF: {
Rafi Kamal58d44202019-11-11 17:06:56 -0800178 GOOGLE_CHECK(test_message->SerializeToString(
179 response->mutable_protobuf_payload()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700180 break;
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700181 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700182
Josh Habermanb0500b32015-07-10 16:36:59 -0700183 case conformance::JSON: {
184 string proto_binary;
Yilun Chong020a24d2017-06-29 11:33:22 -0700185 GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
Joshua Haberman5c028d62020-11-20 10:44:58 -0800186 util::Status status =
187 BinaryToJsonString(type_resolver, *type_url, proto_binary,
188 response->mutable_json_payload());
Feng Xiaoe841bac2015-12-11 17:09:20 -0800189 if (!status.ok()) {
190 response->set_serialize_error(
191 string("Failed to serialize JSON output: ") +
Yannic Bonenbergeraa5cb982021-03-10 10:05:31 +0100192 std::string(status.message()));
Feng Xiaoe841bac2015-12-11 17:09:20 -0800193 return;
194 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700195 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700196 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800197
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800198 case conformance::TEXT_FORMAT: {
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700199 TextFormat::Printer printer;
200 printer.SetHideUnknownFields(!request.print_unknown_fields());
201 GOOGLE_CHECK(printer.PrintToString(*test_message,
Rafi Kamal58d44202019-11-11 17:06:56 -0800202 response->mutable_text_payload()));
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800203 break;
204 }
205
Feng Xiaoe841bac2015-12-11 17:09:20 -0800206 default:
207 GOOGLE_LOG(FATAL) << "Unknown output format: "
Rafi Kamal58d44202019-11-11 17:06:56 -0800208 << request.requested_output_format();
Josh Haberman35a1cc72015-04-01 17:23:48 -0700209 }
210}
211
212bool DoTestIo() {
213 string serialized_input;
214 string serialized_output;
215 ConformanceRequest request;
216 ConformanceResponse response;
217 uint32_t bytes;
218
219 if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
220 // EOF.
221 return false;
222 }
223
224 serialized_input.resize(bytes);
225
226 if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
227 GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
228 }
229
230 if (!request.ParseFromString(serialized_input)) {
231 GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
232 return false;
233 }
234
235 DoTest(request, &response);
236
237 response.SerializeToString(&serialized_output);
238
239 bytes = serialized_output.size();
240 CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
241 CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
242
243 if (verbose) {
244 fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
245 request.ShortDebugString().c_str(),
246 response.ShortDebugString().c_str());
247 }
248
249 test_count++;
250
251 return true;
252}
253
Rafi Kamal58d44202019-11-11 17:06:56 -0800254} // namespace protobuf
255} // namespace google
256
Josh Haberman35a1cc72015-04-01 17:23:48 -0700257int main() {
Josh Habermanb0500b32015-07-10 16:36:59 -0700258 type_resolver = NewTypeResolverForDescriptorPool(
259 kTypeUrlPrefix, DescriptorPool::generated_pool());
Yilun Chong3adb0542017-06-30 17:22:32 -0700260 type_url = new string(GetTypeUrl(TestAllTypesProto3::descriptor()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700261 while (1) {
Rafi Kamal58d44202019-11-11 17:06:56 -0800262 if (!google::protobuf::DoTestIo()) {
Josh Haberman35a1cc72015-04-01 17:23:48 -0700263 fprintf(stderr, "conformance-cpp: received EOF from test runner "
264 "after %d tests, exiting\n", test_count);
265 return 0;
266 }
267 }
268}