xref: /aosp_15_r20/external/protobuf/conformance/conformance_cpp.cc (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
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 <google/protobuf/stubs/status.h>
40 #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>
44 
45 using conformance::ConformanceRequest;
46 using conformance::ConformanceResponse;
47 using google::protobuf::Descriptor;
48 using google::protobuf::DescriptorPool;
49 using google::protobuf::Message;
50 using google::protobuf::MessageFactory;
51 using google::protobuf::TextFormat;
52 using google::protobuf::util::BinaryToJsonString;
53 using google::protobuf::util::JsonParseOptions;
54 using google::protobuf::util::JsonToBinaryString;
55 using google::protobuf::util::NewTypeResolverForDescriptorPool;
56 using google::protobuf::util::TypeResolver;
57 using protobuf_test_messages::proto3::TestAllTypesProto3;
58 using protobuf_test_messages::proto2::TestAllTypesProto2;
59 using std::string;
60 
61 static const char kTypeUrlPrefix[] = "type.googleapis.com";
62 
63 const char* kFailures[] = {
64 };
65 
GetTypeUrl(const Descriptor * message)66 static string GetTypeUrl(const Descriptor* message) {
67   return string(kTypeUrlPrefix) + "/" + message->full_name();
68 }
69 
70 int test_count = 0;
71 bool verbose = false;
72 TypeResolver* type_resolver;
73 string* type_url;
74 
75 namespace google {
76 namespace protobuf {
77 
78 using util::Status;
79 
CheckedRead(int fd,void * buf,size_t len)80 bool 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) {
88       GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
89     }
90 
91     len -= bytes_read;
92     ofs += bytes_read;
93   }
94 
95   return true;
96 }
97 
CheckedWrite(int fd,const void * buf,size_t len)98 void 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 
DoTest(const ConformanceRequest & request,ConformanceResponse * response)104 void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
105   Message *test_message;
106   google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
107   google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
108   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();
112   }
113   test_message = MessageFactory::generated_factory()->GetPrototype(descriptor)->New();
114 
115   switch (request.payload_case()) {
116     case ConformanceRequest::kProtobufPayload: {
117       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;
122       }
123       break;
124     }
125 
126     case ConformanceRequest::kJsonPayload: {
127       string proto_binary;
128       JsonParseOptions options;
129       options.ignore_unknown_fields =
130           (request.test_category() ==
131               conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
132       util::Status status =
133           JsonToBinaryString(type_resolver, *type_url, request.json_payload(),
134                              &proto_binary, options);
135       if (!status.ok()) {
136         response->set_parse_error(string("Parse error: ") +
137                                   std::string(status.message()));
138         return;
139       }
140 
141       if (!test_message->ParseFromString(proto_binary)) {
142         response->set_runtime_error(
143             "Parsing JSON generates invalid proto output.");
144         return;
145       }
146       break;
147     }
148 
149     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 
157     case ConformanceRequest::PAYLOAD_NOT_SET:
158       GOOGLE_LOG(FATAL) << "Request didn't have payload.";
159       break;
160 
161     default:
162       GOOGLE_LOG(FATAL) << "unknown payload type: " << request.payload_case();
163       break;
164   }
165 
166   conformance::FailureSet failures;
167   if (descriptor == failures.GetDescriptor()) {
168     for (const char* s : kFailures) failures.add_failure(s);
169     test_message = &failures;
170   }
171 
172   switch (request.requested_output_format()) {
173     case conformance::UNSPECIFIED:
174       GOOGLE_LOG(FATAL) << "Unspecified output format";
175       break;
176 
177     case conformance::PROTOBUF: {
178       GOOGLE_CHECK(test_message->SerializeToString(
179           response->mutable_protobuf_payload()));
180       break;
181     }
182 
183     case conformance::JSON: {
184       string proto_binary;
185       GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
186       util::Status status =
187           BinaryToJsonString(type_resolver, *type_url, proto_binary,
188                              response->mutable_json_payload());
189       if (!status.ok()) {
190         response->set_serialize_error(
191             string("Failed to serialize JSON output: ") +
192             std::string(status.message()));
193         return;
194       }
195       break;
196     }
197 
198     case conformance::TEXT_FORMAT: {
199       TextFormat::Printer printer;
200       printer.SetHideUnknownFields(!request.print_unknown_fields());
201       GOOGLE_CHECK(printer.PrintToString(*test_message,
202                                   response->mutable_text_payload()));
203       break;
204     }
205 
206     default:
207       GOOGLE_LOG(FATAL) << "Unknown output format: "
208                  << request.requested_output_format();
209   }
210 }
211 
DoTestIo()212 bool 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 
254 }  // namespace protobuf
255 }  // namespace google
256 
main()257 int main() {
258   type_resolver = NewTypeResolverForDescriptorPool(
259       kTypeUrlPrefix, DescriptorPool::generated_pool());
260   type_url = new string(GetTypeUrl(TestAllTypesProto3::descriptor()));
261   while (1) {
262     if (!google::protobuf::DoTestIo()) {
263       fprintf(stderr, "conformance-cpp: received EOF from test runner "
264                       "after %d tests, exiting\n", test_count);
265       return 0;
266     }
267   }
268 }
269