blob: 37ee36e24c51f6cd5721998c9c2f5e583260683c [file] [log] [blame]
Josh Haberman325392d2015-08-17 12:30:49 -07001#!/usr/bin/env python
Josh Haberman325392d2015-08-17 12:30:49 -07002# 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
Josh Habermana3faf082015-12-02 13:21:42 -080040from google.protobuf import json_format
Joshua Habermanf1ce60e2016-12-03 11:51:25 -050041from google.protobuf import message
42from google.protobuf import test_messages_proto3_pb2
Yilun Chong18a0c2c2017-06-27 18:24:15 -070043from google.protobuf import test_messages_proto2_pb2
Yilun Chongcb95a7f2019-01-11 11:40:52 -080044from google.protobuf import text_format
Josh Haberman325392d2015-08-17 12:30:49 -070045import 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
Josh Haberman874eb362015-12-04 15:03:12 -080053class ProtocolError(Exception):
54 pass
55
Josh Haberman325392d2015-08-17 12:30:49 -070056def do_test(request):
Yilun Chong0adb74c2019-01-08 15:06:30 -080057 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()
Yilun Chongd8c25012019-02-22 18:13:33 +080065 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:
Yilun Chong0adb74c2019-01-08 15:06:30 -080071 # 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
Yilun Chong3adb0542017-06-30 17:22:32 -0700113 isProto3 = (request.message_type == "protobuf_test_messages.proto3.TestAllTypesProto3")
Yilun Chong18a0c2c2017-06-27 18:24:15 -0700114 isJson = (request.WhichOneof('payload') == 'json_payload')
Yilun Chong020a24d2017-06-29 11:33:22 -0700115 isProto2 = (request.message_type == "protobuf_test_messages.proto2.TestAllTypesProto2")
Yilun Chong0adb74c2019-01-08 15:06:30 -0800116
Yilun Chong020a24d2017-06-29 11:33:22 -0700117 if (not isProto3) and (not isJson) and (not isProto2):
118 raise ProtocolError("Protobuf request doesn't have specific payload type")
Yilun Chong0adb74c2019-01-08 15:06:30 -0800119
Yilun Chong020a24d2017-06-29 11:33:22 -0700120 test_message = test_messages_proto2_pb2.TestAllTypesProto2() if isProto2 else \
Yilun Chong3adb0542017-06-30 17:22:32 -0700121 test_messages_proto3_pb2.TestAllTypesProto3()
122
Josh Haberman325392d2015-08-17 12:30:49 -0700123 try:
124 if request.WhichOneof('payload') == 'protobuf_payload':
Yilun Chong020a24d2017-06-29 11:33:22 -0700125 try:
126 test_message.ParseFromString(request.protobuf_payload)
127 except message.DecodeError as e:
128 response.parse_error = str(e)
Yilun Chong0adb74c2019-01-08 15:06:30 -0800129 return response
130
Josh Haberman325392d2015-08-17 12:30:49 -0700131 elif request.WhichOneof('payload') == 'json_payload':
Josh Habermana3faf082015-12-02 13:21:42 -0800132 try:
Feng Xiao6bbe1972018-08-08 17:00:41 -0700133 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)
Bo Yangcc8ca5b2016-09-19 13:45:07 -0700138 except Exception as e:
Josh Habermana3faf082015-12-02 13:21:42 -0800139 response.parse_error = str(e)
140 return response
Josh Haberman325392d2015-08-17 12:30:49 -0700141
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800142 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
Josh Haberman325392d2015-08-17 12:30:49 -0700149 else:
Josh Haberman874eb362015-12-04 15:03:12 -0800150 raise ProtocolError("Request didn't have payload.")
Josh Haberman325392d2015-08-17 12:30:49 -0700151
152 if request.requested_output_format == conformance_pb2.UNSPECIFIED:
Josh Haberman874eb362015-12-04 15:03:12 -0800153 raise ProtocolError("Unspecified output format")
Josh Haberman325392d2015-08-17 12:30:49 -0700154
155 elif request.requested_output_format == conformance_pb2.PROTOBUF:
Yilun Chong020a24d2017-06-29 11:33:22 -0700156 response.protobuf_payload = test_message.SerializeToString()
Josh Haberman325392d2015-08-17 12:30:49 -0700157
158 elif request.requested_output_format == conformance_pb2.JSON:
Yilun Chong0adb74c2019-01-08 15:06:30 -0800159 try:
Joshua Haberman503a2112020-04-06 09:57:03 -0700160 response.json_payload = json_format.MessageToJson(test_message)
Bo Yangcc8ca5b2016-09-19 13:45:07 -0700161 except Exception as e:
162 response.serialize_error = str(e)
163 return response
Josh Habermana3faf082015-12-02 13:21:42 -0800164
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800165 elif request.requested_output_format == conformance_pb2.TEXT_FORMAT:
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700166 response.text_payload = text_format.MessageToString(
167 test_message, print_unknown_fields=request.print_unknown_fields)
Yilun Chongcb95a7f2019-01-11 11:40:52 -0800168
Josh Haberman325392d2015-08-17 12:30:49 -0700169 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:
Josh Haberman874eb362015-12-04 15:03:12 -0800187 raise IOError("I/O error")
Josh Haberman325392d2015-08-17 12:30:49 -0700188
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)