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# TODO(robinson): Flesh this out considerably. We focused on reflection_test.py 34# first, since it's testing the subtler code, and since it provides decent 35# indirect testing of the protocol compiler output. 36 37"""Unittest that directly tests the output of the pure-Python protocol 38compiler. See //google/protobuf/internal/reflection_test.py for a test which 39further ensures that we can use Python protocol message objects as we expect. 40""" 41 42__author__ = 'robinson@google.com (Will Robinson)' 43 44try: 45 import unittest2 as unittest #PY26 46except ImportError: 47 import unittest 48 49from google.protobuf.internal import test_bad_identifiers_pb2 50from google.protobuf import unittest_custom_options_pb2 51from google.protobuf import unittest_import_pb2 52from google.protobuf import unittest_import_public_pb2 53from google.protobuf import unittest_mset_pb2 54from google.protobuf import unittest_mset_wire_format_pb2 55from google.protobuf import unittest_no_generic_services_pb2 56from google.protobuf import unittest_pb2 57from google.protobuf import service 58from google.protobuf import symbol_database 59 60MAX_EXTENSION = 536870912 61 62 63class GeneratorTest(unittest.TestCase): 64 65 def testNestedMessageDescriptor(self): 66 field_name = 'optional_nested_message' 67 proto_type = unittest_pb2.TestAllTypes 68 self.assertEqual( 69 proto_type.NestedMessage.DESCRIPTOR, 70 proto_type.DESCRIPTOR.fields_by_name[field_name].message_type) 71 72 def testEnums(self): 73 # We test only module-level enums here. 74 # TODO(robinson): Examine descriptors directly to check 75 # enum descriptor output. 76 self.assertEqual(4, unittest_pb2.FOREIGN_FOO) 77 self.assertEqual(5, unittest_pb2.FOREIGN_BAR) 78 self.assertEqual(6, unittest_pb2.FOREIGN_BAZ) 79 80 proto = unittest_pb2.TestAllTypes() 81 self.assertEqual(1, proto.FOO) 82 self.assertEqual(1, unittest_pb2.TestAllTypes.FOO) 83 self.assertEqual(2, proto.BAR) 84 self.assertEqual(2, unittest_pb2.TestAllTypes.BAR) 85 self.assertEqual(3, proto.BAZ) 86 self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ) 87 88 def testExtremeDefaultValues(self): 89 message = unittest_pb2.TestExtremeDefaultValues() 90 91 # Python pre-2.6 does not have isinf() or isnan() functions, so we have 92 # to provide our own. 93 def isnan(val): 94 # NaN is never equal to itself. 95 return val != val 96 def isinf(val): 97 # Infinity times zero equals NaN. 98 return not isnan(val) and isnan(val * 0) 99 100 self.assertTrue(isinf(message.inf_double)) 101 self.assertTrue(message.inf_double > 0) 102 self.assertTrue(isinf(message.neg_inf_double)) 103 self.assertTrue(message.neg_inf_double < 0) 104 self.assertTrue(isnan(message.nan_double)) 105 106 self.assertTrue(isinf(message.inf_float)) 107 self.assertTrue(message.inf_float > 0) 108 self.assertTrue(isinf(message.neg_inf_float)) 109 self.assertTrue(message.neg_inf_float < 0) 110 self.assertTrue(isnan(message.nan_float)) 111 self.assertEqual("? ? ?? ?? ??? ??/ ??-", message.cpp_trigraph) 112 113 def testHasDefaultValues(self): 114 desc = unittest_pb2.TestAllTypes.DESCRIPTOR 115 116 expected_has_default_by_name = { 117 'optional_int32': False, 118 'repeated_int32': False, 119 'optional_nested_message': False, 120 'default_int32': True, 121 } 122 123 has_default_by_name = dict( 124 [(f.name, f.has_default_value) 125 for f in desc.fields 126 if f.name in expected_has_default_by_name]) 127 self.assertEqual(expected_has_default_by_name, has_default_by_name) 128 129 def testContainingTypeBehaviorForExtensions(self): 130 self.assertEqual(unittest_pb2.optional_int32_extension.containing_type, 131 unittest_pb2.TestAllExtensions.DESCRIPTOR) 132 self.assertEqual(unittest_pb2.TestRequired.single.containing_type, 133 unittest_pb2.TestAllExtensions.DESCRIPTOR) 134 135 def testExtensionScope(self): 136 self.assertEqual(unittest_pb2.optional_int32_extension.extension_scope, 137 None) 138 self.assertEqual(unittest_pb2.TestRequired.single.extension_scope, 139 unittest_pb2.TestRequired.DESCRIPTOR) 140 141 def testIsExtension(self): 142 self.assertTrue(unittest_pb2.optional_int32_extension.is_extension) 143 self.assertTrue(unittest_pb2.TestRequired.single.is_extension) 144 145 message_descriptor = unittest_pb2.TestRequired.DESCRIPTOR 146 non_extension_descriptor = message_descriptor.fields_by_name['a'] 147 self.assertTrue(not non_extension_descriptor.is_extension) 148 149 def testOptions(self): 150 proto = unittest_mset_wire_format_pb2.TestMessageSet() 151 self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format) 152 153 def testMessageWithCustomOptions(self): 154 proto = unittest_custom_options_pb2.TestMessageWithCustomOptions() 155 enum_options = proto.DESCRIPTOR.enum_types_by_name['AnEnum'].GetOptions() 156 self.assertTrue(enum_options is not None) 157 # TODO(gps): We really should test for the presence of the enum_opt1 158 # extension and for its value to be set to -789. 159 160 def testNestedTypes(self): 161 self.assertEqual( 162 set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types), 163 set([ 164 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR, 165 unittest_pb2.TestAllTypes.OptionalGroup.DESCRIPTOR, 166 unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR, 167 ])) 168 self.assertEqual(unittest_pb2.TestEmptyMessage.DESCRIPTOR.nested_types, []) 169 self.assertEqual( 170 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.nested_types, []) 171 172 def testContainingType(self): 173 self.assertTrue( 174 unittest_pb2.TestEmptyMessage.DESCRIPTOR.containing_type is None) 175 self.assertTrue( 176 unittest_pb2.TestAllTypes.DESCRIPTOR.containing_type is None) 177 self.assertEqual( 178 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, 179 unittest_pb2.TestAllTypes.DESCRIPTOR) 180 self.assertEqual( 181 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, 182 unittest_pb2.TestAllTypes.DESCRIPTOR) 183 self.assertEqual( 184 unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR.containing_type, 185 unittest_pb2.TestAllTypes.DESCRIPTOR) 186 187 def testContainingTypeInEnumDescriptor(self): 188 self.assertTrue(unittest_pb2._FOREIGNENUM.containing_type is None) 189 self.assertEqual(unittest_pb2._TESTALLTYPES_NESTEDENUM.containing_type, 190 unittest_pb2.TestAllTypes.DESCRIPTOR) 191 192 def testPackage(self): 193 self.assertEqual( 194 unittest_pb2.TestAllTypes.DESCRIPTOR.file.package, 195 'protobuf_unittest') 196 desc = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR 197 self.assertEqual(desc.file.package, 'protobuf_unittest') 198 self.assertEqual( 199 unittest_import_pb2.ImportMessage.DESCRIPTOR.file.package, 200 'protobuf_unittest_import') 201 202 self.assertEqual( 203 unittest_pb2._FOREIGNENUM.file.package, 'protobuf_unittest') 204 self.assertEqual( 205 unittest_pb2._TESTALLTYPES_NESTEDENUM.file.package, 206 'protobuf_unittest') 207 self.assertEqual( 208 unittest_import_pb2._IMPORTENUM.file.package, 209 'protobuf_unittest_import') 210 211 def testExtensionRange(self): 212 self.assertEqual( 213 unittest_pb2.TestAllTypes.DESCRIPTOR.extension_ranges, []) 214 self.assertEqual( 215 unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges, 216 [(1, MAX_EXTENSION)]) 217 self.assertEqual( 218 unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges, 219 [(42, 43), (4143, 4244), (65536, MAX_EXTENSION)]) 220 221 def testFileDescriptor(self): 222 self.assertEqual(unittest_pb2.DESCRIPTOR.name, 223 'google/protobuf/unittest.proto') 224 self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest') 225 self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None) 226 self.assertEqual(unittest_pb2.DESCRIPTOR.dependencies, 227 [unittest_import_pb2.DESCRIPTOR]) 228 self.assertEqual(unittest_import_pb2.DESCRIPTOR.dependencies, 229 [unittest_import_public_pb2.DESCRIPTOR]) 230 231 def testNoGenericServices(self): 232 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage")) 233 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "FOO")) 234 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "test_extension")) 235 236 # Make sure unittest_no_generic_services_pb2 has no services subclassing 237 # Proto2 Service class. 238 if hasattr(unittest_no_generic_services_pb2, "TestService"): 239 self.assertFalse(issubclass(unittest_no_generic_services_pb2.TestService, 240 service.Service)) 241 242 def testMessageTypesByName(self): 243 file_type = unittest_pb2.DESCRIPTOR 244 self.assertEqual( 245 unittest_pb2._TESTALLTYPES, 246 file_type.message_types_by_name[unittest_pb2._TESTALLTYPES.name]) 247 248 # Nested messages shouldn't be included in the message_types_by_name 249 # dictionary (like in the C++ API). 250 self.assertFalse( 251 unittest_pb2._TESTALLTYPES_NESTEDMESSAGE.name in 252 file_type.message_types_by_name) 253 254 def testEnumTypesByName(self): 255 file_type = unittest_pb2.DESCRIPTOR 256 self.assertEqual( 257 unittest_pb2._FOREIGNENUM, 258 file_type.enum_types_by_name[unittest_pb2._FOREIGNENUM.name]) 259 260 def testExtensionsByName(self): 261 file_type = unittest_pb2.DESCRIPTOR 262 self.assertEqual( 263 unittest_pb2.my_extension_string, 264 file_type.extensions_by_name[unittest_pb2.my_extension_string.name]) 265 266 def testPublicImports(self): 267 # Test public imports as embedded message. 268 all_type_proto = unittest_pb2.TestAllTypes() 269 self.assertEqual(0, all_type_proto.optional_public_import_message.e) 270 271 # PublicImportMessage is actually defined in unittest_import_public_pb2 272 # module, and is public imported by unittest_import_pb2 module. 273 public_import_proto = unittest_import_pb2.PublicImportMessage() 274 self.assertEqual(0, public_import_proto.e) 275 self.assertTrue(unittest_import_public_pb2.PublicImportMessage is 276 unittest_import_pb2.PublicImportMessage) 277 278 def testBadIdentifiers(self): 279 # We're just testing that the code was imported without problems. 280 message = test_bad_identifiers_pb2.TestBadIdentifiers() 281 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.message], 282 "foo") 283 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.descriptor], 284 "bar") 285 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.reflection], 286 "baz") 287 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.service], 288 "qux") 289 290 def testOneof(self): 291 desc = unittest_pb2.TestAllTypes.DESCRIPTOR 292 self.assertEqual(1, len(desc.oneofs)) 293 self.assertEqual('oneof_field', desc.oneofs[0].name) 294 self.assertEqual(0, desc.oneofs[0].index) 295 self.assertIs(desc, desc.oneofs[0].containing_type) 296 self.assertIs(desc.oneofs[0], desc.oneofs_by_name['oneof_field']) 297 nested_names = set(['oneof_uint32', 'oneof_nested_message', 298 'oneof_string', 'oneof_bytes']) 299 self.assertEqual( 300 nested_names, 301 set([field.name for field in desc.oneofs[0].fields])) 302 for field_name, field_desc in desc.fields_by_name.items(): 303 if field_name in nested_names: 304 self.assertIs(desc.oneofs[0], field_desc.containing_oneof) 305 else: 306 self.assertIsNone(field_desc.containing_oneof) 307 308 309class SymbolDatabaseRegistrationTest(unittest.TestCase): 310 """Checks that messages, enums and files are correctly registered.""" 311 312 def testGetSymbol(self): 313 self.assertEqual( 314 unittest_pb2.TestAllTypes, symbol_database.Default().GetSymbol( 315 'protobuf_unittest.TestAllTypes')) 316 self.assertEqual( 317 unittest_pb2.TestAllTypes.NestedMessage, 318 symbol_database.Default().GetSymbol( 319 'protobuf_unittest.TestAllTypes.NestedMessage')) 320 with self.assertRaises(KeyError): 321 symbol_database.Default().GetSymbol('protobuf_unittest.NestedMessage') 322 self.assertEqual( 323 unittest_pb2.TestAllTypes.OptionalGroup, 324 symbol_database.Default().GetSymbol( 325 'protobuf_unittest.TestAllTypes.OptionalGroup')) 326 self.assertEqual( 327 unittest_pb2.TestAllTypes.RepeatedGroup, 328 symbol_database.Default().GetSymbol( 329 'protobuf_unittest.TestAllTypes.RepeatedGroup')) 330 331 def testEnums(self): 332 self.assertEqual( 333 'protobuf_unittest.ForeignEnum', 334 symbol_database.Default().pool.FindEnumTypeByName( 335 'protobuf_unittest.ForeignEnum').full_name) 336 self.assertEqual( 337 'protobuf_unittest.TestAllTypes.NestedEnum', 338 symbol_database.Default().pool.FindEnumTypeByName( 339 'protobuf_unittest.TestAllTypes.NestedEnum').full_name) 340 341 def testFindFileByName(self): 342 self.assertEqual( 343 'google/protobuf/unittest.proto', 344 symbol_database.Default().pool.FindFileByName( 345 'google/protobuf/unittest.proto').name) 346 347if __name__ == '__main__': 348 unittest.main() 349