"""Tests for the check-weak-tests pre-commit hook.""" import importlib.util from pathlib import Path # Load the hook module by path (hyphenated filename isn't importable directly). _HOOK_PATH = ( Path(__file__).resolve().parents[2] / ".pre-commit-hooks" / "check-weak-tests.py" ) _spec = importlib.util.spec_from_file_location("check_weak_tests", _HOOK_PATH) check_weak_tests = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(check_weak_tests) def _write(tmp_path, body: str) -> str: fp = tmp_path / "test_sample.py" fp.write_text(body) return str(fp) class TestAssertTrueOnly: def test_flags_assert_true_only(self, tmp_path): fp = _write( tmp_path, "def test_x():\n do_thing()\n assert True\n", ) issues = check_weak_tests.check_file(fp) assert len(issues) == 1 assert "no real assertion" in issues[0][1] def test_real_assertion_not_flagged(self, tmp_path): fp = _write( tmp_path, "def test_x():\n assert compute() == 42\n", ) assert check_weak_tests.check_file(fp) == [] def test_assert_true_alongside_real_assert_not_flagged(self, tmp_path): # If a real assertion exists, the test is not a pure no-op. fp = _write( tmp_path, "def test_x():\n assert compute() == 1\n assert True\n", ) assert check_weak_tests.check_file(fp) == [] class TestImportExistence: def test_flags_import_existence(self, tmp_path): fp = _write( tmp_path, "def test_x():\n from mymod import thing\n" " assert thing is not None\n", ) issues = check_weak_tests.check_file(fp) assert len(issues) == 1 assert "import-existence tautology" in issues[0][1] def test_import_then_real_use_not_flagged(self, tmp_path): fp = _write( tmp_path, "def test_x():\n from mymod import thing\n" " assert thing() == 5\n", ) assert check_weak_tests.check_file(fp) == [] class TestOrTrueTautology: def test_flags_or_true(self, tmp_path): fp = _write( tmp_path, "def test_x():\n result = run()\n assert result or True\n", ) issues = check_weak_tests.check_file(fp) assert len(issues) == 1 assert "always true" in issues[0][1] class TestNullcheckTautology: def test_flags_is_none_or_is_not_none(self, tmp_path): fp = _write( tmp_path, "def test_x():\n r = run()\n" " assert r is None or r is not None\n", ) issues = check_weak_tests.check_file(fp) assert len(issues) == 1 assert "accepts any value" in issues[0][1] def test_flags_reversed_ordering(self, tmp_path): fp = _write( tmp_path, "def test_x():\n r = run()\n" " assert r is not None or r is None\n", ) assert len(check_weak_tests.check_file(fp)) == 1 def test_different_operands_not_flagged(self, tmp_path): # `a is None or b is not None` is a real (if odd) condition. fp = _write( tmp_path, "def test_x():\n assert a is None or b is not None\n", ) assert check_weak_tests.check_file(fp) == [] class TestOptOut: def test_allow_comment_on_def_line(self, tmp_path): fp = _write( tmp_path, "def test_x(): # allow: weak-test\n assert True\n", ) assert check_weak_tests.check_file(fp) == [] def test_allow_comment_on_assert_line(self, tmp_path): fp = _write( tmp_path, "def test_x():\n r = run()\n" " assert r or True # allow: weak-test\n", ) assert check_weak_tests.check_file(fp) == [] class TestSkipMarkers: def test_skip_decorated_test_not_flagged(self, tmp_path): fp = _write( tmp_path, "import pytest\n\n" "@pytest.mark.skip(reason='wip')\n" "def test_x():\n assert True\n", ) assert check_weak_tests.check_file(fp) == [] def test_xfail_decorated_test_not_flagged(self, tmp_path): fp = _write( tmp_path, "import pytest\n\n" "@pytest.mark.xfail(reason='not yet')\n" "def test_x():\n assert True\n", ) assert check_weak_tests.check_file(fp) == [] class TestEdgeCases: def test_non_test_function_not_flagged(self, tmp_path): # Helper functions (not test_*) are out of scope. fp = _write( tmp_path, "def helper():\n assert True\n", ) assert check_weak_tests.check_file(fp) == [] def test_docstring_stripped_before_analysis(self, tmp_path): fp = _write( tmp_path, 'def test_x():\n """A docstring."""\n assert True\n', ) assert len(check_weak_tests.check_file(fp)) == 1 def test_syntax_error_returns_no_issues(self, tmp_path): fp = _write(tmp_path, "def test_x(:\n assert True\n") # Syntax errors are left to ruff/py_compile, not this hook. assert check_weak_tests.check_file(fp) == [] def test_main_exit_code_clean(self, tmp_path): fp = _write( tmp_path, "def test_x():\n assert compute() == 1\n", ) assert check_weak_tests.main([fp]) == 0 def test_main_exit_code_dirty(self, tmp_path): fp = _write( tmp_path, "def test_x():\n assert True\n", ) assert check_weak_tests.main([fp]) == 1