Mercurial > hg
changeset 26842:0f76c64f5cc3
testing: add hypothesis fuzz testing
Hypothesis a library for adding fuzzing over a range of structure
data to your test suite: http://hypothesis.readthedocs.org/en/latest/
This adds the ability to build tests using Hypothesis within the Mercurial test
suite. New tests and fixes using this helpers comes in later changesets.
author | David R. MacIver <david@drmaciver.com> |
---|---|
date | Sat, 24 Oct 2015 12:46:03 +0100 |
parents | e16b1f86e9f6 |
children | f580c78ea667 |
files | tests/hghave.py tests/hypothesishelpers.py |
diffstat | 2 files changed, 71 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/tests/hghave.py Mon Nov 02 13:00:45 2015 +0000 +++ b/tests/hghave.py Sat Oct 24 12:46:03 2015 +0100 @@ -463,3 +463,12 @@ @check("slow", "allow slow tests") def has_slow(): return os.environ.get('HGTEST_SLOW') == 'slow' + +@check("hypothesis", "is Hypothesis installed") +def has_hypothesis(): + try: + import hypothesis + hypothesis.given + return True + except ImportError: + return False
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/hypothesishelpers.py Sat Oct 24 12:46:03 2015 +0100 @@ -0,0 +1,62 @@ +# Helper module to use the Hypothesis tool in tests +# +# Copyright 2015 David R. MacIver +# +# For details see http://hypothesis.readthedocs.org + +import os +import sys +import traceback + +from hypothesis.settings import set_hypothesis_home_dir +import hypothesis.strategies as st +from hypothesis import given, Settings + +# hypothesis store data regarding generate example and code +set_hypothesis_home_dir(os.path.join( + os.getenv('TESTTMP'), ".hypothesis" +)) + +def check(*args, **kwargs): + """decorator to make a function a hypothesis test + + Decorated function are run immediately (to be used doctest style)""" + def accept(f): + # Workaround for https://github.com/DRMacIver/hypothesis/issues/206 + # Fixed in version 1.13 (released 2015 october 29th) + f.__module__ = '__anon__' + try: + given(*args, settings=Settings(max_examples=2000), **kwargs)(f)() + except Exception: + traceback.print_exc(file=sys.stdout) + sys.exit(1) + return accept + + +def roundtrips(data, decode, encode): + """helper to tests function that must do proper encode/decode roundtripping + """ + @given(data) + def testroundtrips(value): + encoded = encode(value) + decoded = decode(encoded) + if decoded != value: + raise ValueError( + "Round trip failed: %s(%r) -> %s(%r) -> %r" % ( + encode.__name__, value, decode.__name__, encoded, + decoded + )) + try: + testroundtrips() + except Exception: + # heredoc swallow traceback, we work around it + traceback.print_exc(file=sys.stdout) + raise + print("Round trip OK") + + +# strategy for generating bytestring that might be an issue for Mercurial +bytestrings = ( + st.builds(lambda s, e: s.encode(e), st.text(), st.sampled_from([ + 'utf-8', 'utf-16', + ]))) | st.binary()