Home | History | Annotate | Download | only in internal
      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
     38 compiler.  See //google/protobuf/reflection_test.py for a test which
     39 further ensures that we can use Python protocol message objects as we expect.
     40 """
     41 
     42 __author__ = 'robinson (at] google.com (Will Robinson)'
     43 
     44 from google.apputils import basetest
     45 from google.protobuf.internal import test_bad_identifiers_pb2
     46 from google.protobuf import unittest_custom_options_pb2
     47 from google.protobuf import unittest_import_pb2
     48 from google.protobuf import unittest_import_public_pb2
     49 from google.protobuf import unittest_mset_pb2
     50 from google.protobuf import unittest_no_generic_services_pb2
     51 from google.protobuf import unittest_pb2
     52 from google.protobuf import service
     53 from google.protobuf import symbol_database
     54 
     55 MAX_EXTENSION = 536870912
     56 
     57 
     58 class 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 
    304 class 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 
    342 if __name__ == '__main__':
    343   basetest.main()
    344