xref: /aosp_15_r20/external/protobuf/conformance/conformance_cpp.cc (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
2*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc.  All rights reserved.
3*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
4*1b3f573fSAndroid Build Coastguard Worker //
5*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
6*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
7*1b3f573fSAndroid Build Coastguard Worker // met:
8*1b3f573fSAndroid Build Coastguard Worker //
9*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
10*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
11*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
12*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
13*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
14*1b3f573fSAndroid Build Coastguard Worker // distribution.
15*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
16*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
17*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
18*1b3f573fSAndroid Build Coastguard Worker //
19*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*1b3f573fSAndroid Build Coastguard Worker 
31*1b3f573fSAndroid Build Coastguard Worker #include <errno.h>
32*1b3f573fSAndroid Build Coastguard Worker #include <stdarg.h>
33*1b3f573fSAndroid Build Coastguard Worker #include <unistd.h>
34*1b3f573fSAndroid Build Coastguard Worker 
35*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/message.h>
36*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/text_format.h>
37*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/util/json_util.h>
38*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/util/type_resolver_util.h>
39*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/stubs/status.h>
40*1b3f573fSAndroid Build Coastguard Worker #include "conformance.pb.h"
41*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/test_messages_proto2.pb.h>
42*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/test_messages_proto3.pb.h>
43*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/stubs/status.h>
44*1b3f573fSAndroid Build Coastguard Worker 
45*1b3f573fSAndroid Build Coastguard Worker using conformance::ConformanceRequest;
46*1b3f573fSAndroid Build Coastguard Worker using conformance::ConformanceResponse;
47*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::Descriptor;
48*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::DescriptorPool;
49*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::Message;
50*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::MessageFactory;
51*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::TextFormat;
52*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::util::BinaryToJsonString;
53*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::util::JsonParseOptions;
54*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::util::JsonToBinaryString;
55*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::util::NewTypeResolverForDescriptorPool;
56*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::util::TypeResolver;
57*1b3f573fSAndroid Build Coastguard Worker using protobuf_test_messages::proto3::TestAllTypesProto3;
58*1b3f573fSAndroid Build Coastguard Worker using protobuf_test_messages::proto2::TestAllTypesProto2;
59*1b3f573fSAndroid Build Coastguard Worker using std::string;
60*1b3f573fSAndroid Build Coastguard Worker 
61*1b3f573fSAndroid Build Coastguard Worker static const char kTypeUrlPrefix[] = "type.googleapis.com";
62*1b3f573fSAndroid Build Coastguard Worker 
63*1b3f573fSAndroid Build Coastguard Worker const char* kFailures[] = {
64*1b3f573fSAndroid Build Coastguard Worker };
65*1b3f573fSAndroid Build Coastguard Worker 
GetTypeUrl(const Descriptor * message)66*1b3f573fSAndroid Build Coastguard Worker static string GetTypeUrl(const Descriptor* message) {
67*1b3f573fSAndroid Build Coastguard Worker   return string(kTypeUrlPrefix) + "/" + message->full_name();
68*1b3f573fSAndroid Build Coastguard Worker }
69*1b3f573fSAndroid Build Coastguard Worker 
70*1b3f573fSAndroid Build Coastguard Worker int test_count = 0;
71*1b3f573fSAndroid Build Coastguard Worker bool verbose = false;
72*1b3f573fSAndroid Build Coastguard Worker TypeResolver* type_resolver;
73*1b3f573fSAndroid Build Coastguard Worker string* type_url;
74*1b3f573fSAndroid Build Coastguard Worker 
75*1b3f573fSAndroid Build Coastguard Worker namespace google {
76*1b3f573fSAndroid Build Coastguard Worker namespace protobuf {
77*1b3f573fSAndroid Build Coastguard Worker 
78*1b3f573fSAndroid Build Coastguard Worker using util::Status;
79*1b3f573fSAndroid Build Coastguard Worker 
CheckedRead(int fd,void * buf,size_t len)80*1b3f573fSAndroid Build Coastguard Worker bool CheckedRead(int fd, void *buf, size_t len) {
81*1b3f573fSAndroid Build Coastguard Worker   size_t ofs = 0;
82*1b3f573fSAndroid Build Coastguard Worker   while (len > 0) {
83*1b3f573fSAndroid Build Coastguard Worker     ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
84*1b3f573fSAndroid Build Coastguard Worker 
85*1b3f573fSAndroid Build Coastguard Worker     if (bytes_read == 0) return false;
86*1b3f573fSAndroid Build Coastguard Worker 
87*1b3f573fSAndroid Build Coastguard Worker     if (bytes_read < 0) {
88*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_LOG(FATAL) << "Error reading from test runner: " << strerror(errno);
89*1b3f573fSAndroid Build Coastguard Worker     }
90*1b3f573fSAndroid Build Coastguard Worker 
91*1b3f573fSAndroid Build Coastguard Worker     len -= bytes_read;
92*1b3f573fSAndroid Build Coastguard Worker     ofs += bytes_read;
93*1b3f573fSAndroid Build Coastguard Worker   }
94*1b3f573fSAndroid Build Coastguard Worker 
95*1b3f573fSAndroid Build Coastguard Worker   return true;
96*1b3f573fSAndroid Build Coastguard Worker }
97*1b3f573fSAndroid Build Coastguard Worker 
CheckedWrite(int fd,const void * buf,size_t len)98*1b3f573fSAndroid Build Coastguard Worker void CheckedWrite(int fd, const void *buf, size_t len) {
99*1b3f573fSAndroid Build Coastguard Worker   if (write(fd, buf, len) != len) {
100*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
101*1b3f573fSAndroid Build Coastguard Worker   }
102*1b3f573fSAndroid Build Coastguard Worker }
103*1b3f573fSAndroid Build Coastguard Worker 
DoTest(const ConformanceRequest & request,ConformanceResponse * response)104*1b3f573fSAndroid Build Coastguard Worker void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
105*1b3f573fSAndroid Build Coastguard Worker   Message *test_message;
106*1b3f573fSAndroid Build Coastguard Worker   google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
107*1b3f573fSAndroid Build Coastguard Worker   google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
108*1b3f573fSAndroid Build Coastguard Worker   const Descriptor *descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(
109*1b3f573fSAndroid Build Coastguard Worker       request.message_type());
110*1b3f573fSAndroid Build Coastguard Worker   if (!descriptor) {
111*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(FATAL) << "No such message type: " << request.message_type();
112*1b3f573fSAndroid Build Coastguard Worker   }
113*1b3f573fSAndroid Build Coastguard Worker   test_message = MessageFactory::generated_factory()->GetPrototype(descriptor)->New();
114*1b3f573fSAndroid Build Coastguard Worker 
115*1b3f573fSAndroid Build Coastguard Worker   switch (request.payload_case()) {
116*1b3f573fSAndroid Build Coastguard Worker     case ConformanceRequest::kProtobufPayload: {
117*1b3f573fSAndroid Build Coastguard Worker       if (!test_message->ParseFromString(request.protobuf_payload())) {
118*1b3f573fSAndroid Build Coastguard Worker         // Getting parse details would involve something like:
119*1b3f573fSAndroid Build Coastguard Worker         //   http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
120*1b3f573fSAndroid Build Coastguard Worker         response->set_parse_error("Parse error (no more details available).");
121*1b3f573fSAndroid Build Coastguard Worker         return;
122*1b3f573fSAndroid Build Coastguard Worker       }
123*1b3f573fSAndroid Build Coastguard Worker       break;
124*1b3f573fSAndroid Build Coastguard Worker     }
125*1b3f573fSAndroid Build Coastguard Worker 
126*1b3f573fSAndroid Build Coastguard Worker     case ConformanceRequest::kJsonPayload: {
127*1b3f573fSAndroid Build Coastguard Worker       string proto_binary;
128*1b3f573fSAndroid Build Coastguard Worker       JsonParseOptions options;
129*1b3f573fSAndroid Build Coastguard Worker       options.ignore_unknown_fields =
130*1b3f573fSAndroid Build Coastguard Worker           (request.test_category() ==
131*1b3f573fSAndroid Build Coastguard Worker               conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
132*1b3f573fSAndroid Build Coastguard Worker       util::Status status =
133*1b3f573fSAndroid Build Coastguard Worker           JsonToBinaryString(type_resolver, *type_url, request.json_payload(),
134*1b3f573fSAndroid Build Coastguard Worker                              &proto_binary, options);
135*1b3f573fSAndroid Build Coastguard Worker       if (!status.ok()) {
136*1b3f573fSAndroid Build Coastguard Worker         response->set_parse_error(string("Parse error: ") +
137*1b3f573fSAndroid Build Coastguard Worker                                   std::string(status.message()));
138*1b3f573fSAndroid Build Coastguard Worker         return;
139*1b3f573fSAndroid Build Coastguard Worker       }
140*1b3f573fSAndroid Build Coastguard Worker 
141*1b3f573fSAndroid Build Coastguard Worker       if (!test_message->ParseFromString(proto_binary)) {
142*1b3f573fSAndroid Build Coastguard Worker         response->set_runtime_error(
143*1b3f573fSAndroid Build Coastguard Worker             "Parsing JSON generates invalid proto output.");
144*1b3f573fSAndroid Build Coastguard Worker         return;
145*1b3f573fSAndroid Build Coastguard Worker       }
146*1b3f573fSAndroid Build Coastguard Worker       break;
147*1b3f573fSAndroid Build Coastguard Worker     }
148*1b3f573fSAndroid Build Coastguard Worker 
149*1b3f573fSAndroid Build Coastguard Worker     case ConformanceRequest::kTextPayload: {
150*1b3f573fSAndroid Build Coastguard Worker       if (!TextFormat::ParseFromString(request.text_payload(), test_message)) {
151*1b3f573fSAndroid Build Coastguard Worker         response->set_parse_error("Parse error");
152*1b3f573fSAndroid Build Coastguard Worker         return;
153*1b3f573fSAndroid Build Coastguard Worker       }
154*1b3f573fSAndroid Build Coastguard Worker       break;
155*1b3f573fSAndroid Build Coastguard Worker     }
156*1b3f573fSAndroid Build Coastguard Worker 
157*1b3f573fSAndroid Build Coastguard Worker     case ConformanceRequest::PAYLOAD_NOT_SET:
158*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_LOG(FATAL) << "Request didn't have payload.";
159*1b3f573fSAndroid Build Coastguard Worker       break;
160*1b3f573fSAndroid Build Coastguard Worker 
161*1b3f573fSAndroid Build Coastguard Worker     default:
162*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_LOG(FATAL) << "unknown payload type: " << request.payload_case();
163*1b3f573fSAndroid Build Coastguard Worker       break;
164*1b3f573fSAndroid Build Coastguard Worker   }
165*1b3f573fSAndroid Build Coastguard Worker 
166*1b3f573fSAndroid Build Coastguard Worker   conformance::FailureSet failures;
167*1b3f573fSAndroid Build Coastguard Worker   if (descriptor == failures.GetDescriptor()) {
168*1b3f573fSAndroid Build Coastguard Worker     for (const char* s : kFailures) failures.add_failure(s);
169*1b3f573fSAndroid Build Coastguard Worker     test_message = &failures;
170*1b3f573fSAndroid Build Coastguard Worker   }
171*1b3f573fSAndroid Build Coastguard Worker 
172*1b3f573fSAndroid Build Coastguard Worker   switch (request.requested_output_format()) {
173*1b3f573fSAndroid Build Coastguard Worker     case conformance::UNSPECIFIED:
174*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_LOG(FATAL) << "Unspecified output format";
175*1b3f573fSAndroid Build Coastguard Worker       break;
176*1b3f573fSAndroid Build Coastguard Worker 
177*1b3f573fSAndroid Build Coastguard Worker     case conformance::PROTOBUF: {
178*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_CHECK(test_message->SerializeToString(
179*1b3f573fSAndroid Build Coastguard Worker           response->mutable_protobuf_payload()));
180*1b3f573fSAndroid Build Coastguard Worker       break;
181*1b3f573fSAndroid Build Coastguard Worker     }
182*1b3f573fSAndroid Build Coastguard Worker 
183*1b3f573fSAndroid Build Coastguard Worker     case conformance::JSON: {
184*1b3f573fSAndroid Build Coastguard Worker       string proto_binary;
185*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
186*1b3f573fSAndroid Build Coastguard Worker       util::Status status =
187*1b3f573fSAndroid Build Coastguard Worker           BinaryToJsonString(type_resolver, *type_url, proto_binary,
188*1b3f573fSAndroid Build Coastguard Worker                              response->mutable_json_payload());
189*1b3f573fSAndroid Build Coastguard Worker       if (!status.ok()) {
190*1b3f573fSAndroid Build Coastguard Worker         response->set_serialize_error(
191*1b3f573fSAndroid Build Coastguard Worker             string("Failed to serialize JSON output: ") +
192*1b3f573fSAndroid Build Coastguard Worker             std::string(status.message()));
193*1b3f573fSAndroid Build Coastguard Worker         return;
194*1b3f573fSAndroid Build Coastguard Worker       }
195*1b3f573fSAndroid Build Coastguard Worker       break;
196*1b3f573fSAndroid Build Coastguard Worker     }
197*1b3f573fSAndroid Build Coastguard Worker 
198*1b3f573fSAndroid Build Coastguard Worker     case conformance::TEXT_FORMAT: {
199*1b3f573fSAndroid Build Coastguard Worker       TextFormat::Printer printer;
200*1b3f573fSAndroid Build Coastguard Worker       printer.SetHideUnknownFields(!request.print_unknown_fields());
201*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_CHECK(printer.PrintToString(*test_message,
202*1b3f573fSAndroid Build Coastguard Worker                                   response->mutable_text_payload()));
203*1b3f573fSAndroid Build Coastguard Worker       break;
204*1b3f573fSAndroid Build Coastguard Worker     }
205*1b3f573fSAndroid Build Coastguard Worker 
206*1b3f573fSAndroid Build Coastguard Worker     default:
207*1b3f573fSAndroid Build Coastguard Worker       GOOGLE_LOG(FATAL) << "Unknown output format: "
208*1b3f573fSAndroid Build Coastguard Worker                  << request.requested_output_format();
209*1b3f573fSAndroid Build Coastguard Worker   }
210*1b3f573fSAndroid Build Coastguard Worker }
211*1b3f573fSAndroid Build Coastguard Worker 
DoTestIo()212*1b3f573fSAndroid Build Coastguard Worker bool DoTestIo() {
213*1b3f573fSAndroid Build Coastguard Worker   string serialized_input;
214*1b3f573fSAndroid Build Coastguard Worker   string serialized_output;
215*1b3f573fSAndroid Build Coastguard Worker   ConformanceRequest request;
216*1b3f573fSAndroid Build Coastguard Worker   ConformanceResponse response;
217*1b3f573fSAndroid Build Coastguard Worker   uint32_t bytes;
218*1b3f573fSAndroid Build Coastguard Worker 
219*1b3f573fSAndroid Build Coastguard Worker   if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
220*1b3f573fSAndroid Build Coastguard Worker     // EOF.
221*1b3f573fSAndroid Build Coastguard Worker     return false;
222*1b3f573fSAndroid Build Coastguard Worker   }
223*1b3f573fSAndroid Build Coastguard Worker 
224*1b3f573fSAndroid Build Coastguard Worker   serialized_input.resize(bytes);
225*1b3f573fSAndroid Build Coastguard Worker 
226*1b3f573fSAndroid Build Coastguard Worker   if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
227*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
228*1b3f573fSAndroid Build Coastguard Worker   }
229*1b3f573fSAndroid Build Coastguard Worker 
230*1b3f573fSAndroid Build Coastguard Worker   if (!request.ParseFromString(serialized_input)) {
231*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
232*1b3f573fSAndroid Build Coastguard Worker     return false;
233*1b3f573fSAndroid Build Coastguard Worker   }
234*1b3f573fSAndroid Build Coastguard Worker 
235*1b3f573fSAndroid Build Coastguard Worker   DoTest(request, &response);
236*1b3f573fSAndroid Build Coastguard Worker 
237*1b3f573fSAndroid Build Coastguard Worker   response.SerializeToString(&serialized_output);
238*1b3f573fSAndroid Build Coastguard Worker 
239*1b3f573fSAndroid Build Coastguard Worker   bytes = serialized_output.size();
240*1b3f573fSAndroid Build Coastguard Worker   CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
241*1b3f573fSAndroid Build Coastguard Worker   CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
242*1b3f573fSAndroid Build Coastguard Worker 
243*1b3f573fSAndroid Build Coastguard Worker   if (verbose) {
244*1b3f573fSAndroid Build Coastguard Worker     fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
245*1b3f573fSAndroid Build Coastguard Worker             request.ShortDebugString().c_str(),
246*1b3f573fSAndroid Build Coastguard Worker             response.ShortDebugString().c_str());
247*1b3f573fSAndroid Build Coastguard Worker   }
248*1b3f573fSAndroid Build Coastguard Worker 
249*1b3f573fSAndroid Build Coastguard Worker   test_count++;
250*1b3f573fSAndroid Build Coastguard Worker 
251*1b3f573fSAndroid Build Coastguard Worker   return true;
252*1b3f573fSAndroid Build Coastguard Worker }
253*1b3f573fSAndroid Build Coastguard Worker 
254*1b3f573fSAndroid Build Coastguard Worker }  // namespace protobuf
255*1b3f573fSAndroid Build Coastguard Worker }  // namespace google
256*1b3f573fSAndroid Build Coastguard Worker 
main()257*1b3f573fSAndroid Build Coastguard Worker int main() {
258*1b3f573fSAndroid Build Coastguard Worker   type_resolver = NewTypeResolverForDescriptorPool(
259*1b3f573fSAndroid Build Coastguard Worker       kTypeUrlPrefix, DescriptorPool::generated_pool());
260*1b3f573fSAndroid Build Coastguard Worker   type_url = new string(GetTypeUrl(TestAllTypesProto3::descriptor()));
261*1b3f573fSAndroid Build Coastguard Worker   while (1) {
262*1b3f573fSAndroid Build Coastguard Worker     if (!google::protobuf::DoTestIo()) {
263*1b3f573fSAndroid Build Coastguard Worker       fprintf(stderr, "conformance-cpp: received EOF from test runner "
264*1b3f573fSAndroid Build Coastguard Worker                       "after %d tests, exiting\n", test_count);
265*1b3f573fSAndroid Build Coastguard Worker       return 0;
266*1b3f573fSAndroid Build Coastguard Worker     }
267*1b3f573fSAndroid Build Coastguard Worker   }
268*1b3f573fSAndroid Build Coastguard Worker }
269