Home | History | Annotate | Download | only in conformance
      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 "conformance.pb.h"
     36 #include <google/protobuf/util/json_util.h>
     37 #include <google/protobuf/util/type_resolver_util.h>
     38 
     39 using conformance::ConformanceRequest;
     40 using conformance::ConformanceResponse;
     41 using conformance::TestAllTypes;
     42 using google::protobuf::Descriptor;
     43 using google::protobuf::DescriptorPool;
     44 using google::protobuf::internal::scoped_ptr;
     45 using google::protobuf::util::BinaryToJsonString;
     46 using google::protobuf::util::JsonToBinaryString;
     47 using google::protobuf::util::NewTypeResolverForDescriptorPool;
     48 using google::protobuf::util::Status;
     49 using google::protobuf::util::TypeResolver;
     50 using std::string;
     51 
     52 static const char kTypeUrlPrefix[] = "type.googleapis.com";
     53 
     54 static string GetTypeUrl(const Descriptor* message) {
     55   return string(kTypeUrlPrefix) + "/" + message->full_name();
     56 }
     57 
     58 int test_count = 0;
     59 bool verbose = false;
     60 TypeResolver* type_resolver;
     61 string* type_url;
     62 
     63 
     64 bool 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 
     82 void 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 
     88 void 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 
    101     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 
    111       if (!test_message.ParseFromString(proto_binary)) {
    112         response->set_runtime_error(
    113             "Parsing JSON generates invalid proto output.");
    114         return;
    115       }
    116       break;
    117     }
    118 
    119     case ConformanceRequest::PAYLOAD_NOT_SET:
    120       GOOGLE_LOG(FATAL) << "Request didn't have payload.";
    121       break;
    122   }
    123 
    124   switch (request.requested_output_format()) {
    125     case conformance::UNSPECIFIED:
    126       GOOGLE_LOG(FATAL) << "Unspecified output format";
    127       break;
    128 
    129     case conformance::PROTOBUF:
    130       GOOGLE_CHECK(
    131           test_message.SerializeToString(response->mutable_protobuf_payload()));
    132       break;
    133 
    134     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());
    139       if (!status.ok()) {
    140         response->set_serialize_error(
    141             string("Failed to serialize JSON output: ") +
    142             status.error_message().as_string());
    143         return;
    144       }
    145       break;
    146     }
    147 
    148     default:
    149       GOOGLE_LOG(FATAL) << "Unknown output format: "
    150                         << request.requested_output_format();
    151   }
    152 }
    153 
    154 bool 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 
    196 int main() {
    197   type_resolver = NewTypeResolverForDescriptorPool(
    198       kTypeUrlPrefix, DescriptorPool::generated_pool());
    199   type_url = new string(GetTypeUrl(TestAllTypes::descriptor()));
    200   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 }
    208