From 09095c1bf48ad63401f224a6365af4100a5824bb Mon Sep 17 00:00:00 2001 From: lowit Date: Fri, 2 Oct 2020 00:56:20 +0300 Subject: [PATCH 1/8] unique_tests: adds unique tests names validator --- .gitignore | 5 ++- flake8_fine_pytest/checker.py | 2 ++ .../watchers/unique_test_names.py | 35 +++++++++++++++++++ tests/test_files/test_not_unique.py | 19 ++++++++++ tests/test_integration/test_unique_names.py | 6 ++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 flake8_fine_pytest/watchers/unique_test_names.py create mode 100644 tests/test_files/test_not_unique.py create mode 100644 tests/test_integration/test_unique_names.py diff --git a/.gitignore b/.gitignore index 95218c2..d21905b 100644 --- a/.gitignore +++ b/.gitignore @@ -102,4 +102,7 @@ venv.bak/ /site # mypy -.mypy_cache/ \ No newline at end of file +.mypy_cache/ + +# IDE +.idea diff --git a/flake8_fine_pytest/checker.py b/flake8_fine_pytest/checker.py index c81c8f4..87e9d9f 100644 --- a/flake8_fine_pytest/checker.py +++ b/flake8_fine_pytest/checker.py @@ -4,6 +4,7 @@ from flake8_fine_pytest import __version__ as version from flake8_fine_pytest.watchers.modules_structure import ModulesStructureWatcher +from flake8_fine_pytest.watchers.unique_test_names import UniqueTestNamesWatcher from flake8_fine_pytest.watchers.xfail_decorator import XfailWatcher from flake8_fine_pytest.watchers.xfail_until_argument_watcher import ( XfailUntilArgumentWatcher, @@ -26,6 +27,7 @@ class FinePytestChecker: AssertCountWatcher, XfailUntilArgumentWatcher, UsefixturesWatcher, + UniqueTestNamesWatcher, ) def __init__(self, tree: ast.AST, filename: str): diff --git a/flake8_fine_pytest/watchers/unique_test_names.py b/flake8_fine_pytest/watchers/unique_test_names.py new file mode 100644 index 0000000..d0bdab9 --- /dev/null +++ b/flake8_fine_pytest/watchers/unique_test_names.py @@ -0,0 +1,35 @@ +import ast +from typing import Set + +from flake8_fine_pytest.watchers.base import BaseWatcher + + +class UniqueTestNamesWatcher(BaseWatcher): + error_template = 'FP009 Duplicate name test case ({})' + + def run(self) -> None: + testcases_names: Set[str] = set() + duplicates: Set[str] = set() + + if not self._is_test_file(self.filename): + return + + for node in ast.walk(self.tree): + if not self._is_properly_node(node): + continue + + node_name = node.name # type: ignore + + if node_name not in testcases_names: + testcases_names.add(node_name) + continue + + if node_name in duplicates: + continue + + duplicates.add(node_name) + error_msg = self.error_template.format(node_name) + self.add_error((node.lineno, 0, error_msg)) + + def _is_properly_node(self, node: ast.AST) -> bool: + return isinstance(node, ast.FunctionDef) and node.name.startswith('test_') diff --git a/tests/test_files/test_not_unique.py b/tests/test_files/test_not_unique.py new file mode 100644 index 0000000..a4673a9 --- /dev/null +++ b/tests/test_files/test_not_unique.py @@ -0,0 +1,19 @@ +import pytest + + +def test_not_uniq() -> None: + pass + + +def test_not_uniq() -> None: + pass + + +@pytest.mark.parametrize('test', ('test',)) +def test_not_uniq_with_decorator(test) -> None: + pass + + +@pytest.mark.parametrize('test', ('test2',)) +def test_not_uniq_with_decorator(test) -> None: + pass diff --git a/tests/test_integration/test_unique_names.py b/tests/test_integration/test_unique_names.py new file mode 100644 index 0000000..dd47068 --- /dev/null +++ b/tests/test_integration/test_unique_names.py @@ -0,0 +1,6 @@ +def test_unique_names(run_validator_for_test_files): + errors = run_validator_for_test_files('test_not_unique.py') + + assert len(errors) == 2 + assert errors[0][2] == 'FP009 Duplicate name test case (test_not_uniq)' + assert errors[1][2] == 'FP009 Duplicate name test case (test_not_uniq_with_decorator)' From fcbf21d6387ad2933b74caf1acdbf507ae5dbb6b Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 00:56:14 +0300 Subject: [PATCH 2/8] unique_tests: simplifies algorithm --- flake8_fine_pytest/watchers/unique_test_names.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/flake8_fine_pytest/watchers/unique_test_names.py b/flake8_fine_pytest/watchers/unique_test_names.py index d0bdab9..8ed9449 100644 --- a/flake8_fine_pytest/watchers/unique_test_names.py +++ b/flake8_fine_pytest/watchers/unique_test_names.py @@ -9,7 +9,6 @@ class UniqueTestNamesWatcher(BaseWatcher): def run(self) -> None: testcases_names: Set[str] = set() - duplicates: Set[str] = set() if not self._is_test_file(self.filename): return @@ -24,10 +23,6 @@ def run(self) -> None: testcases_names.add(node_name) continue - if node_name in duplicates: - continue - - duplicates.add(node_name) error_msg = self.error_template.format(node_name) self.add_error((node.lineno, 0, error_msg)) From 35f68b6dca164bf37eacfcd1be458d86c6b142cf Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 01:30:46 +0300 Subject: [PATCH 3/8] unique_tests: deletes copypaste --- flake8_fine_pytest/watchers/unique_test_names.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/flake8_fine_pytest/watchers/unique_test_names.py b/flake8_fine_pytest/watchers/unique_test_names.py index 8ed9449..eb982fb 100644 --- a/flake8_fine_pytest/watchers/unique_test_names.py +++ b/flake8_fine_pytest/watchers/unique_test_names.py @@ -14,7 +14,7 @@ def run(self) -> None: return for node in ast.walk(self.tree): - if not self._is_properly_node(node): + if not self._is_test_function(node): continue node_name = node.name # type: ignore @@ -25,6 +25,3 @@ def run(self) -> None: error_msg = self.error_template.format(node_name) self.add_error((node.lineno, 0, error_msg)) - - def _is_properly_node(self, node: ast.AST) -> bool: - return isinstance(node, ast.FunctionDef) and node.name.startswith('test_') From 76295e638cf17cd6282d7882ae19c2277872ef7e Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 01:33:59 +0300 Subject: [PATCH 4/8] unique_tests: deletes typing in the testfile --- tests/test_files/test_not_unique.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_files/test_not_unique.py b/tests/test_files/test_not_unique.py index a4673a9..7e5e41d 100644 --- a/tests/test_files/test_not_unique.py +++ b/tests/test_files/test_not_unique.py @@ -1,19 +1,19 @@ import pytest -def test_not_uniq() -> None: +def test_not_uniq(): pass -def test_not_uniq() -> None: +def test_not_uniq(): pass @pytest.mark.parametrize('test', ('test',)) -def test_not_uniq_with_decorator(test) -> None: +def test_not_uniq_with_decorator(test): pass @pytest.mark.parametrize('test', ('test2',)) -def test_not_uniq_with_decorator(test) -> None: +def test_not_uniq_with_decorator(test): pass From a051df322638e73f785168e4f1158ece5fa27019 Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 20:13:02 +0300 Subject: [PATCH 5/8] unique_tests: changes check function --- flake8_fine_pytest/watchers/unique_test_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake8_fine_pytest/watchers/unique_test_names.py b/flake8_fine_pytest/watchers/unique_test_names.py index eb982fb..99aef9e 100644 --- a/flake8_fine_pytest/watchers/unique_test_names.py +++ b/flake8_fine_pytest/watchers/unique_test_names.py @@ -14,7 +14,7 @@ def run(self) -> None: return for node in ast.walk(self.tree): - if not self._is_test_function(node): + if not self._should_check_node(node): continue node_name = node.name # type: ignore From 6db609f378a4c3edd0ac5eb3c53e3455438b7aa0 Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 20:30:24 +0300 Subject: [PATCH 6/8] unique_tests: updates readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b6bf40e..1ce2824 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ tests/test_unit/test_something.py:2:0: FP009 test_something should use fixtures as follows: @pytest.mark.usefixtures('fixture_one') ``` +7) validates that test function uses unique names + ## Installation ```terminal From c3a82cae87d808211fbb91b538cf2e28c9564812 Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 20:35:23 +0300 Subject: [PATCH 7/8] unique_tests: fixes ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d4e74b8..b815979 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - "3.7" - "3.8" install: + - gem install chef-utils -v 16.6.14 - gem install mdl - pip install -r requirements.txt - pip install -e . From a0c339ff272cfb755d44948c15036443531e362e Mon Sep 17 00:00:00 2001 From: lowit Date: Sun, 29 Nov 2020 21:33:22 +0300 Subject: [PATCH 8/8] unique_tests: fixes tests --- tests/test_files/test_not_unique.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_files/test_not_unique.py b/tests/test_files/test_not_unique.py index 7e5e41d..6950b21 100644 --- a/tests/test_files/test_not_unique.py +++ b/tests/test_files/test_not_unique.py @@ -9,11 +9,11 @@ def test_not_uniq(): pass -@pytest.mark.parametrize('test', ('test',)) -def test_not_uniq_with_decorator(test): +@pytest.mark.skip +def test_not_uniq_with_decorator(): pass -@pytest.mark.parametrize('test', ('test2',)) -def test_not_uniq_with_decorator(test): +@pytest.mark.skip +def test_not_uniq_with_decorator(): pass