Skip to content

Refactor tests in test_check.py to use pytest.mark.parametrize for better test isolation #1172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Added test case for `check_all` function ensuring proper behaviour when handling inputs in package notation.
- Improved `get_valid_files_to_check` function by removing unreachable code.
- Refactored `test_check.py` to use pytest.mark.parametrize, improving test isolation and code quality

## [2.10.1] - 2025-02-19

Expand Down
343 changes: 163 additions & 180 deletions tests/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,148 @@
from os import path, remove
from pathlib import Path
from subprocess import Popen
from typing import Union

import pytest

import python_ta

_TEST_FILE_INPUTS = [
[
"examples/nodes/name.py",
],
[
"examples/nodes/dict.py",
"examples/nodes/const.py",
],
[
"examples.sample_usage.draw_cfg",
],
[
"examples.sample_usage",
"examples/nodes/const.py",
],
222,
[
222,
"examples/inline_config_comment.py",
"examples/nodes/dict.py",
"file_does_not_exist",
"module_dne.file_dne",
],
]

_DEFAULT_CONFIG = {
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
}

_SPECIAL_CONFIG = {
# [ELIF]
"max-nested-blocks": 4,
# [FORMAT]
"max-line-length": 80,
# [FORBIDDEN IMPORT]
"allowed-import-modules": ["doctest", "unittest", "hypothesis", "python_ta"],
# [FORBIDDEN IO]
"allowed-io": [],
# [MESSAGES CONTROL]
"disable": [
"R0401",
"R0901",
"R0903",
"R0904",
"R0911",
"R0916",
"W0402",
"W0403",
"W0410",
"W1501",
"W1502",
"W1505",
"E1300",
"E1301",
"E1302",
"E1304",
"W1300",
"W1301",
"W1302",
"W1304",
"E1124",
"E1125",
"E1129",
"E1132",
"W1402",
"W0105",
"E1303",
"W1306",
"W1307",
"E0116",
"E0114",
"E0112",
"E0115",
"E0106",
"E0113",
"E0111",
"E0105",
"E0100",
"E0117",
"W0150",
"W0120",
"W0124",
"W0108",
"W0123",
"W0122",
"W0110",
"C0122",
"C0200",
"W0141",
"W0640",
"W0623",
"W0614",
"W0604",
"W0603",
"W0602",
"W0601",
"E0604",
"E0603",
"E1200",
"E1201",
"E1202",
"W1201",
"E1205",
"E1206",
"similarities",
"newstyle",
"python3",
"W0512",
"C0403",
"C0401",
"C0402",
"E1701",
"E1700",
"W0332",
"C0327",
"C0328",
"E0202",
"E0241",
"E0704",
"W0211",
"W0232",
"W0511",
"R0204",
"C0303",
"W0231",
],
# [CUSTOM PYTA OPTIONS]
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
}

_CONFIG = [_DEFAULT_CONFIG, _SPECIAL_CONFIG]


def test_check_on_dir():
"""The function, check_all() should handle a top-level dir as input."""
Expand Down Expand Up @@ -47,183 +184,25 @@ def test_check_on_dir():
assert not sample_files, f"the following files not checked by python_ta: {sample_files}"


def test_check_on_file():
"""Test files"""
_inputs = [["examples/nodes/name.py"], ["examples/nodes/dict.py", "examples/nodes/const.py"]]
for item in _inputs:
python_ta.check_all(
item,
config={
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
},
)

@pytest.mark.parametrize(
"input_files",
_TEST_FILE_INPUTS
+ [
"examples/nodes",
],
)
@pytest.mark.parametrize("config", _CONFIG)
def test_check_behaviour(input_files: Union[str, list[str]], config) -> None:
"""Test whether check_all behaves correctly for a variety of valid and invalid inputs."""
python_ta.check_all(input_files, config)

def test_check_on_package():
"""Test inputs written in package notation."""
_inputs = [
["examples.sample_usage.draw_cfg"],
["examples.sample_usage", "examples/nodes/const.py"],
]
for item in _inputs:
python_ta.check_all(
item,
output="pyta_output.html",
config={
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
},
)
file_exists = path.exists("pyta_output.html")

assert file_exists

# If the file exists, the assertion passes and the file gets removed from the main directory
if file_exists:
remove("pyta_output.html")


def test_check_on_bad_input():
"""Test bad inputs. In all cases, pyta should recover.
Any valid files, if any, should be checked.
"""
_inputs = [
[222],
222,
["examples/nodes/dict.py examples/nodes/const.py"],
[222, "examples/inline_config_comment.py", "examples/nodes/dict.py"],
["file_does_not_exist"],
["module_dne.file_dne"],
]
for item in _inputs:
python_ta.check_all(
item,
config={
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
},
)


def test_check_with_config():
"""Test inputs along with a config arg."""
_inputs = [["examples/nodes/const.py"], ["examples/nodes"]]
CONFIG = {
# [ELIF]
"max-nested-blocks": 4,
# [FORMAT]
"max-line-length": 80,
# [FORBIDDEN IMPORT]
"allowed-import-modules": ["doctest", "unittest", "hypothesis", "python_ta"],
# [FORBIDDEN IO]
"allowed-io": [],
# [MESSAGES CONTROL]
"disable": [
"R0401",
"R0901",
"R0903",
"R0904",
"R0911",
"R0916",
"W0402",
"W0403",
"W0410",
"W1501",
"W1502",
"W1505",
"E1300",
"E1301",
"E1302",
"E1304",
"W1300",
"W1301",
"W1302",
"W1304",
"E1124",
"E1125",
"E1129",
"E1132",
"W1402",
"W0105",
"E1303",
"W1306",
"W1307",
"E0116",
"E0114",
"E0112",
"E0115",
"E0106",
"E0113",
"E0111",
"E0105",
"E0100",
"E0117",
"W0150",
"W0120",
"W0124",
"W0108",
"W0123",
"W0122",
"W0110",
"C0122",
"C0200",
"W0141",
"W0640",
"W0623",
"W0614",
"W0604",
"W0603",
"W0602",
"W0601",
"E0604",
"E0603",
"E1200",
"E1201",
"E1202",
"W1201",
"E1205",
"E1206",
"similarities",
"newstyle",
"python3",
"W0512",
"C0403",
"C0401",
"C0402",
"E1701",
"E1700",
"W0332",
"C0327",
"C0328",
"E0202",
"E0241",
"E0704",
"W0211",
"W0232",
"W0511",
"R0204",
"C0303",
"W0231",
],
# [CUSTOM PYTA OPTIONS]
"output-format": "pyta-plain",
"pyta-error-permission": "no",
"pyta-file-permission": "no",
}
for item in _inputs:
python_ta.check_all(item, config=CONFIG)


def test_check_saves_file() -> None:
@pytest.mark.parametrize("input_files", _TEST_FILE_INPUTS)
def test_check_saves_file(input_files: Union[str, list[str]]) -> None:
"""Test whether or not specifiying an output properly saves a file"""
_inputs = [["examples/nodes/name.py"]]
for item in _inputs:
# Note that the reporter output will be created in the main directory
python_ta.check_all(item, output="pyta_output.html")

# Note that the reporter output will be created in the main directory
python_ta.check_all(input_files, output="pyta_output.html")

file_exists = path.exists("pyta_output.html")

Expand All @@ -234,12 +213,16 @@ def test_check_saves_file() -> None:
remove("pyta_output.html")


def test_check_no_reporter_output(prevent_webbrowser_and_httpserver) -> None:
"""Test whether not specifiying an output does not save a file"""
_inputs = [["examples/nodes/name.py"]]
for item in _inputs:
# Note that the reporter output *would have been* created in the main directory
python_ta.check_all(item)
@pytest.mark.parametrize("input_files", _TEST_FILE_INPUTS)
def test_check_no_reporter_output(
prevent_webbrowser_and_httpserver, input_files: Union[str, list[str]]
) -> None:
"""Test whether not specifying an output does not save a file

An [INFO] message may still be printed because PythonTA logs this by default when no output argument is provided.
Even though no file is created and the browser does not actually open."""

python_ta.check_all(input_files)

file_exists = path.exists("pyta_output.html")

Expand Down