diff options
-rw-r--r-- | docs/fuzzy.rst | 27 | ||||
-rw-r--r-- | factory/fuzzy.py | 20 | ||||
-rw-r--r-- | tests/test_fuzzy.py | 61 |
3 files changed, 108 insertions, 0 deletions
diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index f1f4085..7d56995 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -70,6 +70,33 @@ FuzzyInteger int, the inclusive higher bound of generated integers +FuzzyDate +--------- + +.. class:: FuzzyDate(start_date[, end_date]) + + The :class:`FuzzyDate` fuzzer generates random dates within a given + inclusive range. + + The :attr:`end_date` bound may be omitted, in which case it defaults to the current date: + + .. code-block:: pycon + + >>> fd = FuzzyDate(datetime.date(2008, 1, 1)) + >>> fd.start_date, fd.end_date + datetime.date(2008, 1, 1), datetime.date(2013, 4, 16) + + .. attribute:: start_date + + :class:`datetime.date`, the inclusive lower bound of generated dates + + .. attribute:: end_date + + :class:`datetime.date`, the inclusive higher bound of generated dates + + int, the inclusive higher bound of generated dates + + Custom fuzzy fields ------------------- diff --git a/factory/fuzzy.py b/factory/fuzzy.py index 186b4a7..fea7b05 100644 --- a/factory/fuzzy.py +++ b/factory/fuzzy.py @@ -25,6 +25,7 @@ import random +import datetime from . import declarations @@ -84,3 +85,22 @@ class FuzzyInteger(BaseFuzzyAttribute): def fuzz(self): return random.randint(self.low, self.high) + + +class FuzzyDate(BaseFuzzyAttribute): + """Random date within a given date range.""" + def __init__(self, start_date, end_date=None, **kwargs): + super(FuzzyDate, self).__init__(**kwargs) + if end_date is None: + end_date = datetime.date.today() + + if start_date > end_date: + raise ValueError( + "FuzzyDate boundaries should have start <= end; got %r > %r." + % (start_date, end_date)) + + self.start_date = start_date.toordinal() + self.end_date = end_date.toordinal() + + def fuzz(self): + return datetime.date.fromordinal(random.randint(self.start_date, self.end_date)) diff --git a/tests/test_fuzzy.py b/tests/test_fuzzy.py index 70a2095..e3b5772 100644 --- a/tests/test_fuzzy.py +++ b/tests/test_fuzzy.py @@ -21,6 +21,8 @@ # THE SOFTWARE. +import datetime + from factory import fuzzy from .compat import mock, unittest @@ -102,3 +104,62 @@ class FuzzyIntegerTestCase(unittest.TestCase): res = fuzz.evaluate(2, None, False) self.assertEqual(8, res) + + +class FuzzyDateTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Setup useful constants + cls.jan1 = datetime.date(2013, 1, 1) + cls.jan3 = datetime.date(2013, 1, 3) + cls.jan31 = datetime.date(2013, 1, 31) + + def test_accurate_definition(self): + """Tests all ways of defining a FuzzyDate.""" + fuzz = fuzzy.FuzzyDate(self.jan1, self.jan31) + + for _i in range(20): + res = fuzz.evaluate(2, None, False) + self.assertLessEqual(self.jan1, res) + self.assertLessEqual(res, self.jan31) + + def test_partial_definition(self): + """Test defining a FuzzyDate without passing an end date.""" + with utils.mocked_date_today(self.jan3, fuzzy): + fuzz = fuzzy.FuzzyDate(self.jan1) + + for _i in range(20): + res = fuzz.evaluate(2, None, False) + self.assertLessEqual(self.jan1, res) + self.assertLessEqual(res, self.jan3) + + def test_invalid_definition(self): + self.assertRaises(ValueError, fuzzy.FuzzyDate, + self.jan31, self.jan1) + + def test_invalid_partial_definition(self): + with utils.mocked_date_today(self.jan1, fuzzy): + self.assertRaises(ValueError, fuzzy.FuzzyDate, + self.jan31) + + def test_biased(self): + """Tests a FuzzyDate with a biased random.randint.""" + + fake_randint = lambda low, high: (low + high) // 2 + fuzz = fuzzy.FuzzyDate(self.jan1, self.jan31) + + with mock.patch('random.randint', fake_randint): + res = fuzz.evaluate(2, None, False) + + self.assertEqual(datetime.date(2013, 1, 16), res) + + def test_biased_partial(self): + """Tests a FuzzyDate with a biased random and implicit upper bound.""" + with utils.mocked_date_today(self.jan3, fuzzy): + fuzz = fuzzy.FuzzyDate(self.jan1) + + fake_randint = lambda low, high: (low + high) // 2 + with mock.patch('random.randint', fake_randint): + res = fuzz.evaluate(2, None, False) + + self.assertEqual(datetime.date(2013, 1, 2), res) |