Ticket #5419: fuzz.2.patch
File fuzz.2.patch, 8.0 KB (added by , 12 years ago) |
---|
-
django/test/testcases.py
diff --git a/django/test/testcases.py b/django/test/testcases.py index 1239275..ea806be 100644
a b from django.test.html import HTMLParseError, parse_html 38 38 from django.test.signals import template_rendered 39 39 from django.test.utils import (get_warnings_state, restore_warnings_state, 40 40 override_settings, compare_xml, strip_quotes) 41 from django.test.utils import ContextList 41 from django.test.utils import ContextList, generate_fuzzy_value 42 42 from django.utils import unittest as ut2 43 43 from django.utils.encoding import force_text 44 44 from django.utils import six … … class SimpleTestCase(ut2.TestCase): 391 391 standardMsg = '%s == %s' % (safe_repr(xml1, True), safe_repr(xml2, True)) 392 392 self.fail(self._formatMessage(msg, standardMsg)) 393 393 394 def assertModelUnicodePassesFuzzTest(self, model, repeat=10): 395 """ 396 Asserts that after having assigned random unicode data into each of 397 the fields of an instance of the specified model that calling the 398 __unicode__ method of the instance doesn't raise a UnicodeError. 399 Random data is assigned and the __unicode__ method called repeat times. 400 """ 401 instance = model() 402 opts = model._meta 403 for i in range(repeat): 404 for field in opts.fields: 405 setattr(instance, field.name, generate_fuzzy_value(str)) 406 try: 407 if six.PY3: 408 six.u(instance) 409 else: 410 unicode(instance) 411 except UnicodeError as e: 412 self.fail("Model '%s' unexpectedly raised %s when" 413 " converting to unicode: %s" % ( 414 model.__name__, e.__class__.__name__, e)) 415 416 def assertFunctionPassesFuzzTest(self, func, arg_types=(), 417 permitted_return_types=(), 418 permitted_exceptions=(), repeat=10): 419 """ 420 Asserts that the function when called with random values of the types 421 specified by arg_types that the return value has a type from 422 permitted_return_types and that if an exception is raised it is one 423 that is in permitted_exceptions. The function is called repeat times 424 with random data. 425 """ 426 427 def isiterable(o): 428 try: 429 iter(o) 430 except TypeError: 431 return False 432 return True 433 434 def cartesian_product(L, *lists): 435 if not lists: 436 for x in L: 437 yield (x,) 438 else: 439 for x in L: 440 for y in cartesian_product(lists[0], *lists[1:]): 441 yield (x,) + y 442 443 # Allow the use of None 444 if (None in permitted_return_types) and ( 445 None not in permitted_return_types 446 ): 447 permitted_return_types = list(permitted_return_types) 448 permitted_return_types += (None,) 449 450 arg_types = list(arg_types) 451 # Ensure arg_types is a sequence of iterables 452 for i, arg_type in enumerate(arg_types): 453 if not isiterable(arg_type): 454 arg_types[i] = (arg_type,) 455 456 for i in range(repeat): 457 for atypes in cartesian_product(*arg_types): 458 args = [] 459 for arg_type in atypes: 460 args.append(generate_fuzzy_value(arg_type)) 461 try: 462 return_value = func(*args) 463 except: 464 if permitted_exceptions: 465 exc_type, exc_value = sys.exc_info()[:2] 466 if exc_type not in permitted_exceptions: 467 self.fail("Unexpected %s encountered when calling" 468 " %s with inputs %r: %s" % ( 469 exc_type.__name__, func.__name__, 470 args, exc_value)) 471 else: 472 if permitted_return_types and return_value and ( 473 type(return_value) not in permitted_return_types 474 ): 475 self.fail("Unexpected return value type %s encountered" 476 " when calling %s with inputs %r." % ( 477 return_value.__name__, func.__name__, args)) 478 394 479 395 480 class TransactionTestCase(SimpleTestCase): 396 481 -
django/test/utils.py
diff --git a/django/test/utils.py b/django/test/utils.py index f10d388..91109f8 100644
a b 1 import random 1 2 import re 3 import sys 2 4 import warnings 3 5 from xml.dom.minidom import parseString, Node 4 6 … … from django.utils.translation import deactivate 11 13 from django.utils.functional import wraps 12 14 from django.utils import six 13 15 16 try: 17 unichr 18 except NameError: # Python 3 19 unichr = chr 20 14 21 15 22 __all__ = ( 16 23 'Approximate', 'ContextList', 'get_runner', 'override_settings', 17 24 'setup_test_environment', 'teardown_test_environment', 25 'generate_fuzzy_value' 18 26 ) 19 27 20 28 RESTORE_LOADERS_ATTR = '_original_template_source_loaders' … … def strip_quotes(want, got): 321 329 got = got.strip()[2:-1] 322 330 return want, got 323 331 332 324 333 def str_prefix(s): 325 334 return s % {'_': '' if six.PY3 else 'u'} 335 336 337 def generate_fuzzy_value(value_type): 338 """ 339 Returns a randome value of the specified type, or raises a ValueError if 340 the type is not supported. If value_type is callable then it is called and 341 its return value is returned. This allows you to specify a function that 342 generates a random value of a type that isn't supported. 343 """ 344 if value_type is None: 345 return None 346 if issubclass(value_type, bool): 347 return random.choice((True, False)) 348 if issubclass(value_type, six.integer_types): 349 return random.randint(-six.MAXSIZE - 1, six.MAXSIZE) 350 if issubclass(value_type, float): 351 return random.random() * generate_fuzzy_value(int) 352 if issubclass(value_type, six.string_types): 353 length = random.randint(0, 1000) 354 return ''.join([unichr(random.randint(32, 255)) 355 for _ in range(length)]) 356 if callable(value_type): 357 return value_type() 358 raise ValueError("Unsupported type: %s" % value_type) -
tests/regressiontests/test_utils/models.py
diff --git a/tests/regressiontests/test_utils/models.py b/tests/regressiontests/test_utils/models.py index 4da7a07..830b1b2 100644
a b from django.db import models 3 3 4 4 class Person(models.Model): 5 5 name = models.CharField(max_length=100) 6 7 def __unicode__(self): 8 return unicode(self.name) -
tests/regressiontests/test_utils/tests.py
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py index 95913b5..8a22d04 100644
a b class XMLEqualTests(TestCase): 490 490 self.assertXMLEqual(xml1, xml2) 491 491 492 492 493 class FuzzTests(TestCase): 494 495 def test_simple_model_unicode(self): 496 self.assertModelUnicodePassesFuzzTest(Person) 497 498 def test_simple_call_func_with_random_data(self): 499 def _test_func(intarg, intarg2, boolarg): 500 if boolarg: 501 return None 502 elif not boolarg: 503 raise ValueError('error') 504 elif intarg > intarg2: 505 return intarg 506 elif intarg < intarg2: 507 return intarg2 508 self.assertFunctionPassesFuzzTest(_test_func, 509 arg_types=((int, None), 510 (int, None), bool), 511 permitted_return_types=(None, int), 512 permitted_exceptions=(ValueError,), 513 repeat=100) 514 515 493 516 class SkippingExtraTests(TestCase): 494 517 fixtures = ['should_not_be_loaded.json'] 495 518