• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""Tests for google.protobuf.descriptor_pool."""
34
35__author__ = 'matthewtoia@google.com (Matt Toia)'
36
37import copy
38import os
39import warnings
40
41try:
42  import unittest2 as unittest  #PY26
43except ImportError:
44  import unittest
45
46from google.protobuf import unittest_import_pb2
47from google.protobuf import unittest_import_public_pb2
48from google.protobuf import unittest_pb2
49from google.protobuf import descriptor_pb2
50from google.protobuf.internal import api_implementation
51from google.protobuf.internal import descriptor_pool_test1_pb2
52from google.protobuf.internal import descriptor_pool_test2_pb2
53from google.protobuf.internal import factory_test1_pb2
54from google.protobuf.internal import factory_test2_pb2
55from google.protobuf.internal import file_options_test_pb2
56from google.protobuf.internal import more_messages_pb2
57from google.protobuf.internal import no_package_pb2
58from google.protobuf.internal import testing_refleaks
59from google.protobuf import descriptor
60from google.protobuf import descriptor_database
61from google.protobuf import descriptor_pool
62from google.protobuf import message_factory
63from google.protobuf import symbol_database
64
65
66
67warnings.simplefilter('error', DeprecationWarning)
68
69
70class DescriptorPoolTestBase(object):
71
72  def testFindFileByName(self):
73    name1 = 'google/protobuf/internal/factory_test1.proto'
74    file_desc1 = self.pool.FindFileByName(name1)
75    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
76    self.assertEqual(name1, file_desc1.name)
77    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
78    self.assertIn('Factory1Message', file_desc1.message_types_by_name)
79
80    name2 = 'google/protobuf/internal/factory_test2.proto'
81    file_desc2 = self.pool.FindFileByName(name2)
82    self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
83    self.assertEqual(name2, file_desc2.name)
84    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
85    self.assertIn('Factory2Message', file_desc2.message_types_by_name)
86
87  def testFindFileByNameFailure(self):
88    with self.assertRaises(KeyError):
89      self.pool.FindFileByName('Does not exist')
90
91  def testFindFileContainingSymbol(self):
92    file_desc1 = self.pool.FindFileContainingSymbol(
93        'google.protobuf.python.internal.Factory1Message')
94    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
95    self.assertEqual('google/protobuf/internal/factory_test1.proto',
96                     file_desc1.name)
97    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
98    self.assertIn('Factory1Message', file_desc1.message_types_by_name)
99
100    file_desc2 = self.pool.FindFileContainingSymbol(
101        'google.protobuf.python.internal.Factory2Message')
102    self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
103    self.assertEqual('google/protobuf/internal/factory_test2.proto',
104                     file_desc2.name)
105    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
106    self.assertIn('Factory2Message', file_desc2.message_types_by_name)
107
108    # Tests top level extension.
109    file_desc3 = self.pool.FindFileContainingSymbol(
110        'google.protobuf.python.internal.another_field')
111    self.assertIsInstance(file_desc3, descriptor.FileDescriptor)
112    self.assertEqual('google/protobuf/internal/factory_test2.proto',
113                     file_desc3.name)
114
115    # Tests nested extension inside a message.
116    file_desc4 = self.pool.FindFileContainingSymbol(
117        'google.protobuf.python.internal.Factory2Message.one_more_field')
118    self.assertIsInstance(file_desc4, descriptor.FileDescriptor)
119    self.assertEqual('google/protobuf/internal/factory_test2.proto',
120                     file_desc4.name)
121
122    file_desc5 = self.pool.FindFileContainingSymbol(
123        'protobuf_unittest.TestService')
124    self.assertIsInstance(file_desc5, descriptor.FileDescriptor)
125    self.assertEqual('google/protobuf/unittest.proto',
126                     file_desc5.name)
127    # Tests the generated pool.
128    assert descriptor_pool.Default().FindFileContainingSymbol(
129        'google.protobuf.python.internal.Factory2Message.one_more_field')
130    assert descriptor_pool.Default().FindFileContainingSymbol(
131        'google.protobuf.python.internal.another_field')
132    assert descriptor_pool.Default().FindFileContainingSymbol(
133        'protobuf_unittest.TestService')
134
135    # Can find field.
136    file_desc6 = self.pool.FindFileContainingSymbol(
137        'google.protobuf.python.internal.Factory1Message.list_value')
138    self.assertIsInstance(file_desc6, descriptor.FileDescriptor)
139    self.assertEqual('google/protobuf/internal/factory_test1.proto',
140                     file_desc6.name)
141
142    # Can find top level Enum value.
143    file_desc7 = self.pool.FindFileContainingSymbol(
144        'google.protobuf.python.internal.FACTORY_1_VALUE_0')
145    self.assertIsInstance(file_desc7, descriptor.FileDescriptor)
146    self.assertEqual('google/protobuf/internal/factory_test1.proto',
147                     file_desc7.name)
148
149    # Can find nested Enum value.
150    file_desc8 = self.pool.FindFileContainingSymbol(
151        'protobuf_unittest.TestAllTypes.FOO')
152    self.assertIsInstance(file_desc8, descriptor.FileDescriptor)
153    self.assertEqual('google/protobuf/unittest.proto',
154                     file_desc8.name)
155
156    # TODO(jieluo): Add tests for no package when b/13860351 is fixed.
157
158    self.assertRaises(KeyError, self.pool.FindFileContainingSymbol,
159                      'google.protobuf.python.internal.Factory1Message.none_field')
160
161  def testFindFileContainingSymbolFailure(self):
162    with self.assertRaises(KeyError):
163      self.pool.FindFileContainingSymbol('Does not exist')
164
165  def testFindMessageTypeByName(self):
166    msg1 = self.pool.FindMessageTypeByName(
167        'google.protobuf.python.internal.Factory1Message')
168    self.assertIsInstance(msg1, descriptor.Descriptor)
169    self.assertEqual('Factory1Message', msg1.name)
170    self.assertEqual('google.protobuf.python.internal.Factory1Message',
171                     msg1.full_name)
172    self.assertEqual(None, msg1.containing_type)
173    self.assertFalse(msg1.has_options)
174
175    nested_msg1 = msg1.nested_types[0]
176    self.assertEqual('NestedFactory1Message', nested_msg1.name)
177    self.assertEqual(msg1, nested_msg1.containing_type)
178
179    nested_enum1 = msg1.enum_types[0]
180    self.assertEqual('NestedFactory1Enum', nested_enum1.name)
181    self.assertEqual(msg1, nested_enum1.containing_type)
182
183    self.assertEqual(nested_msg1, msg1.fields_by_name[
184        'nested_factory_1_message'].message_type)
185    self.assertEqual(nested_enum1, msg1.fields_by_name[
186        'nested_factory_1_enum'].enum_type)
187
188    msg2 = self.pool.FindMessageTypeByName(
189        'google.protobuf.python.internal.Factory2Message')
190    self.assertIsInstance(msg2, descriptor.Descriptor)
191    self.assertEqual('Factory2Message', msg2.name)
192    self.assertEqual('google.protobuf.python.internal.Factory2Message',
193                     msg2.full_name)
194    self.assertIsNone(msg2.containing_type)
195
196    nested_msg2 = msg2.nested_types[0]
197    self.assertEqual('NestedFactory2Message', nested_msg2.name)
198    self.assertEqual(msg2, nested_msg2.containing_type)
199
200    nested_enum2 = msg2.enum_types[0]
201    self.assertEqual('NestedFactory2Enum', nested_enum2.name)
202    self.assertEqual(msg2, nested_enum2.containing_type)
203
204    self.assertEqual(nested_msg2, msg2.fields_by_name[
205        'nested_factory_2_message'].message_type)
206    self.assertEqual(nested_enum2, msg2.fields_by_name[
207        'nested_factory_2_enum'].enum_type)
208
209    self.assertTrue(msg2.fields_by_name['int_with_default'].has_default_value)
210    self.assertEqual(
211        1776, msg2.fields_by_name['int_with_default'].default_value)
212
213    self.assertTrue(
214        msg2.fields_by_name['double_with_default'].has_default_value)
215    self.assertEqual(
216        9.99, msg2.fields_by_name['double_with_default'].default_value)
217
218    self.assertTrue(
219        msg2.fields_by_name['string_with_default'].has_default_value)
220    self.assertEqual(
221        'hello world', msg2.fields_by_name['string_with_default'].default_value)
222
223    self.assertTrue(msg2.fields_by_name['bool_with_default'].has_default_value)
224    self.assertFalse(msg2.fields_by_name['bool_with_default'].default_value)
225
226    self.assertTrue(msg2.fields_by_name['enum_with_default'].has_default_value)
227    self.assertEqual(
228        1, msg2.fields_by_name['enum_with_default'].default_value)
229
230    msg3 = self.pool.FindMessageTypeByName(
231        'google.protobuf.python.internal.Factory2Message.NestedFactory2Message')
232    self.assertEqual(nested_msg2, msg3)
233
234    self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value)
235    self.assertEqual(
236        b'a\xfb\x00c',
237        msg2.fields_by_name['bytes_with_default'].default_value)
238
239    self.assertEqual(1, len(msg2.oneofs))
240    self.assertEqual(1, len(msg2.oneofs_by_name))
241    self.assertEqual(2, len(msg2.oneofs[0].fields))
242    for name in ['oneof_int', 'oneof_string']:
243      self.assertEqual(msg2.oneofs[0],
244                       msg2.fields_by_name[name].containing_oneof)
245      self.assertIn(msg2.fields_by_name[name], msg2.oneofs[0].fields)
246
247  def testFindTypeErrors(self):
248    self.assertRaises(TypeError, self.pool.FindExtensionByNumber, '')
249    self.assertRaises(KeyError, self.pool.FindMethodByName, '')
250
251    # TODO(jieluo): Fix python to raise correct errors.
252    if api_implementation.Type() == 'cpp':
253      error_type = TypeError
254    else:
255      error_type = AttributeError
256    self.assertRaises(error_type, self.pool.FindMessageTypeByName, 0)
257    self.assertRaises(error_type, self.pool.FindFieldByName, 0)
258    self.assertRaises(error_type, self.pool.FindExtensionByName, 0)
259    self.assertRaises(error_type, self.pool.FindEnumTypeByName, 0)
260    self.assertRaises(error_type, self.pool.FindOneofByName, 0)
261    self.assertRaises(error_type, self.pool.FindServiceByName, 0)
262    self.assertRaises(error_type, self.pool.FindMethodByName, 0)
263    self.assertRaises(error_type, self.pool.FindFileContainingSymbol, 0)
264    if api_implementation.Type() == 'python':
265      error_type = KeyError
266    self.assertRaises(error_type, self.pool.FindFileByName, 0)
267
268  def testFindMessageTypeByNameFailure(self):
269    with self.assertRaises(KeyError):
270      self.pool.FindMessageTypeByName('Does not exist')
271
272  def testFindEnumTypeByName(self):
273    enum1 = self.pool.FindEnumTypeByName(
274        'google.protobuf.python.internal.Factory1Enum')
275    self.assertIsInstance(enum1, descriptor.EnumDescriptor)
276    self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
277    self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
278    self.assertFalse(enum1.has_options)
279
280    nested_enum1 = self.pool.FindEnumTypeByName(
281        'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
282    self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor)
283    self.assertEqual(
284        0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number)
285    self.assertEqual(
286        1, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_1'].number)
287
288    enum2 = self.pool.FindEnumTypeByName(
289        'google.protobuf.python.internal.Factory2Enum')
290    self.assertIsInstance(enum2, descriptor.EnumDescriptor)
291    self.assertEqual(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number)
292    self.assertEqual(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number)
293
294    nested_enum2 = self.pool.FindEnumTypeByName(
295        'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum')
296    self.assertIsInstance(nested_enum2, descriptor.EnumDescriptor)
297    self.assertEqual(
298        0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number)
299    self.assertEqual(
300        1, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_1'].number)
301
302  def testFindEnumTypeByNameFailure(self):
303    with self.assertRaises(KeyError):
304      self.pool.FindEnumTypeByName('Does not exist')
305
306  def testFindFieldByName(self):
307    field = self.pool.FindFieldByName(
308        'google.protobuf.python.internal.Factory1Message.list_value')
309    self.assertEqual(field.name, 'list_value')
310    self.assertEqual(field.label, field.LABEL_REPEATED)
311    self.assertFalse(field.has_options)
312
313    with self.assertRaises(KeyError):
314      self.pool.FindFieldByName('Does not exist')
315
316  def testFindOneofByName(self):
317    oneof = self.pool.FindOneofByName(
318        'google.protobuf.python.internal.Factory2Message.oneof_field')
319    self.assertEqual(oneof.name, 'oneof_field')
320    with self.assertRaises(KeyError):
321      self.pool.FindOneofByName('Does not exist')
322
323  def testFindExtensionByName(self):
324    # An extension defined in a message.
325    extension = self.pool.FindExtensionByName(
326        'google.protobuf.python.internal.Factory2Message.one_more_field')
327    self.assertEqual(extension.name, 'one_more_field')
328    # An extension defined at file scope.
329    extension = self.pool.FindExtensionByName(
330        'google.protobuf.python.internal.another_field')
331    self.assertEqual(extension.name, 'another_field')
332    self.assertEqual(extension.number, 1002)
333    with self.assertRaises(KeyError):
334      self.pool.FindFieldByName('Does not exist')
335
336  def testFindAllExtensions(self):
337    factory1_message = self.pool.FindMessageTypeByName(
338        'google.protobuf.python.internal.Factory1Message')
339    factory2_message = self.pool.FindMessageTypeByName(
340        'google.protobuf.python.internal.Factory2Message')
341    # An extension defined in a message.
342    one_more_field = factory2_message.extensions_by_name['one_more_field']
343    # An extension defined at file scope.
344    factory_test2 = self.pool.FindFileByName(
345        'google/protobuf/internal/factory_test2.proto')
346    another_field = factory_test2.extensions_by_name['another_field']
347
348    extensions = self.pool.FindAllExtensions(factory1_message)
349    expected_extension_numbers = set([one_more_field, another_field])
350    self.assertEqual(expected_extension_numbers, set(extensions))
351    # Verify that mutating the returned list does not affect the pool.
352    extensions.append('unexpected_element')
353    # Get the extensions again, the returned value does not contain the
354    # 'unexpected_element'.
355    extensions = self.pool.FindAllExtensions(factory1_message)
356    self.assertEqual(expected_extension_numbers, set(extensions))
357
358  def testFindExtensionByNumber(self):
359    factory1_message = self.pool.FindMessageTypeByName(
360        'google.protobuf.python.internal.Factory1Message')
361    # Build factory_test2.proto which will put extensions to the pool
362    self.pool.FindFileByName(
363        'google/protobuf/internal/factory_test2.proto')
364
365    # An extension defined in a message.
366    extension = self.pool.FindExtensionByNumber(factory1_message, 1001)
367    self.assertEqual(extension.name, 'one_more_field')
368    # An extension defined at file scope.
369    extension = self.pool.FindExtensionByNumber(factory1_message, 1002)
370    self.assertEqual(extension.name, 'another_field')
371    with self.assertRaises(KeyError):
372      extension = self.pool.FindExtensionByNumber(factory1_message, 1234567)
373
374  def testExtensionsAreNotFields(self):
375    with self.assertRaises(KeyError):
376      self.pool.FindFieldByName('google.protobuf.python.internal.another_field')
377    with self.assertRaises(KeyError):
378      self.pool.FindFieldByName(
379          'google.protobuf.python.internal.Factory2Message.one_more_field')
380    with self.assertRaises(KeyError):
381      self.pool.FindExtensionByName(
382          'google.protobuf.python.internal.Factory1Message.list_value')
383
384  def testFindService(self):
385    service = self.pool.FindServiceByName('protobuf_unittest.TestService')
386    self.assertEqual(service.full_name, 'protobuf_unittest.TestService')
387    with self.assertRaises(KeyError):
388      self.pool.FindServiceByName('Does not exist')
389
390    method = self.pool.FindMethodByName('protobuf_unittest.TestService.Foo')
391    self.assertIs(method.containing_service, service)
392    with self.assertRaises(KeyError):
393      self.pool.FindMethodByName('protobuf_unittest.TestService.Doesnotexist')
394
395  def testUserDefinedDB(self):
396    db = descriptor_database.DescriptorDatabase()
397    self.pool = descriptor_pool.DescriptorPool(db)
398    db.Add(self.factory_test1_fd)
399    db.Add(self.factory_test2_fd)
400    self.testFindMessageTypeByName()
401
402  def testAddSerializedFile(self):
403    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
404      if api_implementation.Type() == 'cpp':
405        # Cpp extension cannot call Add on a DescriptorPool
406        # that uses a DescriptorDatabase.
407        # TODO(jieluo): Fix python and cpp extension diff.
408        return
409    self.pool = descriptor_pool.DescriptorPool()
410    self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString())
411    self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString())
412    self.testFindMessageTypeByName()
413
414
415  def testEnumDefaultValue(self):
416    """Test the default value of enums which don't start at zero."""
417    def _CheckDefaultValue(file_descriptor):
418      default_value = (file_descriptor
419                       .message_types_by_name['DescriptorPoolTest1']
420                       .fields_by_name['nested_enum']
421                       .default_value)
422      self.assertEqual(default_value,
423                       descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA)
424    # First check what the generated descriptor contains.
425    _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR)
426    # Then check the generated pool. Normally this is the same descriptor.
427    file_descriptor = symbol_database.Default().pool.FindFileByName(
428        'google/protobuf/internal/descriptor_pool_test1.proto')
429    self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR)
430    _CheckDefaultValue(file_descriptor)
431
432    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
433      if api_implementation.Type() == 'cpp':
434        # Cpp extension cannot call Add on a DescriptorPool
435        # that uses a DescriptorDatabase.
436        # TODO(jieluo): Fix python and cpp extension diff.
437        return
438    # Then check the dynamic pool and its internal DescriptorDatabase.
439    descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString(
440        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
441    self.pool.Add(descriptor_proto)
442    # And do the same check as above
443    file_descriptor = self.pool.FindFileByName(
444        'google/protobuf/internal/descriptor_pool_test1.proto')
445    _CheckDefaultValue(file_descriptor)
446
447  def testDefaultValueForCustomMessages(self):
448    """Check the value returned by non-existent fields."""
449    def _CheckValueAndType(value, expected_value, expected_type):
450      self.assertEqual(value, expected_value)
451      self.assertIsInstance(value, expected_type)
452
453    def _CheckDefaultValues(msg):
454      try:
455        int64 = long
456      except NameError:  # Python3
457        int64 = int
458      try:
459        unicode_type = unicode
460      except NameError:  # Python3
461        unicode_type = str
462      _CheckValueAndType(msg.optional_int32, 0, int)
463      _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
464      _CheckValueAndType(msg.optional_float, 0, (float, int))
465      _CheckValueAndType(msg.optional_double, 0, (float, int))
466      _CheckValueAndType(msg.optional_bool, False, bool)
467      _CheckValueAndType(msg.optional_string, u'', unicode_type)
468      _CheckValueAndType(msg.optional_bytes, b'', bytes)
469      _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
470    # First for the generated message
471    _CheckDefaultValues(unittest_pb2.TestAllTypes())
472    # Then for a message built with from the DescriptorPool.
473    pool = descriptor_pool.DescriptorPool()
474    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
475        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
476    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
477        unittest_import_pb2.DESCRIPTOR.serialized_pb))
478    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
479        unittest_pb2.DESCRIPTOR.serialized_pb))
480    message_class = message_factory.MessageFactory(pool).GetPrototype(
481        pool.FindMessageTypeByName(
482            unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
483    _CheckDefaultValues(message_class())
484
485  def testAddFileDescriptor(self):
486    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
487      if api_implementation.Type() == 'cpp':
488        # Cpp extension cannot call Add on a DescriptorPool
489        # that uses a DescriptorDatabase.
490        # TODO(jieluo): Fix python and cpp extension diff.
491        return
492    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
493    self.pool.Add(file_desc)
494    self.pool.AddSerializedFile(file_desc.SerializeToString())
495
496  def testComplexNesting(self):
497    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
498      if api_implementation.Type() == 'cpp':
499        # Cpp extension cannot call Add on a DescriptorPool
500        # that uses a DescriptorDatabase.
501        # TODO(jieluo): Fix python and cpp extension diff.
502        return
503    more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
504        more_messages_pb2.DESCRIPTOR.serialized_pb)
505    test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
506        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
507    test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
508        descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
509    self.pool.Add(more_messages_desc)
510    self.pool.Add(test1_desc)
511    self.pool.Add(test2_desc)
512    TEST1_FILE.CheckFile(self, self.pool)
513    TEST2_FILE.CheckFile(self, self.pool)
514
515  def testConflictRegister(self):
516    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
517      if api_implementation.Type() == 'cpp':
518        # Cpp extension cannot call Add on a DescriptorPool
519        # that uses a DescriptorDatabase.
520        # TODO(jieluo): Fix python and cpp extension diff.
521        return
522    unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
523        unittest_pb2.DESCRIPTOR.serialized_pb)
524    conflict_fd = copy.deepcopy(unittest_fd)
525    conflict_fd.name = 'other_file'
526    if api_implementation.Type() == 'cpp':
527        pass
528    else:
529      pool = copy.deepcopy(self.pool)
530      file_descriptor = unittest_pb2.DESCRIPTOR
531      pool._AddDescriptor(
532          file_descriptor.message_types_by_name['TestAllTypes'])
533      pool._AddEnumDescriptor(
534          file_descriptor.enum_types_by_name['ForeignEnum'])
535      pool._AddServiceDescriptor(
536          file_descriptor.services_by_name['TestService'])
537      pool._AddExtensionDescriptor(
538          file_descriptor.extensions_by_name['optional_int32_extension'])
539      pool.Add(unittest_fd)
540      pool.Add(conflict_fd)
541      pool.FindFileByName(unittest_fd.name)
542      with self.assertRaises(TypeError):
543        pool.FindFileByName(conflict_fd.name)
544
545
546@testing_refleaks.TestCase
547class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
548
549  def setUp(self):
550    self.pool = descriptor_pool.Default()
551    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
552        factory_test1_pb2.DESCRIPTOR.serialized_pb)
553    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
554        factory_test2_pb2.DESCRIPTOR.serialized_pb)
555
556  def testFindMethods(self):
557    self.assertIs(
558        self.pool.FindFileByName('google/protobuf/unittest.proto'),
559        unittest_pb2.DESCRIPTOR)
560    self.assertIs(
561        self.pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
562        unittest_pb2.TestAllTypes.DESCRIPTOR)
563    self.assertIs(
564        self.pool.FindFieldByName(
565            'protobuf_unittest.TestAllTypes.optional_int32'),
566        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
567    self.assertIs(
568        self.pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
569        unittest_pb2.ForeignEnum.DESCRIPTOR)
570    self.assertIs(
571        self.pool.FindExtensionByName(
572            'protobuf_unittest.optional_int32_extension'),
573        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
574    self.assertIs(
575        self.pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
576        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
577    self.assertIs(
578        self.pool.FindServiceByName('protobuf_unittest.TestService'),
579        unittest_pb2.DESCRIPTOR.services_by_name['TestService'])
580
581
582@testing_refleaks.TestCase
583class CreateDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
584
585  def setUp(self):
586    self.pool = descriptor_pool.DescriptorPool()
587    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
588        factory_test1_pb2.DESCRIPTOR.serialized_pb)
589    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
590        factory_test2_pb2.DESCRIPTOR.serialized_pb)
591    self.pool.Add(self.factory_test1_fd)
592    self.pool.Add(self.factory_test2_fd)
593
594    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
595        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
596    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
597        unittest_import_pb2.DESCRIPTOR.serialized_pb))
598    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
599        unittest_pb2.DESCRIPTOR.serialized_pb))
600    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
601        no_package_pb2.DESCRIPTOR.serialized_pb))
602
603
604@testing_refleaks.TestCase
605class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
606                                          unittest.TestCase):
607
608  def setUp(self):
609    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
610        factory_test1_pb2.DESCRIPTOR.serialized_pb)
611    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
612        factory_test2_pb2.DESCRIPTOR.serialized_pb)
613    self.db = descriptor_database.DescriptorDatabase()
614    self.db.Add(self.factory_test1_fd)
615    self.db.Add(self.factory_test2_fd)
616    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
617        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
618    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
619        unittest_import_pb2.DESCRIPTOR.serialized_pb))
620    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
621        unittest_pb2.DESCRIPTOR.serialized_pb))
622    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
623        no_package_pb2.DESCRIPTOR.serialized_pb))
624    self.pool = descriptor_pool.DescriptorPool(descriptor_db=self.db)
625
626  def testErrorCollector(self):
627    file_proto = descriptor_pb2.FileDescriptorProto()
628    file_proto.package = 'collector'
629    file_proto.name = 'error_file'
630    message_type = file_proto.message_type.add()
631    message_type.name = 'ErrorMessage'
632    field = message_type.field.add()
633    field.number = 1
634    field.name = 'nested_message_field'
635    field.label = descriptor.FieldDescriptor.LABEL_OPTIONAL
636    field.type = descriptor.FieldDescriptor.TYPE_MESSAGE
637    field.type_name = 'SubMessage'
638    oneof = message_type.oneof_decl.add()
639    oneof.name = 'MyOneof'
640    enum_type = file_proto.enum_type.add()
641    enum_type.name = 'MyEnum'
642    enum_value = enum_type.value.add()
643    enum_value.name = 'MyEnumValue'
644    enum_value.number = 0
645    self.db.Add(file_proto)
646
647    self.assertRaisesRegexp(KeyError, 'SubMessage',
648                            self.pool.FindMessageTypeByName,
649                            'collector.ErrorMessage')
650    self.assertRaisesRegexp(KeyError, 'SubMessage',
651                            self.pool.FindFileByName, 'error_file')
652    with self.assertRaises(KeyError) as exc:
653      self.pool.FindFileByName('none_file')
654    self.assertIn(str(exc.exception), ('\'none_file\'',
655                                       '\"Couldn\'t find file none_file\"'))
656
657    # Pure python _ConvertFileProtoToFileDescriptor() method has side effect
658    # that all the symbols found in the file will load into the pool even the
659    # file can not build. So when FindMessageTypeByName('ErrorMessage') was
660    # called the first time, a KeyError will be raised but call the find
661    # method later will return a descriptor which is not build.
662    # TODO(jieluo): fix pure python to revert the load if file can not be build
663    if api_implementation.Type() == 'cpp':
664      error_msg = ('Invalid proto descriptor for file "error_file":\\n  '
665                   'collector.ErrorMessage.nested_message_field: "SubMessage" '
666                   'is not defined.\\n  collector.ErrorMessage.MyOneof: Oneof '
667                   'must have at least one field.\\n\'')
668      with self.assertRaises(KeyError) as exc:
669        self.pool.FindMessageTypeByName('collector.ErrorMessage')
670      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for '
671                       'message collector.ErrorMessage\\n' + error_msg)
672
673      with self.assertRaises(KeyError) as exc:
674        self.pool.FindFieldByName('collector.ErrorMessage.nested_message_field')
675      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for field'
676                       ' collector.ErrorMessage.nested_message_field\\n'
677                       + error_msg)
678
679      with self.assertRaises(KeyError) as exc:
680        self.pool.FindEnumTypeByName('collector.MyEnum')
681      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for enum'
682                       ' collector.MyEnum\\n' + error_msg)
683
684      with self.assertRaises(KeyError) as exc:
685        self.pool.FindFileContainingSymbol('collector.MyEnumValue')
686      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for symbol'
687                       ' collector.MyEnumValue\\n' + error_msg)
688
689      with self.assertRaises(KeyError) as exc:
690        self.pool.FindOneofByName('collector.ErrorMessage.MyOneof')
691      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for oneof'
692                       ' collector.ErrorMessage.MyOneof\\n' + error_msg)
693
694
695class ProtoFile(object):
696
697  def __init__(self, name, package, messages, dependencies=None,
698               public_dependencies=None):
699    self.name = name
700    self.package = package
701    self.messages = messages
702    self.dependencies = dependencies or []
703    self.public_dependencies = public_dependencies or []
704
705  def CheckFile(self, test, pool):
706    file_desc = pool.FindFileByName(self.name)
707    test.assertEqual(self.name, file_desc.name)
708    test.assertEqual(self.package, file_desc.package)
709    dependencies_names = [f.name for f in file_desc.dependencies]
710    test.assertEqual(self.dependencies, dependencies_names)
711    public_dependencies_names = [f.name for f in file_desc.public_dependencies]
712    test.assertEqual(self.public_dependencies, public_dependencies_names)
713    for name, msg_type in self.messages.items():
714      msg_type.CheckType(test, None, name, file_desc)
715
716
717class EnumType(object):
718
719  def __init__(self, values):
720    self.values = values
721
722  def CheckType(self, test, msg_desc, name, file_desc):
723    enum_desc = msg_desc.enum_types_by_name[name]
724    test.assertEqual(name, enum_desc.name)
725    expected_enum_full_name = '.'.join([msg_desc.full_name, name])
726    test.assertEqual(expected_enum_full_name, enum_desc.full_name)
727    test.assertEqual(msg_desc, enum_desc.containing_type)
728    test.assertEqual(file_desc, enum_desc.file)
729    for index, (value, number) in enumerate(self.values):
730      value_desc = enum_desc.values_by_name[value]
731      test.assertEqual(value, value_desc.name)
732      test.assertEqual(index, value_desc.index)
733      test.assertEqual(number, value_desc.number)
734      test.assertEqual(enum_desc, value_desc.type)
735      test.assertIn(value, msg_desc.enum_values_by_name)
736
737
738class MessageType(object):
739
740  def __init__(self, type_dict, field_list, is_extendable=False,
741               extensions=None):
742    self.type_dict = type_dict
743    self.field_list = field_list
744    self.is_extendable = is_extendable
745    self.extensions = extensions or []
746
747  def CheckType(self, test, containing_type_desc, name, file_desc):
748    if containing_type_desc is None:
749      desc = file_desc.message_types_by_name[name]
750      expected_full_name = '.'.join([file_desc.package, name])
751    else:
752      desc = containing_type_desc.nested_types_by_name[name]
753      expected_full_name = '.'.join([containing_type_desc.full_name, name])
754
755    test.assertEqual(name, desc.name)
756    test.assertEqual(expected_full_name, desc.full_name)
757    test.assertEqual(containing_type_desc, desc.containing_type)
758    test.assertEqual(desc.file, file_desc)
759    test.assertEqual(self.is_extendable, desc.is_extendable)
760    for name, subtype in self.type_dict.items():
761      subtype.CheckType(test, desc, name, file_desc)
762
763    for index, (name, field) in enumerate(self.field_list):
764      field.CheckField(test, desc, name, index, file_desc)
765
766    for index, (name, field) in enumerate(self.extensions):
767      field.CheckField(test, desc, name, index, file_desc)
768
769
770class EnumField(object):
771
772  def __init__(self, number, type_name, default_value):
773    self.number = number
774    self.type_name = type_name
775    self.default_value = default_value
776
777  def CheckField(self, test, msg_desc, name, index, file_desc):
778    field_desc = msg_desc.fields_by_name[name]
779    enum_desc = msg_desc.enum_types_by_name[self.type_name]
780    test.assertEqual(name, field_desc.name)
781    expected_field_full_name = '.'.join([msg_desc.full_name, name])
782    test.assertEqual(expected_field_full_name, field_desc.full_name)
783    test.assertEqual(index, field_desc.index)
784    test.assertEqual(self.number, field_desc.number)
785    test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type)
786    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM,
787                     field_desc.cpp_type)
788    test.assertTrue(field_desc.has_default_value)
789    test.assertEqual(enum_desc.values_by_name[self.default_value].number,
790                     field_desc.default_value)
791    test.assertFalse(enum_desc.values_by_name[self.default_value].has_options)
792    test.assertEqual(msg_desc, field_desc.containing_type)
793    test.assertEqual(enum_desc, field_desc.enum_type)
794    test.assertEqual(file_desc, enum_desc.file)
795
796
797class MessageField(object):
798
799  def __init__(self, number, type_name):
800    self.number = number
801    self.type_name = type_name
802
803  def CheckField(self, test, msg_desc, name, index, file_desc):
804    field_desc = msg_desc.fields_by_name[name]
805    field_type_desc = msg_desc.nested_types_by_name[self.type_name]
806    test.assertEqual(name, field_desc.name)
807    expected_field_full_name = '.'.join([msg_desc.full_name, name])
808    test.assertEqual(expected_field_full_name, field_desc.full_name)
809    test.assertEqual(index, field_desc.index)
810    test.assertEqual(self.number, field_desc.number)
811    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
812    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
813                     field_desc.cpp_type)
814    test.assertFalse(field_desc.has_default_value)
815    test.assertEqual(msg_desc, field_desc.containing_type)
816    test.assertEqual(field_type_desc, field_desc.message_type)
817    test.assertEqual(file_desc, field_desc.file)
818    test.assertEqual(field_desc.default_value, None)
819
820
821class StringField(object):
822
823  def __init__(self, number, default_value):
824    self.number = number
825    self.default_value = default_value
826
827  def CheckField(self, test, msg_desc, name, index, file_desc):
828    field_desc = msg_desc.fields_by_name[name]
829    test.assertEqual(name, field_desc.name)
830    expected_field_full_name = '.'.join([msg_desc.full_name, name])
831    test.assertEqual(expected_field_full_name, field_desc.full_name)
832    test.assertEqual(index, field_desc.index)
833    test.assertEqual(self.number, field_desc.number)
834    test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type)
835    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING,
836                     field_desc.cpp_type)
837    test.assertTrue(field_desc.has_default_value)
838    test.assertEqual(self.default_value, field_desc.default_value)
839    test.assertEqual(file_desc, field_desc.file)
840
841
842class ExtensionField(object):
843
844  def __init__(self, number, extended_type):
845    self.number = number
846    self.extended_type = extended_type
847
848  def CheckField(self, test, msg_desc, name, index, file_desc):
849    field_desc = msg_desc.extensions_by_name[name]
850    test.assertEqual(name, field_desc.name)
851    expected_field_full_name = '.'.join([msg_desc.full_name, name])
852    test.assertEqual(expected_field_full_name, field_desc.full_name)
853    test.assertEqual(self.number, field_desc.number)
854    test.assertEqual(index, field_desc.index)
855    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
856    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
857                     field_desc.cpp_type)
858    test.assertFalse(field_desc.has_default_value)
859    test.assertTrue(field_desc.is_extension)
860    test.assertEqual(msg_desc, field_desc.extension_scope)
861    test.assertEqual(msg_desc, field_desc.message_type)
862    test.assertEqual(self.extended_type, field_desc.containing_type.name)
863    test.assertEqual(file_desc, field_desc.file)
864
865
866@testing_refleaks.TestCase
867class AddDescriptorTest(unittest.TestCase):
868
869  def _TestMessage(self, prefix):
870    pool = descriptor_pool.DescriptorPool()
871    pool._AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
872    self.assertEqual(
873        'protobuf_unittest.TestAllTypes',
874        pool.FindMessageTypeByName(
875            prefix + 'protobuf_unittest.TestAllTypes').full_name)
876
877    # AddDescriptor is not recursive.
878    with self.assertRaises(KeyError):
879      pool.FindMessageTypeByName(
880          prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
881
882    pool._AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
883    self.assertEqual(
884        'protobuf_unittest.TestAllTypes.NestedMessage',
885        pool.FindMessageTypeByName(
886            prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
887
888    # Files are implicitly also indexed when messages are added.
889    self.assertEqual(
890        'google/protobuf/unittest.proto',
891        pool.FindFileByName(
892            'google/protobuf/unittest.proto').name)
893
894    self.assertEqual(
895        'google/protobuf/unittest.proto',
896        pool.FindFileContainingSymbol(
897            prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
898
899  @unittest.skipIf(api_implementation.Type() == 'cpp',
900                   'With the cpp implementation, Add() must be called first')
901  def testMessage(self):
902    self._TestMessage('')
903    self._TestMessage('.')
904
905  def _TestEnum(self, prefix):
906    pool = descriptor_pool.DescriptorPool()
907    if api_implementation.Type() == 'cpp':
908      pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
909    else:
910      pool._AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
911    self.assertEqual(
912        'protobuf_unittest.ForeignEnum',
913        pool.FindEnumTypeByName(
914            prefix + 'protobuf_unittest.ForeignEnum').full_name)
915
916    # AddEnumDescriptor is not recursive.
917    with self.assertRaises(KeyError):
918      pool.FindEnumTypeByName(
919          prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
920
921    if api_implementation.Type() == 'cpp':
922      pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
923    else:
924      pool._AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
925    self.assertEqual(
926        'protobuf_unittest.TestAllTypes.NestedEnum',
927        pool.FindEnumTypeByName(
928            prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
929
930    # Files are implicitly also indexed when enums are added.
931    self.assertEqual(
932        'google/protobuf/unittest.proto',
933        pool.FindFileByName(
934            'google/protobuf/unittest.proto').name)
935
936    self.assertEqual(
937        'google/protobuf/unittest.proto',
938        pool.FindFileContainingSymbol(
939            prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
940
941  @unittest.skipIf(api_implementation.Type() == 'cpp',
942                   'With the cpp implementation, Add() must be called first')
943  def testEnum(self):
944    self._TestEnum('')
945    self._TestEnum('.')
946
947  @unittest.skipIf(api_implementation.Type() == 'cpp',
948                   'With the cpp implementation, Add() must be called first')
949  def testService(self):
950    pool = descriptor_pool.DescriptorPool()
951    with self.assertRaises(KeyError):
952      pool.FindServiceByName('protobuf_unittest.TestService')
953    pool._AddServiceDescriptor(unittest_pb2._TESTSERVICE)
954    self.assertEqual(
955        'protobuf_unittest.TestService',
956        pool.FindServiceByName('protobuf_unittest.TestService').full_name)
957
958  @unittest.skipIf(api_implementation.Type() == 'cpp',
959                   'With the cpp implementation, Add() must be called first')
960  def testFile(self):
961    pool = descriptor_pool.DescriptorPool()
962    pool._AddFileDescriptor(unittest_pb2.DESCRIPTOR)
963    self.assertEqual(
964        'google/protobuf/unittest.proto',
965        pool.FindFileByName(
966            'google/protobuf/unittest.proto').name)
967
968    # AddFileDescriptor is not recursive; messages and enums within files must
969    # be explicitly registered.
970    with self.assertRaises(KeyError):
971      pool.FindFileContainingSymbol(
972          'protobuf_unittest.TestAllTypes')
973
974  def testEmptyDescriptorPool(self):
975    # Check that an empty DescriptorPool() contains no messages.
976    pool = descriptor_pool.DescriptorPool()
977    proto_file_name = descriptor_pb2.DESCRIPTOR.name
978    self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
979    # Add the above file to the pool
980    file_descriptor = descriptor_pb2.FileDescriptorProto()
981    descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
982    pool.Add(file_descriptor)
983    # Now it exists.
984    self.assertTrue(pool.FindFileByName(proto_file_name))
985
986  def testCustomDescriptorPool(self):
987    # Create a new pool, and add a file descriptor.
988    pool = descriptor_pool.DescriptorPool()
989    file_desc = descriptor_pb2.FileDescriptorProto(
990        name='some/file.proto', package='package')
991    file_desc.message_type.add(name='Message')
992    pool.Add(file_desc)
993    self.assertEqual(pool.FindFileByName('some/file.proto').name,
994                     'some/file.proto')
995    self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
996                     'Message')
997    # Test no package
998    file_proto = descriptor_pb2.FileDescriptorProto(
999        name='some/filename/container.proto')
1000    message_proto = file_proto.message_type.add(
1001        name='TopMessage')
1002    message_proto.field.add(
1003        name='bb',
1004        number=1,
1005        type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
1006        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL)
1007    enum_proto = file_proto.enum_type.add(name='TopEnum')
1008    enum_proto.value.add(name='FOREIGN_FOO', number=4)
1009    file_proto.service.add(name='TopService')
1010    pool = descriptor_pool.DescriptorPool()
1011    pool.Add(file_proto)
1012    self.assertEqual('TopMessage',
1013                     pool.FindMessageTypeByName('TopMessage').name)
1014    self.assertEqual('TopEnum', pool.FindEnumTypeByName('TopEnum').name)
1015    self.assertEqual('TopService', pool.FindServiceByName('TopService').name)
1016
1017  def testFileDescriptorOptionsWithCustomDescriptorPool(self):
1018    # Create a descriptor pool, and add a new FileDescriptorProto to it.
1019    pool = descriptor_pool.DescriptorPool()
1020    file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto'
1021    file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name)
1022    extension_id = file_options_test_pb2.foo_options
1023    file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo'
1024    pool.Add(file_descriptor_proto)
1025    # The options set on the FileDescriptorProto should be available in the
1026    # descriptor even if they contain extensions that cannot be deserialized
1027    # using the pool.
1028    file_descriptor = pool.FindFileByName(file_name)
1029    options = file_descriptor.GetOptions()
1030    self.assertEqual('foo', options.Extensions[extension_id].foo_name)
1031    # The object returned by GetOptions() is cached.
1032    self.assertIs(options, file_descriptor.GetOptions())
1033
1034  def testAddTypeError(self):
1035    pool = descriptor_pool.DescriptorPool()
1036    if api_implementation.Type() == 'cpp':
1037      with self.assertRaises(TypeError):
1038        pool.AddDescriptor(0)
1039      with self.assertRaises(TypeError):
1040        pool.AddEnumDescriptor(0)
1041      with self.assertRaises(TypeError):
1042        pool.AddServiceDescriptor(0)
1043      with self.assertRaises(TypeError):
1044        pool.AddExtensionDescriptor(0)
1045      with self.assertRaises(TypeError):
1046        pool.AddFileDescriptor(0)
1047    else:
1048      with self.assertRaises(TypeError):
1049        pool._AddDescriptor(0)
1050      with self.assertRaises(TypeError):
1051        pool._AddEnumDescriptor(0)
1052      with self.assertRaises(TypeError):
1053        pool._AddServiceDescriptor(0)
1054      with self.assertRaises(TypeError):
1055        pool._AddExtensionDescriptor(0)
1056      with self.assertRaises(TypeError):
1057        pool._AddFileDescriptor(0)
1058
1059
1060TEST1_FILE = ProtoFile(
1061    'google/protobuf/internal/descriptor_pool_test1.proto',
1062    'google.protobuf.python.internal',
1063    {
1064        'DescriptorPoolTest1': MessageType({
1065            'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]),
1066            'NestedMessage': MessageType({
1067                'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]),
1068                'DeepNestedMessage': MessageType({
1069                    'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]),
1070                }, [
1071                    ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')),
1072                    ('nested_field', StringField(2, 'theta')),
1073                ]),
1074            }, [
1075                ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')),
1076                ('nested_field', StringField(2, 'beta')),
1077                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
1078            ])
1079        }, [
1080            ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')),
1081            ('nested_message', MessageField(2, 'NestedMessage')),
1082        ], is_extendable=True),
1083
1084        'DescriptorPoolTest2': MessageType({
1085            'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]),
1086            'NestedMessage': MessageType({
1087                'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]),
1088                'DeepNestedMessage': MessageType({
1089                    'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]),
1090                }, [
1091                    ('nested_enum', EnumField(1, 'NestedEnum', 'MU')),
1092                    ('nested_field', StringField(2, 'lambda')),
1093                ]),
1094            }, [
1095                ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')),
1096                ('nested_field', StringField(2, 'delta')),
1097                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
1098            ])
1099        }, [
1100            ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')),
1101            ('nested_message', MessageField(2, 'NestedMessage')),
1102        ]),
1103    })
1104
1105
1106TEST2_FILE = ProtoFile(
1107    'google/protobuf/internal/descriptor_pool_test2.proto',
1108    'google.protobuf.python.internal',
1109    {
1110        'DescriptorPoolTest3': MessageType({
1111            'NestedEnum': EnumType([('NU', 13), ('XI', 14)]),
1112            'NestedMessage': MessageType({
1113                'NestedEnum': EnumType([('OMICRON', 15), ('PI', 16)]),
1114                'DeepNestedMessage': MessageType({
1115                    'NestedEnum': EnumType([('RHO', 17), ('SIGMA', 18)]),
1116                }, [
1117                    ('nested_enum', EnumField(1, 'NestedEnum', 'RHO')),
1118                    ('nested_field', StringField(2, 'sigma')),
1119                ]),
1120            }, [
1121                ('nested_enum', EnumField(1, 'NestedEnum', 'PI')),
1122                ('nested_field', StringField(2, 'nu')),
1123                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
1124            ])
1125        }, [
1126            ('nested_enum', EnumField(1, 'NestedEnum', 'XI')),
1127            ('nested_message', MessageField(2, 'NestedMessage')),
1128        ], extensions=[
1129            ('descriptor_pool_test',
1130             ExtensionField(1001, 'DescriptorPoolTest1')),
1131        ]),
1132    },
1133    dependencies=['google/protobuf/internal/descriptor_pool_test1.proto',
1134                  'google/protobuf/internal/more_messages.proto'],
1135    public_dependencies=['google/protobuf/internal/more_messages.proto'])
1136
1137
1138if __name__ == '__main__':
1139  unittest.main()
1140