From be8945317cffe0ca30428cb7c20432c5054a6af1 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 26 Apr 2023 02:36:51 +0200 Subject: [PATCH 01/21] =?UTF-8?q?=F0=9F=A7=AA=20Integrate=20Hypothesis=20i?= =?UTF-8?q?n=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/test.txt | 1 + tests/test_quoting.py | 81 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/requirements/test.txt b/requirements/test.txt index 179bac4c6..035e6ce3d 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,4 +1,5 @@ -r cython.txt +hypothesis >= 6.0 idna==3.6 multidict==6.0.4 pytest==7.4.3 diff --git a/tests/test_quoting.py b/tests/test_quoting.py index d9b6ae8e4..941ce4836 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -1,4 +1,6 @@ import pytest +from hypothesis import HealthCheck, assume, example, given, note, settings +from hypothesis import strategies as st from yarl._quoting import NO_EXTENSIONS from yarl._quoting_py import _Quoter as _PyQuoter @@ -455,3 +457,82 @@ def test_quoter_path_with_plus(quoter): def test_unquoter_path_with_plus(unquoter): s = "/test/x+y%2Bz/:+%2B/" assert "/test/x+y+z/:++/" == unquoter(unsafe="+")(s) + + +@example( + # quoter=_PyQuoter, + # unquoter=_PyUnquoter, + text_input="0", + safe="", + unsafe="0", + protected="", + qs=False, + requote=False, +) +@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) +@given( + text_input=st.text(), + safe=st.text(alphabet=st.characters(max_codepoint=127)), + unsafe=st.text(), + protected=st.text(alphabet=st.characters(max_codepoint=127)), + qs=st.booleans(), + requote=st.booleans(), +) +def test_quote_unquote_parameter( + quoter: _PyQuoter, + unquoter: _PyUnquoter, + safe: str, + unsafe: str, + protected: str, + qs: bool, + requote: bool, + text_input: str, +) -> None: + quote = quoter(safe=safe, protected=protected, qs=qs, requote=requote) + unquote = unquoter(unsafe=unsafe, qs=qs) + + text_quoted = quote(text_input) + assume(qs and all(unsafe_char not in text_quoted for unsafe_char in unsafe)) + note(f"{text_quoted=}") + text_output = unquote(text_quoted) + assume(qs or all(unsafe_char not in text_output for unsafe_char in unsafe)) + # assume( + # qs and + # (unsafe in text_quoted and text_input != text_output) or + # (unsafe not in text_quoted) + # ) + + assert text_input == text_output + + +if not NO_EXTENSIONS and False: + test_quote_unquote_parameter = example( + quoter=_PyQuoter, + unquoter=_CUnquoter, + text_input="0", + safe="", + unsafe="0", + protected="", + qs=False, + requote=False, + )(test_quote_unquote_parameter) + test_quote_unquote_parameter = example( + quoter=_CQuoter, + unquoter=_PyUnquoter, + text_input="0", + safe="", + unsafe="0", + protected="", + qs=False, + requote=False, + )(test_quote_unquote_parameter) + test_quote_unquote_parameter = example( + quoter=_CQuoter, + unquoter=_CUnquoter, + text_input="0", + safe="", + unsafe="0", + protected="", + qs=False, + requote=False, + )(test_quote_unquote_parameter) From 31b4b37e7e5ec9a1712dcefdfeaa1ca960c0fca6 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sat, 25 Nov 2023 02:45:37 +0100 Subject: [PATCH 02/21] debug! --- tests/test_quoting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 941ce4836..a1483e8d7 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -493,7 +493,7 @@ def test_quote_unquote_parameter( text_quoted = quote(text_input) assume(qs and all(unsafe_char not in text_quoted for unsafe_char in unsafe)) - note(f"{text_quoted=}") + note(f"text_quoted={text_quoted !r}") text_output = unquote(text_quoted) assume(qs or all(unsafe_char not in text_output for unsafe_char in unsafe)) # assume( From 59cc868a43711ca50ef432e7367c83a477fff773 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:24:06 -0500 Subject: [PATCH 03/21] null encoding --- tests/test_quoting.py | 148 ++++++++++++++++++++++++++++-------------- tests/test_url.py | 3 + 2 files changed, 103 insertions(+), 48 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index a1483e8d7..e5a8ff952 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -3,6 +3,7 @@ from hypothesis import strategies as st from yarl._quoting import NO_EXTENSIONS +from yarl._quoting_py import ALLOWED from yarl._quoting_py import _Quoter as _PyQuoter from yarl._quoting_py import _Unquoter as _PyUnquoter @@ -459,49 +460,77 @@ def test_unquoter_path_with_plus(unquoter): assert "/test/x+y+z/:++/" == unquoter(unsafe="+")(s) -@example( - # quoter=_PyQuoter, - # unquoter=_PyUnquoter, - text_input="0", - safe="", - unsafe="0", - protected="", - qs=False, - requote=False, -) +@given(safe=st.text(), protected=st.text(), qs=st.booleans(), requote=st.booleans()) +def test_fuzz__PyQuoter(safe, protected, qs, requote): + _PyQuoter(safe=safe, protected=protected, qs=qs, requote=requote) + + +@given(ignore=st.text(), unsafe=st.text(), qs=st.booleans()) +def test_fuzz__PyUnquoter(ignore, unsafe, qs): + _PyUnquoter(ignore=ignore, unsafe=unsafe, qs=qs) + + +@example(text_input="0") @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) -@given( - text_input=st.text(), - safe=st.text(alphabet=st.characters(max_codepoint=127)), - unsafe=st.text(), - protected=st.text(alphabet=st.characters(max_codepoint=127)), - qs=st.booleans(), - requote=st.booleans(), -) +@given(text_input=st.text(alphabet=st.characters(max_codepoint=127))) def test_quote_unquote_parameter( quoter: _PyQuoter, unquoter: _PyUnquoter, - safe: str, - unsafe: str, - protected: str, - qs: bool, - requote: bool, text_input: str, ) -> None: - quote = quoter(safe=safe, protected=protected, qs=qs, requote=requote) - unquote = unquoter(unsafe=unsafe, qs=qs) + quote = quoter() + unquote = unquoter() + text_quoted = quote(text_input) + note(f"text_quoted={text_quoted!r}") + text_output = unquote(text_quoted) + import pprint + + pprint.pprint( + [ + "text_input", + text_input, + "text_quoted", + text_quoted, + "text_output", + text_output, + ] + ) + assert text_input == text_output + +@example(text_input="0") +@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) +@given(text_input=st.text(alphabet=st.characters(max_codepoint=127))) +def test_quote_unquote_parameter_requote( + quoter: _PyQuoter, + unquoter: _PyUnquoter, + text_input: str, +) -> None: + quote = quoter(requote=True) + unquote = unquoter() text_quoted = quote(text_input) - assume(qs and all(unsafe_char not in text_quoted for unsafe_char in unsafe)) - note(f"text_quoted={text_quoted !r}") + note(f"text_quoted={text_quoted!r}") text_output = unquote(text_quoted) - assume(qs or all(unsafe_char not in text_output for unsafe_char in unsafe)) - # assume( - # qs and - # (unsafe in text_quoted and text_input != text_output) or - # (unsafe not in text_quoted) - # ) + assert text_input == text_output + +@example(text_input="0") +@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) +@given( + text_input=st.text( + alphabet=st.characters(max_codepoint=127, blacklist_characters="/%+") + ) +) +def test_quote_unquote_parameter_path_safe( + quoter: _PyQuoter, + unquoter: _PyUnquoter, + text_input: str, +) -> None: + quote = quoter() + unquote = unquoter(ignore="/%", unsafe="+") + text_quoted = quote(text_input) + note(f"text_quoted={text_quoted!r}") + text_output = unquote(text_quoted) assert text_input == text_output @@ -510,29 +539,52 @@ def test_quote_unquote_parameter( quoter=_PyQuoter, unquoter=_CUnquoter, text_input="0", - safe="", - unsafe="0", - protected="", - qs=False, - requote=False, )(test_quote_unquote_parameter) + test_quote_unquote_parameter = example( quoter=_CQuoter, unquoter=_PyUnquoter, text_input="0", - safe="", - unsafe="0", - protected="", - qs=False, - requote=False, )(test_quote_unquote_parameter) + test_quote_unquote_parameter = example( quoter=_CQuoter, unquoter=_CUnquoter, text_input="0", - safe="", - unsafe="0", - protected="", - qs=False, - requote=False, )(test_quote_unquote_parameter) + +# test_quote_unquote_parameter_requote = example( +# quoter=_PyQuoter, +# unquoter=_CUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_requote) + +# test_quote_unquote_parameter_requote = example( +# quoter=_CQuoter, +# unquoter=_PyUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_requote) + +# test_quote_unquote_parameter_requote = example( +# quoter=_CQuoter, +# unquoter=_CUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_requote) + +# test_quote_unquote_parameter_path_safe = example( +# quoter=_PyQuoter, +# unquoter=_CUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_path_safe) + +# test_quote_unquote_parameter_path_safe = example( +# quoter=_CQuoter, +# unquoter=_PyUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_path_safe) + +# test_quote_unquote_parameter_path_safe = example( +# quoter=_CQuoter, +# unquoter=_CUnquoter, +# text_input="0", +# )(test_quote_unquote_parameter_path_safe) diff --git a/tests/test_url.py b/tests/test_url.py index 05ac20917..bd28dbe1a 100644 --- a/tests/test_url.py +++ b/tests/test_url.py @@ -2,7 +2,10 @@ from urllib.parse import SplitResult, quote, unquote import pytest +from hypothesis import given +from hypothesis import strategies as st +import yarl from yarl import URL From 687acafc18e6ea53a4322a27791cb6dbf45a36be Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:29:00 -0500 Subject: [PATCH 04/21] wip --- tests/test_quoting.py | 94 +++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index e5a8ff952..f2f603233 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -472,7 +472,11 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): @example(text_input="0") @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) -@given(text_input=st.text(alphabet=st.characters(max_codepoint=127))) +@given( + text_input=st.text( + alphabet=st.characters(max_codepoint=127, blacklist_characters="%") + ) +) def test_quote_unquote_parameter( quoter: _PyQuoter, unquoter: _PyUnquoter, @@ -483,24 +487,16 @@ def test_quote_unquote_parameter( text_quoted = quote(text_input) note(f"text_quoted={text_quoted!r}") text_output = unquote(text_quoted) - import pprint - - pprint.pprint( - [ - "text_input", - text_input, - "text_quoted", - text_quoted, - "text_output", - text_output, - ] - ) assert text_input == text_output @example(text_input="0") @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) -@given(text_input=st.text(alphabet=st.characters(max_codepoint=127))) +@given( + text_input=st.text( + alphabet=st.characters(max_codepoint=127, blacklist_characters="%") + ) +) def test_quote_unquote_parameter_requote( quoter: _PyQuoter, unquoter: _PyUnquoter, @@ -553,38 +549,38 @@ def test_quote_unquote_parameter_path_safe( text_input="0", )(test_quote_unquote_parameter) -# test_quote_unquote_parameter_requote = example( -# quoter=_PyQuoter, -# unquoter=_CUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_requote) - -# test_quote_unquote_parameter_requote = example( -# quoter=_CQuoter, -# unquoter=_PyUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_requote) - -# test_quote_unquote_parameter_requote = example( -# quoter=_CQuoter, -# unquoter=_CUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_requote) - -# test_quote_unquote_parameter_path_safe = example( -# quoter=_PyQuoter, -# unquoter=_CUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_path_safe) - -# test_quote_unquote_parameter_path_safe = example( -# quoter=_CQuoter, -# unquoter=_PyUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_path_safe) - -# test_quote_unquote_parameter_path_safe = example( -# quoter=_CQuoter, -# unquoter=_CUnquoter, -# text_input="0", -# )(test_quote_unquote_parameter_path_safe) + test_quote_unquote_parameter_requote = example( + quoter=_PyQuoter, + unquoter=_CUnquoter, + text_input="0", + )(test_quote_unquote_parameter_requote) + + test_quote_unquote_parameter_requote = example( + quoter=_CQuoter, + unquoter=_PyUnquoter, + text_input="0", + )(test_quote_unquote_parameter_requote) + + test_quote_unquote_parameter_requote = example( + quoter=_CQuoter, + unquoter=_CUnquoter, + text_input="0", + )(test_quote_unquote_parameter_requote) + + test_quote_unquote_parameter_path_safe = example( + quoter=_PyQuoter, + unquoter=_CUnquoter, + text_input="0", + )(test_quote_unquote_parameter_path_safe) + + test_quote_unquote_parameter_path_safe = example( + quoter=_CQuoter, + unquoter=_PyUnquoter, + text_input="0", + )(test_quote_unquote_parameter_path_safe) + + test_quote_unquote_parameter_path_safe = example( + quoter=_CQuoter, + unquoter=_CUnquoter, + text_input="0", + )(test_quote_unquote_parameter_path_safe) From d85375d03b7db0235f705fa31030bd8ad1b1579b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:31:11 -0500 Subject: [PATCH 05/21] tweaks --- tests/test_quoting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index f2f603233..393ad0bd4 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -3,7 +3,6 @@ from hypothesis import strategies as st from yarl._quoting import NO_EXTENSIONS -from yarl._quoting_py import ALLOWED from yarl._quoting_py import _Quoter as _PyQuoter from yarl._quoting_py import _Unquoter as _PyUnquoter @@ -514,7 +513,7 @@ def test_quote_unquote_parameter_requote( @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( text_input=st.text( - alphabet=st.characters(max_codepoint=127, blacklist_characters="/%+") + alphabet=st.characters(max_codepoint=127, blacklist_characters="%") ) ) def test_quote_unquote_parameter_path_safe( @@ -524,6 +523,7 @@ def test_quote_unquote_parameter_path_safe( ) -> None: quote = quoter() unquote = unquoter(ignore="/%", unsafe="+") + assume("+" not in text_input and "/" not in text_input) text_quoted = quote(text_input) note(f"text_quoted={text_quoted!r}") text_output = unquote(text_quoted) From a1246b1290fe7abc4fea766d2c46495a7b7d0aeb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:31:40 -0500 Subject: [PATCH 06/21] tweaks --- tests/test_url.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_url.py b/tests/test_url.py index bd28dbe1a..05ac20917 100644 --- a/tests/test_url.py +++ b/tests/test_url.py @@ -2,10 +2,7 @@ from urllib.parse import SplitResult, quote, unquote import pytest -from hypothesis import given -from hypothesis import strategies as st -import yarl from yarl import URL From acbeab2b479b7158a9a1045339a7327d022f7c8d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:33:30 -0500 Subject: [PATCH 07/21] lint --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 64e9e3587..5d04910e5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -113,6 +113,7 @@ repos: alias: mypy-py313 name: MyPy, for Python 3.13 additional_dependencies: + - hypothesis - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - multidict - pytest @@ -128,6 +129,7 @@ repos: alias: mypy-py312 name: MyPy, for Python 3.12 additional_dependencies: + - hypothesis - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - multidict - pytest @@ -143,6 +145,7 @@ repos: alias: mypy-py310 name: MyPy, for Python 3.10 additional_dependencies: + - hypothesis - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - multidict - pytest @@ -160,6 +163,7 @@ repos: alias: mypy-py38 name: MyPy, for Python 3.8 additional_dependencies: + - hypothesis - lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report` - multidict - pytest From 4b15efbf9d8ec9e7c5b0d8cee4a68f9b6aa89ddb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:37:14 -0500 Subject: [PATCH 08/21] mypy --- tests/test_quoting.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 393ad0bd4..54c081b3b 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -1,3 +1,5 @@ +from typing import Type + import pytest from hypothesis import HealthCheck, assume, example, given, note, settings from hypothesis import strategies as st @@ -477,8 +479,8 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): ) ) def test_quote_unquote_parameter( - quoter: _PyQuoter, - unquoter: _PyUnquoter, + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter() @@ -497,8 +499,8 @@ def test_quote_unquote_parameter( ) ) def test_quote_unquote_parameter_requote( - quoter: _PyQuoter, - unquoter: _PyUnquoter, + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter(requote=True) @@ -517,8 +519,8 @@ def test_quote_unquote_parameter_requote( ) ) def test_quote_unquote_parameter_path_safe( - quoter: _PyQuoter, - unquoter: _PyUnquoter, + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter() From ce53e9cbdfc8af65a465219cf1336e3c8868e498 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:38:09 -0500 Subject: [PATCH 09/21] mypy --- tests/test_quoting.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 54c081b3b..85047533f 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -532,6 +532,24 @@ def test_quote_unquote_parameter_path_safe( assert text_input == text_output +test_quote_unquote_parameter = example( + quoter=_PyQuoter, + unquoter=_PyUnquoter, + text_input="0", +)(test_quote_unquote_parameter) + +test_quote_unquote_parameter_requote = example( + quoter=_PyQuoter, + unquoter=_PyUnquoter, + text_input="0", +)(test_quote_unquote_parameter_requote) + +test_quote_unquote_parameter_path_safe = example( + quoter=_PyQuoter, + unquoter=_PyUnquoter, + text_input="0", +)(test_quote_unquote_parameter_path_safe) + if not NO_EXTENSIONS and False: test_quote_unquote_parameter = example( quoter=_PyQuoter, From eb9de8a9a077fa3ac6f6ba7fd15758fb3e3c38f2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:39:41 -0500 Subject: [PATCH 10/21] mypy --- tests/test_quoting.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 85047533f..54c081b3b 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -532,24 +532,6 @@ def test_quote_unquote_parameter_path_safe( assert text_input == text_output -test_quote_unquote_parameter = example( - quoter=_PyQuoter, - unquoter=_PyUnquoter, - text_input="0", -)(test_quote_unquote_parameter) - -test_quote_unquote_parameter_requote = example( - quoter=_PyQuoter, - unquoter=_PyUnquoter, - text_input="0", -)(test_quote_unquote_parameter_requote) - -test_quote_unquote_parameter_path_safe = example( - quoter=_PyQuoter, - unquoter=_PyUnquoter, - text_input="0", -)(test_quote_unquote_parameter_path_safe) - if not NO_EXTENSIONS and False: test_quote_unquote_parameter = example( quoter=_PyQuoter, From 8a68d654edec3420b576069b48f2ce2c5c0f7960 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:42:49 -0500 Subject: [PATCH 11/21] mypy --- tests/test_quoting.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 54c081b3b..6dd99088b 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -1,4 +1,4 @@ -from typing import Type +from typing import Type, Union import pytest from hypothesis import HealthCheck, assume, example, given, note, settings @@ -30,6 +30,9 @@ def quoter(request): def unquoter(request): return request.param + _CUnquoter = _PyUnquoter # type: ignore[misc, assignment] + _CQuoter = _PyQuoter # type: ignore[misc, assignment] + def hexescape(char): """Escape char as RFC 2396 specifies""" @@ -479,8 +482,8 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): ) ) def test_quote_unquote_parameter( - quoter: Type[_PyQuoter], - unquoter: Type[_PyUnquoter], + quoter: Union[Type[_PyQuoter], Type[_CQuoter]], + unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], text_input: str, ) -> None: quote = quoter() @@ -499,8 +502,8 @@ def test_quote_unquote_parameter( ) ) def test_quote_unquote_parameter_requote( - quoter: Type[_PyQuoter], - unquoter: Type[_PyUnquoter], + quoter: Union[Type[_PyQuoter], Type[_CQuoter]], + unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], text_input: str, ) -> None: quote = quoter(requote=True) @@ -519,8 +522,8 @@ def test_quote_unquote_parameter_requote( ) ) def test_quote_unquote_parameter_path_safe( - quoter: Type[_PyQuoter], - unquoter: Type[_PyUnquoter], + quoter: Union[Type[_PyQuoter], Type[_CQuoter]], + unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], text_input: str, ) -> None: quote = quoter() From c7d24a2ca80332d035b779432c7b89e65060bc69 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:44:27 -0500 Subject: [PATCH 12/21] mypy --- tests/test_quoting.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 6dd99088b..54c081b3b 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -1,4 +1,4 @@ -from typing import Type, Union +from typing import Type import pytest from hypothesis import HealthCheck, assume, example, given, note, settings @@ -30,9 +30,6 @@ def quoter(request): def unquoter(request): return request.param - _CUnquoter = _PyUnquoter # type: ignore[misc, assignment] - _CQuoter = _PyQuoter # type: ignore[misc, assignment] - def hexescape(char): """Escape char as RFC 2396 specifies""" @@ -482,8 +479,8 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): ) ) def test_quote_unquote_parameter( - quoter: Union[Type[_PyQuoter], Type[_CQuoter]], - unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter() @@ -502,8 +499,8 @@ def test_quote_unquote_parameter( ) ) def test_quote_unquote_parameter_requote( - quoter: Union[Type[_PyQuoter], Type[_CQuoter]], - unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter(requote=True) @@ -522,8 +519,8 @@ def test_quote_unquote_parameter_requote( ) ) def test_quote_unquote_parameter_path_safe( - quoter: Union[Type[_PyQuoter], Type[_CQuoter]], - unquoter: Union[Type[_PyUnquoter], Type[_CUnquoter]], + quoter: Type[_PyQuoter], + unquoter: Type[_PyUnquoter], text_input: str, ) -> None: quote = quoter() From a331326f9ec47efd63aadca4face91da6fa99208 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 11:46:29 -0500 Subject: [PATCH 13/21] changelog --- CHANGES/860.contrib.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/860.contrib.rst diff --git a/CHANGES/860.contrib.rst b/CHANGES/860.contrib.rst new file mode 100644 index 000000000..e68e5ea94 --- /dev/null +++ b/CHANGES/860.contrib.rst @@ -0,0 +1 @@ +Started testing with hypothesis -- by :user:`webknjaz` and :user:`bdraco`. From d41780c53c636fbb4b136b634c776617be5e9579 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 14:53:16 -0500 Subject: [PATCH 14/21] docs strings --- tests/test_quoting.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 54c081b3b..07608c72b 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -463,12 +463,14 @@ def test_unquoter_path_with_plus(unquoter): @given(safe=st.text(), protected=st.text(), qs=st.booleans(), requote=st.booleans()) def test_fuzz__PyQuoter(safe, protected, qs, requote): - _PyQuoter(safe=safe, protected=protected, qs=qs, requote=requote) + """Verify that _PyQuoter can be instantiated with any valid arguments.""" + assert _PyQuoter(safe=safe, protected=protected, qs=qs, requote=requote) @given(ignore=st.text(), unsafe=st.text(), qs=st.booleans()) def test_fuzz__PyUnquoter(ignore, unsafe, qs): - _PyUnquoter(ignore=ignore, unsafe=unsafe, qs=qs) + """Verify that _PyUnquoter can be instantiated with any valid arguments.""" + assert _PyUnquoter(ignore=ignore, unsafe=unsafe, qs=qs) @example(text_input="0") From 55f50c7a942ab11b61a58ba1bb22e049c8939d62 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 14:55:43 -0500 Subject: [PATCH 15/21] adjust coveragerc --- .coveragerc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index b48bd2906..e3c2c22ea 100644 --- a/.coveragerc +++ b/.coveragerc @@ -10,7 +10,7 @@ source = */Lib/site-packages/yarl [report] -fail_under = 98.95 +fail_under = 98.84 skip_covered = true skip_empty = true show_missing = true From 5da9e009d2b64ce3d0ec9ebda46719567cfd5ddc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 14:56:07 -0500 Subject: [PATCH 16/21] Update CHANGES/860.contrib.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- CHANGES/860.contrib.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES/860.contrib.rst b/CHANGES/860.contrib.rst index e68e5ea94..99ebba6ba 100644 --- a/CHANGES/860.contrib.rst +++ b/CHANGES/860.contrib.rst @@ -1 +1,3 @@ -Started testing with hypothesis -- by :user:`webknjaz` and :user:`bdraco`. +Started testing with Hypothesis -- by :user:`webknjaz` and :user:`bdraco`. + +Special thanks to :user:`Zac-HD` for helping us get started with this framework. From 2fef0943bca32c467d51b7cfb5994ba6449ec783 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 14:56:23 -0500 Subject: [PATCH 17/21] Update tests/test_quoting.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- tests/test_quoting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 07608c72b..88d803bba 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -534,7 +534,7 @@ def test_quote_unquote_parameter_path_safe( assert text_input == text_output -if not NO_EXTENSIONS and False: +if not NO_EXTENSIONS: test_quote_unquote_parameter = example( quoter=_PyQuoter, unquoter=_CUnquoter, From 7bd626f0e002b44e7c6f1b583ee59de8b1c3d388 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 15:16:08 -0500 Subject: [PATCH 18/21] reduce --- tests/test_quoting.py | 79 ++++++++++--------------------------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 88d803bba..57fac6dd9 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -20,6 +20,8 @@ def quoter(request): def unquoter(request): return request.param + quoters = st.sampled_from([_PyQuoter, _CQuoter]) + unquoters = st.sampled_from([_PyUnquoter, _CUnquoter]) else: @pytest.fixture(params=[_PyQuoter], ids=["py_quoter"]) @@ -30,6 +32,9 @@ def quoter(request): def unquoter(request): return request.param + quoters = st.just(_PyQuoter) + unquoters = st.just(_PyUnquoter) + def hexescape(char): """Escape char as RFC 2396 specifies""" @@ -473,12 +478,14 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): assert _PyUnquoter(ignore=ignore, unsafe=unsafe, qs=qs) -@example(text_input="0") +@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( + quoter=quoters, + unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") - ) + ), ) def test_quote_unquote_parameter( quoter: Type[_PyQuoter], @@ -493,12 +500,14 @@ def test_quote_unquote_parameter( assert text_input == text_output -@example(text_input="0") +@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( + quoter=quoters, + unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") - ) + ), ) def test_quote_unquote_parameter_requote( quoter: Type[_PyQuoter], @@ -513,12 +522,14 @@ def test_quote_unquote_parameter_requote( assert text_input == text_output -@example(text_input="0") +@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) @settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( + quoter=quoters, + unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") - ) + ), ) def test_quote_unquote_parameter_path_safe( quoter: Type[_PyQuoter], @@ -532,59 +543,3 @@ def test_quote_unquote_parameter_path_safe( note(f"text_quoted={text_quoted!r}") text_output = unquote(text_quoted) assert text_input == text_output - - -if not NO_EXTENSIONS: - test_quote_unquote_parameter = example( - quoter=_PyQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter) - - test_quote_unquote_parameter = example( - quoter=_CQuoter, - unquoter=_PyUnquoter, - text_input="0", - )(test_quote_unquote_parameter) - - test_quote_unquote_parameter = example( - quoter=_CQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter) - - test_quote_unquote_parameter_requote = example( - quoter=_PyQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter_requote) - - test_quote_unquote_parameter_requote = example( - quoter=_CQuoter, - unquoter=_PyUnquoter, - text_input="0", - )(test_quote_unquote_parameter_requote) - - test_quote_unquote_parameter_requote = example( - quoter=_CQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter_requote) - - test_quote_unquote_parameter_path_safe = example( - quoter=_PyQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter_path_safe) - - test_quote_unquote_parameter_path_safe = example( - quoter=_CQuoter, - unquoter=_PyUnquoter, - text_input="0", - )(test_quote_unquote_parameter_path_safe) - - test_quote_unquote_parameter_path_safe = example( - quoter=_CQuoter, - unquoter=_CUnquoter, - text_input="0", - )(test_quote_unquote_parameter_path_safe) From f39d74b2316ac4711e37113be078927d78a4f8b4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 15:17:13 -0500 Subject: [PATCH 19/21] reduce --- tests/test_quoting.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 57fac6dd9..8ba1a735a 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -1,7 +1,7 @@ from typing import Type import pytest -from hypothesis import HealthCheck, assume, example, given, note, settings +from hypothesis import assume, example, given, note from hypothesis import strategies as st from yarl._quoting import NO_EXTENSIONS @@ -479,7 +479,6 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): @example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) -@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( quoter=quoters, unquoter=unquoters, @@ -501,7 +500,6 @@ def test_quote_unquote_parameter( @example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) -@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( quoter=quoters, unquoter=unquoters, @@ -523,7 +521,6 @@ def test_quote_unquote_parameter_requote( @example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) -@settings(suppress_health_check=(HealthCheck.function_scoped_fixture,)) @given( quoter=quoters, unquoter=unquoters, From 583050aec373c8b51adc7aa5043045f2daa0ee7d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 15:18:05 -0500 Subject: [PATCH 20/21] Update .coveragerc --- .coveragerc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index e3c2c22ea..b48bd2906 100644 --- a/.coveragerc +++ b/.coveragerc @@ -10,7 +10,7 @@ source = */Lib/site-packages/yarl [report] -fail_under = 98.84 +fail_under = 98.95 skip_covered = true skip_empty = true show_missing = true From b5a3d891f7ec89d9774fce341bca52a2f135c3e8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Oct 2024 15:29:59 -0500 Subject: [PATCH 21/21] param instread --- tests/test_quoting.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 8ba1a735a..1f9cba6aa 100644 --- a/tests/test_quoting.py +++ b/tests/test_quoting.py @@ -20,8 +20,10 @@ def quoter(request): def unquoter(request): return request.param - quoters = st.sampled_from([_PyQuoter, _CQuoter]) - unquoters = st.sampled_from([_PyUnquoter, _CUnquoter]) + quoters = [_PyQuoter, _CQuoter] + quoter_ids = ["PyQuoter", "CQuoter"] + unquoters = [_PyUnquoter, _CUnquoter] + unquoter_ids = ["PyUnquoter", "CUnquoter"] else: @pytest.fixture(params=[_PyQuoter], ids=["py_quoter"]) @@ -32,8 +34,10 @@ def quoter(request): def unquoter(request): return request.param - quoters = st.just(_PyQuoter) - unquoters = st.just(_PyUnquoter) + quoters = [_PyQuoter] + quoter_ids = ["PyQuoter"] + unquoters = [_PyUnquoter] + unquoter_ids = ["PyUnquoter"] def hexescape(char): @@ -478,14 +482,14 @@ def test_fuzz__PyUnquoter(ignore, unsafe, qs): assert _PyUnquoter(ignore=ignore, unsafe=unsafe, qs=qs) -@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) +@example(text_input="0") @given( - quoter=quoters, - unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") ), ) +@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids) +@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids) def test_quote_unquote_parameter( quoter: Type[_PyQuoter], unquoter: Type[_PyUnquoter], @@ -499,14 +503,14 @@ def test_quote_unquote_parameter( assert text_input == text_output -@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) +@example(text_input="0") @given( - quoter=quoters, - unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") ), ) +@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids) +@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids) def test_quote_unquote_parameter_requote( quoter: Type[_PyQuoter], unquoter: Type[_PyUnquoter], @@ -520,14 +524,14 @@ def test_quote_unquote_parameter_requote( assert text_input == text_output -@example(text_input="0", quoter=_PyQuoter, unquoter=_PyUnquoter) +@example(text_input="0") @given( - quoter=quoters, - unquoter=unquoters, text_input=st.text( alphabet=st.characters(max_codepoint=127, blacklist_characters="%") ), ) +@pytest.mark.parametrize("quoter", quoters, ids=quoter_ids) +@pytest.mark.parametrize("unquoter", unquoters, ids=unquoter_ids) def test_quote_unquote_parameter_path_safe( quoter: Type[_PyQuoter], unquoter: Type[_PyUnquoter],