def test_no_hashability_filter(): # In from_type, we ordinarily protect users from really weird cases like # `Decimal('snan')` - a unhashable value of a hashable type - but in the # ghostwriter we instead want to present this to the user for an explicit # decision. They can pass `allow_nan=False`, fix their custom type's # hashing logic, or whatever else; simply doing nothing will usually work. source_code = ghostwriter.fuzz(hopefully_hashable) assert "@given(foo=st.sets(st.decimals()))" in source_code assert "_can_hash" not in source_code
def test_run_ghostwriter_fuzz(): # This test covers the whole lifecycle: first, we get the default code. # The first argument is unknown, so we fail to draw from st.nothing() source_code = ghostwriter.fuzz(sorted) with pytest.raises(Unsatisfiable): get_test_function(source_code)() # Replacing that nothing() with a strategy for sequences of integers makes the # test pass, incidentally checking our handling of positional-only arguments. source_code = source_code.replace("st.nothing()", "st.lists(st.integers())") get_test_function(source_code)()
def divide(a: int, b: int) -> float: """This is a RST-style docstring for `divide`. :raises ZeroDivisionError: if b == 0 """ return a / b # Note: for some of the `expected` outputs, we replace away some small # parts which vary between minor versions of Python. @pytest.mark.parametrize( "data", [ ("fuzz_sorted", ghostwriter.fuzz(sorted)), ("fuzz_classmethod", ghostwriter.fuzz(A_Class.a_classmethod)), ("fuzz_ufunc", ghostwriter.fuzz(numpy.add)), ("magic_gufunc", ghostwriter.magic(numpy.matmul)), ("magic_base64_roundtrip", ghostwriter.magic(base64.b64encode)), ("re_compile", ghostwriter.fuzz(re.compile)), ( "re_compile_except", ghostwriter.fuzz(re.compile, except_=re.error) # re.error fixed it's __module__ in Python 3.7 .replace("import sre_constants\n", "").replace("sre_constants.", "re."), ), ("re_compile_unittest", ghostwriter.fuzz(re.compile, style="unittest")), ("base64_magic", ghostwriter.magic(base64)), ("sorted_idempotent", ghostwriter.idempotent(sorted)), ("timsort_idempotent", ghostwriter.idempotent(timsort)),
def test_ghostwriter_exploits_arguments_with_enum_defaults(): source_code = ghostwriter.fuzz(takes_enum) test = get_test_function(source_code) with pytest.raises(AssertionError): test()
def test_run_ghostwriter_fuzz(): # Our strategy-guessing code works for all the arguments to sorted, # and we handle positional-only arguments in calls correctly too. source_code = ghostwriter.fuzz(sorted) assert "st.nothing()" not in source_code get_test_function(source_code)()
def test_inference_from_defaults_and_none_booleans_reprs_not_just_and_sampled_from( ): source_code = ghostwriter.fuzz(no_annotations) assert "@given(foo=st.none(), bar=st.booleans())" in source_code
def test_ghostwriter_unittest_style(func, ex): source_code = ghostwriter.fuzz(func, except_=ex, style="unittest") assert issubclass(get_test_function(source_code), unittest.TestCase)
def test_ghostwriter_fuzz(func, ex): source_code = ghostwriter.fuzz(func, except_=ex) get_test_function(source_code)
from hypothesis.errors import StopTest from hypothesis.extra.ghostwriter import ( binary_operation, equivalent, fuzz, idempotent, roundtrip, ) @pytest.mark.parametrize( "cli,code", [ # Passing one argument falls back to one-argument tests ("--equivalent re.compile", lambda: fuzz(re.compile)), ("--roundtrip sorted", lambda: idempotent(sorted)), # For multiple arguments, they're equivalent to the function call ( "--equivalent eval ast.literal_eval", lambda: equivalent(eval, ast.literal_eval), ), ( "--roundtrip json.loads json.dumps --except ValueError", lambda: roundtrip(json.loads, json.dumps, except_=ValueError), ), # Imports submodule (importlib.import_module passes; __import__ fails) ("hypothesis.errors.StopTest", lambda: fuzz(StopTest)), # Search for identity element does not print e.g. "You can use @seed ..." ("--binary-op operator.add", lambda: binary_operation(operator.add)), ],
@pytest.fixture def update_recorded_outputs(request): return request.config.getoption("--hypothesis-update-outputs") def timsort(seq: Sequence[int]) -> Sequence[int]: return sorted(seq) # Note: for some of the `expected` outputs, we replace away some small # parts which vary between minor versions of Python. @pytest.mark.parametrize( "data", [ ("fuzz_sorted", ghostwriter.fuzz(sorted)), ("re_compile", ghostwriter.fuzz(re.compile)), ( "re_compile_except", ghostwriter.fuzz(re.compile, except_=re.error) # re.error fixed it's __module__ in Python 3.7 .replace("import sre_constants\n", "").replace( "sre_constants.", "re."), ), ("re_compile_unittest", ghostwriter.fuzz(re.compile, style="unittest")), ], ids=lambda x: x[0], ) def test_ghostwriter_example_outputs(update_recorded_outputs, data): name, actual = data