diff --git a/dev-requirements.txt b/dev-requirements.txt index 683d4a8..b52efdd 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,4 @@ coverage pytest +hypothesis ipdb diff --git a/setup.py b/setup.py index 719ea7d..73feeee 100644 --- a/setup.py +++ b/setup.py @@ -78,4 +78,5 @@ def find_meta(meta): zip_safe=False, classifiers=CLASSIFIERS, install_requires=INSTALL_REQUIRES, + tests_require=["hypothesis"] ) diff --git a/tests/test_requires.py b/tests/test_requires.py index 3e29279..2ef84cb 100644 --- a/tests/test_requires.py +++ b/tests/test_requires.py @@ -1,24 +1,44 @@ import pytest from required import Requires, R, RequirementError +from hypothesis import given +from hypothesis.strategies import ( + data, integers, one_of, booleans, + floats, complex_numbers, tuples, + none, lists, sets, fixed_dictionaries, + characters, text, binary, +) + +all_types = ( + integers(), none(), + floats(), complex_numbers(), tuples(), + characters(), text(), binary(), booleans(), +) class TestRequires(object): - def test_value_no_dependency_does_not_raise_error(self): - requires = Requires("x", "y") - data = {"x": 1} - requires._validate("y", data) + @given(data()) + def test_value_no_dependency_does_not_raise_error(self, draw): + requires = Requires("x", R("x") < R("y")) + + x = draw.draw(integers()) + y = draw.draw(integers(min_value=x+1)) + + data = {"x": x, "y": y} + requires.validate(data) - def test_exists_dependency_raises_requirements_error(self): + @given(one_of(*all_types)) + def test_exists_dependency_raises_requirements_error(self, item): requires = Requires("x", "y") - data = {"x": 1} + data = {"x": item} with pytest.raises(RequirementError): requires._validate("x", data) - def test_triple_dependency_raises_correct_error(self): + @given(one_of(*all_types)) + def test_triple_dependency_raises_correct_error(self, item): requires = Requires("x", "y") + Requires("y", "z") - data = {"x": 1} + data = {"x": item} with pytest.raises(RequirementError): requires._validate("x", data) @@ -28,63 +48,72 @@ def test_triple_dependency_raises_correct_error(self): requires._validate("z", data) - def test_multiple_dependencies_requires_all(self): + @given(one_of(*all_types), one_of(*all_types), one_of(*all_types)) + def test_multiple_dependencies_requires_all(self, x, y, z): requires = Requires("x", "y") + Requires("x", "z") - data = {"x": 1, "y": 2} + data = {"x": x, "y": y} with pytest.raises(RequirementError): requires._validate("x", data) - data = {"x": 1, "z": 2} + data = {"x": x, "z": z} with pytest.raises(RequirementError): requires._validate("x", data) - data = {"x": 1, "z": 2, "y": 2} + data = {"x": x, "z": y, "y": z} requires._validate("x", data) - def test_circular_dependency_requires_both(self): + @given(one_of(*all_types), one_of(*all_types)) + def test_circular_dependency_requires_both(self, x, y): requires = Requires("x", "y") + Requires("y", "x") - data = {"x": 1} + data = {"x": x} with pytest.raises(RequirementError): requires._validate("x", data) - data = {"y": 1} + data = {"y": y} with pytest.raises(RequirementError): requires._validate("y", data) - data = {"x": 1, "y": 2} + data = {"x": x, "y": y} requires._validate("y", data) requires._validate("x", data) - def test_simple_expression_dependency_equal(self): - requires = Requires("x", R("y") == 1) - data = {"x": 1, "y": 2} + @given(one_of(*all_types), integers()) + def test_simple_expression_dependency_equal(self, x, y): + requires = Requires("x", R("y") == y) + data = {"x": x, "y": y + 1} with pytest.raises(RequirementError): requires._validate("x", data) - data = {"x": 1, "y": 1} + data = {"x": x, "y": y} requires._validate("x", data) - def test_simple_expression_dependency_greater_or_equal(self): + @given(data()) + def test_simple_expression_dependency_greater_or_equal(self, draw): requires = Requires("x", R("y") >= 1) - data = {"x": 1, "y": 0} + + x = draw.draw(integers()) + y = draw.draw(integers(max_value=0)) + + data = {"x": x, "y": y} with pytest.raises(RequirementError): requires._validate("x", data) - data = {"x": 1, "y": 1} - requires._validate("x", data) + x = draw.draw(integers()) + y = draw.draw(integers(min_value=1)) - data = {"x": 1, "y": 2} + data = {"x": x, "y": y} requires._validate("x", data) - data = {"y": 2} + data = {"y": x} requires._validate("y", data) - def test_multi_expression_dependency_correctly_validates(self): - requires = Requires("x", R("y") >= 1) + Requires("z", R("y") <= 1) + @given(integers(), integers(), integers(), integers()) + def test_multi_expression_dependency_correctly_validates(self, x, y, z, gte): + requires = Requires("x", R("y") >= gte) + Requires("z", R("y") <= gte) - data = {"x": 1, "y": 2, "z": 1} + data = {"x": x, "y": gte + 1, "z": z} with pytest.raises(RequirementError): requires._validate("z", data) @@ -92,7 +121,7 @@ def test_multi_expression_dependency_correctly_validates(self): requires._validate("x", data) requires._validate("y", data) - data = {"x": 1, "y": 1, "z": 1} + data = {"x": gte, "y": gte, "z": gte} requires._validate("z", data) def test_multi_r_in_expression_correctly_validates(self): @@ -277,13 +306,17 @@ def test_multi_partial_dependency_simple_all_satisifed(self): data = {"x": 2, "z": "hello"} requires.validate(data) - def test_simple_self_dependency(self): + @given(data()) + def test_simple_self_dependency(self, draw): requires = Requires("x", R("x") > 1) - data = {"x": 1} + + x = draw.draw(integers(max_value=1)) + data = {"x": x} with pytest.raises(RequirementError): requires.validate(data) - data = {"x": 2} + x = draw.draw(integers(min_value=2)) + data = {"x": x} requires.validate(data) def test_simple_length_equals(self):