PageRenderTime 45ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/validators/tests.py

https://gitlab.com/mayakarya/django
Python | 477 lines | 467 code | 8 blank | 2 comment | 3 complexity | 452650fb8150e401ff8aa51cf4e445e1 MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import io
  4. import os
  5. import re
  6. import types
  7. from datetime import datetime, timedelta
  8. from unittest import TestCase, skipUnless
  9. from django.core.exceptions import ValidationError
  10. from django.core.files.base import ContentFile
  11. from django.core.validators import (
  12. BaseValidator, DecimalValidator, EmailValidator, FileExtensionValidator,
  13. MaxLengthValidator, MaxValueValidator, MinLengthValidator,
  14. MinValueValidator, RegexValidator, URLValidator, int_list_validator,
  15. validate_comma_separated_integer_list, validate_email,
  16. validate_image_file_extension, validate_integer, validate_ipv4_address,
  17. validate_ipv6_address, validate_ipv46_address, validate_slug,
  18. validate_unicode_slug,
  19. )
  20. from django.test import SimpleTestCase
  21. from django.test.utils import str_prefix
  22. from django.utils._os import upath
  23. try:
  24. from PIL import Image # noqa
  25. except ImportError:
  26. PILLOW_IS_INSTALLED = False
  27. else:
  28. PILLOW_IS_INSTALLED = True
  29. NOW = datetime.now()
  30. EXTENDED_SCHEMES = ['http', 'https', 'ftp', 'ftps', 'git', 'file', 'git+ssh']
  31. TEST_DATA = [
  32. # (validator, value, expected),
  33. (validate_integer, '42', None),
  34. (validate_integer, '-42', None),
  35. (validate_integer, -42, None),
  36. (validate_integer, -42.5, ValidationError),
  37. (validate_integer, None, ValidationError),
  38. (validate_integer, 'a', ValidationError),
  39. (validate_integer, '\n42', ValidationError),
  40. (validate_integer, '42\n', ValidationError),
  41. (validate_email, 'email@here.com', None),
  42. (validate_email, 'weirder-email@here.and.there.com', None),
  43. (validate_email, 'email@[127.0.0.1]', None),
  44. (validate_email, 'email@[2001:dB8::1]', None),
  45. (validate_email, 'email@[2001:dB8:0:0:0:0:0:1]', None),
  46. (validate_email, 'email@[::fffF:127.0.0.1]', None),
  47. (validate_email, 'example@valid-----hyphens.com', None),
  48. (validate_email, 'example@valid-with-hyphens.com', None),
  49. (validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None),
  50. (validate_email, 'email@localhost', None),
  51. (EmailValidator(whitelist=['localdomain']), 'email@localdomain', None),
  52. (validate_email, '"test@test"@example.com', None),
  53. (validate_email, 'example@atm.%s' % ('a' * 63), None),
  54. (validate_email, 'example@%s.atm' % ('a' * 63), None),
  55. (validate_email, 'example@%s.%s.atm' % ('a' * 63, 'b' * 10), None),
  56. (validate_email, 'example@atm.%s' % ('a' * 64), ValidationError),
  57. (validate_email, 'example@%s.atm.%s' % ('b' * 64, 'a' * 63), ValidationError),
  58. (validate_email, None, ValidationError),
  59. (validate_email, '', ValidationError),
  60. (validate_email, 'abc', ValidationError),
  61. (validate_email, 'abc@', ValidationError),
  62. (validate_email, 'abc@bar', ValidationError),
  63. (validate_email, 'a @x.cz', ValidationError),
  64. (validate_email, 'abc@.com', ValidationError),
  65. (validate_email, 'something@@somewhere.com', ValidationError),
  66. (validate_email, 'email@127.0.0.1', ValidationError),
  67. (validate_email, 'email@[127.0.0.256]', ValidationError),
  68. (validate_email, 'email@[2001:db8::12345]', ValidationError),
  69. (validate_email, 'email@[2001:db8:0:0:0:0:1]', ValidationError),
  70. (validate_email, 'email@[::ffff:127.0.0.256]', ValidationError),
  71. (validate_email, 'example@invalid-.com', ValidationError),
  72. (validate_email, 'example@-invalid.com', ValidationError),
  73. (validate_email, 'example@invalid.com-', ValidationError),
  74. (validate_email, 'example@inv-.alid-.com', ValidationError),
  75. (validate_email, 'example@inv-.-alid.com', ValidationError),
  76. (validate_email, 'test@example.com\n\n<script src="x.js">', ValidationError),
  77. # Quoted-string format (CR not allowed)
  78. (validate_email, '"\\\011"@here.com', None),
  79. (validate_email, '"\\\012"@here.com', ValidationError),
  80. (validate_email, 'trailingdot@shouldfail.com.', ValidationError),
  81. # Max length of domain name labels is 63 characters per RFC 1034.
  82. (validate_email, 'a@%s.us' % ('a' * 63), None),
  83. (validate_email, 'a@%s.us' % ('a' * 64), ValidationError),
  84. # Trailing newlines in username or domain not allowed
  85. (validate_email, 'a@b.com\n', ValidationError),
  86. (validate_email, 'a\n@b.com', ValidationError),
  87. (validate_email, '"test@test"\n@example.com', ValidationError),
  88. (validate_email, 'a@[127.0.0.1]\n', ValidationError),
  89. (validate_slug, 'slug-ok', None),
  90. (validate_slug, 'longer-slug-still-ok', None),
  91. (validate_slug, '--------', None),
  92. (validate_slug, 'nohyphensoranything', None),
  93. (validate_slug, 'a', None),
  94. (validate_slug, '1', None),
  95. (validate_slug, 'a1', None),
  96. (validate_slug, '', ValidationError),
  97. (validate_slug, ' text ', ValidationError),
  98. (validate_slug, ' ', ValidationError),
  99. (validate_slug, 'some@mail.com', ValidationError),
  100. (validate_slug, '你好', ValidationError),
  101. (validate_slug, '你 好', ValidationError),
  102. (validate_slug, '\n', ValidationError),
  103. (validate_slug, 'trailing-newline\n', ValidationError),
  104. (validate_unicode_slug, 'slug-ok', None),
  105. (validate_unicode_slug, 'longer-slug-still-ok', None),
  106. (validate_unicode_slug, '--------', None),
  107. (validate_unicode_slug, 'nohyphensoranything', None),
  108. (validate_unicode_slug, 'a', None),
  109. (validate_unicode_slug, '1', None),
  110. (validate_unicode_slug, 'a1', None),
  111. (validate_unicode_slug, '你好', None),
  112. (validate_unicode_slug, '', ValidationError),
  113. (validate_unicode_slug, ' text ', ValidationError),
  114. (validate_unicode_slug, ' ', ValidationError),
  115. (validate_unicode_slug, 'some@mail.com', ValidationError),
  116. (validate_unicode_slug, '\n', ValidationError),
  117. (validate_unicode_slug, '你 好', ValidationError),
  118. (validate_unicode_slug, 'trailing-newline\n', ValidationError),
  119. (validate_ipv4_address, '1.1.1.1', None),
  120. (validate_ipv4_address, '255.0.0.0', None),
  121. (validate_ipv4_address, '0.0.0.0', None),
  122. (validate_ipv4_address, '256.1.1.1', ValidationError),
  123. (validate_ipv4_address, '25.1.1.', ValidationError),
  124. (validate_ipv4_address, '25,1,1,1', ValidationError),
  125. (validate_ipv4_address, '25.1 .1.1', ValidationError),
  126. (validate_ipv4_address, '1.1.1.1\n', ValidationError),
  127. # validate_ipv6_address uses django.utils.ipv6, which
  128. # is tested in much greater detail in its own testcase
  129. (validate_ipv6_address, 'fe80::1', None),
  130. (validate_ipv6_address, '::1', None),
  131. (validate_ipv6_address, '1:2:3:4:5:6:7:8', None),
  132. (validate_ipv6_address, '1:2', ValidationError),
  133. (validate_ipv6_address, '::zzz', ValidationError),
  134. (validate_ipv6_address, '12345::', ValidationError),
  135. (validate_ipv46_address, '1.1.1.1', None),
  136. (validate_ipv46_address, '255.0.0.0', None),
  137. (validate_ipv46_address, '0.0.0.0', None),
  138. (validate_ipv46_address, 'fe80::1', None),
  139. (validate_ipv46_address, '::1', None),
  140. (validate_ipv46_address, '1:2:3:4:5:6:7:8', None),
  141. (validate_ipv46_address, '256.1.1.1', ValidationError),
  142. (validate_ipv46_address, '25.1.1.', ValidationError),
  143. (validate_ipv46_address, '25,1,1,1', ValidationError),
  144. (validate_ipv46_address, '25.1 .1.1', ValidationError),
  145. (validate_ipv46_address, '1:2', ValidationError),
  146. (validate_ipv46_address, '::zzz', ValidationError),
  147. (validate_ipv46_address, '12345::', ValidationError),
  148. (validate_comma_separated_integer_list, '1', None),
  149. (validate_comma_separated_integer_list, '12', None),
  150. (validate_comma_separated_integer_list, '1,2', None),
  151. (validate_comma_separated_integer_list, '1,2,3', None),
  152. (validate_comma_separated_integer_list, '10,32', None),
  153. (validate_comma_separated_integer_list, '', ValidationError),
  154. (validate_comma_separated_integer_list, 'a', ValidationError),
  155. (validate_comma_separated_integer_list, 'a,b,c', ValidationError),
  156. (validate_comma_separated_integer_list, '1, 2, 3', ValidationError),
  157. (validate_comma_separated_integer_list, ',', ValidationError),
  158. (validate_comma_separated_integer_list, '1,2,3,', ValidationError),
  159. (validate_comma_separated_integer_list, '1,2,', ValidationError),
  160. (validate_comma_separated_integer_list, ',1', ValidationError),
  161. (validate_comma_separated_integer_list, '1,,2', ValidationError),
  162. (int_list_validator(sep='.'), '1.2.3', None),
  163. (int_list_validator(sep='.', allow_negative=True), '1.2.3', None),
  164. (int_list_validator(allow_negative=True), '-1,-2,3', None),
  165. (int_list_validator(allow_negative=True), '1,-2,-12', None),
  166. (int_list_validator(), '-1,2,3', ValidationError),
  167. (int_list_validator(sep='.'), '1,2,3', ValidationError),
  168. (int_list_validator(sep='.'), '1.2.3\n', ValidationError),
  169. (MaxValueValidator(10), 10, None),
  170. (MaxValueValidator(10), -10, None),
  171. (MaxValueValidator(10), 0, None),
  172. (MaxValueValidator(NOW), NOW, None),
  173. (MaxValueValidator(NOW), NOW - timedelta(days=1), None),
  174. (MaxValueValidator(0), 1, ValidationError),
  175. (MaxValueValidator(NOW), NOW + timedelta(days=1), ValidationError),
  176. (MinValueValidator(-10), -10, None),
  177. (MinValueValidator(-10), 10, None),
  178. (MinValueValidator(-10), 0, None),
  179. (MinValueValidator(NOW), NOW, None),
  180. (MinValueValidator(NOW), NOW + timedelta(days=1), None),
  181. (MinValueValidator(0), -1, ValidationError),
  182. (MinValueValidator(NOW), NOW - timedelta(days=1), ValidationError),
  183. (MaxLengthValidator(10), '', None),
  184. (MaxLengthValidator(10), 10 * 'x', None),
  185. (MaxLengthValidator(10), 15 * 'x', ValidationError),
  186. (MinLengthValidator(10), 15 * 'x', None),
  187. (MinLengthValidator(10), 10 * 'x', None),
  188. (MinLengthValidator(10), '', ValidationError),
  189. (URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None),
  190. (URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None),
  191. (URLValidator(EXTENDED_SCHEMES), 'git+ssh://git@github.com/example/hg-git.git', None),
  192. (URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
  193. # Trailing newlines not accepted
  194. (URLValidator(), 'http://www.djangoproject.com/\n', ValidationError),
  195. (URLValidator(), 'http://[::ffff:192.9.5.5]\n', ValidationError),
  196. # Trailing junk does not take forever to reject
  197. (URLValidator(), 'http://www.asdasdasdasdsadfm.com.br ', ValidationError),
  198. (URLValidator(), 'http://www.asdasdasdasdsadfm.com.br z', ValidationError),
  199. (BaseValidator(True), True, None),
  200. (BaseValidator(True), False, ValidationError),
  201. (RegexValidator(), '', None),
  202. (RegexValidator(), 'x1x2', None),
  203. (RegexValidator('[0-9]+'), 'xxxxxx', ValidationError),
  204. (RegexValidator('[0-9]+'), '1234', None),
  205. (RegexValidator(re.compile('[0-9]+')), '1234', None),
  206. (RegexValidator('.*'), '', None),
  207. (RegexValidator(re.compile('.*')), '', None),
  208. (RegexValidator('.*'), 'xxxxx', None),
  209. (RegexValidator('x'), 'y', ValidationError),
  210. (RegexValidator(re.compile('x')), 'y', ValidationError),
  211. (RegexValidator('x', inverse_match=True), 'y', None),
  212. (RegexValidator(re.compile('x'), inverse_match=True), 'y', None),
  213. (RegexValidator('x', inverse_match=True), 'x', ValidationError),
  214. (RegexValidator(re.compile('x'), inverse_match=True), 'x', ValidationError),
  215. (RegexValidator('x', flags=re.IGNORECASE), 'y', ValidationError),
  216. (RegexValidator('a'), 'A', ValidationError),
  217. (RegexValidator('a', flags=re.IGNORECASE), 'A', None),
  218. (FileExtensionValidator(['txt']), ContentFile('contents', name='fileWithUnsupportedExt.jpg'), ValidationError),
  219. (FileExtensionValidator(['txt']), ContentFile('contents', name='fileWithNoExtenstion'), ValidationError),
  220. (FileExtensionValidator([]), ContentFile('contents', name='file.txt'), ValidationError),
  221. (FileExtensionValidator(['txt']), ContentFile('contents', name='file.txt'), None),
  222. (FileExtensionValidator(), ContentFile('contents', name='file.jpg'), None),
  223. (validate_image_file_extension, ContentFile('contents', name='file.jpg'), None),
  224. (validate_image_file_extension, ContentFile('contents', name='file.png'), None),
  225. (validate_image_file_extension, ContentFile('contents', name='file.txt'), ValidationError),
  226. (validate_image_file_extension, ContentFile('contents', name='file'), ValidationError),
  227. ]
  228. def create_path(filename):
  229. return os.path.abspath(os.path.join(os.path.dirname(upath(__file__)), filename))
  230. # Add valid and invalid URL tests.
  231. # This only tests the validator without extended schemes.
  232. with io.open(create_path('valid_urls.txt'), encoding='utf8') as f:
  233. for url in f:
  234. TEST_DATA.append((URLValidator(), url.strip(), None))
  235. with io.open(create_path('invalid_urls.txt'), encoding='utf8') as f:
  236. for url in f:
  237. TEST_DATA.append((URLValidator(), url.strip(), ValidationError))
  238. def create_simple_test_method(validator, expected, value, num):
  239. if expected is not None and issubclass(expected, Exception):
  240. test_mask = 'test_%s_raises_error_%d'
  241. def test_func(self):
  242. # assertRaises not used, so as to be able to produce an error message
  243. # containing the tested value
  244. try:
  245. validator(value)
  246. except expected:
  247. pass
  248. else:
  249. self.fail("%s not raised when validating '%s'" % (
  250. expected.__name__, value))
  251. else:
  252. test_mask = 'test_%s_%d'
  253. def test_func(self):
  254. try:
  255. self.assertEqual(expected, validator(value))
  256. except ValidationError as e:
  257. self.fail("Validation of '%s' failed. Error message was: %s" % (
  258. value, str(e)))
  259. if isinstance(validator, types.FunctionType):
  260. val_name = validator.__name__
  261. else:
  262. val_name = validator.__class__.__name__
  263. test_name = test_mask % (val_name, num)
  264. if validator is validate_image_file_extension:
  265. SKIP_MSG = "Pillow is required to test validate_image_file_extension"
  266. test_func = skipUnless(PILLOW_IS_INSTALLED, SKIP_MSG)(test_func)
  267. return test_name, test_func
  268. # Dynamically assemble a test class with the contents of TEST_DATA
  269. class TestSimpleValidators(SimpleTestCase):
  270. def test_single_message(self):
  271. v = ValidationError('Not Valid')
  272. self.assertEqual(str(v), str_prefix("[%(_)s'Not Valid']"))
  273. self.assertEqual(repr(v), str_prefix("ValidationError([%(_)s'Not Valid'])"))
  274. def test_message_list(self):
  275. v = ValidationError(['First Problem', 'Second Problem'])
  276. self.assertEqual(str(v), str_prefix("[%(_)s'First Problem', %(_)s'Second Problem']"))
  277. self.assertEqual(repr(v), str_prefix("ValidationError([%(_)s'First Problem', %(_)s'Second Problem'])"))
  278. def test_message_dict(self):
  279. v = ValidationError({'first': ['First Problem']})
  280. self.assertEqual(str(v), str_prefix("{%(_)s'first': [%(_)s'First Problem']}"))
  281. self.assertEqual(repr(v), str_prefix("ValidationError({%(_)s'first': [%(_)s'First Problem']})"))
  282. def test_regex_validator_flags(self):
  283. with self.assertRaises(TypeError):
  284. RegexValidator(re.compile('a'), flags=re.IGNORECASE)
  285. def test_max_length_validator_message(self):
  286. v = MaxLengthValidator(16, message='"%(value)s" has more than %(limit_value)d characters.')
  287. with self.assertRaisesMessage(ValidationError, '"djangoproject.com" has more than 16 characters.'):
  288. v('djangoproject.com')
  289. test_counter = 0
  290. for validator, value, expected in TEST_DATA:
  291. name, method = create_simple_test_method(validator, expected, value, test_counter)
  292. setattr(TestSimpleValidators, name, method)
  293. test_counter += 1
  294. class TestValidatorEquality(TestCase):
  295. """
  296. Tests that validators have valid equality operators (#21638)
  297. """
  298. def test_regex_equality(self):
  299. self.assertEqual(
  300. RegexValidator(r'^(?:[a-z0-9\.\-]*)://'),
  301. RegexValidator(r'^(?:[a-z0-9\.\-]*)://'),
  302. )
  303. self.assertNotEqual(
  304. RegexValidator(r'^(?:[a-z0-9\.\-]*)://'),
  305. RegexValidator(r'^(?:[0-9\.\-]*)://'),
  306. )
  307. self.assertEqual(
  308. RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"),
  309. RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"),
  310. )
  311. self.assertNotEqual(
  312. RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh", "invalid"),
  313. RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"),
  314. )
  315. self.assertNotEqual(
  316. RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"),
  317. RegexValidator(r'^(?:[a-z0-9\.\-]*)://'),
  318. )
  319. self.assertNotEqual(
  320. RegexValidator('', flags=re.IGNORECASE),
  321. RegexValidator(''),
  322. )
  323. self.assertNotEqual(
  324. RegexValidator(''),
  325. RegexValidator('', inverse_match=True),
  326. )
  327. def test_regex_equality_nocache(self):
  328. pattern = r'^(?:[a-z0-9\.\-]*)://'
  329. left = RegexValidator(pattern)
  330. re.purge()
  331. right = RegexValidator(pattern)
  332. self.assertEqual(
  333. left,
  334. right,
  335. )
  336. def test_regex_equality_blank(self):
  337. self.assertEqual(
  338. RegexValidator(),
  339. RegexValidator(),
  340. )
  341. def test_email_equality(self):
  342. self.assertEqual(
  343. EmailValidator(),
  344. EmailValidator(),
  345. )
  346. self.assertNotEqual(
  347. EmailValidator(message="BAD EMAIL"),
  348. EmailValidator(),
  349. )
  350. self.assertEqual(
  351. EmailValidator(message="BAD EMAIL", code="bad"),
  352. EmailValidator(message="BAD EMAIL", code="bad"),
  353. )
  354. def test_basic_equality(self):
  355. self.assertEqual(
  356. MaxValueValidator(44),
  357. MaxValueValidator(44),
  358. )
  359. self.assertNotEqual(
  360. MaxValueValidator(44),
  361. MinValueValidator(44),
  362. )
  363. self.assertNotEqual(
  364. MinValueValidator(45),
  365. MinValueValidator(11),
  366. )
  367. def test_decimal_equality(self):
  368. self.assertEqual(
  369. DecimalValidator(1, 2),
  370. DecimalValidator(1, 2),
  371. )
  372. self.assertNotEqual(
  373. DecimalValidator(1, 2),
  374. DecimalValidator(1, 1),
  375. )
  376. self.assertNotEqual(
  377. DecimalValidator(1, 2),
  378. DecimalValidator(2, 2),
  379. )
  380. self.assertNotEqual(
  381. DecimalValidator(1, 2),
  382. MinValueValidator(11),
  383. )
  384. def test_file_extension_equality(self):
  385. self.assertEqual(
  386. FileExtensionValidator(),
  387. FileExtensionValidator()
  388. )
  389. self.assertEqual(
  390. FileExtensionValidator(['txt']),
  391. FileExtensionValidator(['txt'])
  392. )
  393. self.assertEqual(
  394. FileExtensionValidator(['txt']),
  395. FileExtensionValidator(['txt'], code='invalid_extension')
  396. )
  397. self.assertNotEqual(
  398. FileExtensionValidator(['txt']),
  399. FileExtensionValidator(['png'])
  400. )
  401. self.assertNotEqual(
  402. FileExtensionValidator(['txt']),
  403. FileExtensionValidator(['png', 'jpg'])
  404. )
  405. self.assertNotEqual(
  406. FileExtensionValidator(['txt']),
  407. FileExtensionValidator(['txt'], code='custom_code')
  408. )
  409. self.assertNotEqual(
  410. FileExtensionValidator(['txt']),
  411. FileExtensionValidator(['txt'], message='custom error message')
  412. )