summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Crosley <timothy.crosley@gmail.com>2020-08-26 21:09:35 -0700
committerTimothy Crosley <timothy.crosley@gmail.com>2020-08-26 21:09:35 -0700
commitce6b98159904f322f1655ed4472e25b5c901d01c (patch)
tree65703c6d4c1f421c30c4fcb736bd15d534262b61
parentc872f883d25e7c5ff6118e8865b3f416ff7d6cf1 (diff)
downloadisort-issue/1393/add-property-based-testing-of-complex-code-snippet.tar.gz
-rw-r--r--tests/integration/conftest.py51
-rw-r--r--tests/integration/test_setting_combinations.py110
2 files changed, 161 insertions, 0 deletions
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
new file mode 100644
index 00000000..e83f690c
--- /dev/null
+++ b/tests/integration/conftest.py
@@ -0,0 +1,51 @@
+import isort
+from hypothesis import strategies as st
+from typing import get_type_hints
+
+
+def _as_config(kw) -> isort.Config:
+ if "wrap_length" in kw and "line_length" in kw:
+ kw["wrap_length"], kw["line_length"] = sorted([kw["wrap_length"], kw["line_length"]])
+ try:
+ return isort.Config(**kw)
+ except ValueError:
+ kw["wrap_length"] = 0
+ return isort.Config(**kw)
+
+
+def configs(**force_strategies: st.SearchStrategy) -> st.SearchStrategy[isort.Config]:
+ """Generate arbitrary Config objects."""
+ skip = {
+ "line_ending",
+ "sections",
+ "known_future_library",
+ "forced_separate",
+ "lines_after_imports",
+ "lines_between_sections",
+ "lines_between_types",
+ "sources",
+ "virtual_env",
+ "conda_env",
+ "directory",
+ "formatter",
+ "formatting_function",
+ }
+ inferred_kwargs = {
+ k: st.from_type(v)
+ for k, v in get_type_hints(isort.settings._Config).items()
+ if k not in skip
+ }
+ specific = {
+ "line_length": st.integers(0, 200),
+ "wrap_length": st.integers(0, 200),
+ "indent": st.integers(0, 20).map(lambda n: n * " "),
+ "default_section": st.sampled_from(sorted(isort.settings.KNOWN_SECTION_MAPPING)),
+ "force_grid_wrap": st.integers(0, 20),
+ "profile": st.sampled_from(sorted(isort.settings.profiles)),
+ "py_version": st.sampled_from(("auto",) + isort.settings.VALID_PY_TARGETS),
+ }
+ kwargs = {**inferred_kwargs, **specific, **force_strategies}
+ return st.fixed_dictionaries({}, optional=kwargs).map(_as_config)
+
+
+st.register_type_strategy(isort.Config, configs())
diff --git a/tests/integration/test_setting_combinations.py b/tests/integration/test_setting_combinations.py
new file mode 100644
index 00000000..c3fae0ee
--- /dev/null
+++ b/tests/integration/test_setting_combinations.py
@@ -0,0 +1,110 @@
+import isort
+import hypothesis
+from hypothesis import find, settings, Verbosity
+from hypothesis import strategies as st
+
+CODE_SNIPPET = """
+''' Taken from bottle.py
+
+Copyright (c) 2009-2018, Marcel Hellkamp.
+License: MIT (see LICENSE for details)
+'''
+# Lots of stdlib and builtin differences.
+if py3k:
+ import http.client as httplib
+ import _thread as thread
+ from urllib.parse import urljoin, SplitResult as UrlSplitResult
+ from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
+ urlunquote = functools.partial(urlunquote, encoding='latin1')
+ from http.cookies import SimpleCookie, Morsel, CookieError
+ from collections.abc import MutableMapping as DictMixin
+ import pickle # comment number 2
+ from io import BytesIO
+ import configparser
+
+ basestring = str
+ unicode = str
+ json_loads = lambda s: json_lds(touni(s))
+ callable = lambda x: hasattr(x, '__call__')
+ imap = map
+
+ def _raise(*a):
+ raise a[0](a[1]).with_traceback(a[2])
+else: # 2.x
+ import httplib
+ import thread
+ from urlparse import urljoin, SplitResult as UrlSplitResult
+ from urllib import urlencode, quote as urlquote, unquote as urlunquote
+ from Cookie import SimpleCookie, Morsel, CookieError
+ from itertools import imap
+ import cPickle as pickle
+ from StringIO import StringIO as BytesIO
+ import ConfigParser as configparser # commentnumberone
+ from collections import MutableMapping as DictMixin
+ unicode = unicode
+ json_loads = json_lds
+ exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '<py3fix>', 'exec'))
+"""
+SHOULD_RETAIN = ["""''' Taken from bottle.py
+
+Copyright (c) 2009-2018, Marcel Hellkamp.
+License: MIT (see LICENSE for details)
+'''""",
+"# Lots of stdlib and builtin differences.",
+"if py3k:",
+"http.client",
+"_thread",
+"urllib.parse",
+"urlencode",
+"urlunquote = functools.partial(urlunquote, encoding='latin1')",
+"http.cookies",
+"SimpleCookie",
+"collections.abc",
+"pickle",
+"# comment number 2",
+"io",
+"configparser",
+"""basestring = str
+ unicode = str
+ json_loads = lambda s: json_lds(touni(s))
+ callable = lambda x: hasattr(x, '__call__')
+ imap = map
+
+ def _raise(*a):
+ raise a[0](a[1]).with_traceback(a[2])
+else: # 2.x
+""",
+ "httplib",
+ "thread",
+ "urlparse",
+ "urllib",
+ "Cookie",
+ "itertools",
+ "cPickle",
+ "StringIO",
+ "ConfigParser",
+ "commentnumberone",
+ "collections",
+ """unicode = unicode
+ json_loads = json_lds
+ exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '<py3fix>', 'exec'))"""
+]
+
+
+@hypothesis.given(
+ config=st.from_type(isort.Config),
+ disregard_skip=st.booleans(),
+)
+def test_isort_is_idempotent(config: isort.Config, disregard_skip: bool) -> None:
+ result = isort.code(CODE_SNIPPET, config=config, disregard_skip=disregard_skip)
+ assert result == isort.code(result, config=config, disregard_skip=disregard_skip)
+
+
+@hypothesis.given(
+ config=st.from_type(isort.Config),
+ disregard_skip=st.booleans(),
+)
+def test_isort_is_doesnt_lose_imports_or_comments(config: isort.Config, disregard_skip: bool) -> None:
+ result = isort.code(CODE_SNIPPET, config=config, disregard_skip=disregard_skip)
+ for should_be_retained in SHOULD_RETAIN:
+ assert should_be_retained in result