1#! /usr/bin/python
2#
3# Protocol Buffers - Google's data interchange format
4# Copyright 2008 Google Inc.  All rights reserved.
5# http://code.google.com/p/protobuf/
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
44import unittest
45from google.protobuf import unittest_import_pb2
46from google.protobuf import unittest_mset_pb2
47from google.protobuf import unittest_pb2
48from google.protobuf import unittest_no_generic_services_pb2
49
50
51MAX_EXTENSION = 536870912
52
53
54class GeneratorTest(unittest.TestCase):
55
56  def testNestedMessageDescriptor(self):
57    field_name = 'optional_nested_message'
58    proto_type = unittest_pb2.TestAllTypes
59    self.assertEqual(
60        proto_type.NestedMessage.DESCRIPTOR,
61        proto_type.DESCRIPTOR.fields_by_name[field_name].message_type)
62
63  def testEnums(self):
64    # We test only module-level enums here.
65    # TODO(robinson): Examine descriptors directly to check
66    # enum descriptor output.
67    self.assertEqual(4, unittest_pb2.FOREIGN_FOO)
68    self.assertEqual(5, unittest_pb2.FOREIGN_BAR)
69    self.assertEqual(6, unittest_pb2.FOREIGN_BAZ)
70
71    proto = unittest_pb2.TestAllTypes()
72    self.assertEqual(1, proto.FOO)
73    self.assertEqual(1, unittest_pb2.TestAllTypes.FOO)
74    self.assertEqual(2, proto.BAR)
75    self.assertEqual(2, unittest_pb2.TestAllTypes.BAR)
76    self.assertEqual(3, proto.BAZ)
77    self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ)
78
79  def testExtremeDefaultValues(self):
80    message = unittest_pb2.TestExtremeDefaultValues()
81
82    # Python pre-2.6 does not have isinf() or isnan() functions, so we have
83    # to provide our own.
84    def isnan(val):
85      # NaN is never equal to itself.
86      return val != val
87    def isinf(val):
88      # Infinity times zero equals NaN.
89      return not isnan(val) and isnan(val * 0)
90
91    self.assertTrue(isinf(message.inf_double))
92    self.assertTrue(message.inf_double > 0)
93    self.assertTrue(isinf(message.neg_inf_double))
94    self.assertTrue(message.neg_inf_double < 0)
95    self.assertTrue(isnan(message.nan_double))
96
97    self.assertTrue(isinf(message.inf_float))
98    self.assertTrue(message.inf_float > 0)
99    self.assertTrue(isinf(message.neg_inf_float))
100    self.assertTrue(message.neg_inf_float < 0)
101    self.assertTrue(isnan(message.nan_float))
102
103  def testHasDefaultValues(self):
104    desc = unittest_pb2.TestAllTypes.DESCRIPTOR
105
106    expected_has_default_by_name = {
107        'optional_int32': False,
108        'repeated_int32': False,
109        'optional_nested_message': False,
110        'default_int32': True,
111    }
112
113    has_default_by_name = dict(
114        [(f.name, f.has_default_value)
115         for f in desc.fields
116         if f.name in expected_has_default_by_name])
117    self.assertEqual(expected_has_default_by_name, has_default_by_name)
118
119  def testContainingTypeBehaviorForExtensions(self):
120    self.assertEqual(unittest_pb2.optional_int32_extension.containing_type,
121                     unittest_pb2.TestAllExtensions.DESCRIPTOR)
122    self.assertEqual(unittest_pb2.TestRequired.single.containing_type,
123                     unittest_pb2.TestAllExtensions.DESCRIPTOR)
124
125  def testExtensionScope(self):
126    self.assertEqual(unittest_pb2.optional_int32_extension.extension_scope,
127                     None)
128    self.assertEqual(unittest_pb2.TestRequired.single.extension_scope,
129                     unittest_pb2.TestRequired.DESCRIPTOR)
130
131  def testIsExtension(self):
132    self.assertTrue(unittest_pb2.optional_int32_extension.is_extension)
133    self.assertTrue(unittest_pb2.TestRequired.single.is_extension)
134
135    message_descriptor = unittest_pb2.TestRequired.DESCRIPTOR
136    non_extension_descriptor = message_descriptor.fields_by_name['a']
137    self.assertTrue(not non_extension_descriptor.is_extension)
138
139  def testOptions(self):
140    proto = unittest_mset_pb2.TestMessageSet()
141    self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
142
143  def testNestedTypes(self):
144    self.assertEquals(
145        set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types),
146        set([
147            unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR,
148            unittest_pb2.TestAllTypes.OptionalGroup.DESCRIPTOR,
149            unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR,
150        ]))
151    self.assertEqual(unittest_pb2.TestEmptyMessage.DESCRIPTOR.nested_types, [])
152    self.assertEqual(
153        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.nested_types, [])
154
155  def testContainingType(self):
156    self.assertTrue(
157        unittest_pb2.TestEmptyMessage.DESCRIPTOR.containing_type is None)
158    self.assertTrue(
159        unittest_pb2.TestAllTypes.DESCRIPTOR.containing_type is None)
160    self.assertEqual(
161        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type,
162        unittest_pb2.TestAllTypes.DESCRIPTOR)
163    self.assertEqual(
164        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type,
165        unittest_pb2.TestAllTypes.DESCRIPTOR)
166    self.assertEqual(
167        unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR.containing_type,
168        unittest_pb2.TestAllTypes.DESCRIPTOR)
169
170  def testContainingTypeInEnumDescriptor(self):
171    self.assertTrue(unittest_pb2._FOREIGNENUM.containing_type is None)
172    self.assertEqual(unittest_pb2._TESTALLTYPES_NESTEDENUM.containing_type,
173                     unittest_pb2.TestAllTypes.DESCRIPTOR)
174
175  def testPackage(self):
176    self.assertEqual(
177        unittest_pb2.TestAllTypes.DESCRIPTOR.file.package,
178        'protobuf_unittest')
179    desc = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR
180    self.assertEqual(desc.file.package, 'protobuf_unittest')
181    self.assertEqual(
182        unittest_import_pb2.ImportMessage.DESCRIPTOR.file.package,
183        'protobuf_unittest_import')
184
185    self.assertEqual(
186        unittest_pb2._FOREIGNENUM.file.package, 'protobuf_unittest')
187    self.assertEqual(
188        unittest_pb2._TESTALLTYPES_NESTEDENUM.file.package,
189        'protobuf_unittest')
190    self.assertEqual(
191        unittest_import_pb2._IMPORTENUM.file.package,
192        'protobuf_unittest_import')
193
194  def testExtensionRange(self):
195    self.assertEqual(
196        unittest_pb2.TestAllTypes.DESCRIPTOR.extension_ranges, [])
197    self.assertEqual(
198        unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges,
199        [(1, MAX_EXTENSION)])
200    self.assertEqual(
201        unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges,
202        [(42, 43), (4143, 4244), (65536, MAX_EXTENSION)])
203
204  def testFileDescriptor(self):
205    self.assertEqual(unittest_pb2.DESCRIPTOR.name,
206                     'google/protobuf/unittest.proto')
207    self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest')
208    self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None)
209
210  def testNoGenericServices(self):
211    # unittest_no_generic_services.proto should contain defs for everything
212    # except services.
213    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage"))
214    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "FOO"))
215    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "test_extension"))
216    self.assertFalse(hasattr(unittest_no_generic_services_pb2, "TestService"))
217
218
219if __name__ == '__main__':
220  unittest.main()
221