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