1#!/usr/bin/env python 2# 3# Copyright 2010 Google Inc. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18"""Tests for apitools.base.protorpclite.descriptor.""" 19import platform 20import types 21 22import six 23import unittest2 24 25from apitools.base.protorpclite import descriptor 26from apitools.base.protorpclite import message_types 27from apitools.base.protorpclite import messages 28from apitools.base.protorpclite import test_util 29 30 31RUSSIA = u'\u0420\u043e\u0441\u0441\u0438\u044f' 32 33 34class ModuleInterfaceTest(test_util.ModuleInterfaceTest, 35 test_util.TestCase): 36 37 MODULE = descriptor 38 39 40class DescribeEnumValueTest(test_util.TestCase): 41 42 def testDescribe(self): 43 class MyEnum(messages.Enum): 44 MY_NAME = 10 45 46 expected = descriptor.EnumValueDescriptor() 47 expected.name = 'MY_NAME' 48 expected.number = 10 49 50 described = descriptor.describe_enum_value(MyEnum.MY_NAME) 51 described.check_initialized() 52 self.assertEquals(expected, described) 53 54 55class DescribeEnumTest(test_util.TestCase): 56 57 def testEmptyEnum(self): 58 class EmptyEnum(messages.Enum): 59 pass 60 61 expected = descriptor.EnumDescriptor() 62 expected.name = 'EmptyEnum' 63 64 described = descriptor.describe_enum(EmptyEnum) 65 described.check_initialized() 66 self.assertEquals(expected, described) 67 68 def testNestedEnum(self): 69 class MyScope(messages.Message): 70 71 class NestedEnum(messages.Enum): 72 pass 73 74 expected = descriptor.EnumDescriptor() 75 expected.name = 'NestedEnum' 76 77 described = descriptor.describe_enum(MyScope.NestedEnum) 78 described.check_initialized() 79 self.assertEquals(expected, described) 80 81 @unittest2.skipIf('PyPy' in platform.python_implementation(), 82 'todo: reenable this') 83 def testEnumWithItems(self): 84 class EnumWithItems(messages.Enum): 85 A = 3 86 B = 1 87 C = 2 88 89 expected = descriptor.EnumDescriptor() 90 expected.name = 'EnumWithItems' 91 92 a = descriptor.EnumValueDescriptor() 93 a.name = 'A' 94 a.number = 3 95 96 b = descriptor.EnumValueDescriptor() 97 b.name = 'B' 98 b.number = 1 99 100 c = descriptor.EnumValueDescriptor() 101 c.name = 'C' 102 c.number = 2 103 104 expected.values = [b, c, a] 105 106 described = descriptor.describe_enum(EnumWithItems) 107 described.check_initialized() 108 self.assertEquals(expected, described) 109 110 111class DescribeFieldTest(test_util.TestCase): 112 113 def testLabel(self): 114 for repeated, required, expected_label in ( 115 (True, False, descriptor.FieldDescriptor.Label.REPEATED), 116 (False, True, descriptor.FieldDescriptor.Label.REQUIRED), 117 (False, False, descriptor.FieldDescriptor.Label.OPTIONAL)): 118 field = messages.IntegerField( 119 10, required=required, repeated=repeated) 120 field.name = 'a_field' 121 122 expected = descriptor.FieldDescriptor() 123 expected.name = 'a_field' 124 expected.number = 10 125 expected.label = expected_label 126 expected.variant = descriptor.FieldDescriptor.Variant.INT64 127 128 described = descriptor.describe_field(field) 129 described.check_initialized() 130 self.assertEquals(expected, described) 131 132 def testDefault(self): 133 test_cases = ( 134 (messages.IntegerField, 200, '200'), 135 (messages.FloatField, 1.5, '1.5'), 136 (messages.FloatField, 1e6, '1000000.0'), 137 (messages.BooleanField, True, 'true'), 138 (messages.BooleanField, False, 'false'), 139 (messages.BytesField, 140 b''.join([six.int2byte(x) for x in (31, 32, 33)]), 141 b'\\x1f !'), 142 (messages.StringField, RUSSIA, RUSSIA), 143 ) 144 for field_class, default, expected_default in test_cases: 145 field = field_class(10, default=default) 146 field.name = u'a_field' 147 148 expected = descriptor.FieldDescriptor() 149 expected.name = u'a_field' 150 expected.number = 10 151 expected.label = descriptor.FieldDescriptor.Label.OPTIONAL 152 expected.variant = field_class.DEFAULT_VARIANT 153 expected.default_value = expected_default 154 155 described = descriptor.describe_field(field) 156 described.check_initialized() 157 self.assertEquals(expected, described) 158 159 def testDefault_EnumField(self): 160 class MyEnum(messages.Enum): 161 162 VAL = 1 163 164 module_name = test_util.get_module_name(MyEnum) 165 field = messages.EnumField(MyEnum, 10, default=MyEnum.VAL) 166 field.name = 'a_field' 167 168 expected = descriptor.FieldDescriptor() 169 expected.name = 'a_field' 170 expected.number = 10 171 expected.label = descriptor.FieldDescriptor.Label.OPTIONAL 172 expected.variant = messages.EnumField.DEFAULT_VARIANT 173 expected.type_name = '%s.MyEnum' % module_name 174 expected.default_value = '1' 175 176 described = descriptor.describe_field(field) 177 self.assertEquals(expected, described) 178 179 def testMessageField(self): 180 field = messages.MessageField(descriptor.FieldDescriptor, 10) 181 field.name = 'a_field' 182 183 expected = descriptor.FieldDescriptor() 184 expected.name = 'a_field' 185 expected.number = 10 186 expected.label = descriptor.FieldDescriptor.Label.OPTIONAL 187 expected.variant = messages.MessageField.DEFAULT_VARIANT 188 expected.type_name = ( 189 'apitools.base.protorpclite.descriptor.FieldDescriptor') 190 191 described = descriptor.describe_field(field) 192 described.check_initialized() 193 self.assertEquals(expected, described) 194 195 def testDateTimeField(self): 196 field = message_types.DateTimeField(20) 197 field.name = 'a_timestamp' 198 199 expected = descriptor.FieldDescriptor() 200 expected.name = 'a_timestamp' 201 expected.number = 20 202 expected.label = descriptor.FieldDescriptor.Label.OPTIONAL 203 expected.variant = messages.MessageField.DEFAULT_VARIANT 204 expected.type_name = ( 205 'apitools.base.protorpclite.message_types.DateTimeMessage') 206 207 described = descriptor.describe_field(field) 208 described.check_initialized() 209 self.assertEquals(expected, described) 210 211 212class DescribeMessageTest(test_util.TestCase): 213 214 def testEmptyDefinition(self): 215 class MyMessage(messages.Message): 216 pass 217 218 expected = descriptor.MessageDescriptor() 219 expected.name = 'MyMessage' 220 221 described = descriptor.describe_message(MyMessage) 222 described.check_initialized() 223 self.assertEquals(expected, described) 224 225 def testDefinitionWithFields(self): 226 class MessageWithFields(messages.Message): 227 field1 = messages.IntegerField(10) 228 field2 = messages.StringField(30) 229 field3 = messages.IntegerField(20) 230 231 expected = descriptor.MessageDescriptor() 232 expected.name = 'MessageWithFields' 233 234 expected.fields = [ 235 descriptor.describe_field( 236 MessageWithFields.field_by_name('field1')), 237 descriptor.describe_field( 238 MessageWithFields.field_by_name('field3')), 239 descriptor.describe_field( 240 MessageWithFields.field_by_name('field2')), 241 ] 242 243 described = descriptor.describe_message(MessageWithFields) 244 described.check_initialized() 245 self.assertEquals(expected, described) 246 247 def testNestedEnum(self): 248 class MessageWithEnum(messages.Message): 249 250 class Mood(messages.Enum): 251 GOOD = 1 252 BAD = 2 253 UGLY = 3 254 255 class Music(messages.Enum): 256 CLASSIC = 1 257 JAZZ = 2 258 BLUES = 3 259 260 expected = descriptor.MessageDescriptor() 261 expected.name = 'MessageWithEnum' 262 263 expected.enum_types = [descriptor.describe_enum(MessageWithEnum.Mood), 264 descriptor.describe_enum(MessageWithEnum.Music)] 265 266 described = descriptor.describe_message(MessageWithEnum) 267 described.check_initialized() 268 self.assertEquals(expected, described) 269 270 def testNestedMessage(self): 271 class MessageWithMessage(messages.Message): 272 273 class Nesty(messages.Message): 274 pass 275 276 expected = descriptor.MessageDescriptor() 277 expected.name = 'MessageWithMessage' 278 279 expected.message_types = [ 280 descriptor.describe_message(MessageWithMessage.Nesty)] 281 282 described = descriptor.describe_message(MessageWithMessage) 283 described.check_initialized() 284 self.assertEquals(expected, described) 285 286 287class DescribeFileTest(test_util.TestCase): 288 """Test describing modules.""" 289 290 def LoadModule(self, module_name, source): 291 result = { 292 '__name__': module_name, 293 'messages': messages, 294 } 295 exec(source, result) 296 297 module = types.ModuleType(module_name) 298 for name, value in result.items(): 299 setattr(module, name, value) 300 301 return module 302 303 def testEmptyModule(self): 304 """Test describing an empty file.""" 305 module = types.ModuleType('my.package.name') 306 307 expected = descriptor.FileDescriptor() 308 expected.package = 'my.package.name' 309 310 described = descriptor.describe_file(module) 311 described.check_initialized() 312 self.assertEquals(expected, described) 313 314 def testNoPackageName(self): 315 """Test describing a module with no module name.""" 316 module = types.ModuleType('') 317 318 expected = descriptor.FileDescriptor() 319 320 described = descriptor.describe_file(module) 321 described.check_initialized() 322 self.assertEquals(expected, described) 323 324 def testPackageName(self): 325 """Test using the 'package' module attribute.""" 326 module = types.ModuleType('my.module.name') 327 module.package = 'my.package.name' 328 329 expected = descriptor.FileDescriptor() 330 expected.package = 'my.package.name' 331 332 described = descriptor.describe_file(module) 333 described.check_initialized() 334 self.assertEquals(expected, described) 335 336 def testMain(self): 337 """Test using the 'package' module attribute.""" 338 module = types.ModuleType('__main__') 339 module.__file__ = '/blim/blam/bloom/my_package.py' 340 341 expected = descriptor.FileDescriptor() 342 expected.package = 'my_package' 343 344 described = descriptor.describe_file(module) 345 described.check_initialized() 346 self.assertEquals(expected, described) 347 348 def testMessages(self): 349 """Test that messages are described.""" 350 module = self.LoadModule('my.package', 351 'class Message1(messages.Message): pass\n' 352 'class Message2(messages.Message): pass\n') 353 354 message1 = descriptor.MessageDescriptor() 355 message1.name = 'Message1' 356 357 message2 = descriptor.MessageDescriptor() 358 message2.name = 'Message2' 359 360 expected = descriptor.FileDescriptor() 361 expected.package = 'my.package' 362 expected.message_types = [message1, message2] 363 364 described = descriptor.describe_file(module) 365 described.check_initialized() 366 self.assertEquals(expected, described) 367 368 def testEnums(self): 369 """Test that enums are described.""" 370 module = self.LoadModule('my.package', 371 'class Enum1(messages.Enum): pass\n' 372 'class Enum2(messages.Enum): pass\n') 373 374 enum1 = descriptor.EnumDescriptor() 375 enum1.name = 'Enum1' 376 377 enum2 = descriptor.EnumDescriptor() 378 enum2.name = 'Enum2' 379 380 expected = descriptor.FileDescriptor() 381 expected.package = 'my.package' 382 expected.enum_types = [enum1, enum2] 383 384 described = descriptor.describe_file(module) 385 described.check_initialized() 386 self.assertEquals(expected, described) 387 388 389class DescribeFileSetTest(test_util.TestCase): 390 """Test describing multiple modules.""" 391 392 def testNoModules(self): 393 """Test what happens when no modules provided.""" 394 described = descriptor.describe_file_set([]) 395 described.check_initialized() 396 # The described FileSet.files will be None. 397 self.assertEquals(descriptor.FileSet(), described) 398 399 def testWithModules(self): 400 """Test what happens when no modules provided.""" 401 modules = [types.ModuleType('package1'), types.ModuleType('package1')] 402 403 file1 = descriptor.FileDescriptor() 404 file1.package = 'package1' 405 file2 = descriptor.FileDescriptor() 406 file2.package = 'package2' 407 408 expected = descriptor.FileSet() 409 expected.files = [file1, file1] 410 411 described = descriptor.describe_file_set(modules) 412 described.check_initialized() 413 self.assertEquals(expected, described) 414 415 416class DescribeTest(test_util.TestCase): 417 418 def testModule(self): 419 self.assertEquals(descriptor.describe_file(test_util), 420 descriptor.describe(test_util)) 421 422 def testField(self): 423 self.assertEquals( 424 descriptor.describe_field(test_util.NestedMessage.a_value), 425 descriptor.describe(test_util.NestedMessage.a_value)) 426 427 def testEnumValue(self): 428 self.assertEquals( 429 descriptor.describe_enum_value( 430 test_util.OptionalMessage.SimpleEnum.VAL1), 431 descriptor.describe(test_util.OptionalMessage.SimpleEnum.VAL1)) 432 433 def testMessage(self): 434 self.assertEquals(descriptor.describe_message(test_util.NestedMessage), 435 descriptor.describe(test_util.NestedMessage)) 436 437 def testEnum(self): 438 self.assertEquals( 439 descriptor.describe_enum(test_util.OptionalMessage.SimpleEnum), 440 descriptor.describe(test_util.OptionalMessage.SimpleEnum)) 441 442 def testUndescribable(self): 443 class NonService(object): 444 445 def fn(self): 446 pass 447 448 for value in (NonService, 449 NonService.fn, 450 1, 451 'string', 452 1.2, 453 None): 454 self.assertEquals(None, descriptor.describe(value)) 455 456 457class ModuleFinderTest(test_util.TestCase): 458 459 def testFindMessage(self): 460 self.assertEquals( 461 descriptor.describe_message(descriptor.FileSet), 462 descriptor.import_descriptor_loader( 463 'apitools.base.protorpclite.descriptor.FileSet')) 464 465 def testFindField(self): 466 self.assertEquals( 467 descriptor.describe_field(descriptor.FileSet.files), 468 descriptor.import_descriptor_loader( 469 'apitools.base.protorpclite.descriptor.FileSet.files')) 470 471 def testFindEnumValue(self): 472 self.assertEquals( 473 descriptor.describe_enum_value( 474 test_util.OptionalMessage.SimpleEnum.VAL1), 475 descriptor.import_descriptor_loader( 476 'apitools.base.protorpclite.test_util.' 477 'OptionalMessage.SimpleEnum.VAL1')) 478 479 480class DescriptorLibraryTest(test_util.TestCase): 481 482 def setUp(self): 483 self.packageless = descriptor.MessageDescriptor() 484 self.packageless.name = 'Packageless' 485 self.library = descriptor.DescriptorLibrary( 486 descriptors={ 487 'not.real.Packageless': self.packageless, 488 'Packageless': self.packageless, 489 }) 490 491 def testLookupPackage(self): 492 self.assertEquals('csv', self.library.lookup_package('csv')) 493 self.assertEquals( 494 'apitools.base.protorpclite', 495 self.library.lookup_package('apitools.base.protorpclite')) 496 497 def testLookupNonPackages(self): 498 lib = 'apitools.base.protorpclite.descriptor.DescriptorLibrary' 499 for name in ('', 'a', lib): 500 self.assertRaisesWithRegexpMatch( 501 messages.DefinitionNotFoundError, 502 'Could not find definition for %s' % name, 503 self.library.lookup_package, name) 504 505 def testNoPackage(self): 506 self.assertRaisesWithRegexpMatch( 507 messages.DefinitionNotFoundError, 508 'Could not find definition for not.real', 509 self.library.lookup_package, 'not.real.Packageless') 510 511 self.assertEquals(None, self.library.lookup_package('Packageless')) 512 513 514if __name__ == '__main__': 515 unittest2.main() 516