• 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 os
38import sys
39
40try:
41  import unittest2 as unittest  #PY26
42except ImportError:
43  import unittest
44
45from google.protobuf import unittest_import_pb2
46from google.protobuf import unittest_import_public_pb2
47from google.protobuf import unittest_pb2
48from google.protobuf import descriptor_pb2
49from google.protobuf.internal import api_implementation
50from google.protobuf.internal import descriptor_pool_test1_pb2
51from google.protobuf.internal import descriptor_pool_test2_pb2
52from google.protobuf.internal import factory_test1_pb2
53from google.protobuf.internal import factory_test2_pb2
54from google.protobuf.internal import more_messages_pb2
55from google.protobuf import descriptor
56from google.protobuf import descriptor_database
57from google.protobuf import descriptor_pool
58from google.protobuf import message_factory
59from google.protobuf import symbol_database
60
61
62class DescriptorPoolTest(unittest.TestCase):
63
64  def setUp(self):
65    self.pool = descriptor_pool.DescriptorPool()
66    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
67        factory_test1_pb2.DESCRIPTOR.serialized_pb)
68    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
69        factory_test2_pb2.DESCRIPTOR.serialized_pb)
70    self.pool.Add(self.factory_test1_fd)
71    self.pool.Add(self.factory_test2_fd)
72
73  def testFindFileByName(self):
74    name1 = 'google/protobuf/internal/factory_test1.proto'
75    file_desc1 = self.pool.FindFileByName(name1)
76    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
77    self.assertEqual(name1, file_desc1.name)
78    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
79    self.assertIn('Factory1Message', file_desc1.message_types_by_name)
80
81    name2 = 'google/protobuf/internal/factory_test2.proto'
82    file_desc2 = self.pool.FindFileByName(name2)
83    self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
84    self.assertEqual(name2, file_desc2.name)
85    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
86    self.assertIn('Factory2Message', file_desc2.message_types_by_name)
87
88  def testFindFileByNameFailure(self):
89    with self.assertRaises(KeyError):
90      self.pool.FindFileByName('Does not exist')
91
92  def testFindFileContainingSymbol(self):
93    file_desc1 = self.pool.FindFileContainingSymbol(
94        'google.protobuf.python.internal.Factory1Message')
95    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
96    self.assertEqual('google/protobuf/internal/factory_test1.proto',
97                     file_desc1.name)
98    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
99    self.assertIn('Factory1Message', file_desc1.message_types_by_name)
100
101    file_desc2 = self.pool.FindFileContainingSymbol(
102        'google.protobuf.python.internal.Factory2Message')
103    self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
104    self.assertEqual('google/protobuf/internal/factory_test2.proto',
105                     file_desc2.name)
106    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
107    self.assertIn('Factory2Message', file_desc2.message_types_by_name)
108
109  def testFindFileContainingSymbolFailure(self):
110    with self.assertRaises(KeyError):
111      self.pool.FindFileContainingSymbol('Does not exist')
112
113  def testFindMessageTypeByName(self):
114    msg1 = self.pool.FindMessageTypeByName(
115        'google.protobuf.python.internal.Factory1Message')
116    self.assertIsInstance(msg1, descriptor.Descriptor)
117    self.assertEqual('Factory1Message', msg1.name)
118    self.assertEqual('google.protobuf.python.internal.Factory1Message',
119                     msg1.full_name)
120    self.assertEqual(None, msg1.containing_type)
121
122    nested_msg1 = msg1.nested_types[0]
123    self.assertEqual('NestedFactory1Message', nested_msg1.name)
124    self.assertEqual(msg1, nested_msg1.containing_type)
125
126    nested_enum1 = msg1.enum_types[0]
127    self.assertEqual('NestedFactory1Enum', nested_enum1.name)
128    self.assertEqual(msg1, nested_enum1.containing_type)
129
130    self.assertEqual(nested_msg1, msg1.fields_by_name[
131        'nested_factory_1_message'].message_type)
132    self.assertEqual(nested_enum1, msg1.fields_by_name[
133        'nested_factory_1_enum'].enum_type)
134
135    msg2 = self.pool.FindMessageTypeByName(
136        'google.protobuf.python.internal.Factory2Message')
137    self.assertIsInstance(msg2, descriptor.Descriptor)
138    self.assertEqual('Factory2Message', msg2.name)
139    self.assertEqual('google.protobuf.python.internal.Factory2Message',
140                     msg2.full_name)
141    self.assertIsNone(msg2.containing_type)
142
143    nested_msg2 = msg2.nested_types[0]
144    self.assertEqual('NestedFactory2Message', nested_msg2.name)
145    self.assertEqual(msg2, nested_msg2.containing_type)
146
147    nested_enum2 = msg2.enum_types[0]
148    self.assertEqual('NestedFactory2Enum', nested_enum2.name)
149    self.assertEqual(msg2, nested_enum2.containing_type)
150
151    self.assertEqual(nested_msg2, msg2.fields_by_name[
152        'nested_factory_2_message'].message_type)
153    self.assertEqual(nested_enum2, msg2.fields_by_name[
154        'nested_factory_2_enum'].enum_type)
155
156    self.assertTrue(msg2.fields_by_name['int_with_default'].has_default_value)
157    self.assertEqual(
158        1776, msg2.fields_by_name['int_with_default'].default_value)
159
160    self.assertTrue(
161        msg2.fields_by_name['double_with_default'].has_default_value)
162    self.assertEqual(
163        9.99, msg2.fields_by_name['double_with_default'].default_value)
164
165    self.assertTrue(
166        msg2.fields_by_name['string_with_default'].has_default_value)
167    self.assertEqual(
168        'hello world', msg2.fields_by_name['string_with_default'].default_value)
169
170    self.assertTrue(msg2.fields_by_name['bool_with_default'].has_default_value)
171    self.assertFalse(msg2.fields_by_name['bool_with_default'].default_value)
172
173    self.assertTrue(msg2.fields_by_name['enum_with_default'].has_default_value)
174    self.assertEqual(
175        1, msg2.fields_by_name['enum_with_default'].default_value)
176
177    msg3 = self.pool.FindMessageTypeByName(
178        'google.protobuf.python.internal.Factory2Message.NestedFactory2Message')
179    self.assertEqual(nested_msg2, msg3)
180
181    self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value)
182    self.assertEqual(
183        b'a\xfb\x00c',
184        msg2.fields_by_name['bytes_with_default'].default_value)
185
186    self.assertEqual(1, len(msg2.oneofs))
187    self.assertEqual(1, len(msg2.oneofs_by_name))
188    self.assertEqual(2, len(msg2.oneofs[0].fields))
189    for name in ['oneof_int', 'oneof_string']:
190      self.assertEqual(msg2.oneofs[0],
191                       msg2.fields_by_name[name].containing_oneof)
192      self.assertIn(msg2.fields_by_name[name], msg2.oneofs[0].fields)
193
194  def testFindMessageTypeByNameFailure(self):
195    with self.assertRaises(KeyError):
196      self.pool.FindMessageTypeByName('Does not exist')
197
198  def testFindEnumTypeByName(self):
199    enum1 = self.pool.FindEnumTypeByName(
200        'google.protobuf.python.internal.Factory1Enum')
201    self.assertIsInstance(enum1, descriptor.EnumDescriptor)
202    self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
203    self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
204
205    nested_enum1 = self.pool.FindEnumTypeByName(
206        'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
207    self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor)
208    self.assertEqual(
209        0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number)
210    self.assertEqual(
211        1, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_1'].number)
212
213    enum2 = self.pool.FindEnumTypeByName(
214        'google.protobuf.python.internal.Factory2Enum')
215    self.assertIsInstance(enum2, descriptor.EnumDescriptor)
216    self.assertEqual(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number)
217    self.assertEqual(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number)
218
219    nested_enum2 = self.pool.FindEnumTypeByName(
220        'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum')
221    self.assertIsInstance(nested_enum2, descriptor.EnumDescriptor)
222    self.assertEqual(
223        0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number)
224    self.assertEqual(
225        1, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_1'].number)
226
227  def testFindEnumTypeByNameFailure(self):
228    with self.assertRaises(KeyError):
229      self.pool.FindEnumTypeByName('Does not exist')
230
231  def testFindFieldByName(self):
232    field = self.pool.FindFieldByName(
233        'google.protobuf.python.internal.Factory1Message.list_value')
234    self.assertEqual(field.name, 'list_value')
235    self.assertEqual(field.label, field.LABEL_REPEATED)
236    with self.assertRaises(KeyError):
237      self.pool.FindFieldByName('Does not exist')
238
239  def testFindExtensionByName(self):
240    # An extension defined in a message.
241    extension = self.pool.FindExtensionByName(
242        'google.protobuf.python.internal.Factory2Message.one_more_field')
243    self.assertEqual(extension.name, 'one_more_field')
244    # An extension defined at file scope.
245    extension = self.pool.FindExtensionByName(
246        'google.protobuf.python.internal.another_field')
247    self.assertEqual(extension.name, 'another_field')
248    self.assertEqual(extension.number, 1002)
249    with self.assertRaises(KeyError):
250      self.pool.FindFieldByName('Does not exist')
251
252  def testExtensionsAreNotFields(self):
253    with self.assertRaises(KeyError):
254      self.pool.FindFieldByName('google.protobuf.python.internal.another_field')
255    with self.assertRaises(KeyError):
256      self.pool.FindFieldByName(
257          'google.protobuf.python.internal.Factory2Message.one_more_field')
258    with self.assertRaises(KeyError):
259      self.pool.FindExtensionByName(
260          'google.protobuf.python.internal.Factory1Message.list_value')
261
262  def testUserDefinedDB(self):
263    db = descriptor_database.DescriptorDatabase()
264    self.pool = descriptor_pool.DescriptorPool(db)
265    db.Add(self.factory_test1_fd)
266    db.Add(self.factory_test2_fd)
267    self.testFindMessageTypeByName()
268
269  def testAddSerializedFile(self):
270    self.pool = descriptor_pool.DescriptorPool()
271    self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString())
272    self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString())
273    self.testFindMessageTypeByName()
274
275  def testComplexNesting(self):
276    more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
277        more_messages_pb2.DESCRIPTOR.serialized_pb)
278    test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
279        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
280    test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
281        descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
282    self.pool.Add(more_messages_desc)
283    self.pool.Add(test1_desc)
284    self.pool.Add(test2_desc)
285    TEST1_FILE.CheckFile(self, self.pool)
286    TEST2_FILE.CheckFile(self, self.pool)
287
288
289  def testEnumDefaultValue(self):
290    """Test the default value of enums which don't start at zero."""
291    def _CheckDefaultValue(file_descriptor):
292      default_value = (file_descriptor
293                       .message_types_by_name['DescriptorPoolTest1']
294                       .fields_by_name['nested_enum']
295                       .default_value)
296      self.assertEqual(default_value,
297                       descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA)
298    # First check what the generated descriptor contains.
299    _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR)
300    # Then check the generated pool. Normally this is the same descriptor.
301    file_descriptor = symbol_database.Default().pool.FindFileByName(
302        'google/protobuf/internal/descriptor_pool_test1.proto')
303    self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR)
304    _CheckDefaultValue(file_descriptor)
305
306    # Then check the dynamic pool and its internal DescriptorDatabase.
307    descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString(
308        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
309    self.pool.Add(descriptor_proto)
310    # And do the same check as above
311    file_descriptor = self.pool.FindFileByName(
312        'google/protobuf/internal/descriptor_pool_test1.proto')
313    _CheckDefaultValue(file_descriptor)
314
315  def testDefaultValueForCustomMessages(self):
316    """Check the value returned by non-existent fields."""
317    def _CheckValueAndType(value, expected_value, expected_type):
318      self.assertEqual(value, expected_value)
319      self.assertIsInstance(value, expected_type)
320
321    def _CheckDefaultValues(msg):
322      try:
323        int64 = long
324      except NameError:  # Python3
325        int64 = int
326      try:
327        unicode_type = unicode
328      except NameError:  # Python3
329        unicode_type = str
330      _CheckValueAndType(msg.optional_int32, 0, int)
331      _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
332      _CheckValueAndType(msg.optional_float, 0, (float, int))
333      _CheckValueAndType(msg.optional_double, 0, (float, int))
334      _CheckValueAndType(msg.optional_bool, False, bool)
335      _CheckValueAndType(msg.optional_string, u'', unicode_type)
336      _CheckValueAndType(msg.optional_bytes, b'', bytes)
337      _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
338    # First for the generated message
339    _CheckDefaultValues(unittest_pb2.TestAllTypes())
340    # Then for a message built with from the DescriptorPool.
341    pool = descriptor_pool.DescriptorPool()
342    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
343        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
344    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
345        unittest_import_pb2.DESCRIPTOR.serialized_pb))
346    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
347        unittest_pb2.DESCRIPTOR.serialized_pb))
348    message_class = message_factory.MessageFactory(pool).GetPrototype(
349        pool.FindMessageTypeByName(
350            unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
351    _CheckDefaultValues(message_class())
352
353
354class ProtoFile(object):
355
356  def __init__(self, name, package, messages, dependencies=None,
357               public_dependencies=None):
358    self.name = name
359    self.package = package
360    self.messages = messages
361    self.dependencies = dependencies or []
362    self.public_dependencies = public_dependencies or []
363
364  def CheckFile(self, test, pool):
365    file_desc = pool.FindFileByName(self.name)
366    test.assertEqual(self.name, file_desc.name)
367    test.assertEqual(self.package, file_desc.package)
368    dependencies_names = [f.name for f in file_desc.dependencies]
369    test.assertEqual(self.dependencies, dependencies_names)
370    public_dependencies_names = [f.name for f in file_desc.public_dependencies]
371    test.assertEqual(self.public_dependencies, public_dependencies_names)
372    for name, msg_type in self.messages.items():
373      msg_type.CheckType(test, None, name, file_desc)
374
375
376class EnumType(object):
377
378  def __init__(self, values):
379    self.values = values
380
381  def CheckType(self, test, msg_desc, name, file_desc):
382    enum_desc = msg_desc.enum_types_by_name[name]
383    test.assertEqual(name, enum_desc.name)
384    expected_enum_full_name = '.'.join([msg_desc.full_name, name])
385    test.assertEqual(expected_enum_full_name, enum_desc.full_name)
386    test.assertEqual(msg_desc, enum_desc.containing_type)
387    test.assertEqual(file_desc, enum_desc.file)
388    for index, (value, number) in enumerate(self.values):
389      value_desc = enum_desc.values_by_name[value]
390      test.assertEqual(value, value_desc.name)
391      test.assertEqual(index, value_desc.index)
392      test.assertEqual(number, value_desc.number)
393      test.assertEqual(enum_desc, value_desc.type)
394      test.assertIn(value, msg_desc.enum_values_by_name)
395
396
397class MessageType(object):
398
399  def __init__(self, type_dict, field_list, is_extendable=False,
400               extensions=None):
401    self.type_dict = type_dict
402    self.field_list = field_list
403    self.is_extendable = is_extendable
404    self.extensions = extensions or []
405
406  def CheckType(self, test, containing_type_desc, name, file_desc):
407    if containing_type_desc is None:
408      desc = file_desc.message_types_by_name[name]
409      expected_full_name = '.'.join([file_desc.package, name])
410    else:
411      desc = containing_type_desc.nested_types_by_name[name]
412      expected_full_name = '.'.join([containing_type_desc.full_name, name])
413
414    test.assertEqual(name, desc.name)
415    test.assertEqual(expected_full_name, desc.full_name)
416    test.assertEqual(containing_type_desc, desc.containing_type)
417    test.assertEqual(desc.file, file_desc)
418    test.assertEqual(self.is_extendable, desc.is_extendable)
419    for name, subtype in self.type_dict.items():
420      subtype.CheckType(test, desc, name, file_desc)
421
422    for index, (name, field) in enumerate(self.field_list):
423      field.CheckField(test, desc, name, index)
424
425    for index, (name, field) in enumerate(self.extensions):
426      field.CheckField(test, desc, name, index)
427
428
429class EnumField(object):
430
431  def __init__(self, number, type_name, default_value):
432    self.number = number
433    self.type_name = type_name
434    self.default_value = default_value
435
436  def CheckField(self, test, msg_desc, name, index):
437    field_desc = msg_desc.fields_by_name[name]
438    enum_desc = msg_desc.enum_types_by_name[self.type_name]
439    test.assertEqual(name, field_desc.name)
440    expected_field_full_name = '.'.join([msg_desc.full_name, name])
441    test.assertEqual(expected_field_full_name, field_desc.full_name)
442    test.assertEqual(index, field_desc.index)
443    test.assertEqual(self.number, field_desc.number)
444    test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type)
445    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM,
446                     field_desc.cpp_type)
447    test.assertTrue(field_desc.has_default_value)
448    test.assertEqual(enum_desc.values_by_name[self.default_value].number,
449                     field_desc.default_value)
450    test.assertEqual(msg_desc, field_desc.containing_type)
451    test.assertEqual(enum_desc, field_desc.enum_type)
452
453
454class MessageField(object):
455
456  def __init__(self, number, type_name):
457    self.number = number
458    self.type_name = type_name
459
460  def CheckField(self, test, msg_desc, name, index):
461    field_desc = msg_desc.fields_by_name[name]
462    field_type_desc = msg_desc.nested_types_by_name[self.type_name]
463    test.assertEqual(name, field_desc.name)
464    expected_field_full_name = '.'.join([msg_desc.full_name, name])
465    test.assertEqual(expected_field_full_name, field_desc.full_name)
466    test.assertEqual(index, field_desc.index)
467    test.assertEqual(self.number, field_desc.number)
468    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
469    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
470                     field_desc.cpp_type)
471    test.assertFalse(field_desc.has_default_value)
472    test.assertEqual(msg_desc, field_desc.containing_type)
473    test.assertEqual(field_type_desc, field_desc.message_type)
474
475
476class StringField(object):
477
478  def __init__(self, number, default_value):
479    self.number = number
480    self.default_value = default_value
481
482  def CheckField(self, test, msg_desc, name, index):
483    field_desc = msg_desc.fields_by_name[name]
484    test.assertEqual(name, field_desc.name)
485    expected_field_full_name = '.'.join([msg_desc.full_name, name])
486    test.assertEqual(expected_field_full_name, field_desc.full_name)
487    test.assertEqual(index, field_desc.index)
488    test.assertEqual(self.number, field_desc.number)
489    test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type)
490    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING,
491                     field_desc.cpp_type)
492    test.assertTrue(field_desc.has_default_value)
493    test.assertEqual(self.default_value, field_desc.default_value)
494
495
496class ExtensionField(object):
497
498  def __init__(self, number, extended_type):
499    self.number = number
500    self.extended_type = extended_type
501
502  def CheckField(self, test, msg_desc, name, index):
503    field_desc = msg_desc.extensions_by_name[name]
504    test.assertEqual(name, field_desc.name)
505    expected_field_full_name = '.'.join([msg_desc.full_name, name])
506    test.assertEqual(expected_field_full_name, field_desc.full_name)
507    test.assertEqual(self.number, field_desc.number)
508    test.assertEqual(index, field_desc.index)
509    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
510    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
511                     field_desc.cpp_type)
512    test.assertFalse(field_desc.has_default_value)
513    test.assertTrue(field_desc.is_extension)
514    test.assertEqual(msg_desc, field_desc.extension_scope)
515    test.assertEqual(msg_desc, field_desc.message_type)
516    test.assertEqual(self.extended_type, field_desc.containing_type.name)
517
518
519class AddDescriptorTest(unittest.TestCase):
520
521  def _TestMessage(self, prefix):
522    pool = descriptor_pool.DescriptorPool()
523    pool.AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
524    self.assertEqual(
525        'protobuf_unittest.TestAllTypes',
526        pool.FindMessageTypeByName(
527            prefix + 'protobuf_unittest.TestAllTypes').full_name)
528
529    # AddDescriptor is not recursive.
530    with self.assertRaises(KeyError):
531      pool.FindMessageTypeByName(
532          prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
533
534    pool.AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
535    self.assertEqual(
536        'protobuf_unittest.TestAllTypes.NestedMessage',
537        pool.FindMessageTypeByName(
538            prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
539
540    # Files are implicitly also indexed when messages are added.
541    self.assertEqual(
542        'google/protobuf/unittest.proto',
543        pool.FindFileByName(
544            'google/protobuf/unittest.proto').name)
545
546    self.assertEqual(
547        'google/protobuf/unittest.proto',
548        pool.FindFileContainingSymbol(
549            prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
550
551  @unittest.skipIf(api_implementation.Type() == 'cpp',
552                   'With the cpp implementation, Add() must be called first')
553  def testMessage(self):
554    self._TestMessage('')
555    self._TestMessage('.')
556
557  def _TestEnum(self, prefix):
558    pool = descriptor_pool.DescriptorPool()
559    pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
560    self.assertEqual(
561        'protobuf_unittest.ForeignEnum',
562        pool.FindEnumTypeByName(
563            prefix + 'protobuf_unittest.ForeignEnum').full_name)
564
565    # AddEnumDescriptor is not recursive.
566    with self.assertRaises(KeyError):
567      pool.FindEnumTypeByName(
568          prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
569
570    pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
571    self.assertEqual(
572        'protobuf_unittest.TestAllTypes.NestedEnum',
573        pool.FindEnumTypeByName(
574            prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
575
576    # Files are implicitly also indexed when enums are added.
577    self.assertEqual(
578        'google/protobuf/unittest.proto',
579        pool.FindFileByName(
580            'google/protobuf/unittest.proto').name)
581
582    self.assertEqual(
583        'google/protobuf/unittest.proto',
584        pool.FindFileContainingSymbol(
585            prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
586
587  @unittest.skipIf(api_implementation.Type() == 'cpp',
588                   'With the cpp implementation, Add() must be called first')
589  def testEnum(self):
590    self._TestEnum('')
591    self._TestEnum('.')
592
593  @unittest.skipIf(api_implementation.Type() == 'cpp',
594                   'With the cpp implementation, Add() must be called first')
595  def testFile(self):
596    pool = descriptor_pool.DescriptorPool()
597    pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR)
598    self.assertEqual(
599        'google/protobuf/unittest.proto',
600        pool.FindFileByName(
601            'google/protobuf/unittest.proto').name)
602
603    # AddFileDescriptor is not recursive; messages and enums within files must
604    # be explicitly registered.
605    with self.assertRaises(KeyError):
606      pool.FindFileContainingSymbol(
607          'protobuf_unittest.TestAllTypes')
608
609  def testEmptyDescriptorPool(self):
610    # Check that an empty DescriptorPool() contains no messages.
611    pool = descriptor_pool.DescriptorPool()
612    proto_file_name = descriptor_pb2.DESCRIPTOR.name
613    self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
614    # Add the above file to the pool
615    file_descriptor = descriptor_pb2.FileDescriptorProto()
616    descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
617    pool.Add(file_descriptor)
618    # Now it exists.
619    self.assertTrue(pool.FindFileByName(proto_file_name))
620
621  def testCustomDescriptorPool(self):
622    # Create a new pool, and add a file descriptor.
623    pool = descriptor_pool.DescriptorPool()
624    file_desc = descriptor_pb2.FileDescriptorProto(
625        name='some/file.proto', package='package')
626    file_desc.message_type.add(name='Message')
627    pool.Add(file_desc)
628    self.assertEqual(pool.FindFileByName('some/file.proto').name,
629                     'some/file.proto')
630    self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
631                     'Message')
632
633
634@unittest.skipIf(
635    api_implementation.Type() != 'cpp',
636    'default_pool is only supported by the C++ implementation')
637class DefaultPoolTest(unittest.TestCase):
638
639  def testFindMethods(self):
640    # pylint: disable=g-import-not-at-top
641    from google.protobuf.pyext import _message
642    pool = _message.default_pool
643    self.assertIs(
644        pool.FindFileByName('google/protobuf/unittest.proto'),
645        unittest_pb2.DESCRIPTOR)
646    self.assertIs(
647        pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
648        unittest_pb2.TestAllTypes.DESCRIPTOR)
649    self.assertIs(
650        pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
651        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
652    self.assertIs(
653        pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
654        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
655    self.assertIs(
656        pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
657        unittest_pb2.ForeignEnum.DESCRIPTOR)
658    self.assertIs(
659        pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
660        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
661
662  def testAddFileDescriptor(self):
663    # pylint: disable=g-import-not-at-top
664    from google.protobuf.pyext import _message
665    pool = _message.default_pool
666    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
667    pool.Add(file_desc)
668    pool.AddSerializedFile(file_desc.SerializeToString())
669
670
671TEST1_FILE = ProtoFile(
672    'google/protobuf/internal/descriptor_pool_test1.proto',
673    'google.protobuf.python.internal',
674    {
675        'DescriptorPoolTest1': MessageType({
676            'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]),
677            'NestedMessage': MessageType({
678                'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]),
679                'DeepNestedMessage': MessageType({
680                    'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]),
681                }, [
682                    ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')),
683                    ('nested_field', StringField(2, 'theta')),
684                ]),
685            }, [
686                ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')),
687                ('nested_field', StringField(2, 'beta')),
688                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
689            ])
690        }, [
691            ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')),
692            ('nested_message', MessageField(2, 'NestedMessage')),
693        ], is_extendable=True),
694
695        'DescriptorPoolTest2': MessageType({
696            'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]),
697            'NestedMessage': MessageType({
698                'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]),
699                'DeepNestedMessage': MessageType({
700                    'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]),
701                }, [
702                    ('nested_enum', EnumField(1, 'NestedEnum', 'MU')),
703                    ('nested_field', StringField(2, 'lambda')),
704                ]),
705            }, [
706                ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')),
707                ('nested_field', StringField(2, 'delta')),
708                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
709            ])
710        }, [
711            ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')),
712            ('nested_message', MessageField(2, 'NestedMessage')),
713        ]),
714    })
715
716
717TEST2_FILE = ProtoFile(
718    'google/protobuf/internal/descriptor_pool_test2.proto',
719    'google.protobuf.python.internal',
720    {
721        'DescriptorPoolTest3': MessageType({
722            'NestedEnum': EnumType([('NU', 13), ('XI', 14)]),
723            'NestedMessage': MessageType({
724                'NestedEnum': EnumType([('OMICRON', 15), ('PI', 16)]),
725                'DeepNestedMessage': MessageType({
726                    'NestedEnum': EnumType([('RHO', 17), ('SIGMA', 18)]),
727                }, [
728                    ('nested_enum', EnumField(1, 'NestedEnum', 'RHO')),
729                    ('nested_field', StringField(2, 'sigma')),
730                ]),
731            }, [
732                ('nested_enum', EnumField(1, 'NestedEnum', 'PI')),
733                ('nested_field', StringField(2, 'nu')),
734                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
735            ])
736        }, [
737            ('nested_enum', EnumField(1, 'NestedEnum', 'XI')),
738            ('nested_message', MessageField(2, 'NestedMessage')),
739        ], extensions=[
740            ('descriptor_pool_test',
741             ExtensionField(1001, 'DescriptorPoolTest1')),
742        ]),
743    },
744    dependencies=['google/protobuf/internal/descriptor_pool_test1.proto',
745                  'google/protobuf/internal/more_messages.proto'],
746    public_dependencies=['google/protobuf/internal/more_messages.proto'])
747
748
749if __name__ == '__main__':
750  unittest.main()
751