diff --git a/.gitignore b/.gitignore index 04b6a6f..743bfba 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,6 @@ doc/_build .lint.json .lint.txt + +/.serena +/.codex diff --git a/doc/dependencies.rst b/doc/dependencies.rst index bd6353f..8b34844 100644 --- a/doc/dependencies.rst +++ b/doc/dependencies.rst @@ -19,9 +19,7 @@ Test Dependencies Dependency Purpose License ===================== ========================== ======== `Pytest`_ Testing framework MIT -`Prysk`_ Testing framework GPL ===================== ========================== ======== .. _Python 3: https://docs.python.org/3 .. _Pytest: https://docs.pytest.org/en/stable/ -.. _Prysk: https://www.prysk.net diff --git a/poetry.lock b/poetry.lock index ff7d838..db50717 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2348,25 +2348,6 @@ wcwidth = "*" [package.extras] tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] -[[package]] -name = "prysk" -version = "0.15.2" -description = "Functional tests for command line applications" -optional = false -python-versions = ">=3.7,<4.0.0" -groups = ["dev"] -files = [ - {file = "prysk-0.15.2-py3-none-any.whl", hash = "sha256:9c571b31166bd0db1b2ea1b6d5f8fb6e6335d6172c9921ee3f9e680f6649a81d"}, - {file = "prysk-0.15.2.tar.gz", hash = "sha256:953b608561daed91aced9856fcd9e008e963c07e4bf1684d79be0b218d29b8bd"}, -] - -[package.dependencies] -pytest = {version = ">=7.0.1", optional = true, markers = "extra == \"pytest-plugin\""} -rich = ">=13.3.1,<14.0.0" - -[package.extras] -pytest-plugin = ["pytest (>=7.0.1)"] - [[package]] name = "py-serializable" version = "2.1.0" @@ -3893,4 +3874,4 @@ type = ["pytest-mypy (>=1.0.1) ; platform_python_implementation != \"PyPy\""] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "0bf7929c8b8e3699c6f66635a019a12a86cc1ec56f1d4b48c92467e650d33756" +content-hash = "8b39bc1b4faf29f33a1b3a98b0bbf487a7d45d3537158759b8b5cf40c2d33542" diff --git a/pyproject.toml b/pyproject.toml index 8769921..0ddd07e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ ec = "exasol.error._cli:main" [dependency-groups] dev = [ "pytest>=7.1.2,<10", - "prysk[pytest-plugin]>=0.15.1", "exasol-toolbox>=8.1.1, <9", ] diff --git a/test/integration/cli_integration_test.py b/test/integration/cli_integration_test.py new file mode 100644 index 0000000..a03522a --- /dev/null +++ b/test/integration/cli_integration_test.py @@ -0,0 +1,112 @@ +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parents[2] +PYMODULE_CONTENT = """from exasol import error +from exasol.error import Parameter +error1 = error.ExaError( + "E-TEST-1", + "this is an error", + ["no mitigation available"], + {"param": Parameter("value", "some description")}, +) +error2 = error.ExaError( + "E-TEST-2", "this is an error", ["no mitigation available"], {"param": "value"} +) +""" +EXPECTED_ERRORS = [ + { + "identifier": "E-TEST-1", + "message": "this is an error", + "messagePlaceholders": [ + {"placeholder": "param", "description": "some description"} + ], + "description": None, + "internalDescription": None, + "potentialCauses": None, + "mitigations": ["no mitigation available"], + "sourceFile": "pymodule.py", + "sourceLine": 3, + "contextHash": None, + }, + { + "identifier": "E-TEST-2", + "message": "this is an error", + "messagePlaceholders": [{"placeholder": "param", "description": ""}], + "description": None, + "internalDescription": None, + "potentialCauses": None, + "mitigations": ["no mitigation available"], + "sourceFile": "pymodule.py", + "sourceLine": 9, + "contextHash": None, + }, +] + + +def _env(): + env = os.environ.copy() + pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + f"{REPO_ROOT}{os.pathsep}{pythonpath}" if pythonpath else str(REPO_ROOT) + ) + return env + + +def _run(command: list[str], *args: str, cwd: Path) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [*command, "--debug", *args], + cwd=cwd, + env=_env(), + check=True, + capture_output=True, + text=True, + ) + + +def _commands(): + yield pytest.param([sys.executable, "-m", "exasol.error"], id="module-entrypoint") + ec_path = shutil.which("ec") + if ec_path: + yield pytest.param([ec_path], id="console-script") + else: + yield pytest.param( + [sys.executable, "-c", "from exasol.error._cli import main; main()"], + id="cli-module-fallback", + ) + + +@pytest.fixture +def sample_module(tmp_path: Path) -> Path: + module = tmp_path / "pymodule.py" + module.write_text(PYMODULE_CONTENT, encoding="utf-8") + return module + + +@pytest.mark.parametrize("command", _commands()) +def test_parse_subcommand(command: list[str], sample_module: Path): + result = _run(command, "parse", sample_module.name, cwd=sample_module.parent) + + assert result.stderr == "" + assert [json.loads(line) for line in result.stdout.splitlines()] == EXPECTED_ERRORS + + +@pytest.mark.parametrize("command", _commands()) +def test_generate_subcommand(command: list[str], sample_module: Path): + result = _run( + command, "generate", "modulename", "1.2.0", ".", cwd=sample_module.parent + ) + + assert result.stderr == "" + assert json.loads(result.stdout) == { + "$schema": "https://schemas.exasol.com/error_code_report-1.0.0.json", + "projectName": "modulename", + "projectVersion": "1.2.0", + "errorCodes": EXPECTED_ERRORS, + } diff --git a/test/integration/generate-subcommand.t b/test/integration/generate-subcommand.t deleted file mode 100644 index bbe1f8a..0000000 --- a/test/integration/generate-subcommand.t +++ /dev/null @@ -1,115 +0,0 @@ -Prepare Test - - $ export ROOT=$TESTDIR/../../ - - $ cat > pymodule.py << EOF - > from exasol import error - > from exasol.error import Parameter - > error1 = error.ExaError( - > "E-TEST-1", - > "this is an error", - > ["no mitigation available"], - > {"param": Parameter("value", "some description")}, - > ) - > error2 = error.ExaError( - > "E-TEST-2", "this is an error", ["no mitigation available"], {"param": "value"} - > ) - > EOF - -Test module entry point - - $ python -m exasol.error --debug generate modulename 1.2.0 . | python -m json.tool --json-lines - { - "$schema": "https://schemas.exasol.com/error_code_report-1.0.0.json", - "projectName": "modulename", - "projectVersion": "1.2.0", - "errorCodes": [ - { - "identifier": "E-TEST-1", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "some description" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 3, - "contextHash": null - }, - { - "identifier": "E-TEST-2", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 9, - "contextHash": null - } - ] - } - -Test cli command - - $ ec --debug generate modulename 1.2.0 . | python -m json.tool --json-lines - { - "$schema": "https://schemas.exasol.com/error_code_report-1.0.0.json", - "projectName": "modulename", - "projectVersion": "1.2.0", - "errorCodes": [ - { - "identifier": "E-TEST-1", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "some description" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 3, - "contextHash": null - }, - { - "identifier": "E-TEST-2", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 9, - "contextHash": null - } - ] - } diff --git a/test/integration/parse-subcommand.t b/test/integration/parse-subcommand.t deleted file mode 100644 index a666b21..0000000 --- a/test/integration/parse-subcommand.t +++ /dev/null @@ -1,101 +0,0 @@ -Prepare Test - - $ export ROOT=$TESTDIR/../../ - - $ cat > pymodule.py << EOF - > from exasol import error - > from exasol.error import Parameter - > error1 = error.ExaError( - > "E-TEST-1", - > "this is an error", - > ["no mitigation available"], - > {"param": Parameter("value", "some description")}, - > ) - > error2 = error.ExaError( - > "E-TEST-2", "this is an error", ["no mitigation available"], {"param": "value"} - > ) - > EOF - -Test module entry point - - $ python -m exasol.error --debug parse pymodule.py | python -m json.tool --json-lines - { - "identifier": "E-TEST-1", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "some description" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 3, - "contextHash": null - } - { - "identifier": "E-TEST-2", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 9, - "contextHash": null - } - -Test cli command - - $ ec --debug parse pymodule.py | python -m json.tool --json-lines - { - "identifier": "E-TEST-1", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "some description" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 3, - "contextHash": null - } - { - "identifier": "E-TEST-2", - "message": "this is an error", - "messagePlaceholders": [ - { - "placeholder": "param", - "description": "" - } - ], - "description": null, - "internalDescription": null, - "potentialCauses": null, - "mitigations": [ - "no mitigation available" - ], - "sourceFile": "pymodule.py", - "sourceLine": 9, - "contextHash": null - }