descriptor_pool_test.py 31 KB

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