• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Protocol Buffers - Google's data interchange format
3# Copyright 2008 Google Inc.  All rights reserved.
4# https://developers.google.com/protocol-buffers/
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met:
9#
10#     * Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12#     * Redistributions in binary form must reproduce the above
13# copyright notice, this list of conditions and the following disclaimer
14# in the documentation and/or other materials provided with the
15# distribution.
16#     * Neither the name of Google Inc. nor the names of its
17# contributors may be used to endorse or promote products derived from
18# this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32"""A conformance test implementation for the Python protobuf library.
33
34See conformance.proto for more information.
35"""
36
37import struct
38import sys
39import os
40from google.protobuf import json_format
41from google.protobuf import message
42from google.protobuf import test_messages_proto3_pb2
43from google.protobuf import test_messages_proto2_pb2
44from google.protobuf import text_format
45import conformance_pb2
46
47sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
48sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
49
50test_count = 0
51verbose = False
52
53class ProtocolError(Exception):
54  pass
55
56def do_test(request):
57  response = conformance_pb2.ConformanceResponse()
58
59  if request.message_type == "conformance.FailureSet":
60    failure_set = conformance_pb2.FailureSet()
61    failures = []
62    # TODO(gerbens): Remove, this is a hack to detect if the old vs new
63    # parser is used by the cpp code. Relying on a bug in the old parser.
64    hack_proto = test_messages_proto2_pb2.TestAllTypesProto2()
65    old_parser = True
66    try:
67      hack_proto.ParseFromString(b"\322\002\001")
68    except message.DecodeError as e:
69      old_parser = False
70    if old_parser:
71      # the string above is one of the failing conformance test strings of the
72      # old parser. If we succeed the c++ implementation is using the old
73      # parser so we add the list of failing conformance tests.
74      failures = [
75          "Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
76          "Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
77          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.BOOL",
78          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.DOUBLE",
79          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.ENUM",
80          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED32",
81          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED64",
82          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FLOAT",
83          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT32",
84          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT64",
85          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED32",
86          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED64",
87          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT32",
88          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT64",
89          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT32",
90          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT64",
91          "Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
92          "Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
93          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.BOOL",
94          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.DOUBLE",
95          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.ENUM",
96          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED32",
97          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED64",
98          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FLOAT",
99          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT32",
100          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT64",
101          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED32",
102          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED64",
103          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32",
104          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64",
105          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32",
106          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64",
107      ]
108    for x in failures:
109      failure_set.failure.append(x)
110    response.protobuf_payload = failure_set.SerializeToString()
111    return response
112
113  isProto3 = (request.message_type == "protobuf_test_messages.proto3.TestAllTypesProto3")
114  isJson = (request.WhichOneof('payload') == 'json_payload')
115  isProto2 = (request.message_type == "protobuf_test_messages.proto2.TestAllTypesProto2")
116
117  if (not isProto3) and (not isJson) and (not isProto2):
118    raise ProtocolError("Protobuf request doesn't have specific payload type")
119
120  test_message = test_messages_proto2_pb2.TestAllTypesProto2() if isProto2 else \
121    test_messages_proto3_pb2.TestAllTypesProto3()
122
123  try:
124    if request.WhichOneof('payload') == 'protobuf_payload':
125      try:
126        test_message.ParseFromString(request.protobuf_payload)
127      except message.DecodeError as e:
128        response.parse_error = str(e)
129        return response
130
131    elif request.WhichOneof('payload') == 'json_payload':
132      try:
133        ignore_unknown_fields = \
134            request.test_category == \
135                conformance_pb2.JSON_IGNORE_UNKNOWN_PARSING_TEST
136        json_format.Parse(request.json_payload, test_message,
137                          ignore_unknown_fields)
138      except Exception as e:
139        response.parse_error = str(e)
140        return response
141
142    elif request.WhichOneof('payload') == 'text_payload':
143      try:
144        text_format.Parse(request.text_payload, test_message)
145      except Exception as e:
146        response.parse_error = str(e)
147        return response
148
149    else:
150      raise ProtocolError("Request didn't have payload.")
151
152    if request.requested_output_format == conformance_pb2.UNSPECIFIED:
153      raise ProtocolError("Unspecified output format")
154
155    elif request.requested_output_format == conformance_pb2.PROTOBUF:
156      response.protobuf_payload = test_message.SerializeToString()
157
158    elif request.requested_output_format == conformance_pb2.JSON:
159      try:
160        response.json_payload = json_format.MessageToJson(test_message)
161      except Exception as e:
162        response.serialize_error = str(e)
163        return response
164
165    elif request.requested_output_format == conformance_pb2.TEXT_FORMAT:
166      response.text_payload = text_format.MessageToString(
167          test_message, print_unknown_fields=request.print_unknown_fields)
168
169  except Exception as e:
170    response.runtime_error = str(e)
171
172  return response
173
174def do_test_io():
175  length_bytes = sys.stdin.read(4)
176  if len(length_bytes) == 0:
177    return False   # EOF
178  elif len(length_bytes) != 4:
179    raise IOError("I/O error")
180
181  # "I" is "unsigned int", so this depends on running on a platform with
182  # 32-bit "unsigned int" type.  The Python struct module unfortunately
183  # has no format specifier for uint32_t.
184  length = struct.unpack("<I", length_bytes)[0]
185  serialized_request = sys.stdin.read(length)
186  if len(serialized_request) != length:
187    raise IOError("I/O error")
188
189  request = conformance_pb2.ConformanceRequest()
190  request.ParseFromString(serialized_request)
191
192  response = do_test(request)
193
194  serialized_response = response.SerializeToString()
195  sys.stdout.write(struct.pack("<I", len(serialized_response)))
196  sys.stdout.write(serialized_response)
197  sys.stdout.flush()
198
199  if verbose:
200    sys.stderr.write("conformance_python: request=%s, response=%s\n" % (
201                       request.ShortDebugString().c_str(),
202                       response.ShortDebugString().c_str()))
203
204  global test_count
205  test_count += 1
206
207  return True
208
209while True:
210  if not do_test_io():
211    sys.stderr.write("conformance_python: received EOF from test runner " +
212                     "after %s tests, exiting\n" % (test_count))
213    sys.exit(0)
214