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