From 5306763dc3b05473f05718f40cb5fb2c04b3ec6d Mon Sep 17 00:00:00 2001 From: Zac-HD Date: Fri, 19 Apr 2019 00:12:49 +1000 Subject: [PATCH 1/2] Check for duplicate tests --- requirements/tools.in | 1 + requirements/tools.txt | 11 +++++++---- tooling/src/hypothesistooling/__main__.py | 10 ++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/requirements/tools.in b/requirements/tools.in index f8043f2f03..200b49edda 100644 --- a/requirements/tools.in +++ b/requirements/tools.in @@ -15,6 +15,7 @@ more-itertools<6 # Py3-only in 6.0+ mypy numpy pip-tools +pylint pytest python-dateutil pyupio diff --git a/requirements/tools.txt b/requirements/tools.txt index f0434923de..d218c00846 100644 --- a/requirements/tools.txt +++ b/requirements/tools.txt @@ -6,6 +6,7 @@ # alabaster==0.7.12 # via sphinx appdirs==1.4.3 # via black +astroid==2.2.5 # via pylint atomicwrites==1.3.0 # via pytest attrs==19.1.0 babel==2.6.0 # via sphinx @@ -39,8 +40,9 @@ isort==4.3.17 jedi==0.13.3 # via ipython jinja2==2.10.1 # via pyupio, sphinx lark-parser==0.7.0 +lazy-object-proxy==1.3.1 # via astroid markupsafe==1.1.1 # via jinja2 -mccabe==0.6.1 # via flake8 +mccabe==0.6.1 # via flake8, pylint mock==2.0.0 more-itertools==5.0.0 mypy-extensions==0.4.1 # via mypy @@ -63,6 +65,7 @@ pyflakes==2.1.1 # via flake8 pygithub==1.43.6 # via pyupio pygments==2.3.1 # via ipython, readme-renderer, sphinx pyjwt==1.7.1 # via pygithub +pylint==2.3.1 pyparsing==2.4.0 # via packaging pytest==4.4.0 python-dateutil==2.8.0 @@ -75,7 +78,7 @@ requests-toolbelt==0.9.1 # via twine requests==2.21.0 restructuredtext-lint==1.3.0 safety==1.8.5 # via pyupio -six==1.12.0 # via bandit, bleach, dparse, mock, more-itertools, packaging, pip-tools, prompt-toolkit, pydocstyle, pytest, python-dateutil, python-gitlab, pyupio, readme-renderer, stevedore, tox, traitlets +six==1.12.0 # via astroid, bandit, bleach, dparse, mock, more-itertools, packaging, pip-tools, prompt-toolkit, pydocstyle, pytest, python-dateutil, python-gitlab, pyupio, readme-renderer, stevedore, tox, traitlets smmap2==2.0.5 # via gitdb2 snowballstemmer==1.2.1 # via pydocstyle, sphinx sphinx-rtd-theme==0.4.3 @@ -93,9 +96,9 @@ tox==3.8.6 tqdm==4.31.1 # via pyupio, twine traitlets==4.3.2 # via ipython twine==1.13.0 -typed-ast==1.3.1 # via mypy +typed-ast==1.3.1 # via astroid, mypy urllib3==1.24.1 # via requests virtualenv==16.4.3 # via tox wcwidth==0.1.7 # via prompt-toolkit webencodings==0.5.1 # via bleach -wrapt==1.11.1 # via deprecated +wrapt==1.11.1 # via astroid, deprecated diff --git a/tooling/src/hypothesistooling/__main__.py b/tooling/src/hypothesistooling/__main__.py index 4ce54ac683..c15ed62268 100644 --- a/tooling/src/hypothesistooling/__main__.py +++ b/tooling/src/hypothesistooling/__main__.py @@ -80,6 +80,16 @@ def lint(): "--config", os.path.join(tools.ROOT, ".flake8"), ) + # Check for redefined test functions, where e.g. a copy-pasted definition + # will shadow the earlier test and Pytest never sees or executes it. + pip_tool( + "pylint", + "--score=n", + "--jobs=0", + "--disable=all", + "--enable=function-redefined", + "hypothesis-python/tests/", + ) HEAD = tools.hash_for_name("HEAD") From 42a476796f0668ade273407044ccd9b2b18e3457 Mon Sep 17 00:00:00 2001 From: Zac-HD Date: Fri, 19 Apr 2019 00:12:59 +1000 Subject: [PATCH 2/2] De-duplicate tests --- hypothesis-python/tests/common/debug.py | 18 ++++----------- hypothesis-python/tests/cover/test_regex.py | 6 +++-- .../tests/cover/test_simple_strings.py | 22 +++++++----------- .../django/toystore/test_given_models.py | 4 ++-- .../tests/numpy/test_gen_data.py | 23 ------------------- .../tests/quality/test_poisoned_trees.py | 6 +++-- 6 files changed, 23 insertions(+), 56 deletions(-) diff --git a/hypothesis-python/tests/common/debug.py b/hypothesis-python/tests/common/debug.py index 294f6f2c57..db17012dbb 100644 --- a/hypothesis-python/tests/common/debug.py +++ b/hypothesis-python/tests/common/debug.py @@ -33,18 +33,16 @@ def minimal(definition, condition=None, settings=None, timeout_after=10, random= runtime = [] - if condition is None: - - def condition(x): - return True - def wrapped_condition(x): if timeout_after is not None: if runtime: runtime[0] += TIME_INCREMENT if runtime[0] >= timeout_after: raise Timeout() - result = condition(x) + if condition is None: + result = True + else: + result = condition(x) if result and not runtime: runtime.append(0.0) return result @@ -52,14 +50,8 @@ def wrapped_condition(x): return find(definition, wrapped_condition, settings=settings, random=random) -def find_any(definition, condition=None, settings=None, random=None): +def find_any(definition, condition=lambda _: True, settings=None, random=None): settings = Settings(settings, max_examples=10000, phases=no_shrink, database=None) - - if condition is None: - - def condition(x): - return True - return find(definition, condition, settings=settings, random=random) diff --git a/hypothesis-python/tests/cover/test_regex.py b/hypothesis-python/tests/cover/test_regex.py index 19be1d39aa..bb4f136f1d 100644 --- a/hypothesis-python/tests/cover/test_regex.py +++ b/hypothesis-python/tests/cover/test_regex.py @@ -104,13 +104,15 @@ def test_matching(category, predicate, invert, is_unicode): if predicate is None: # Special behaviour due to \x1c, INFORMATION SEPARATOR FOUR predicate = is_unicode_space if is_unicode else is_space - pred = predicate if invert: category = category.swapcase() def pred(s): return not predicate(s) + else: + pred = predicate + _test_matching_pattern(category, pred, is_unicode) @@ -224,7 +226,7 @@ def test_groups(pattern, is_unicode, invert): pattern = pattern.swapcase() _p = group_pred - def group_pred(s): + def group_pred(s): # pylint:disable=function-redefined return not _p(s) pattern = u"^%s\\Z" % (pattern,) diff --git a/hypothesis-python/tests/cover/test_simple_strings.py b/hypothesis-python/tests/cover/test_simple_strings.py index 77e5fde287..4fd0b98c6e 100644 --- a/hypothesis-python/tests/cover/test_simple_strings.py +++ b/hypothesis-python/tests/cover/test_simple_strings.py @@ -19,12 +19,10 @@ from random import Random -import pytest - from hypothesis import given from hypothesis.strategies import binary, characters, text, tuples from tests.common.debug import minimal -from tests.common.utils import checks_deprecated_behaviour +from tests.common.utils import checks_deprecated_behaviour, fails_with def test_can_minimize_up_to_zero(): @@ -62,19 +60,15 @@ def test_finds_single_element_strings(): assert minimal(text(), bool, random=Random(4)) == u"0" -def test_binary_respects_changes_in_size(): - @given(binary()) - def test_foo(x): - assert len(x) <= 5 - - with pytest.raises(AssertionError): - test_foo() +@fails_with(AssertionError) +@given(binary()) +def test_binary_generates_large_examples(x): + assert len(x) <= 20 - @given(binary(max_size=5)) - def test_foo(x): - assert len(x) <= 5 - test_foo() +@given(binary(max_size=5)) +def test_binary_respects_max_size(x): + assert len(x) <= 5 def test_does_not_simplify_into_surrogates(): diff --git a/hypothesis-python/tests/django/toystore/test_given_models.py b/hypothesis-python/tests/django/toystore/test_given_models.py index b9aceef887..528c7ca466 100644 --- a/hypothesis-python/tests/django/toystore/test_given_models.py +++ b/hypothesis-python/tests/django/toystore/test_given_models.py @@ -154,8 +154,8 @@ def test_mandatory_computed_field_default(self, x): assert x.company.name == x.name + u"_company" @given(from_model(CustomishDefault, customish=infer)) - def test_customish_default_generated(self, x): - assert x.customish == u"b" + def test_customish_default_overridden_by_infer(self, x): + assert x.customish == u"a" @given(from_model(CustomishDefault, customish=infer)) def test_customish_infer_uses_registered_instead_of_default(self, x): diff --git a/hypothesis-python/tests/numpy/test_gen_data.py b/hypothesis-python/tests/numpy/test_gen_data.py index 1be87c9bac..9423c8fda4 100644 --- a/hypothesis-python/tests/numpy/test_gen_data.py +++ b/hypothesis-python/tests/numpy/test_gen_data.py @@ -671,29 +671,6 @@ def test_broadcastable_shape_shrinking_with_singleton_out_of_bounds( assert smallest == (min_side,) * min_dim -@settings(deadline=None) -@given(min_dim=st.integers(0, 4), min_side=st.integers(2, 3), data=st.data()) -def test_broadcastable_shape_shrinking_with_singleton_out_of_bounds( - min_dim, min_side, data -): - max_dim = data.draw(st.one_of(st.none(), st.integers(min_dim, 4)), label="max_dim") - max_side = data.draw( - st.one_of(st.none(), st.integers(min_side, 6)), label="max_side" - ) - ndims = data.draw(st.integers(1, 4), label="ndim") - shape = (1,) * ndims - smallest = minimal( - nps.broadcastable_shapes( - shape, - min_side=min_side, - max_side=max_side, - min_dims=min_dim, - max_dims=max_dim, - ) - ) - assert smallest == (min_side,) * min_dim - - @settings(deadline=None) @given( shape=nps.array_shapes(min_dims=0, max_dims=3, min_side=0, max_side=5), diff --git a/hypothesis-python/tests/quality/test_poisoned_trees.py b/hypothesis-python/tests/quality/test_poisoned_trees.py index 7637a02fe7..9e566909fa 100644 --- a/hypothesis-python/tests/quality/test_poisoned_trees.py +++ b/hypothesis-python/tests/quality/test_poisoned_trees.py @@ -120,13 +120,15 @@ def test_function(data): u = starts[i] marker = hbytes([1, 2, 3, 4]) - def test_function(data): + def test_function_with_poison(data): v = data.draw(strat) m = data.draw_bytes(len(marker)) if POISON in v and m == marker: data.mark_interesting() - runner = ConjectureRunner(test_function, random=random, settings=TEST_SETTINGS) + runner = ConjectureRunner( + test_function_with_poison, random=random, settings=TEST_SETTINGS + ) runner.cached_test_function( data.buffer[:u] + hbytes([255]) * 4 + data.buffer[u + 4 :] + marker