blob: 1a2654932587d25fe7d6006c1736ee3e3d14de3a [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
35#include "conformance.pb.h"
Josh Habermanb0500b32015-07-10 16:36:59 -070036#include <google/protobuf/util/json_util.h>
37#include <google/protobuf/util/type_resolver_util.h>
Josh Haberman35a1cc72015-04-01 17:23:48 -070038
Josh Haberman35a1cc72015-04-01 17:23:48 -070039using conformance::ConformanceRequest;
40using conformance::ConformanceResponse;
41using conformance::TestAllTypes;
Josh Habermanb0500b32015-07-10 16:36:59 -070042using google::protobuf::Descriptor;
43using google::protobuf::DescriptorPool;
44using google::protobuf::internal::scoped_ptr;
45using google::protobuf::util::BinaryToJsonString;
46using google::protobuf::util::JsonToBinaryString;
47using google::protobuf::util::NewTypeResolverForDescriptorPool;
48using google::protobuf::util::Status;
49using google::protobuf::util::TypeResolver;
50using std::string;
51
52static const char kTypeUrlPrefix[] = "type.googleapis.com";
53
54static string GetTypeUrl(const Descriptor* message) {
55 return string(kTypeUrlPrefix) + "/" + message->full_name();
56}
Josh Haberman35a1cc72015-04-01 17:23:48 -070057
58int test_count = 0;
59bool verbose = false;
Josh Habermanb0500b32015-07-10 16:36:59 -070060TypeResolver* type_resolver;
61string* type_url;
62
Josh Haberman35a1cc72015-04-01 17:23:48 -070063
64bool CheckedRead(int fd, void *buf, size_t len) {
65 size_t ofs = 0;
66 while (len > 0) {
67 ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
68
69 if (bytes_read == 0) return false;
70
71 if (bytes_read < 0) {
72 GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
73 }
74
75 len -= bytes_read;
76 ofs += bytes_read;
77 }
78
79 return true;
80}
81
82void CheckedWrite(int fd, const void *buf, size_t len) {
83 if (write(fd, buf, len) != len) {
84 GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
85 }
86}
87
88void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
89 TestAllTypes test_message;
90
91 switch (request.payload_case()) {
92 case ConformanceRequest::kProtobufPayload:
93 if (!test_message.ParseFromString(request.protobuf_payload())) {
94 // Getting parse details would involve something like:
95 // http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
96 response->set_parse_error("Parse error (no more details available).");
97 return;
98 }
99 break;
100
Josh Habermanb0500b32015-07-10 16:36:59 -0700101 case ConformanceRequest::kJsonPayload: {
102 string proto_binary;
103 Status status = JsonToBinaryString(type_resolver, *type_url,
104 request.json_payload(), &proto_binary);
105 if (!status.ok()) {
106 response->set_parse_error(string("Parse error: ") +
107 status.error_message().as_string());
108 return;
109 }
110
Feng Xiaoe841bac2015-12-11 17:09:20 -0800111 if (!test_message.ParseFromString(proto_binary)) {
112 response->set_runtime_error(
113 "Parsing JSON generates invalid proto output.");
114 return;
115 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700116 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700117 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700118
119 case ConformanceRequest::PAYLOAD_NOT_SET:
120 GOOGLE_LOG(FATAL) << "Request didn't have payload.";
121 break;
122 }
123
Josh Habermanb0500b32015-07-10 16:36:59 -0700124 switch (request.requested_output_format()) {
125 case conformance::UNSPECIFIED:
Josh Haberman35a1cc72015-04-01 17:23:48 -0700126 GOOGLE_LOG(FATAL) << "Unspecified output format";
127 break;
128
Josh Habermanb0500b32015-07-10 16:36:59 -0700129 case conformance::PROTOBUF:
130 GOOGLE_CHECK(
131 test_message.SerializeToString(response->mutable_protobuf_payload()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700132 break;
133
Josh Habermanb0500b32015-07-10 16:36:59 -0700134 case conformance::JSON: {
135 string proto_binary;
136 GOOGLE_CHECK(test_message.SerializeToString(&proto_binary));
137 Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
138 response->mutable_json_payload());
Feng Xiaoe841bac2015-12-11 17:09:20 -0800139 if (!status.ok()) {
140 response->set_serialize_error(
141 string("Failed to serialize JSON output: ") +
142 status.error_message().as_string());
143 return;
144 }
Josh Haberman35a1cc72015-04-01 17:23:48 -0700145 break;
Josh Habermanb0500b32015-07-10 16:36:59 -0700146 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800147
148 default:
149 GOOGLE_LOG(FATAL) << "Unknown output format: "
150 << request.requested_output_format();
Josh Haberman35a1cc72015-04-01 17:23:48 -0700151 }
152}
153
154bool DoTestIo() {
155 string serialized_input;
156 string serialized_output;
157 ConformanceRequest request;
158 ConformanceResponse response;
159 uint32_t bytes;
160
161 if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
162 // EOF.
163 return false;
164 }
165
166 serialized_input.resize(bytes);
167
168 if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
169 GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
170 }
171
172 if (!request.ParseFromString(serialized_input)) {
173 GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
174 return false;
175 }
176
177 DoTest(request, &response);
178
179 response.SerializeToString(&serialized_output);
180
181 bytes = serialized_output.size();
182 CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
183 CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
184
185 if (verbose) {
186 fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
187 request.ShortDebugString().c_str(),
188 response.ShortDebugString().c_str());
189 }
190
191 test_count++;
192
193 return true;
194}
195
196int main() {
Josh Habermanb0500b32015-07-10 16:36:59 -0700197 type_resolver = NewTypeResolverForDescriptorPool(
198 kTypeUrlPrefix, DescriptorPool::generated_pool());
199 type_url = new string(GetTypeUrl(TestAllTypes::descriptor()));
Josh Haberman35a1cc72015-04-01 17:23:48 -0700200 while (1) {
201 if (!DoTestIo()) {
202 fprintf(stderr, "conformance-cpp: received EOF from test runner "
203 "after %d tests, exiting\n", test_count);
204 return 0;
205 }
206 }
207}