• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <errno.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 
35 #include <google/protobuf/message.h>
36 #include <google/protobuf/text_format.h>
37 #include <google/protobuf/util/json_util.h>
38 #include <google/protobuf/util/type_resolver_util.h>
39 #include "conformance.pb.h"
40 #include <google/protobuf/test_messages_proto2.pb.h>
41 #include <google/protobuf/test_messages_proto3.pb.h>
42 #include <google/protobuf/stubs/status.h>
43 
44 using conformance::ConformanceRequest;
45 using conformance::ConformanceResponse;
46 using google::protobuf::Descriptor;
47 using google::protobuf::DescriptorPool;
48 using google::protobuf::Message;
49 using google::protobuf::MessageFactory;
50 using google::protobuf::TextFormat;
51 using google::protobuf::util::BinaryToJsonString;
52 using google::protobuf::util::JsonParseOptions;
53 using google::protobuf::util::JsonToBinaryString;
54 using google::protobuf::util::NewTypeResolverForDescriptorPool;
55 using google::protobuf::util::TypeResolver;
56 using protobuf_test_messages::proto3::TestAllTypesProto3;
57 using std::string;
58 
59 static const char kTypeUrlPrefix[] = "type.googleapis.com";
60 
61 const char* kFailures[] = {
62 };
63 
GetTypeUrl(const Descriptor * message)64 static string GetTypeUrl(const Descriptor* message) {
65   return string(kTypeUrlPrefix) + "/" + message->full_name();
66 }
67 
68 int test_count = 0;
69 bool verbose = false;
70 TypeResolver* type_resolver;
71 string* type_url;
72 
73 namespace google {
74 namespace protobuf {
75 
76 using util::Status;
77 
CheckedRead(int fd,void * buf,size_t len)78 bool CheckedRead(int fd, void *buf, size_t len) {
79   size_t ofs = 0;
80   while (len > 0) {
81     ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
82 
83     if (bytes_read == 0) return false;
84 
85     if (bytes_read < 0) {
86       GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
87     }
88 
89     len -= bytes_read;
90     ofs += bytes_read;
91   }
92 
93   return true;
94 }
95 
CheckedWrite(int fd,const void * buf,size_t len)96 void CheckedWrite(int fd, const void *buf, size_t len) {
97   if (write(fd, buf, len) != len) {
98     GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
99   }
100 }
101 
DoTest(const ConformanceRequest & request,ConformanceResponse * response)102 void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
103   Message *test_message;
104   const Descriptor *descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(
105       request.message_type());
106   if (!descriptor) {
107     GOOGLE_LOG(FATAL) << "No such message type: " << request.message_type();
108   }
109   test_message = MessageFactory::generated_factory()->GetPrototype(descriptor)->New();
110 
111   switch (request.payload_case()) {
112     case ConformanceRequest::kProtobufPayload: {
113       if (!test_message->ParseFromString(request.protobuf_payload())) {
114         // Getting parse details would involve something like:
115         //   http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
116         response->set_parse_error("Parse error (no more details available).");
117         return;
118       }
119       break;
120     }
121 
122     case ConformanceRequest::kJsonPayload: {
123       string proto_binary;
124       JsonParseOptions options;
125       options.ignore_unknown_fields =
126           (request.test_category() ==
127               conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
128       Status status = JsonToBinaryString(type_resolver, *type_url,
129                                          request.json_payload(), &proto_binary,
130                                          options);
131       if (!status.ok()) {
132         response->set_parse_error(string("Parse error: ") +
133                                   std::string(status.error_message()));
134         return;
135       }
136 
137       if (!test_message->ParseFromString(proto_binary)) {
138         response->set_runtime_error(
139             "Parsing JSON generates invalid proto output.");
140         return;
141       }
142       break;
143     }
144 
145     case ConformanceRequest::kTextPayload: {
146       if (!TextFormat::ParseFromString(request.text_payload(), test_message)) {
147         response->set_parse_error("Parse error");
148         return;
149       }
150       break;
151     }
152 
153     case ConformanceRequest::PAYLOAD_NOT_SET:
154       GOOGLE_LOG(FATAL) << "Request didn't have payload.";
155       break;
156 
157     default:
158       GOOGLE_LOG(FATAL) << "unknown payload type: " << request.payload_case();
159       break;
160   }
161 
162   conformance::FailureSet failures;
163   if (descriptor == failures.GetDescriptor()) {
164     for (const char* s : kFailures) failures.add_failure(s);
165     test_message = &failures;
166   }
167 
168   switch (request.requested_output_format()) {
169     case conformance::UNSPECIFIED:
170       GOOGLE_LOG(FATAL) << "Unspecified output format";
171       break;
172 
173     case conformance::PROTOBUF: {
174       GOOGLE_CHECK(test_message->SerializeToString(
175           response->mutable_protobuf_payload()));
176       break;
177     }
178 
179     case conformance::JSON: {
180       string proto_binary;
181       GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
182       Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
183                                          response->mutable_json_payload());
184       if (!status.ok()) {
185         response->set_serialize_error(
186             string("Failed to serialize JSON output: ") +
187             std::string(status.error_message()));
188         return;
189       }
190       break;
191     }
192 
193     case conformance::TEXT_FORMAT: {
194       TextFormat::Printer printer;
195       printer.SetHideUnknownFields(!request.print_unknown_fields());
196       GOOGLE_CHECK(printer.PrintToString(*test_message,
197                                   response->mutable_text_payload()));
198       break;
199     }
200 
201     default:
202       GOOGLE_LOG(FATAL) << "Unknown output format: "
203                  << request.requested_output_format();
204   }
205 }
206 
DoTestIo()207 bool DoTestIo() {
208   string serialized_input;
209   string serialized_output;
210   ConformanceRequest request;
211   ConformanceResponse response;
212   uint32_t bytes;
213 
214   if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
215     // EOF.
216     return false;
217   }
218 
219   serialized_input.resize(bytes);
220 
221   if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
222     GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
223   }
224 
225   if (!request.ParseFromString(serialized_input)) {
226     GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
227     return false;
228   }
229 
230   DoTest(request, &response);
231 
232   response.SerializeToString(&serialized_output);
233 
234   bytes = serialized_output.size();
235   CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
236   CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
237 
238   if (verbose) {
239     fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
240             request.ShortDebugString().c_str(),
241             response.ShortDebugString().c_str());
242   }
243 
244   test_count++;
245 
246   return true;
247 }
248 
249 }  // namespace protobuf
250 }  // namespace google
251 
main()252 int main() {
253   type_resolver = NewTypeResolverForDescriptorPool(
254       kTypeUrlPrefix, DescriptorPool::generated_pool());
255   type_url = new string(GetTypeUrl(TestAllTypesProto3::descriptor()));
256   while (1) {
257     if (!google::protobuf::DoTestIo()) {
258       fprintf(stderr, "conformance-cpp: received EOF from test runner "
259                       "after %d tests, exiting\n", test_count);
260       return 0;
261     }
262   }
263 }
264