| 
									
										
										
										
											2011-03-21 17:17:06 -04:00
										 |  |  | import os | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  | import collections | 
					
						
							| 
									
										
										
										
											2011-03-31 12:20:23 -04:00
										 |  |  | import email | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  | from email.message import Message | 
					
						
							|  |  |  | from email._policybase import compat32 | 
					
						
							| 
									
										
										
										
											2014-07-23 12:00:29 -05:00
										 |  |  | from test.support import load_package_tests | 
					
						
							| 
									
										
										
										
											2011-03-31 12:20:23 -04:00
										 |  |  | from test.test_email import __file__ as landmark | 
					
						
							| 
									
										
										
										
											2011-03-21 17:17:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-23 12:00:29 -05:00
										 |  |  | # Load all tests in package | 
					
						
							|  |  |  | def load_tests(*args): | 
					
						
							|  |  |  |     return load_package_tests(os.path.dirname(__file__), *args) | 
					
						
							| 
									
										
										
										
											2011-03-31 12:20:23 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # helper code used by a number of test modules. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def openfile(filename, *args, **kws): | 
					
						
							|  |  |  |     path = os.path.join(os.path.dirname(landmark), 'data', filename) | 
					
						
							|  |  |  |     return open(path, *args, **kws) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Base test class | 
					
						
							|  |  |  | class TestEmailBase(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-18 13:59:37 -04:00
										 |  |  |     maxDiff = None | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  |     # Currently the default policy is compat32.  By setting that as the default | 
					
						
							|  |  |  |     # here we make minimal changes in the test_email tests compared to their | 
					
						
							|  |  |  |     # pre-3.3 state. | 
					
						
							|  |  |  |     policy = compat32 | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |     # Likewise, the default message object is Message. | 
					
						
							|  |  |  |     message = Message | 
					
						
							| 
									
										
										
										
											2011-04-18 13:59:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-31 13:11:40 -04:00
										 |  |  |     def __init__(self, *args, **kw): | 
					
						
							|  |  |  |         super().__init__(*args, **kw) | 
					
						
							|  |  |  |         self.addTypeEqualityFunc(bytes, self.assertBytesEqual) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  |     # Backward compatibility to minimize test_email test changes. | 
					
						
							| 
									
										
										
										
											2011-04-10 15:28:29 -04:00
										 |  |  |     ndiffAssertEqual = unittest.TestCase.assertEqual | 
					
						
							| 
									
										
										
										
											2011-03-31 12:20:23 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _msgobj(self, filename): | 
					
						
							|  |  |  |         with openfile(filename) as fp: | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  |             return email.message_from_file(fp, policy=self.policy) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |     def _str_msg(self, string, message=None, policy=None): | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  |         if policy is None: | 
					
						
							|  |  |  |             policy = self.policy | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |         if message is None: | 
					
						
							|  |  |  |             message = self.message | 
					
						
							| 
									
										
										
										
											2012-05-25 15:01:48 -04:00
										 |  |  |         return email.message_from_string(string, message, policy=policy) | 
					
						
							| 
									
										
										
										
											2011-03-31 13:11:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |     def _bytes_msg(self, bytestring, message=None, policy=None): | 
					
						
							|  |  |  |         if policy is None: | 
					
						
							|  |  |  |             policy = self.policy | 
					
						
							|  |  |  |         if message is None: | 
					
						
							|  |  |  |             message = self.message | 
					
						
							|  |  |  |         return email.message_from_bytes(bytestring, message, policy=policy) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _make_message(self): | 
					
						
							|  |  |  |         return self.message(policy=self.policy) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-31 13:11:40 -04:00
										 |  |  |     def _bytes_repr(self, b): | 
					
						
							| 
									
										
										
										
											2011-09-28 17:37:55 +03:00
										 |  |  |         return [repr(x) for x in b.splitlines(keepends=True)] | 
					
						
							| 
									
										
										
										
											2011-03-31 13:11:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def assertBytesEqual(self, first, second, msg): | 
					
						
							|  |  |  |         """Our byte strings are really encoded strings; improve diff output""" | 
					
						
							|  |  |  |         self.assertEqual(self._bytes_repr(first), self._bytes_repr(second)) | 
					
						
							| 
									
										
										
										
											2012-05-25 18:42:14 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def assertDefectsEqual(self, actual, expected): | 
					
						
							|  |  |  |         self.assertEqual(len(actual), len(expected), actual) | 
					
						
							|  |  |  |         for i in range(len(actual)): | 
					
						
							|  |  |  |             self.assertIsInstance(actual[i], expected[i], | 
					
						
							|  |  |  |                                     'item {}'.format(i)) | 
					
						
							| 
									
										
										
										
											2012-05-30 21:53:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  | def parameterize(cls): | 
					
						
							|  |  |  |     """A test method parameterization class decorator.
 | 
					
						
							| 
									
										
										
										
											2012-05-30 21:53:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Parameters are specified as the value of a class attribute that ends with | 
					
						
							|  |  |  |     the string '_params'.  Call the portion before '_params' the prefix.  Then | 
					
						
							|  |  |  |     a method to be parameterized must have the same prefix, the string | 
					
						
							|  |  |  |     '_as_', and an arbitrary suffix. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The value of the _params attribute may be either a dictionary or a list. | 
					
						
							|  |  |  |     The values in the dictionary and the elements of the list may either be | 
					
						
							|  |  |  |     single values, or a list.  If single values, they are turned into single | 
					
						
							|  |  |  |     element tuples.  However derived, the resulting sequence is passed via | 
					
						
							|  |  |  |     *args to the parameterized test function. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 09:30:01 +03:00
										 |  |  |     In a _params dictionary, the keys become part of the name of the generated | 
					
						
							| 
									
										
										
										
											2012-05-30 21:53:40 -04:00
										 |  |  |     tests.  In a _params list, the values in the list are converted into a | 
					
						
							|  |  |  |     string by joining the string values of the elements of the tuple by '_' and | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |     converting any blanks into '_'s, and this become part of the name. | 
					
						
							|  |  |  |     The  full name of a generated test is a 'test_' prefix, the portion of the | 
					
						
							|  |  |  |     test function name after the  '_as_' separator, plus an '_', plus the name | 
					
						
							|  |  |  |     derived as explained above. | 
					
						
							| 
									
										
										
										
											2012-05-30 21:53:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     For example, if we have: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         count_params = range(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def count_as_foo_arg(self, foo): | 
					
						
							|  |  |  |             self.assertEqual(foo+1, myfunc(foo)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     we will get parameterized test methods named: | 
					
						
							|  |  |  |         test_foo_arg_0 | 
					
						
							|  |  |  |         test_foo_arg_1 | 
					
						
							|  |  |  |         test_foo_arg_2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Or we could have: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         example_params = {'foo': ('bar', 1), 'bing': ('bang', 2)} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def example_as_myfunc_input(self, name, count): | 
					
						
							|  |  |  |             self.assertEqual(name+str(count), myfunc(name, count)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     and get: | 
					
						
							|  |  |  |         test_myfunc_input_foo | 
					
						
							|  |  |  |         test_myfunc_input_bing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Note: if and only if the generated test name is a valid identifier can it | 
					
						
							|  |  |  |     be used to select the test individually from the unittest command line. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 15:00:09 -04:00
										 |  |  |     The values in the params dict can be a single value, a tuple, or a | 
					
						
							|  |  |  |     dict.  If a single value of a tuple, it is passed to the test function | 
					
						
							|  |  |  |     as positional arguments.  If a dict, it is a passed via **kw. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-30 21:53:40 -04:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |     paramdicts = {} | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |     testers = collections.defaultdict(list) | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |     for name, attr in cls.__dict__.items(): | 
					
						
							|  |  |  |         if name.endswith('_params'): | 
					
						
							|  |  |  |             if not hasattr(attr, 'keys'): | 
					
						
							|  |  |  |                 d = {} | 
					
						
							|  |  |  |                 for x in attr: | 
					
						
							|  |  |  |                     if not hasattr(x, '__iter__'): | 
					
						
							|  |  |  |                         x = (x,) | 
					
						
							|  |  |  |                     n = '_'.join(str(v) for v in x).replace(' ', '_') | 
					
						
							|  |  |  |                     d[n] = x | 
					
						
							|  |  |  |                 attr = d | 
					
						
							|  |  |  |             paramdicts[name[:-7] + '_as_'] = attr | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |         if '_as_' in name: | 
					
						
							|  |  |  |             testers[name.split('_as_')[0] + '_as_'].append(name) | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |     testfuncs = {} | 
					
						
							| 
									
										
										
										
											2013-10-16 22:48:40 -04:00
										 |  |  |     for name in paramdicts: | 
					
						
							|  |  |  |         if name not in testers: | 
					
						
							|  |  |  |             raise ValueError("No tester found for {}".format(name)) | 
					
						
							|  |  |  |     for name in testers: | 
					
						
							|  |  |  |         if name not in paramdicts: | 
					
						
							|  |  |  |             raise ValueError("No params found for {}".format(name)) | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |     for name, attr in cls.__dict__.items(): | 
					
						
							|  |  |  |         for paramsname, paramsdict in paramdicts.items(): | 
					
						
							|  |  |  |             if name.startswith(paramsname): | 
					
						
							|  |  |  |                 testnameroot = 'test_' + name[len(paramsname):] | 
					
						
							|  |  |  |                 for paramname, params in paramsdict.items(): | 
					
						
							| 
									
										
										
										
											2016-09-09 15:00:09 -04:00
										 |  |  |                     if hasattr(params, 'keys'): | 
					
						
							|  |  |  |                         test = (lambda self, name=name, params=params: | 
					
						
							|  |  |  |                                     getattr(self, name)(**params)) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         test = (lambda self, name=name, params=params: | 
					
						
							|  |  |  |                                         getattr(self, name)(*params)) | 
					
						
							| 
									
										
										
										
											2012-05-31 18:00:45 -04:00
										 |  |  |                     testname = testnameroot + '_' + paramname | 
					
						
							|  |  |  |                     test.__name__ = testname | 
					
						
							|  |  |  |                     testfuncs[testname] = test | 
					
						
							|  |  |  |     for key, value in testfuncs.items(): | 
					
						
							|  |  |  |         setattr(cls, key, value) | 
					
						
							|  |  |  |     return cls |