blob: 97ae1a7a209b5deb10c9e11616f1dad8b458a792 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// 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
35#include "conformance.pb.h"
Austin Schuh40c16522018-10-28 20:27:54 -070036#include <google/protobuf/test_messages_proto3.pb.h>
37#include <google/protobuf/test_messages_proto2.pb.h>
38#include <google/protobuf/message.h>
Brian Silverman9c614bc2016-02-15 20:20:02 -050039#include <google/protobuf/util/json_util.h>
40#include <google/protobuf/util/type_resolver_util.h>
41
42using conformance::ConformanceRequest;
43using conformance::ConformanceResponse;
Brian Silverman9c614bc2016-02-15 20:20:02 -050044using google::protobuf::Descriptor;
45using google::protobuf::DescriptorPool;
Austin Schuh40c16522018-10-28 20:27:54 -070046using google::protobuf::Message;
47using google::protobuf::MessageFactory;
Brian Silverman9c614bc2016-02-15 20:20:02 -050048using google::protobuf::util::BinaryToJsonString;
49using google::protobuf::util::JsonToBinaryString;
50using google::protobuf::util::NewTypeResolverForDescriptorPool;
51using google::protobuf::util::Status;
52using google::protobuf::util::TypeResolver;
Austin Schuh40c16522018-10-28 20:27:54 -070053using protobuf_test_messages::proto3::TestAllTypesProto3;
54using protobuf_test_messages::proto2::TestAllTypesProto2;
Brian Silverman9c614bc2016-02-15 20:20:02 -050055using std::string;
56
57static const char kTypeUrlPrefix[] = "type.googleapis.com";
58
59static string GetTypeUrl(const Descriptor* message) {
60 return string(kTypeUrlPrefix) + "/" + message->full_name();
61}
62
63int test_count = 0;
64bool verbose = false;
65TypeResolver* type_resolver;
66string* type_url;
67
68
69bool CheckedRead(int fd, void *buf, size_t len) {
70 size_t ofs = 0;
71 while (len > 0) {
72 ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
73
74 if (bytes_read == 0) return false;
75
76 if (bytes_read < 0) {
77 GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
78 }
79
80 len -= bytes_read;
81 ofs += bytes_read;
82 }
83
84 return true;
85}
86
87void CheckedWrite(int fd, const void *buf, size_t len) {
88 if (write(fd, buf, len) != len) {
89 GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
90 }
91}
92
93void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
Austin Schuh40c16522018-10-28 20:27:54 -070094 Message *test_message;
95 const Descriptor *descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(
96 request.message_type());
97 if (!descriptor) {
98 GOOGLE_LOG(FATAL) << "No such message type: " << request.message_type();
99 }
100 test_message = MessageFactory::generated_factory()->GetPrototype(descriptor)->New();
Brian Silverman9c614bc2016-02-15 20:20:02 -0500101
102 switch (request.payload_case()) {
Austin Schuh40c16522018-10-28 20:27:54 -0700103 case ConformanceRequest::kProtobufPayload: {
104 if (!test_message->ParseFromString(request.protobuf_payload())) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500105 // Getting parse details would involve something like:
106 // http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
107 response->set_parse_error("Parse error (no more details available).");
108 return;
109 }
110 break;
Austin Schuh40c16522018-10-28 20:27:54 -0700111 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500112
113 case ConformanceRequest::kJsonPayload: {
114 string proto_binary;
115 Status status = JsonToBinaryString(type_resolver, *type_url,
116 request.json_payload(), &proto_binary);
117 if (!status.ok()) {
118 response->set_parse_error(string("Parse error: ") +
119 status.error_message().as_string());
120 return;
121 }
122
Austin Schuh40c16522018-10-28 20:27:54 -0700123 if (!test_message->ParseFromString(proto_binary)) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500124 response->set_runtime_error(
125 "Parsing JSON generates invalid proto output.");
126 return;
127 }
128 break;
129 }
130
131 case ConformanceRequest::PAYLOAD_NOT_SET:
132 GOOGLE_LOG(FATAL) << "Request didn't have payload.";
133 break;
134 }
135
136 switch (request.requested_output_format()) {
137 case conformance::UNSPECIFIED:
138 GOOGLE_LOG(FATAL) << "Unspecified output format";
139 break;
140
Austin Schuh40c16522018-10-28 20:27:54 -0700141 case conformance::PROTOBUF: {
142 GOOGLE_CHECK(test_message->SerializeToString(response->mutable_protobuf_payload()));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500143 break;
Austin Schuh40c16522018-10-28 20:27:54 -0700144 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500145
146 case conformance::JSON: {
147 string proto_binary;
Austin Schuh40c16522018-10-28 20:27:54 -0700148 GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500149 Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
150 response->mutable_json_payload());
151 if (!status.ok()) {
152 response->set_serialize_error(
153 string("Failed to serialize JSON output: ") +
154 status.error_message().as_string());
155 return;
156 }
157 break;
158 }
159
160 default:
161 GOOGLE_LOG(FATAL) << "Unknown output format: "
162 << request.requested_output_format();
163 }
164}
165
166bool DoTestIo() {
167 string serialized_input;
168 string serialized_output;
169 ConformanceRequest request;
170 ConformanceResponse response;
171 uint32_t bytes;
172
173 if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
174 // EOF.
175 return false;
176 }
177
178 serialized_input.resize(bytes);
179
180 if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
181 GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
182 }
183
184 if (!request.ParseFromString(serialized_input)) {
185 GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
186 return false;
187 }
188
189 DoTest(request, &response);
190
191 response.SerializeToString(&serialized_output);
192
193 bytes = serialized_output.size();
194 CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
195 CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
196
197 if (verbose) {
198 fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
199 request.ShortDebugString().c_str(),
200 response.ShortDebugString().c_str());
201 }
202
203 test_count++;
204
205 return true;
206}
207
208int main() {
209 type_resolver = NewTypeResolverForDescriptorPool(
210 kTypeUrlPrefix, DescriptorPool::generated_pool());
Austin Schuh40c16522018-10-28 20:27:54 -0700211 type_url = new string(GetTypeUrl(TestAllTypesProto3::descriptor()));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500212 while (1) {
213 if (!DoTestIo()) {
214 fprintf(stderr, "conformance-cpp: received EOF from test runner "
215 "after %d tests, exiting\n", test_count);
216 return 0;
217 }
218 }
219}