1# Protocol Buffers - Google's data interchange format 2# Copyright 2008 Google Inc. All rights reserved. 3# 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file or at 6# https://developers.google.com/open-source/licenses/bsd 7 8# TODO: Flesh this out considerably. We focused on reflection_test.py 9# first, since it's testing the subtler code, and since it provides decent 10# indirect testing of the protocol compiler output. 11 12"""Unittest that directly tests the output of the pure-Python protocol 13compiler. See //google/protobuf/internal/reflection_test.py for a test which 14further ensures that we can use Python protocol message objects as we expect. 15""" 16 17__author__ = 'robinson@google.com (Will Robinson)' 18 19import unittest 20 21from google.protobuf.internal import test_bad_identifiers_pb2 22from google.protobuf import service 23from google.protobuf import symbol_database 24from google.protobuf import unittest_import_pb2 25from google.protobuf import unittest_import_public_pb2 26from google.protobuf import unittest_mset_pb2 27from google.protobuf import unittest_mset_wire_format_pb2 28from google.protobuf import unittest_pb2 29from google.protobuf import unittest_retention_pb2 30from google.protobuf import unittest_custom_options_pb2 31from google.protobuf import unittest_no_generic_services_pb2 32 33MAX_EXTENSION = 536870912 34 35 36class GeneratorTest(unittest.TestCase): 37 38 def testNestedMessageDescriptor(self): 39 field_name = 'optional_nested_message' 40 proto_type = unittest_pb2.TestAllTypes 41 self.assertEqual( 42 proto_type.NestedMessage.DESCRIPTOR, 43 proto_type.DESCRIPTOR.fields_by_name[field_name].message_type) 44 45 def testEnums(self): 46 # We test only module-level enums here. 47 # TODO: Examine descriptors directly to check 48 # enum descriptor output. 49 self.assertEqual(4, unittest_pb2.FOREIGN_FOO) 50 self.assertEqual(5, unittest_pb2.FOREIGN_BAR) 51 self.assertEqual(6, unittest_pb2.FOREIGN_BAZ) 52 53 proto = unittest_pb2.TestAllTypes() 54 self.assertEqual(1, proto.FOO) 55 self.assertEqual(1, unittest_pb2.TestAllTypes.FOO) 56 self.assertEqual(2, proto.BAR) 57 self.assertEqual(2, unittest_pb2.TestAllTypes.BAR) 58 self.assertEqual(3, proto.BAZ) 59 self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ) 60 61 def testExtremeDefaultValues(self): 62 message = unittest_pb2.TestExtremeDefaultValues() 63 64 # Python pre-2.6 does not have isinf() or isnan() functions, so we have 65 # to provide our own. 66 def isnan(val): 67 # NaN is never equal to itself. 68 return val != val 69 def isinf(val): 70 # Infinity times zero equals NaN. 71 return not isnan(val) and isnan(val * 0) 72 73 self.assertTrue(isinf(message.inf_double)) 74 self.assertTrue(message.inf_double > 0) 75 self.assertTrue(isinf(message.neg_inf_double)) 76 self.assertTrue(message.neg_inf_double < 0) 77 self.assertTrue(isnan(message.nan_double)) 78 79 self.assertTrue(isinf(message.inf_float)) 80 self.assertTrue(message.inf_float > 0) 81 self.assertTrue(isinf(message.neg_inf_float)) 82 self.assertTrue(message.neg_inf_float < 0) 83 self.assertTrue(isnan(message.nan_float)) 84 self.assertEqual("? ? ?? ?? ??? ??/ ??-", message.cpp_trigraph) 85 86 def testHasDefaultValues(self): 87 desc = unittest_pb2.TestAllTypes.DESCRIPTOR 88 89 expected_has_default_by_name = { 90 'optional_int32': False, 91 'repeated_int32': False, 92 'optional_nested_message': False, 93 'default_int32': True, 94 } 95 96 has_default_by_name = dict( 97 [(f.name, f.has_default_value) 98 for f in desc.fields 99 if f.name in expected_has_default_by_name]) 100 self.assertEqual(expected_has_default_by_name, has_default_by_name) 101 102 def testContainingTypeBehaviorForExtensions(self): 103 self.assertEqual(unittest_pb2.optional_int32_extension.containing_type, 104 unittest_pb2.TestAllExtensions.DESCRIPTOR) 105 self.assertEqual(unittest_pb2.TestRequired.single.containing_type, 106 unittest_pb2.TestAllExtensions.DESCRIPTOR) 107 108 def testExtensionScope(self): 109 self.assertEqual(unittest_pb2.optional_int32_extension.extension_scope, 110 None) 111 self.assertEqual(unittest_pb2.TestRequired.single.extension_scope, 112 unittest_pb2.TestRequired.DESCRIPTOR) 113 114 def testIsExtension(self): 115 self.assertTrue(unittest_pb2.optional_int32_extension.is_extension) 116 self.assertTrue(unittest_pb2.TestRequired.single.is_extension) 117 118 message_descriptor = unittest_pb2.TestRequired.DESCRIPTOR 119 non_extension_descriptor = message_descriptor.fields_by_name['a'] 120 self.assertTrue(not non_extension_descriptor.is_extension) 121 122 def testOptions(self): 123 proto = unittest_mset_wire_format_pb2.TestMessageSet() 124 self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format) 125 126 def testMessageWithCustomOptions(self): 127 proto = unittest_custom_options_pb2.TestMessageWithCustomOptions() 128 enum_options = proto.DESCRIPTOR.enum_types_by_name['AnEnum'].GetOptions() 129 self.assertTrue(enum_options is not None) 130 # TODO: We really should test for the presence of the enum_opt1 131 # extension and for its value to be set to -789. 132 133 # Options that are explicitly marked RETENTION_SOURCE should not be present 134 # in the descriptors in the binary. 135 def testOptionRetention(self): 136 # Direct options 137 options = unittest_retention_pb2.DESCRIPTOR.GetOptions() 138 self.assertTrue(options.HasExtension(unittest_retention_pb2.plain_option)) 139 self.assertTrue( 140 options.HasExtension(unittest_retention_pb2.runtime_retention_option) 141 ) 142 self.assertFalse( 143 options.HasExtension(unittest_retention_pb2.source_retention_option) 144 ) 145 146 def check_options_message_is_stripped_correctly(options): 147 self.assertEqual(options.plain_field, 1) 148 self.assertEqual(options.runtime_retention_field, 2) 149 self.assertFalse(options.HasField('source_retention_field')) 150 self.assertEqual(options.source_retention_field, 0) 151 152 # Verify that our test OptionsMessage is stripped correctly on all 153 # different entity types. 154 check_options_message_is_stripped_correctly( 155 options.Extensions[unittest_retention_pb2.file_option] 156 ) 157 check_options_message_is_stripped_correctly( 158 unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.GetOptions().Extensions[ 159 unittest_retention_pb2.message_option 160 ] 161 ) 162 check_options_message_is_stripped_correctly( 163 unittest_retention_pb2.TopLevelMessage.NestedMessage.DESCRIPTOR.GetOptions().Extensions[ 164 unittest_retention_pb2.message_option 165 ] 166 ) 167 check_options_message_is_stripped_correctly( 168 unittest_retention_pb2._TOPLEVELENUM.GetOptions().Extensions[ 169 unittest_retention_pb2.enum_option 170 ] 171 ) 172 check_options_message_is_stripped_correctly( 173 unittest_retention_pb2._TOPLEVELMESSAGE_NESTEDENUM.GetOptions().Extensions[ 174 unittest_retention_pb2.enum_option 175 ] 176 ) 177 check_options_message_is_stripped_correctly( 178 unittest_retention_pb2._TOPLEVELENUM.values[0] 179 .GetOptions() 180 .Extensions[unittest_retention_pb2.enum_entry_option] 181 ) 182 check_options_message_is_stripped_correctly( 183 unittest_retention_pb2.DESCRIPTOR.extensions_by_name['i'] 184 .GetOptions() 185 .Extensions[unittest_retention_pb2.field_option] 186 ) 187 check_options_message_is_stripped_correctly( 188 unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.fields[0] 189 .GetOptions() 190 .Extensions[unittest_retention_pb2.field_option] 191 ) 192 check_options_message_is_stripped_correctly( 193 unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.oneofs[0] 194 .GetOptions() 195 .Extensions[unittest_retention_pb2.oneof_option] 196 ) 197 check_options_message_is_stripped_correctly( 198 unittest_retention_pb2.DESCRIPTOR.services_by_name['Service'] 199 .GetOptions() 200 .Extensions[unittest_retention_pb2.service_option] 201 ) 202 check_options_message_is_stripped_correctly( 203 unittest_retention_pb2.DESCRIPTOR.services_by_name['Service'] 204 .methods[0] 205 .GetOptions() 206 .Extensions[unittest_retention_pb2.method_option] 207 ) 208 209 def testNestedTypes(self): 210 self.assertEqual( 211 set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types), 212 set([ 213 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR, 214 unittest_pb2.TestAllTypes.OptionalGroup.DESCRIPTOR, 215 unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR, 216 ])) 217 self.assertEqual(unittest_pb2.TestEmptyMessage.DESCRIPTOR.nested_types, []) 218 self.assertEqual( 219 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.nested_types, []) 220 221 def testContainingType(self): 222 self.assertTrue( 223 unittest_pb2.TestEmptyMessage.DESCRIPTOR.containing_type is None) 224 self.assertTrue( 225 unittest_pb2.TestAllTypes.DESCRIPTOR.containing_type is None) 226 self.assertEqual( 227 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, 228 unittest_pb2.TestAllTypes.DESCRIPTOR) 229 self.assertEqual( 230 unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type, 231 unittest_pb2.TestAllTypes.DESCRIPTOR) 232 self.assertEqual( 233 unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR.containing_type, 234 unittest_pb2.TestAllTypes.DESCRIPTOR) 235 236 def testContainingTypeInEnumDescriptor(self): 237 self.assertTrue(unittest_pb2._FOREIGNENUM.containing_type is None) 238 self.assertEqual(unittest_pb2._TESTALLTYPES_NESTEDENUM.containing_type, 239 unittest_pb2.TestAllTypes.DESCRIPTOR) 240 241 def testPackage(self): 242 self.assertEqual( 243 unittest_pb2.TestAllTypes.DESCRIPTOR.file.package, 244 'protobuf_unittest') 245 desc = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR 246 self.assertEqual(desc.file.package, 'protobuf_unittest') 247 self.assertEqual( 248 unittest_import_pb2.ImportMessage.DESCRIPTOR.file.package, 249 'protobuf_unittest_import') 250 251 self.assertEqual( 252 unittest_pb2._FOREIGNENUM.file.package, 'protobuf_unittest') 253 self.assertEqual( 254 unittest_pb2._TESTALLTYPES_NESTEDENUM.file.package, 255 'protobuf_unittest') 256 self.assertEqual( 257 unittest_import_pb2._IMPORTENUM.file.package, 258 'protobuf_unittest_import') 259 260 def testExtensionRange(self): 261 self.assertEqual( 262 unittest_pb2.TestAllTypes.DESCRIPTOR.extension_ranges, []) 263 self.assertEqual( 264 unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges, 265 [(1, MAX_EXTENSION)]) 266 self.assertEqual( 267 unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges, 268 [(42, 43), (4143, 4244), (65536, MAX_EXTENSION)]) 269 270 def testFileDescriptor(self): 271 self.assertEqual(unittest_pb2.DESCRIPTOR.name, 272 'google/protobuf/unittest.proto') 273 self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest') 274 self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None) 275 self.assertEqual(unittest_pb2.DESCRIPTOR.dependencies, 276 [unittest_import_pb2.DESCRIPTOR]) 277 self.assertEqual(unittest_import_pb2.DESCRIPTOR.dependencies, 278 [unittest_import_public_pb2.DESCRIPTOR]) 279 self.assertEqual(unittest_import_pb2.DESCRIPTOR.public_dependencies, 280 [unittest_import_public_pb2.DESCRIPTOR]) 281 def testNoGenericServices(self): 282 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage")) 283 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "FOO")) 284 self.assertTrue(hasattr(unittest_no_generic_services_pb2, "test_extension")) 285 286 # Make sure unittest_no_generic_services_pb2 has no services subclassing 287 # Proto2 Service class. 288 if hasattr(unittest_no_generic_services_pb2, "TestService"): 289 self.assertFalse(issubclass(unittest_no_generic_services_pb2.TestService, 290 service.Service)) 291 292 def testMessageTypesByName(self): 293 file_type = unittest_pb2.DESCRIPTOR 294 self.assertEqual( 295 unittest_pb2._TESTALLTYPES, 296 file_type.message_types_by_name[unittest_pb2._TESTALLTYPES.name]) 297 298 # Nested messages shouldn't be included in the message_types_by_name 299 # dictionary (like in the C++ API). 300 self.assertFalse( 301 unittest_pb2._TESTALLTYPES_NESTEDMESSAGE.name in 302 file_type.message_types_by_name) 303 304 def testEnumTypesByName(self): 305 file_type = unittest_pb2.DESCRIPTOR 306 self.assertEqual( 307 unittest_pb2._FOREIGNENUM, 308 file_type.enum_types_by_name[unittest_pb2._FOREIGNENUM.name]) 309 310 def testExtensionsByName(self): 311 file_type = unittest_pb2.DESCRIPTOR 312 self.assertEqual( 313 unittest_pb2.my_extension_string, 314 file_type.extensions_by_name[unittest_pb2.my_extension_string.name]) 315 316 def testPublicImports(self): 317 # Test public imports as embedded message. 318 all_type_proto = unittest_pb2.TestAllTypes() 319 self.assertEqual(0, all_type_proto.optional_public_import_message.e) 320 321 # PublicImportMessage is actually defined in unittest_import_public_pb2 322 # module, and is public imported by unittest_import_pb2 module. 323 public_import_proto = unittest_import_pb2.PublicImportMessage() 324 self.assertEqual(0, public_import_proto.e) 325 self.assertTrue(unittest_import_public_pb2.PublicImportMessage is 326 unittest_import_pb2.PublicImportMessage) 327 328 def testBadIdentifiers(self): 329 # We're just testing that the code was imported without problems. 330 message = test_bad_identifiers_pb2.TestBadIdentifiers() 331 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.message], 332 "foo") 333 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.descriptor], 334 "bar") 335 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.reflection], 336 "baz") 337 self.assertEqual(message.Extensions[test_bad_identifiers_pb2.service], 338 "qux") 339 340 def testOneof(self): 341 desc = unittest_pb2.TestAllTypes.DESCRIPTOR 342 self.assertEqual(1, len(desc.oneofs)) 343 self.assertEqual('oneof_field', desc.oneofs[0].name) 344 self.assertEqual(0, desc.oneofs[0].index) 345 self.assertIs(desc, desc.oneofs[0].containing_type) 346 self.assertIs(desc.oneofs[0], desc.oneofs_by_name['oneof_field']) 347 nested_names = set([ 348 'oneof_uint32', 349 'oneof_nested_message', 350 'oneof_string', 351 'oneof_bytes', 352 'oneof_cord', 353 'oneof_string_piece', 354 'oneof_lazy_nested_message', 355 ]) 356 self.assertEqual( 357 nested_names, 358 set([field.name for field in desc.oneofs[0].fields])) 359 for field_name, field_desc in desc.fields_by_name.items(): 360 if field_name in nested_names: 361 self.assertIs(desc.oneofs[0], field_desc.containing_oneof) 362 else: 363 self.assertIsNone(field_desc.containing_oneof) 364 365 def testEnumWithDupValue(self): 366 self.assertEqual('FOO1', 367 unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.FOO1)) 368 self.assertEqual('FOO1', 369 unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.FOO2)) 370 self.assertEqual('BAR1', 371 unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.BAR1)) 372 self.assertEqual('BAR1', 373 unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.BAR2)) 374 375 376class SymbolDatabaseRegistrationTest(unittest.TestCase): 377 """Checks that messages, enums and files are correctly registered.""" 378 379 def testGetSymbol(self): 380 self.assertEqual( 381 unittest_pb2.TestAllTypes, symbol_database.Default().GetSymbol( 382 'protobuf_unittest.TestAllTypes')) 383 self.assertEqual( 384 unittest_pb2.TestAllTypes.NestedMessage, 385 symbol_database.Default().GetSymbol( 386 'protobuf_unittest.TestAllTypes.NestedMessage')) 387 with self.assertRaises(KeyError): 388 symbol_database.Default().GetSymbol('protobuf_unittest.NestedMessage') 389 self.assertEqual( 390 unittest_pb2.TestAllTypes.OptionalGroup, 391 symbol_database.Default().GetSymbol( 392 'protobuf_unittest.TestAllTypes.OptionalGroup')) 393 self.assertEqual( 394 unittest_pb2.TestAllTypes.RepeatedGroup, 395 symbol_database.Default().GetSymbol( 396 'protobuf_unittest.TestAllTypes.RepeatedGroup')) 397 398 def testEnums(self): 399 self.assertEqual( 400 'protobuf_unittest.ForeignEnum', 401 symbol_database.Default().pool.FindEnumTypeByName( 402 'protobuf_unittest.ForeignEnum').full_name) 403 self.assertEqual( 404 'protobuf_unittest.TestAllTypes.NestedEnum', 405 symbol_database.Default().pool.FindEnumTypeByName( 406 'protobuf_unittest.TestAllTypes.NestedEnum').full_name) 407 408 def testFindFileByName(self): 409 self.assertEqual( 410 'google/protobuf/unittest.proto', 411 symbol_database.Default().pool.FindFileByName( 412 'google/protobuf/unittest.proto').name) 413 414if __name__ == '__main__': 415 unittest.main() 416