def instance_of(s): """Constructs a new data structure instance conforming to given schema. This function proceeds recursively. """ if isinstance(s, Mapping): res = (OrderedDict() if isinstance(s, OrderedDict) else dict()) items = s.iteritems() else: res = [None] * len(s) items = enumerate(s) for key, value in items: if is_arbitrary(value): value = to_arbitrary(value) res[key] = next(value) elif isinstance(value, Iterable): res[key] = instance_of(value) else: res[key] = value if isinstance(s, tuple): res = tuple(res) return res
def __init__(self, func, data, tests_count=None): """Constructor. Callers should specify the function which encodes the testing property, and arbitrary values' generator for test data (function arguments). """ self.func = self.__coerce_to_generator_func(func) self.data = dict((k, to_arbitrary(v) if is_arbitrary(v) else v) for k, v in data.iteritems()) if tests_count is not None: self.tests_count = tests_count
def set_(of, min_length=0, max_length=1024): """Generator for arbitrary sets. Parameters for this generator allow for adjusting the size of resulting set and elements they contain. :param of: Generator for set elements :param min_length: A minimum size of set to generate :param max_length: A maximum size of set to generate """ size = random.randint(min_length, max_length) if is_arbitrary(of): return set(next(of) for _ in xrange(size)) return set(random.choice(of) for _ in xrange(size))
def wrapped(*args, **kwargs): if not args: return func(**kwargs) new_args = [] for arg in args: arg_collection = (isinstance(arg, Iterable) and not is_arbitrary(arg)) if arg_collection: arg = map(_2arbitrary, arg) new_args.extend(arg) else: arg = _2arbitrary(arg) new_args.append(arg) return func(*new_args, **kwargs)
def unicode_(of=int_(min=0, max=65535), min_length=1, max_length=64): """Generator for arbitrary Unicode strings. Parameters for this generator allow for adjusting the length of resulting strings and the set of characters they are composed of. :param of: Characters used to construct the strings. This can be either an iterable of characters (e.g. a string) or a generator that produces them. :param min_length: A minimum length of string to generate :param max_length: A maximum length of string to generate """ length = random.randint(min_length, max_length) char = lambda ch: ch if isinstance(ch, basestring) else unichr(ch) if is_arbitrary(of): return u''.join(char(next(of)) for _ in xrange(length)) return u''.join(char(random.choice(of)) for _ in xrange(length))
def elements(*args, **kwargs): """Generator that returns random elements from given set. Elements can be passed either directly as arguments:: elements(1, 2, 3) or as a list:: elements([1, 2, 3]) Every element has equal probability of being chosen. :param count: Optional number of elements in every returned subset. If omitted, a single element will be yield every time. If provided, it should always be passed as keyword argument, e.g. ``elements(range(10), count=3)``. This can be also a generator - such as :func:`int_` - if there's a need to randomize the subset size, too. .. note:: There is difference between ``elements(foo)`` and ``elements(foo, count=1)``. The first form returns random element from the set ``foo``, while the second returns random *1-element subset* of ``foo`` - ``x`` vs ``[x]``, essentially. """ if not args: raise ValueError("cannot pick random elements from empty sequence") count = kwargs.get('count', None) if count is None: return random.choice(args) if is_arbitrary(count): count = next(to_arbitrary(count)) count = min(count, len(args)) return random.sample(args, count)
def combinator(func): """Decorator for arbitrary combinator functions which take a collection of arguments as either an actual list/sequence, or as positional arguments. In other words, it makes it possible to use the following two forms of invocation:: func([1, 2, 3]) func(1, 2, 3) In both cases ``func`` receives 1, 2 and 3 as positional arguments (``*args``). """ _2arbitrary = recursive( lambda obj: to_arbitrary(obj) if is_arbitrary(obj) else obj) @arbitrary @functools.wraps(func) def wrapped(*args, **kwargs): if not args: return func(**kwargs) new_args = [] for arg in args: arg_collection = (isinstance(arg, Iterable) and not is_arbitrary(arg)) if arg_collection: arg = map(_2arbitrary, arg) new_args.extend(arg) else: arg = _2arbitrary(arg) new_args.append(arg) return func(*new_args, **kwargs) return wrapped
def list_(of, min_length=0, max_length=1024): """Generator for arbitrary lists. Parameters for this generator allow for adjusting the length of resulting list and elements they contain. :param of: Generator for list elements :param min_length: A minimum length of list to generate :param max_length: A maximum length of list to generate Example of test property that uses :func:`list_`:: @qc def calculating_average( l=list_(of=int_(min=0, max=1024), min_length=16, max_length=2048) ): average = sum(l) / len(l) assert min(l) <= average <= max(l) """ length = random.randint(min_length, max_length) if is_arbitrary(of): return [next(of) for _ in xrange(length)] return [random.choice(of) for _ in xrange(length)]
def __generate_data(self): """Returns a dictionary of test data to be passed as keyword arguments to property function. """ return dict((k, next(v) if is_arbitrary(v) else v) for k, v in self.data.iteritems())