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