descriptor_pool_test.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  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. import sys
  36. try:
  37. import unittest2 as unittest #PY26
  38. except ImportError:
  39. import unittest
  40. from google.protobuf import unittest_import_pb2
  41. from google.protobuf import unittest_import_public_pb2
  42. from google.protobuf import unittest_pb2
  43. from google.protobuf import descriptor_pb2
  44. from google.protobuf.internal import api_implementation
  45. from google.protobuf.internal import descriptor_pool_test1_pb2
  46. from google.protobuf.internal import descriptor_pool_test2_pb2
  47. from google.protobuf.internal import factory_test1_pb2
  48. from google.protobuf.internal import factory_test2_pb2
  49. from google.protobuf.internal import file_options_test_pb2
  50. from google.protobuf.internal import more_messages_pb2
  51. from google.protobuf import descriptor
  52. from google.protobuf import descriptor_database
  53. from google.protobuf import descriptor_pool
  54. from google.protobuf import message_factory
  55. from google.protobuf import symbol_database
  56. class DescriptorPoolTest(unittest.TestCase):
  57. def setUp(self):
  58. self.pool = descriptor_pool.DescriptorPool()
  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. more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
  236. more_messages_pb2.DESCRIPTOR.serialized_pb)
  237. test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
  238. descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
  239. test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
  240. descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
  241. self.pool.Add(more_messages_desc)
  242. self.pool.Add(test1_desc)
  243. self.pool.Add(test2_desc)
  244. TEST1_FILE.CheckFile(self, self.pool)
  245. TEST2_FILE.CheckFile(self, self.pool)
  246. def testEnumDefaultValue(self):
  247. """Test the default value of enums which don't start at zero."""
  248. def _CheckDefaultValue(file_descriptor):
  249. default_value = (file_descriptor
  250. .message_types_by_name['DescriptorPoolTest1']
  251. .fields_by_name['nested_enum']
  252. .default_value)
  253. self.assertEqual(default_value,
  254. descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA)
  255. # First check what the generated descriptor contains.
  256. _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR)
  257. # Then check the generated pool. Normally this is the same descriptor.
  258. file_descriptor = symbol_database.Default().pool.FindFileByName(
  259. 'google/protobuf/internal/descriptor_pool_test1.proto')
  260. self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR)
  261. _CheckDefaultValue(file_descriptor)
  262. # Then check the dynamic pool and its internal DescriptorDatabase.
  263. descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString(
  264. descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
  265. self.pool.Add(descriptor_proto)
  266. # And do the same check as above
  267. file_descriptor = self.pool.FindFileByName(
  268. 'google/protobuf/internal/descriptor_pool_test1.proto')
  269. _CheckDefaultValue(file_descriptor)
  270. def testDefaultValueForCustomMessages(self):
  271. """Check the value returned by non-existent fields."""
  272. def _CheckValueAndType(value, expected_value, expected_type):
  273. self.assertEqual(value, expected_value)
  274. self.assertIsInstance(value, expected_type)
  275. def _CheckDefaultValues(msg):
  276. try:
  277. int64 = long
  278. except NameError: # Python3
  279. int64 = int
  280. try:
  281. unicode_type = unicode
  282. except NameError: # Python3
  283. unicode_type = str
  284. _CheckValueAndType(msg.optional_int32, 0, int)
  285. _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
  286. _CheckValueAndType(msg.optional_float, 0, (float, int))
  287. _CheckValueAndType(msg.optional_double, 0, (float, int))
  288. _CheckValueAndType(msg.optional_bool, False, bool)
  289. _CheckValueAndType(msg.optional_string, u'', unicode_type)
  290. _CheckValueAndType(msg.optional_bytes, b'', bytes)
  291. _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
  292. # First for the generated message
  293. _CheckDefaultValues(unittest_pb2.TestAllTypes())
  294. # Then for a message built with from the DescriptorPool.
  295. pool = descriptor_pool.DescriptorPool()
  296. pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
  297. unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
  298. pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
  299. unittest_import_pb2.DESCRIPTOR.serialized_pb))
  300. pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
  301. unittest_pb2.DESCRIPTOR.serialized_pb))
  302. message_class = message_factory.MessageFactory(pool).GetPrototype(
  303. pool.FindMessageTypeByName(
  304. unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
  305. _CheckDefaultValues(message_class())
  306. class ProtoFile(object):
  307. def __init__(self, name, package, messages, dependencies=None,
  308. public_dependencies=None):
  309. self.name = name
  310. self.package = package
  311. self.messages = messages
  312. self.dependencies = dependencies or []
  313. self.public_dependencies = public_dependencies or []
  314. def CheckFile(self, test, pool):
  315. file_desc = pool.FindFileByName(self.name)
  316. test.assertEqual(self.name, file_desc.name)
  317. test.assertEqual(self.package, file_desc.package)
  318. dependencies_names = [f.name for f in file_desc.dependencies]
  319. test.assertEqual(self.dependencies, dependencies_names)
  320. public_dependencies_names = [f.name for f in file_desc.public_dependencies]
  321. test.assertEqual(self.public_dependencies, public_dependencies_names)
  322. for name, msg_type in self.messages.items():
  323. msg_type.CheckType(test, None, name, file_desc)
  324. class EnumType(object):
  325. def __init__(self, values):
  326. self.values = values
  327. def CheckType(self, test, msg_desc, name, file_desc):
  328. enum_desc = msg_desc.enum_types_by_name[name]
  329. test.assertEqual(name, enum_desc.name)
  330. expected_enum_full_name = '.'.join([msg_desc.full_name, name])
  331. test.assertEqual(expected_enum_full_name, enum_desc.full_name)
  332. test.assertEqual(msg_desc, enum_desc.containing_type)
  333. test.assertEqual(file_desc, enum_desc.file)
  334. for index, (value, number) in enumerate(self.values):
  335. value_desc = enum_desc.values_by_name[value]
  336. test.assertEqual(value, value_desc.name)
  337. test.assertEqual(index, value_desc.index)
  338. test.assertEqual(number, value_desc.number)
  339. test.assertEqual(enum_desc, value_desc.type)
  340. test.assertIn(value, msg_desc.enum_values_by_name)
  341. class MessageType(object):
  342. def __init__(self, type_dict, field_list, is_extendable=False,
  343. extensions=None):
  344. self.type_dict = type_dict
  345. self.field_list = field_list
  346. self.is_extendable = is_extendable
  347. self.extensions = extensions or []
  348. def CheckType(self, test, containing_type_desc, name, file_desc):
  349. if containing_type_desc is None:
  350. desc = file_desc.message_types_by_name[name]
  351. expected_full_name = '.'.join([file_desc.package, name])
  352. else:
  353. desc = containing_type_desc.nested_types_by_name[name]
  354. expected_full_name = '.'.join([containing_type_desc.full_name, name])
  355. test.assertEqual(name, desc.name)
  356. test.assertEqual(expected_full_name, desc.full_name)
  357. test.assertEqual(containing_type_desc, desc.containing_type)
  358. test.assertEqual(desc.file, file_desc)
  359. test.assertEqual(self.is_extendable, desc.is_extendable)
  360. for name, subtype in self.type_dict.items():
  361. subtype.CheckType(test, desc, name, file_desc)
  362. for index, (name, field) in enumerate(self.field_list):
  363. field.CheckField(test, desc, name, index)
  364. for index, (name, field) in enumerate(self.extensions):
  365. field.CheckField(test, desc, name, index)
  366. class EnumField(object):
  367. def __init__(self, number, type_name, default_value):
  368. self.number = number
  369. self.type_name = type_name
  370. self.default_value = default_value
  371. def CheckField(self, test, msg_desc, name, index):
  372. field_desc = msg_desc.fields_by_name[name]
  373. enum_desc = msg_desc.enum_types_by_name[self.type_name]
  374. test.assertEqual(name, field_desc.name)
  375. expected_field_full_name = '.'.join([msg_desc.full_name, name])
  376. test.assertEqual(expected_field_full_name, field_desc.full_name)
  377. test.assertEqual(index, field_desc.index)
  378. test.assertEqual(self.number, field_desc.number)
  379. test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type)
  380. test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM,
  381. field_desc.cpp_type)
  382. test.assertTrue(field_desc.has_default_value)
  383. test.assertEqual(enum_desc.values_by_name[self.default_value].number,
  384. field_desc.default_value)
  385. test.assertEqual(msg_desc, field_desc.containing_type)
  386. test.assertEqual(enum_desc, field_desc.enum_type)
  387. class MessageField(object):
  388. def __init__(self, number, type_name):
  389. self.number = number
  390. self.type_name = type_name
  391. def CheckField(self, test, msg_desc, name, index):
  392. field_desc = msg_desc.fields_by_name[name]
  393. field_type_desc = msg_desc.nested_types_by_name[self.type_name]
  394. test.assertEqual(name, field_desc.name)
  395. expected_field_full_name = '.'.join([msg_desc.full_name, name])
  396. test.assertEqual(expected_field_full_name, field_desc.full_name)
  397. test.assertEqual(index, field_desc.index)
  398. test.assertEqual(self.number, field_desc.number)
  399. test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
  400. test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
  401. field_desc.cpp_type)
  402. test.assertFalse(field_desc.has_default_value)
  403. test.assertEqual(msg_desc, field_desc.containing_type)
  404. test.assertEqual(field_type_desc, field_desc.message_type)
  405. class StringField(object):
  406. def __init__(self, number, default_value):
  407. self.number = number
  408. self.default_value = default_value
  409. def CheckField(self, test, msg_desc, name, index):
  410. field_desc = msg_desc.fields_by_name[name]
  411. test.assertEqual(name, field_desc.name)
  412. expected_field_full_name = '.'.join([msg_desc.full_name, name])
  413. test.assertEqual(expected_field_full_name, field_desc.full_name)
  414. test.assertEqual(index, field_desc.index)
  415. test.assertEqual(self.number, field_desc.number)
  416. test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type)
  417. test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING,
  418. field_desc.cpp_type)
  419. test.assertTrue(field_desc.has_default_value)
  420. test.assertEqual(self.default_value, field_desc.default_value)
  421. class ExtensionField(object):
  422. def __init__(self, number, extended_type):
  423. self.number = number
  424. self.extended_type = extended_type
  425. def CheckField(self, test, msg_desc, name, index):
  426. field_desc = msg_desc.extensions_by_name[name]
  427. test.assertEqual(name, field_desc.name)
  428. expected_field_full_name = '.'.join([msg_desc.full_name, name])
  429. test.assertEqual(expected_field_full_name, field_desc.full_name)
  430. test.assertEqual(self.number, field_desc.number)
  431. test.assertEqual(index, field_desc.index)
  432. test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
  433. test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
  434. field_desc.cpp_type)
  435. test.assertFalse(field_desc.has_default_value)
  436. test.assertTrue(field_desc.is_extension)
  437. test.assertEqual(msg_desc, field_desc.extension_scope)
  438. test.assertEqual(msg_desc, field_desc.message_type)
  439. test.assertEqual(self.extended_type, field_desc.containing_type.name)
  440. class AddDescriptorTest(unittest.TestCase):
  441. def _TestMessage(self, prefix):
  442. pool = descriptor_pool.DescriptorPool()
  443. pool.AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
  444. self.assertEqual(
  445. 'protobuf_unittest.TestAllTypes',
  446. pool.FindMessageTypeByName(
  447. prefix + 'protobuf_unittest.TestAllTypes').full_name)
  448. # AddDescriptor is not recursive.
  449. with self.assertRaises(KeyError):
  450. pool.FindMessageTypeByName(
  451. prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
  452. pool.AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
  453. self.assertEqual(
  454. 'protobuf_unittest.TestAllTypes.NestedMessage',
  455. pool.FindMessageTypeByName(
  456. prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
  457. # Files are implicitly also indexed when messages are added.
  458. self.assertEqual(
  459. 'google/protobuf/unittest.proto',
  460. pool.FindFileByName(
  461. 'google/protobuf/unittest.proto').name)
  462. self.assertEqual(
  463. 'google/protobuf/unittest.proto',
  464. pool.FindFileContainingSymbol(
  465. prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
  466. @unittest.skipIf(api_implementation.Type() == 'cpp',
  467. 'With the cpp implementation, Add() must be called first')
  468. def testMessage(self):
  469. self._TestMessage('')
  470. self._TestMessage('.')
  471. def _TestEnum(self, prefix):
  472. pool = descriptor_pool.DescriptorPool()
  473. pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
  474. self.assertEqual(
  475. 'protobuf_unittest.ForeignEnum',
  476. pool.FindEnumTypeByName(
  477. prefix + 'protobuf_unittest.ForeignEnum').full_name)
  478. # AddEnumDescriptor is not recursive.
  479. with self.assertRaises(KeyError):
  480. pool.FindEnumTypeByName(
  481. prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
  482. pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
  483. self.assertEqual(
  484. 'protobuf_unittest.TestAllTypes.NestedEnum',
  485. pool.FindEnumTypeByName(
  486. prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
  487. # Files are implicitly also indexed when enums are added.
  488. self.assertEqual(
  489. 'google/protobuf/unittest.proto',
  490. pool.FindFileByName(
  491. 'google/protobuf/unittest.proto').name)
  492. self.assertEqual(
  493. 'google/protobuf/unittest.proto',
  494. pool.FindFileContainingSymbol(
  495. prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
  496. @unittest.skipIf(api_implementation.Type() == 'cpp',
  497. 'With the cpp implementation, Add() must be called first')
  498. def testEnum(self):
  499. self._TestEnum('')
  500. self._TestEnum('.')
  501. @unittest.skipIf(api_implementation.Type() == 'cpp',
  502. 'With the cpp implementation, Add() must be called first')
  503. def testFile(self):
  504. pool = descriptor_pool.DescriptorPool()
  505. pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR)
  506. self.assertEqual(
  507. 'google/protobuf/unittest.proto',
  508. pool.FindFileByName(
  509. 'google/protobuf/unittest.proto').name)
  510. # AddFileDescriptor is not recursive; messages and enums within files must
  511. # be explicitly registered.
  512. with self.assertRaises(KeyError):
  513. pool.FindFileContainingSymbol(
  514. 'protobuf_unittest.TestAllTypes')
  515. def testEmptyDescriptorPool(self):
  516. # Check that an empty DescriptorPool() contains no messages.
  517. pool = descriptor_pool.DescriptorPool()
  518. proto_file_name = descriptor_pb2.DESCRIPTOR.name
  519. self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
  520. # Add the above file to the pool
  521. file_descriptor = descriptor_pb2.FileDescriptorProto()
  522. descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
  523. pool.Add(file_descriptor)
  524. # Now it exists.
  525. self.assertTrue(pool.FindFileByName(proto_file_name))
  526. def testCustomDescriptorPool(self):
  527. # Create a new pool, and add a file descriptor.
  528. pool = descriptor_pool.DescriptorPool()
  529. file_desc = descriptor_pb2.FileDescriptorProto(
  530. name='some/file.proto', package='package')
  531. file_desc.message_type.add(name='Message')
  532. pool.Add(file_desc)
  533. self.assertEqual(pool.FindFileByName('some/file.proto').name,
  534. 'some/file.proto')
  535. self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
  536. 'Message')
  537. def testFileDescriptorOptionsWithCustomDescriptorPool(self):
  538. # Create a descriptor pool, and add a new FileDescriptorProto to it.
  539. pool = descriptor_pool.DescriptorPool()
  540. file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto'
  541. file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name)
  542. extension_id = file_options_test_pb2.foo_options
  543. file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo'
  544. pool.Add(file_descriptor_proto)
  545. # The options set on the FileDescriptorProto should be available in the
  546. # descriptor even if they contain extensions that cannot be deserialized
  547. # using the pool.
  548. file_descriptor = pool.FindFileByName(file_name)
  549. options = file_descriptor.GetOptions()
  550. self.assertEqual('foo', options.Extensions[extension_id].foo_name)
  551. # The object returned by GetOptions() is cached.
  552. self.assertIs(options, file_descriptor.GetOptions())
  553. @unittest.skipIf(
  554. api_implementation.Type() != 'cpp',
  555. 'default_pool is only supported by the C++ implementation')
  556. class DefaultPoolTest(unittest.TestCase):
  557. def testFindMethods(self):
  558. # pylint: disable=g-import-not-at-top
  559. from google.protobuf.pyext import _message
  560. pool = _message.default_pool
  561. self.assertIs(
  562. pool.FindFileByName('google/protobuf/unittest.proto'),
  563. unittest_pb2.DESCRIPTOR)
  564. self.assertIs(
  565. pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
  566. unittest_pb2.TestAllTypes.DESCRIPTOR)
  567. self.assertIs(
  568. pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
  569. unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
  570. self.assertIs(
  571. pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
  572. unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
  573. self.assertIs(
  574. pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
  575. unittest_pb2.ForeignEnum.DESCRIPTOR)
  576. self.assertIs(
  577. pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
  578. unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
  579. def testAddFileDescriptor(self):
  580. # pylint: disable=g-import-not-at-top
  581. from google.protobuf.pyext import _message
  582. pool = _message.default_pool
  583. file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
  584. pool.Add(file_desc)
  585. pool.AddSerializedFile(file_desc.SerializeToString())
  586. TEST1_FILE = ProtoFile(
  587. 'google/protobuf/internal/descriptor_pool_test1.proto',
  588. 'google.protobuf.python.internal',
  589. {
  590. 'DescriptorPoolTest1': MessageType({
  591. 'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]),
  592. 'NestedMessage': MessageType({
  593. 'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]),
  594. 'DeepNestedMessage': MessageType({
  595. 'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]),
  596. }, [
  597. ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')),
  598. ('nested_field', StringField(2, 'theta')),
  599. ]),
  600. }, [
  601. ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')),
  602. ('nested_field', StringField(2, 'beta')),
  603. ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
  604. ])
  605. }, [
  606. ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')),
  607. ('nested_message', MessageField(2, 'NestedMessage')),
  608. ], is_extendable=True),
  609. 'DescriptorPoolTest2': MessageType({
  610. 'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]),
  611. 'NestedMessage': MessageType({
  612. 'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]),
  613. 'DeepNestedMessage': MessageType({
  614. 'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]),
  615. }, [
  616. ('nested_enum', EnumField(1, 'NestedEnum', 'MU')),
  617. ('nested_field', StringField(2, 'lambda')),
  618. ]),
  619. }, [
  620. ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')),
  621. ('nested_field', StringField(2, 'delta')),
  622. ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
  623. ])
  624. }, [
  625. ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')),
  626. ('nested_message', MessageField(2, 'NestedMessage')),
  627. ]),
  628. })
  629. TEST2_FILE = ProtoFile(
  630. 'google/protobuf/internal/descriptor_pool_test2.proto',
  631. 'google.protobuf.python.internal',
  632. {
  633. 'DescriptorPoolTest3': MessageType({
  634. 'NestedEnum': EnumType([('NU', 13), ('XI', 14)]),
  635. 'NestedMessage': MessageType({
  636. 'NestedEnum': EnumType([('OMICRON', 15), ('PI', 16)]),
  637. 'DeepNestedMessage': MessageType({
  638. 'NestedEnum': EnumType([('RHO', 17), ('SIGMA', 18)]),
  639. }, [
  640. ('nested_enum', EnumField(1, 'NestedEnum', 'RHO')),
  641. ('nested_field', StringField(2, 'sigma')),
  642. ]),
  643. }, [
  644. ('nested_enum', EnumField(1, 'NestedEnum', 'PI')),
  645. ('nested_field', StringField(2, 'nu')),
  646. ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
  647. ])
  648. }, [
  649. ('nested_enum', EnumField(1, 'NestedEnum', 'XI')),
  650. ('nested_message', MessageField(2, 'NestedMessage')),
  651. ], extensions=[
  652. ('descriptor_pool_test',
  653. ExtensionField(1001, 'DescriptorPoolTest1')),
  654. ]),
  655. },
  656. dependencies=['google/protobuf/internal/descriptor_pool_test1.proto',
  657. 'google/protobuf/internal/more_messages.proto'],
  658. public_dependencies=['google/protobuf/internal/more_messages.proto'])
  659. if __name__ == '__main__':
  660. unittest.main()