diff --git a/tests/admin_docs/test_views.py b/tests/admin_docs/test_views.py index 0915e01dc4..b9955717f4 100644 --- a/tests/admin_docs/test_views.py +++ b/tests/admin_docs/test_views.py @@ -339,4 +339,5 @@ class AdminDocViewFunctionsTests(SimpleTestCase): (r'^a/?$', '/a/'), ) for pattern, output in tests: - self.assertEqual(simplify_regex(pattern), output) + with self.subTest(pattern=pattern): + self.assertEqual(simplify_regex(pattern), output) diff --git a/tests/admin_views/test_multidb.py b/tests/admin_views/test_multidb.py index 3687bec16f..9907e16d69 100644 --- a/tests/admin_views/test_multidb.py +++ b/tests/admin_views/test_multidb.py @@ -47,32 +47,35 @@ class MultiDatabaseTests(TestCase): @mock.patch('django.contrib.admin.options.transaction') def test_add_view(self, mock): for db in connections: - Router.target_db = db - self.client.force_login(self.superusers[db]) - self.client.post( - reverse('test_adminsite:admin_views_book_add'), - {'name': 'Foobar: 5th edition'}, - ) - mock.atomic.assert_called_with(using=db) + with self.subTest(db=db): + Router.target_db = db + self.client.force_login(self.superusers[db]) + self.client.post( + reverse('test_adminsite:admin_views_book_add'), + {'name': 'Foobar: 5th edition'}, + ) + mock.atomic.assert_called_with(using=db) @mock.patch('django.contrib.admin.options.transaction') def test_change_view(self, mock): for db in connections: - Router.target_db = db - self.client.force_login(self.superusers[db]) - self.client.post( - reverse('test_adminsite:admin_views_book_change', args=[self.test_book_ids[db]]), - {'name': 'Test Book 2: Test more'}, - ) - mock.atomic.assert_called_with(using=db) + with self.subTest(db=db): + Router.target_db = db + self.client.force_login(self.superusers[db]) + self.client.post( + reverse('test_adminsite:admin_views_book_change', args=[self.test_book_ids[db]]), + {'name': 'Test Book 2: Test more'}, + ) + mock.atomic.assert_called_with(using=db) @mock.patch('django.contrib.admin.options.transaction') def test_delete_view(self, mock): for db in connections: - Router.target_db = db - self.client.force_login(self.superusers[db]) - self.client.post( - reverse('test_adminsite:admin_views_book_delete', args=[self.test_book_ids[db]]), - {'post': 'yes'}, - ) - mock.atomic.assert_called_with(using=db) + with self.subTest(db=db): + Router.target_db = db + self.client.force_login(self.superusers[db]) + self.client.post( + reverse('test_adminsite:admin_views_book_delete', args=[self.test_book_ids[db]]), + {'post': 'yes'}, + ) + mock.atomic.assert_called_with(using=db) diff --git a/tests/auth_tests/test_admin_multidb.py b/tests/auth_tests/test_admin_multidb.py index 6b36b50a16..f86ea86dd8 100644 --- a/tests/auth_tests/test_admin_multidb.py +++ b/tests/auth_tests/test_admin_multidb.py @@ -42,11 +42,12 @@ class MultiDatabaseTests(TestCase): @mock.patch('django.contrib.auth.admin.transaction') def test_add_view(self, mock): for db in connections: - Router.target_db = db - self.client.force_login(self.superusers[db]) - self.client.post(reverse('test_adminsite:auth_user_add'), { - 'username': 'some_user', - 'password1': 'helloworld', - 'password2': 'helloworld', - }) - mock.atomic.assert_called_with(using=db) + with self.subTest(db_connection=db): + Router.target_db = db + self.client.force_login(self.superusers[db]) + self.client.post(reverse('test_adminsite:auth_user_add'), { + 'username': 'some_user', + 'password1': 'helloworld', + 'password2': 'helloworld', + }) + mock.atomic.assert_called_with(using=db) diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py index aec7021cab..cf12fd4168 100644 --- a/tests/auth_tests/test_hashers.py +++ b/tests/auth_tests/test_hashers.py @@ -300,13 +300,14 @@ class TestUtilsHashPass(SimpleTestCase): def test_upgrade(self): self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm) for algo in ('sha1', 'md5'): - encoded = make_password('lètmein', hasher=algo) - state = {'upgraded': False} + with self.subTest(algo=algo): + encoded = make_password('lètmein', hasher=algo) + state = {'upgraded': False} - def setter(password): - state['upgraded'] = True - self.assertTrue(check_password('lètmein', encoded, setter)) - self.assertTrue(state['upgraded']) + def setter(password): + state['upgraded'] = True + self.assertTrue(check_password('lètmein', encoded, setter)) + self.assertTrue(state['upgraded']) def test_no_upgrade(self): encoded = make_password('lètmein') @@ -327,13 +328,14 @@ class TestUtilsHashPass(SimpleTestCase): def test_no_upgrade_on_incorrect_pass(self): self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm) for algo in ('sha1', 'md5'): - encoded = make_password('lètmein', hasher=algo) - state = {'upgraded': False} + with self.subTest(algo=algo): + encoded = make_password('lètmein', hasher=algo) + state = {'upgraded': False} - def setter(): - state['upgraded'] = True - self.assertFalse(check_password('WRONG', encoded, setter)) - self.assertFalse(state['upgraded']) + def setter(): + state['upgraded'] = True + self.assertFalse(check_password('WRONG', encoded, setter)) + self.assertFalse(state['upgraded']) def test_pbkdf2_upgrade(self): hasher = get_hasher('default') diff --git a/tests/auth_tests/test_models.py b/tests/auth_tests/test_models.py index 142fbcc39c..e546d61c64 100644 --- a/tests/auth_tests/test_models.py +++ b/tests/auth_tests/test_models.py @@ -161,7 +161,7 @@ class AbstractBaseUserTests(TestCase): # The normalization happens in AbstractBaseUser.clean() ohm_username = 'iamtheΩ' # U+2126 OHM SIGN for model in ('auth.User', 'auth_tests.CustomUser'): - with self.settings(AUTH_USER_MODEL=model): + with self.subTest(model=model), self.settings(AUTH_USER_MODEL=model): User = get_user_model() user = User(**{User.USERNAME_FIELD: ohm_username, 'password': 'foo'}) user.clean() diff --git a/tests/auth_tests/test_validators.py b/tests/auth_tests/test_validators.py index e9dc1f7f3f..068dec9981 100644 --- a/tests/auth_tests/test_validators.py +++ b/tests/auth_tests/test_validators.py @@ -214,17 +214,21 @@ class UsernameValidatorsTests(TestCase): ] v = validators.UnicodeUsernameValidator() for valid in valid_usernames: - v(valid) + with self.subTest(valid=valid): + v(valid) for invalid in invalid_usernames: - with self.assertRaises(ValidationError): - v(invalid) + with self.subTest(invalid=invalid): + with self.assertRaises(ValidationError): + v(invalid) def test_ascii_validator(self): valid_usernames = ['glenn', 'GLEnN', 'jean-marc'] invalid_usernames = ["o'connell", 'Éric', 'jean marc', "أحمد"] v = validators.ASCIIUsernameValidator() for valid in valid_usernames: - v(valid) + with self.subTest(valid=valid): + v(valid) for invalid in invalid_usernames: - with self.assertRaises(ValidationError): - v(invalid) + with self.subTest(invalid=invalid): + with self.assertRaises(ValidationError): + v(invalid) diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py index 40c48b7e9e..7dbf74928d 100644 --- a/tests/auth_tests/test_views.py +++ b/tests/auth_tests/test_views.py @@ -108,10 +108,11 @@ class AuthViewNamedURLTests(AuthViewsTestCase): ('password_reset_complete', [], {}), ] for name, args, kwargs in expected_named_urls: - try: - reverse(name, args=args, kwargs=kwargs) - except NoReverseMatch: - self.fail("Reversal of url named '%s' failed with NoReverseMatch" % name) + with self.subTest(name=name): + try: + reverse(name, args=args, kwargs=kwargs) + except NoReverseMatch: + self.fail("Reversal of url named '%s' failed with NoReverseMatch" % name) class PasswordResetTest(AuthViewsTestCase): @@ -559,48 +560,54 @@ class LoginTest(AuthViewsTestCase): def test_security_check(self): login_url = reverse('login') - # Those URLs should not pass the security check - for bad_url in ('http://example.com', - 'http:///example.com', - 'https://example.com', - 'ftp://example.com', - '///example.com', - '//example.com', - 'javascript:alert("XSS")'): + # These URLs should not pass the security check. + bad_urls = ( + 'http://example.com', + 'http:///example.com', + 'https://example.com', + 'ftp://example.com', + '///example.com', + '//example.com', + 'javascript:alert("XSS")', + ) + for bad_url in bad_urls: + with self.subTest(bad_url=bad_url): + nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { + 'url': login_url, + 'next': REDIRECT_FIELD_NAME, + 'bad_url': quote(bad_url), + } + response = self.client.post(nasty_url, { + 'username': 'testclient', + 'password': 'password', + }) + self.assertEqual(response.status_code, 302) + self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url) - nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { - 'url': login_url, - 'next': REDIRECT_FIELD_NAME, - 'bad_url': quote(bad_url), - } - response = self.client.post(nasty_url, { - 'username': 'testclient', - 'password': 'password', - }) - self.assertEqual(response.status_code, 302) - self.assertNotIn(bad_url, response.url, - "%s should be blocked" % bad_url) - - # These URLs *should* still pass the security check - for good_url in ('/view/?param=http://example.com', - '/view/?param=https://example.com', - '/view?param=ftp://example.com', - 'view/?param=//example.com', - 'https://testserver/', - 'HTTPS://testserver/', - '//testserver/', - '/url%20with%20spaces/'): # see ticket #12534 - safe_url = '%(url)s?%(next)s=%(good_url)s' % { - 'url': login_url, - 'next': REDIRECT_FIELD_NAME, - 'good_url': quote(good_url), - } - response = self.client.post(safe_url, { - 'username': 'testclient', - 'password': 'password', - }) - self.assertEqual(response.status_code, 302) - self.assertIn(good_url, response.url, "%s should be allowed" % good_url) + # These URLs should pass the security check. + good_urls = ( + '/view/?param=http://example.com', + '/view/?param=https://example.com', + '/view?param=ftp://example.com', + 'view/?param=//example.com', + 'https://testserver/', + 'HTTPS://testserver/', + '//testserver/', + '/url%20with%20spaces/', + ) + for good_url in good_urls: + with self.subTest(good_url=good_url): + safe_url = '%(url)s?%(next)s=%(good_url)s' % { + 'url': login_url, + 'next': REDIRECT_FIELD_NAME, + 'good_url': quote(good_url), + } + response = self.client.post(safe_url, { + 'username': 'testclient', + 'password': 'password', + }) + self.assertEqual(response.status_code, 302) + self.assertIn(good_url, response.url, '%s should be allowed' % good_url) def test_security_check_https(self): login_url = reverse('login') @@ -988,45 +995,52 @@ class LogoutTest(AuthViewsTestCase): def test_security_check(self): logout_url = reverse('logout') - # Those URLs should not pass the security check - for bad_url in ('http://example.com', - 'http:///example.com', - 'https://example.com', - 'ftp://example.com', - '///example.com', - '//example.com', - 'javascript:alert("XSS")'): - nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { - 'url': logout_url, - 'next': REDIRECT_FIELD_NAME, - 'bad_url': quote(bad_url), - } - self.login() - response = self.client.get(nasty_url) - self.assertEqual(response.status_code, 302) - self.assertNotIn(bad_url, response.url, - "%s should be blocked" % bad_url) - self.confirm_logged_out() + # These URLs should not pass the security check. + bad_urls = ( + 'http://example.com', + 'http:///example.com', + 'https://example.com', + 'ftp://example.com', + '///example.com', + '//example.com', + 'javascript:alert("XSS")', + ) + for bad_url in bad_urls: + with self.subTest(bad_url=bad_url): + nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { + 'url': logout_url, + 'next': REDIRECT_FIELD_NAME, + 'bad_url': quote(bad_url), + } + self.login() + response = self.client.get(nasty_url) + self.assertEqual(response.status_code, 302) + self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url) + self.confirm_logged_out() - # These URLs *should* still pass the security check - for good_url in ('/view/?param=http://example.com', - '/view/?param=https://example.com', - '/view?param=ftp://example.com', - 'view/?param=//example.com', - 'https://testserver/', - 'HTTPS://testserver/', - '//testserver/', - '/url%20with%20spaces/'): # see ticket #12534 - safe_url = '%(url)s?%(next)s=%(good_url)s' % { - 'url': logout_url, - 'next': REDIRECT_FIELD_NAME, - 'good_url': quote(good_url), - } - self.login() - response = self.client.get(safe_url) - self.assertEqual(response.status_code, 302) - self.assertIn(good_url, response.url, "%s should be allowed" % good_url) - self.confirm_logged_out() + # These URLs should pass the security check. + good_urls = ( + '/view/?param=http://example.com', + '/view/?param=https://example.com', + '/view?param=ftp://example.com', + 'view/?param=//example.com', + 'https://testserver/', + 'HTTPS://testserver/', + '//testserver/', + '/url%20with%20spaces/', + ) + for good_url in good_urls: + with self.subTest(good_url=good_url): + safe_url = '%(url)s?%(next)s=%(good_url)s' % { + 'url': logout_url, + 'next': REDIRECT_FIELD_NAME, + 'good_url': quote(good_url), + } + self.login() + response = self.client.get(safe_url) + self.assertEqual(response.status_code, 302) + self.assertIn(good_url, response.url, '%s should be allowed' % good_url) + self.confirm_logged_out() def test_security_check_https(self): logout_url = reverse('logout') diff --git a/tests/cache/tests.py b/tests/cache/tests.py index 203f2f5152..e14c72754d 100644 --- a/tests/cache/tests.py +++ b/tests/cache/tests.py @@ -169,8 +169,9 @@ class DummyCacheTests(SimpleTestCase): 'ascii2': {'x': 1} } for (key, value) in stuff.items(): - cache.set(key, value) - self.assertIsNone(cache.get(key)) + with self.subTest(key=key): + cache.set(key, value) + self.assertIsNone(cache.get(key)) def test_set_many(self): "set_many does nothing for the dummy cache backend" @@ -420,21 +421,24 @@ class BaseCacheTests: } # Test `set` for (key, value) in stuff.items(): - cache.set(key, value) - self.assertEqual(cache.get(key), value) + with self.subTest(key=key): + cache.set(key, value) + self.assertEqual(cache.get(key), value) # Test `add` for (key, value) in stuff.items(): - cache.delete(key) - cache.add(key, value) - self.assertEqual(cache.get(key), value) + with self.subTest(key=key): + cache.delete(key) + cache.add(key, value) + self.assertEqual(cache.get(key), value) # Test `set_many` for (key, value) in stuff.items(): cache.delete(key) cache.set_many(stuff) for (key, value) in stuff.items(): - self.assertEqual(cache.get(key), value) + with self.subTest(key=key): + self.assertEqual(cache.get(key), value) def test_binary_string(self): # Binary strings should be cacheable @@ -1151,9 +1155,10 @@ class BaseMemcachedTests(BaseCacheTests): 'server1.tld,server2:11211', ] for location in locations: - params = {'BACKEND': self.base_params['BACKEND'], 'LOCATION': location} - with self.settings(CACHES={'default': params}): - self.assertEqual(cache._servers, ['server1.tld', 'server2:11211']) + with self.subTest(location=location): + params = {'BACKEND': self.base_params['BACKEND'], 'LOCATION': location} + with self.settings(CACHES={'default': params}): + self.assertEqual(cache._servers, ['server1.tld', 'server2:11211']) def test_invalid_key_characters(self): """ @@ -1250,7 +1255,8 @@ class MemcachedCacheTests(BaseMemcachedTests, TestCase): def test_memcached_uses_highest_pickle_version(self): # Regression test for #19810 for cache_key in settings.CACHES: - self.assertEqual(caches[cache_key]._cache.pickleProtocol, pickle.HIGHEST_PROTOCOL) + with self.subTest(cache_key=cache_key): + self.assertEqual(caches[cache_key]._cache.pickleProtocol, pickle.HIGHEST_PROTOCOL) @override_settings(CACHES=caches_setting_for_tests( base=MemcachedCache_params, @@ -1521,11 +1527,12 @@ class CacheUtils(SimpleTestCase): ('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'), ) for initial_vary, newheaders, resulting_vary in headers: - response = HttpResponse() - if initial_vary is not None: - response['Vary'] = initial_vary - patch_vary_headers(response, newheaders) - self.assertEqual(response['Vary'], resulting_vary) + with self.subTest(initial_vary=initial_vary, newheaders=newheaders): + response = HttpResponse() + if initial_vary is not None: + response['Vary'] = initial_vary + patch_vary_headers(response, newheaders) + self.assertEqual(response['Vary'], resulting_vary) def test_get_cache_key(self): request = self.factory.get(self.path) @@ -1605,12 +1612,13 @@ class CacheUtils(SimpleTestCase): cc_delim_re = re.compile(r'\s*,\s*') for initial_cc, newheaders, expected_cc in tests: - response = HttpResponse() - if initial_cc is not None: - response['Cache-Control'] = initial_cc - patch_cache_control(response, **newheaders) - parts = set(cc_delim_re.split(response['Cache-Control'])) - self.assertEqual(parts, expected_cc) + with self.subTest(initial_cc=initial_cc, newheaders=newheaders): + response = HttpResponse() + if initial_cc is not None: + response['Cache-Control'] = initial_cc + patch_cache_control(response, **newheaders) + parts = set(cc_delim_re.split(response['Cache-Control'])) + self.assertEqual(parts, expected_cc) @override_settings( @@ -2179,12 +2187,13 @@ class TestWithTemplateResponse(SimpleTestCase): ('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'), ) for initial_vary, newheaders, resulting_vary in headers: - template = engines['django'].from_string("This is a test") - response = TemplateResponse(HttpRequest(), template) - if initial_vary is not None: - response['Vary'] = initial_vary - patch_vary_headers(response, newheaders) - self.assertEqual(response['Vary'], resulting_vary) + with self.subTest(initial_vary=initial_vary, newheaders=newheaders): + template = engines['django'].from_string("This is a test") + response = TemplateResponse(HttpRequest(), template) + if initial_vary is not None: + response['Vary'] = initial_vary + patch_vary_headers(response, newheaders) + self.assertEqual(response['Vary'], resulting_vary) def test_get_cache_key(self): request = self.factory.get(self.path) diff --git a/tests/contenttypes_tests/test_views.py b/tests/contenttypes_tests/test_views.py index d1165c6818..cdfa1e0961 100644 --- a/tests/contenttypes_tests/test_views.py +++ b/tests/contenttypes_tests/test_views.py @@ -45,9 +45,10 @@ class ContentTypesViewsTests(TestCase): def test_shortcut_with_absolute_url(self): "Can view a shortcut for an Author object that has a get_absolute_url method" for obj in Author.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk) - response = self.client.get(short_url) - self.assertRedirects(response, 'http://testserver%s' % obj.get_absolute_url(), target_status_code=404) + with self.subTest(obj=obj): + short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk) + response = self.client.get(short_url) + self.assertRedirects(response, 'http://testserver%s' % obj.get_absolute_url(), target_status_code=404) def test_shortcut_with_absolute_url_including_scheme(self): """ @@ -55,9 +56,10 @@ class ContentTypesViewsTests(TestCase): the tested URLs are: "http://...", "https://..." and "//..." """ for obj in SchemeIncludedURL.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(SchemeIncludedURL).id, obj.pk) - response = self.client.get(short_url) - self.assertRedirects(response, obj.get_absolute_url(), fetch_redirect_response=False) + with self.subTest(obj=obj): + short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(SchemeIncludedURL).id, obj.pk) + response = self.client.get(short_url) + self.assertRedirects(response, obj.get_absolute_url(), fetch_redirect_response=False) def test_shortcut_no_absolute_url(self): """ @@ -65,9 +67,10 @@ class ContentTypesViewsTests(TestCase): 404. """ for obj in Article.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk) - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) + with self.subTest(obj=obj): + short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk) + response = self.client.get(short_url) + self.assertEqual(response.status_code, 404) def test_wrong_type_pk(self): short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, 'nobody/expects') diff --git a/tests/custom_managers/tests.py b/tests/custom_managers/tests.py index 54f3b58a79..d095036f10 100644 --- a/tests/custom_managers/tests.py +++ b/tests/custom_managers/tests.py @@ -42,41 +42,44 @@ class CustomManagerTests(TestCase): default Manager. """ for manager_name in self.custom_manager_names: - manager = getattr(Person, manager_name) + with self.subTest(manager_name=manager_name): + manager = getattr(Person, manager_name) - # Public methods are copied - manager.public_method() - # Private methods are not copied - with self.assertRaises(AttributeError): - manager._private_method() + # Public methods are copied + manager.public_method() + # Private methods are not copied + with self.assertRaises(AttributeError): + manager._private_method() def test_manager_honors_queryset_only(self): for manager_name in self.custom_manager_names: - manager = getattr(Person, manager_name) - # Methods with queryset_only=False are copied even if they are private. - manager._optin_private_method() - # Methods with queryset_only=True aren't copied even if they are public. - with self.assertRaises(AttributeError): - manager.optout_public_method() + with self.subTest(manager_name=manager_name): + manager = getattr(Person, manager_name) + # Methods with queryset_only=False are copied even if they are private. + manager._optin_private_method() + # Methods with queryset_only=True aren't copied even if they are public. + with self.assertRaises(AttributeError): + manager.optout_public_method() def test_manager_use_queryset_methods(self): """ Custom manager will use the queryset methods """ for manager_name in self.custom_manager_names: - manager = getattr(Person, manager_name) - queryset = manager.filter() - self.assertQuerysetEqual(queryset, ["Bugs Bunny"], str) - self.assertIs(queryset._filter_CustomQuerySet, True) + with self.subTest(manager_name=manager_name): + manager = getattr(Person, manager_name) + queryset = manager.filter() + self.assertQuerysetEqual(queryset, ["Bugs Bunny"], str) + self.assertIs(queryset._filter_CustomQuerySet, True) - # Specialized querysets inherit from our custom queryset. - queryset = manager.values_list('first_name', flat=True).filter() - self.assertEqual(list(queryset), ["Bugs"]) - self.assertIs(queryset._filter_CustomQuerySet, True) + # Specialized querysets inherit from our custom queryset. + queryset = manager.values_list('first_name', flat=True).filter() + self.assertEqual(list(queryset), ["Bugs"]) + self.assertIs(queryset._filter_CustomQuerySet, True) - self.assertIsInstance(queryset.values(), CustomQuerySet) - self.assertIsInstance(queryset.values().values(), CustomQuerySet) - self.assertIsInstance(queryset.values_list().values(), CustomQuerySet) + self.assertIsInstance(queryset.values(), CustomQuerySet) + self.assertIsInstance(queryset.values().values(), CustomQuerySet) + self.assertIsInstance(queryset.values_list().values(), CustomQuerySet) def test_init_args(self): """ diff --git a/tests/db_typecasts/tests.py b/tests/db_typecasts/tests.py index 56d37c112d..4d65ca8d4d 100644 --- a/tests/db_typecasts/tests.py +++ b/tests/db_typecasts/tests.py @@ -54,9 +54,9 @@ class DBTypeCasts(unittest.TestCase): def test_typeCasts(self): for k, v in TEST_CASES.items(): for inpt, expected in v: - got = getattr(typecasts, k)(inpt) - self.assertEqual( - got, - expected, - "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got) - ) + with self.subTest(k=k, inpt=inpt): + got = getattr(typecasts, k)(inpt) + self.assertEqual( + got, expected, + "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got) + ) diff --git a/tests/forms_tests/field_tests/test_filepathfield.py b/tests/forms_tests/field_tests/test_filepathfield.py index cbdf97b4c2..56bf0e9fda 100644 --- a/tests/forms_tests/field_tests/test_filepathfield.py +++ b/tests/forms_tests/field_tests/test_filepathfield.py @@ -38,8 +38,9 @@ class FilePathFieldTest(SimpleTestCase): ('/django/forms/widgets.py', 'widgets.py') ] for exp, got in zip(expected, fix_os_paths(f.choices)): - self.assertEqual(exp[1], got[1]) - self.assertTrue(got[0].endswith(exp[0])) + with self.subTest(expected=exp): + self.assertEqual(exp[1], got[1]) + self.assertTrue(got[0].endswith(exp[0])) msg = "'Select a valid choice. fields.py is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): f.clean('fields.py') @@ -61,8 +62,9 @@ class FilePathFieldTest(SimpleTestCase): ('/django/forms/widgets.py', 'widgets.py') ] for exp, got in zip(expected, fix_os_paths(f.choices)): - self.assertEqual(exp[1], got[1]) - self.assertTrue(got[0].endswith(exp[0])) + with self.subTest(expected=exp): + self.assertEqual(exp[1], got[1]) + self.assertTrue(got[0].endswith(exp[0])) def test_filepathfield_4(self): path = os.path.dirname(os.path.abspath(forms.__file__)) + '/' @@ -80,8 +82,9 @@ class FilePathFieldTest(SimpleTestCase): ('/django/forms/widgets.py', 'widgets.py') ] for exp, got in zip(expected, fix_os_paths(f.choices)): - self.assertEqual(exp[1], got[1]) - self.assertTrue(got[0].endswith(exp[0])) + with self.subTest(expected=exp): + self.assertEqual(exp[1], got[1]) + self.assertTrue(got[0].endswith(exp[0])) def test_filepathfield_folders(self): path = os.path.abspath(os.path.join(__file__, '..', '..')) + '/tests/filepath_test_files/' @@ -93,8 +96,9 @@ class FilePathFieldTest(SimpleTestCase): actual = fix_os_paths(f.choices) self.assertEqual(len(expected), len(actual)) for exp, got in zip(expected, actual): - self.assertEqual(exp[1], got[1]) - self.assertTrue(got[0].endswith(exp[0])) + with self.subTest(expected=exp): + self.assertEqual(exp[1], got[1]) + self.assertTrue(got[0].endswith(exp[0])) f = FilePathField(path=path, allow_folders=True, allow_files=True) f.choices.sort() @@ -110,5 +114,6 @@ class FilePathFieldTest(SimpleTestCase): actual = fix_os_paths(f.choices) self.assertEqual(len(expected), len(actual)) for exp, got in zip(expected, actual): - self.assertEqual(exp[1], got[1]) - self.assertTrue(got[0].endswith(exp[0])) + with self.subTest(expected=exp): + self.assertEqual(exp[1], got[1]) + self.assertTrue(got[0].endswith(exp[0])) diff --git a/tests/forms_tests/field_tests/test_urlfield.py b/tests/forms_tests/field_tests/test_urlfield.py index 715e8e99e0..2ecf189112 100644 --- a/tests/forms_tests/field_tests/test_urlfield.py +++ b/tests/forms_tests/field_tests/test_urlfield.py @@ -127,8 +127,9 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): 'http://العربية.idn.icann.org/', ) for url in urls: - # Valid IDN - self.assertEqual(url, f.clean(url)) + with self.subTest(url=url): + # Valid IDN + self.assertEqual(url, f.clean(url)) def test_urlfield_10(self): """URLField correctly validates IPv6 (#18779).""" @@ -138,7 +139,8 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): 'http://[a34:9238::]:8080/', ) for url in urls: - self.assertEqual(url, f.clean(url)) + with self.subTest(url=url): + self.assertEqual(url, f.clean(url)) def test_urlfield_not_string(self): f = URLField(required=False) diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index 9f32953b47..63209a1f62 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -3008,7 +3008,8 @@ Good luck picking a username that doesn't already exist.

] for args, kwargs, expected in testcases: - self.assertHTMLEqual(boundfield.label_tag(*args, **kwargs), expected) + with self.subTest(args=args, kwargs=kwargs): + self.assertHTMLEqual(boundfield.label_tag(*args, **kwargs), expected) def test_boundfield_label_tag_no_id(self): """ diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py index a1965cd47b..043b8e0edc 100644 --- a/tests/forms_tests/tests/tests.py +++ b/tests/forms_tests/tests/tests.py @@ -335,12 +335,12 @@ class EmptyLabelTestCase(TestCase): ] for form, key, expected in tests: - f = form({'name': 'some-key', key: ''}) - self.assertTrue(f.is_valid()) - m = f.save() - self.assertEqual(expected, getattr(m, key)) - self.assertEqual('No Preference', - getattr(m, 'get_{}_display'.format(key))()) + with self.subTest(form=form): + f = form({'name': 'some-key', key: ''}) + self.assertTrue(f.is_valid()) + m = f.save() + self.assertEqual(expected, getattr(m, key)) + self.assertEqual('No Preference', getattr(m, 'get_{}_display'.format(key))()) def test_empty_field_integer(self): f = EmptyIntegerLabelChoiceForm() diff --git a/tests/gis_tests/distapp/tests.py b/tests/gis_tests/distapp/tests.py index 70e1f98d20..eab144b3e4 100644 --- a/tests/gis_tests/distapp/tests.py +++ b/tests/gis_tests/distapp/tests.py @@ -68,32 +68,35 @@ class DistanceTest(TestCase): qs1 = SouthTexasCity.objects.filter(point__dwithin=(self.stx_pnt, dist1)) qs2 = SouthTexasCityFt.objects.filter(point__dwithin=(self.stx_pnt, dist2)) for qs in qs1, qs2: - self.assertEqual(tx_cities, self.get_names(qs)) + with self.subTest(dist=dist, qs=qs): + self.assertEqual(tx_cities, self.get_names(qs)) # Now performing the `dwithin` queries on a geodetic coordinate system. for dist in au_dists: - if isinstance(dist, D) and not oracle: - type_error = True - else: - type_error = False - - if isinstance(dist, tuple): - if oracle or spatialite: - # Result in meters - dist = dist[1] + with self.subTest(dist=dist): + if isinstance(dist, D) and not oracle: + type_error = True else: - # Result in units of the field - dist = dist[0] + type_error = False - # Creating the query set. - qs = AustraliaCity.objects.order_by('name') - if type_error: - # A ValueError should be raised on PostGIS when trying to pass - # Distance objects into a DWithin query using a geodetic field. - with self.assertRaises(ValueError): - AustraliaCity.objects.filter(point__dwithin=(self.au_pnt, dist)).count() - else: - self.assertEqual(au_cities, self.get_names(qs.filter(point__dwithin=(self.au_pnt, dist)))) + if isinstance(dist, tuple): + if oracle or spatialite: + # Result in meters + dist = dist[1] + else: + # Result in units of the field + dist = dist[0] + + # Creating the query set. + qs = AustraliaCity.objects.order_by('name') + if type_error: + # A ValueError should be raised on PostGIS when trying to + # pass Distance objects into a DWithin query using a + # geodetic field. + with self.assertRaises(ValueError): + AustraliaCity.objects.filter(point__dwithin=(self.au_pnt, dist)).count() + else: + self.assertEqual(au_cities, self.get_names(qs.filter(point__dwithin=(self.au_pnt, dist)))) @skipUnlessDBFeature("supports_distances_lookups") def test_distance_lookups(self): @@ -298,8 +301,9 @@ class DistanceFunctionsTests(TestCase): # Ensuring expected distances are returned for each distance queryset. for qs in dist_qs: for i, c in enumerate(qs): - self.assertAlmostEqual(m_distances[i], c.distance.m, tol) - self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol) + with self.subTest(c=c): + self.assertAlmostEqual(m_distances[i], c.distance.m, tol) + self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol) @skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic") def test_distance_geodetic(self): @@ -318,9 +322,10 @@ class DistanceFunctionsTests(TestCase): 40435.4335201384, 0, 68272.3896586844, 12375.0643697706, 0] qs = AustraliaCity.objects.annotate(distance=Distance('point', ls)).order_by('name') for city, distance in zip(qs, distances): - # Testing equivalence to within a meter (kilometer on SpatiaLite). - tol = -3 if spatialite else 0 - self.assertAlmostEqual(distance, city.distance.m, tol) + with self.subTest(city=city, distance=distance): + # Testing equivalence to within a meter (kilometer on SpatiaLite). + tol = -3 if spatialite else 0 + self.assertAlmostEqual(distance, city.distance.m, tol) @skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic") def test_distance_geodetic_spheroid(self): @@ -349,14 +354,16 @@ class DistanceFunctionsTests(TestCase): distance=Distance('point', hillsdale.point, spheroid=True) ).order_by('id') for i, c in enumerate(qs): - self.assertAlmostEqual(spheroid_distances[i], c.distance.m, tol) + with self.subTest(c=c): + self.assertAlmostEqual(spheroid_distances[i], c.distance.m, tol) if postgis or spatialite: # PostGIS uses sphere-only distances by default, testing these as well. qs = AustraliaCity.objects.exclude(id=hillsdale.id).annotate( distance=Distance('point', hillsdale.point) ).order_by('id') for i, c in enumerate(qs): - self.assertAlmostEqual(sphere_distances[i], c.distance.m, tol) + with self.subTest(c=c): + self.assertAlmostEqual(sphere_distances[i], c.distance.m, tol) @skipIfDBFeature("supports_distance_geodetic") @skipUnlessDBFeature("has_Distance_function") diff --git a/tests/gis_tests/test_geoforms.py b/tests/gis_tests/test_geoforms.py index 12066da013..cdcbe47685 100644 --- a/tests/gis_tests/test_geoforms.py +++ b/tests/gis_tests/test_geoforms.py @@ -15,8 +15,9 @@ class GeometryFieldTest(SimpleTestCase): "Testing GeometryField initialization with defaults." fld = forms.GeometryField() for bad_default in ('blah', 3, 'FoO', None, 0): - with self.assertRaises(ValidationError): - fld.clean(bad_default) + with self.subTest(bad_default=bad_default): + with self.assertRaises(ValidationError): + fld.clean(bad_default) def test_srid(self): "Testing GeometryField with a SRID set." @@ -50,9 +51,10 @@ class GeometryFieldTest(SimpleTestCase): # By default, all geometry types are allowed. fld = forms.GeometryField() for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'): - # `to_python` uses the SRID of OpenLayersWidget if the converted - # value doesn't have an SRID itself. - self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.clean(wkt)) + with self.subTest(wkt=wkt): + # to_python() uses the SRID of OpenLayersWidget if the + # converted value doesn't have an SRID. + self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.clean(wkt)) pnt_fld = forms.GeometryField(geom_type='POINT') self.assertEqual(GEOSGeometry('POINT(5 23)', srid=pnt_fld.widget.map_srid), pnt_fld.clean('POINT(5 23)')) @@ -73,11 +75,13 @@ class GeometryFieldTest(SimpleTestCase): fld = forms.GeometryField() # to_python returns the same GEOSGeometry for a WKT for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'): - self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.to_python(wkt)) + with self.subTest(wkt=wkt): + self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.to_python(wkt)) # but raises a ValidationError for any other string for wkt in ('POINT(5)', 'MULTI POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'): - with self.assertRaises(forms.ValidationError): - fld.to_python(wkt) + with self.subTest(wkt=wkt): + with self.assertRaises(forms.ValidationError): + fld.to_python(wkt) def test_field_with_text_widget(self): class PointForm(forms.Form): diff --git a/tests/gis_tests/test_measure.py b/tests/gis_tests/test_measure.py index 3616fcde1a..c6a844d8b5 100644 --- a/tests/gis_tests/test_measure.py +++ b/tests/gis_tests/test_measure.py @@ -143,7 +143,8 @@ class DistanceTest(unittest.TestCase): unit_tuple = [('Yard', 'yd'), ('Nautical Mile', 'nm'), ('German legal metre', 'german_m'), ('Indian yard', 'indian_yd'), ('Chain (Sears)', 'chain_sears'), ('Chain', 'chain')] for nm, att in unit_tuple: - self.assertEqual(att, D.unit_attname(nm)) + with self.subTest(nm=nm): + self.assertEqual(att, D.unit_attname(nm)) class AreaTest(unittest.TestCase): diff --git a/tests/gis_tests/tests.py b/tests/gis_tests/tests.py index 0cbfd97dcc..6b42384203 100644 --- a/tests/gis_tests/tests.py +++ b/tests/gis_tests/tests.py @@ -76,17 +76,19 @@ class TestPostGISVersionCheck(unittest.TestCase): ] for version in versions: - ops = FakePostGISOperations(version[0]) - actual = ops.spatial_version - self.assertEqual(version[1:], actual) + with self.subTest(version=version): + ops = FakePostGISOperations(version[0]) + actual = ops.spatial_version + self.assertEqual(version[1:], actual) def test_invalid_version_numbers(self): versions = ['nope', '123'] for version in versions: - ops = FakePostGISOperations(version) - with self.assertRaises(Exception): - ops.spatial_version + with self.subTest(version=version): + ops = FakePostGISOperations(version) + with self.assertRaises(Exception): + ops.spatial_version def test_no_version_number(self): ops = FakePostGISOperations()