From 975893443cc7e1c258c82e1272fbc3fd7268d1df Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 15:43:10 +0200 Subject: [PATCH 1/6] Add property based test. --- .gitignore | 1 + requirements-dev.txt | 1 + tests.py | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/.gitignore b/.gitignore index 179770e..56a7db7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build dist *.egg-info/ doc/_build +.hypothesis/ diff --git a/requirements-dev.txt b/requirements-dev.txt index 21daf9a..744c41c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,3 @@ wheel pypandoc +hypothesis >= 3 diff --git a/tests.py b/tests.py index 51d9517..60e3352 100755 --- a/tests.py +++ b/tests.py @@ -9,6 +9,8 @@ import jsonpatch import jsonpointer import sys +import string +from hypothesis import given, note, strategies as st class ApplyPatchTestCase(unittest.TestCase): @@ -518,6 +520,26 @@ def test_replace_missing(self): self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, src, patch_obj) +json_st = st.recursive( + st.one_of([ + st.none(), + st.booleans(), + st.floats(), + st.text(string.printable)]), + lambda children: + st.lists(children) + | st.dictionaries(st.text(string.printable), children)) + + +class RoundtripTests(unittest.TestCase): + @given(json_st, json_st) + def test_roundtrip(self, src, dst): + patch = jsonpatch.JsonPatch.from_diff(src, dst, False) + note('Patch: %s' % (patch,)) + res = patch.apply(src) + self.assertEqual(res, dst) + + if __name__ == '__main__': modules = ['jsonpatch'] @@ -531,6 +553,7 @@ def get_suite(): suite.addTest(unittest.makeSuite(InvalidInputTests)) suite.addTest(unittest.makeSuite(ConflictTests)) suite.addTest(unittest.makeSuite(OptimizationTests)) + suite.addTest(unittest.makeSuite(RoundtripTests)) return suite From 24d3196fd84e591553b865691d93eabe62002206 Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 15:53:41 +0200 Subject: [PATCH 2/6] Don't generate NaNs. JSON doesn't actually allow these (despite the json module in Python happily serializing / parsing 'nan'), and they make assertEqual fail since they're not equal to anything, including themselves. --- tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.py b/tests.py index 60e3352..e724873 100755 --- a/tests.py +++ b/tests.py @@ -524,7 +524,7 @@ def test_replace_missing(self): st.one_of([ st.none(), st.booleans(), - st.floats(), + st.floats(allow_nan=False), st.text(string.printable)]), lambda children: st.lists(children) From 313e1b34176210a178c404cfbed6f0350b5e92d1 Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 15:56:46 +0200 Subject: [PATCH 3/6] Install dev requirements to run the tests. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 77f8b19..473716c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ python: - "pypy3" install: - - travis_retry pip install -r requirements.txt + - travis_retry pip install -r requirements.txt -r requirements-dev.txt - if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install 'coverage<4'; fi - travis_retry pip install coveralls From 49b6c74b662471b6849442becf5a165348376420 Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 16:03:18 +0200 Subject: [PATCH 4/6] Tolerate Hypothesis being missing (no 2.6, 3.2, or 3.3 support). --- .travis.yml | 3 ++- tests.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 473716c..c95cbfc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,8 @@ python: - "pypy3" install: - - travis_retry pip install -r requirements.txt -r requirements-dev.txt + - travis_retry pip install -r requirements.txt + - if [ "$TRAVIS_PYTHON_VERSION" != "2.6" -a "$TRAVIS_PYTHON_VERSION" != "3.2" -a "$TRAVIS_PYTHON_VERSION" != "3.3" ]; then travis_retry pip install hypothesis; fi - if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install 'coverage<4'; fi - travis_retry pip install coveralls diff --git a/tests.py b/tests.py index e724873..08bea16 100755 --- a/tests.py +++ b/tests.py @@ -10,7 +10,11 @@ import jsonpointer import sys import string -from hypothesis import given, note, strategies as st +try: + import hypothesis + from hypothesis import strategies as st +except ImportError: + hypothesis = None class ApplyPatchTestCase(unittest.TestCase): @@ -520,24 +524,24 @@ def test_replace_missing(self): self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, src, patch_obj) -json_st = st.recursive( - st.one_of([ - st.none(), - st.booleans(), - st.floats(allow_nan=False), - st.text(string.printable)]), - lambda children: - st.lists(children) - | st.dictionaries(st.text(string.printable), children)) +if hypothesis is not None: + json_st = st.recursive( + st.one_of([ + st.none(), + st.booleans(), + st.floats(allow_nan=False), + st.text(string.printable)]), + lambda children: + st.lists(children) + | st.dictionaries(st.text(string.printable), children)) - -class RoundtripTests(unittest.TestCase): - @given(json_st, json_st) - def test_roundtrip(self, src, dst): - patch = jsonpatch.JsonPatch.from_diff(src, dst, False) - note('Patch: %s' % (patch,)) - res = patch.apply(src) - self.assertEqual(res, dst) + class RoundtripTests(unittest.TestCase): + @hypothesis.given(json_st, json_st) + def test_roundtrip(self, src, dst): + patch = jsonpatch.JsonPatch.from_diff(src, dst, False) + hypothesis.note('Patch: %s' % (patch,)) + res = patch.apply(src) + self.assertEqual(res, dst) if __name__ == '__main__': @@ -553,7 +557,8 @@ def get_suite(): suite.addTest(unittest.makeSuite(InvalidInputTests)) suite.addTest(unittest.makeSuite(ConflictTests)) suite.addTest(unittest.makeSuite(OptimizationTests)) - suite.addTest(unittest.makeSuite(RoundtripTests)) + if hypothesis is not None: + suite.addTest(unittest.makeSuite(RoundtripTests)) return suite From 6cc61b1f646edac4ed90929b18143da1515e813d Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 16:18:29 +0200 Subject: [PATCH 5/6] Add explicit example. --- tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests.py b/tests.py index 08bea16..0ba2488 100755 --- a/tests.py +++ b/tests.py @@ -536,6 +536,8 @@ def test_replace_missing(self): | st.dictionaries(st.text(string.printable), children)) class RoundtripTests(unittest.TestCase): + @hypothesis.example({}, {u'%20': None}) + @hypothesis.example({u'%20': None}, {}) @hypothesis.given(json_st, json_st) def test_roundtrip(self, src, dst): patch = jsonpatch.JsonPatch.from_diff(src, dst, False) From 6f107152a1c7f04c6eee9098e34ed777d6ddff74 Mon Sep 17 00:00:00 2001 From: Tristan Seligmann Date: Thu, 6 Jul 2017 16:25:01 +0200 Subject: [PATCH 6/6] Fix 3.2 compat. --- tests.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests.py b/tests.py index 0ba2488..7e79202 100755 --- a/tests.py +++ b/tests.py @@ -10,12 +10,18 @@ import jsonpointer import sys import string + try: import hypothesis from hypothesis import strategies as st except ImportError: hypothesis = None +try: + unicode +except NameError: + unicode = str + class ApplyPatchTestCase(unittest.TestCase): @@ -536,8 +542,8 @@ def test_replace_missing(self): | st.dictionaries(st.text(string.printable), children)) class RoundtripTests(unittest.TestCase): - @hypothesis.example({}, {u'%20': None}) - @hypothesis.example({u'%20': None}, {}) + @hypothesis.example({}, {unicode('%20'): None}) + @hypothesis.example({unicode('%20'): None}, {}) @hypothesis.given(json_st, json_st) def test_roundtrip(self, src, dst): patch = jsonpatch.JsonPatch.from_diff(src, dst, False)