From 990bfaf44ce39aaa01a2107aadc1933947bcf550 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Fri, 4 Oct 2013 10:52:26 -0700 Subject: Added FuzzyText attribute. Useful for unique model attributes where the specific value can be fuzzy. --- docs/fuzzy.rst | 29 +++++++++++++++++++++++++++++ factory/fuzzy.py | 33 +++++++++++++++++++++++++++++++++ tests/test_fuzzy.py | 41 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index d88cb5a..582a654 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -24,6 +24,35 @@ FuzzyAttribute The callable that generates random values +FuzzyText +--------- + + +.. class:: FuzzyText(length=12, chars=string.ascii_letters, prefix='') + + The :class:`FuzzyText` fuzzer yields random strings beginning with + the given :attr:`prefix`, followed by :attr:`length` charactes chosen + from the :attr:`chars` character set, + and ending with the given :attr:`suffix`. + + .. attribute:: length + + int, the length of the random part + + .. attribute:: prefix + + text, an optional prefix to prepend to the random part + + .. attribute:: suffix + + text, an optional suffix to append to the random part + + .. attribute:: chars + + char iterable, the chars to choose from; defaults to the list of ascii + letters and numbers. + + FuzzyChoice ----------- diff --git a/factory/fuzzy.py b/factory/fuzzy.py index d3b130b..f3e6a31 100644 --- a/factory/fuzzy.py +++ b/factory/fuzzy.py @@ -23,8 +23,11 @@ """Additional declarations for "fuzzy" attribute definitions.""" +from __future__ import unicode_literals + import random +import string import datetime from . import compat @@ -60,6 +63,36 @@ class FuzzyAttribute(BaseFuzzyAttribute): return self.fuzzer() +class FuzzyText(BaseFuzzyAttribute): + """Random string with a given prefix. + + Generates a random string of the given length from chosen chars. + If a prefix or a suffix are supplied, they will be prepended / appended + to the generated string. + + Args: + prefix (text): An optional prefix to prepend to the random string + length (int): the length of the random part + suffix (text): An optional suffix to append to the random string + chars (str list): the chars to choose from + + Useful for generating unique attributes where the exact value is + not important. + """ + + def __init__(self, prefix='', length=12, suffix='', + chars=string.ascii_letters, **kwargs): + super(FuzzyText, self).__init__(**kwargs) + self.prefix = prefix + self.suffix = suffix + self.length = length + self.chars = tuple(chars) # Unroll iterators + + def fuzz(self): + chars = [random.choice(self.chars) for _i in range(self.length)] + return self.prefix + ''.join(chars) + self.suffix + + class FuzzyChoice(BaseFuzzyAttribute): """Handles fuzzy choice of an attribute.""" diff --git a/tests/test_fuzzy.py b/tests/test_fuzzy.py index 97abece..a521ee2 100644 --- a/tests/test_fuzzy.py +++ b/tests/test_fuzzy.py @@ -63,7 +63,7 @@ class FuzzyChoiceTestCase(unittest.TestCase): def options(): for i in range(3): yield i - + d = fuzzy.FuzzyChoice(options()) res = d.evaluate(2, None, False) @@ -401,3 +401,42 @@ class FuzzyDateTimeTestCase(unittest.TestCase): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.datetime(2013, 1, 2, tzinfo=compat.UTC), res) + + +class FuzzyTextTestCase(unittest.TestCase): + + def test_unbiased(self): + chars = ['a', 'b', 'c'] + fuzz = fuzzy.FuzzyText(prefix='pre', suffix='post', chars=chars, length=12) + res = fuzz.evaluate(2, None, False) + + self.assertEqual('pre', res[:3]) + self.assertEqual('post', res[-4:]) + self.assertEqual(3 + 12 + 4, len(res)) + + for char in res[3:-4]: + self.assertIn(char, chars) + + def test_mock(self): + fake_choice = lambda chars: chars[0] + + chars = ['a', 'b', 'c'] + fuzz = fuzzy.FuzzyText(prefix='pre', suffix='post', chars=chars, length=4) + with mock.patch('random.choice', fake_choice): + res = fuzz.evaluate(2, None, False) + + self.assertEqual('preaaaapost', res) + + def test_generator(self): + def options(): + yield 'a' + yield 'b' + yield 'c' + + fuzz = fuzzy.FuzzyText(chars=options(), length=12) + res = fuzz.evaluate(2, None, False) + + self.assertEqual(12, len(res)) + + for char in res: + self.assertIn(char, ['a', 'b', 'c']) -- cgit v1.2.3