gitingest/tests/test_cli.py
Nicolas Iragne bc8cdb4594
feat(ci): build Docker Image on PRs (#382)
* feat(ci): add GitHub Actions workflows for Docker image build and rename PyPI publish

* chore: rename cli module to __main__ so it can be executed without having to build

* Update .github/workflows/docker_image.yml

Co-authored-by: Filip Christiansen <22807962+filipchristiansen@users.noreply.github.com>
2025-07-05 21:04:20 +02:00

99 lines
3.6 KiB
Python

"""Tests for the Gitingest CLI."""
from __future__ import annotations
from inspect import signature
from pathlib import Path
import pytest
from click.testing import CliRunner, Result
from gitingest.__main__ import main
from gitingest.config import MAX_FILE_SIZE, OUTPUT_FILE_NAME
@pytest.mark.parametrize(
("cli_args", "expect_file"),
[
pytest.param(["./"], True, id="default-options"),
pytest.param(
[
"./",
"--output",
str(OUTPUT_FILE_NAME),
"--max-size",
str(MAX_FILE_SIZE),
"--exclude-pattern",
"tests/",
"--include-pattern",
"src/",
"--include-submodules",
],
True,
id="custom-options",
),
],
)
def test_cli_writes_file(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
*,
cli_args: list[str],
expect_file: bool,
) -> None:
"""Run the CLI and verify that the SARIF file is created (or not)."""
expectes_exit_code = 0
# Work inside an isolated temp directory
monkeypatch.chdir(tmp_path)
result = _invoke_isolated_cli_runner(cli_args)
assert result.exit_code == expectes_exit_code, result.stderr
# Summary line should be on STDOUT
stdout_lines = result.stdout.splitlines()
assert f"Analysis complete! Output written to: {OUTPUT_FILE_NAME}" in stdout_lines
# File side-effect
sarif_file = tmp_path / OUTPUT_FILE_NAME
assert sarif_file.exists() is expect_file, f"{OUTPUT_FILE_NAME} existence did not match expectation"
def test_cli_with_stdout_output() -> None:
"""Test CLI invocation with output directed to STDOUT."""
output_file = Path(OUTPUT_FILE_NAME)
# Clean up any existing digest.txt file before test
if output_file.exists():
output_file.unlink()
try:
result = _invoke_isolated_cli_runner(["./", "--output", "-", "--exclude-pattern", "tests/"])
# ─── core expectations (stdout) ────────────────────────────────────-
assert result.exit_code == 0, f"CLI exited with code {result.exit_code}, stderr: {result.stderr}"
assert "---" in result.stdout, "Expected file separator '---' not found in STDOUT"
assert "src/gitingest/__main__.py" in result.stdout, (
"Expected content (e.g., src/gitingest/__main__.py) not found in STDOUT"
)
assert not output_file.exists(), f"Output file {output_file} was unexpectedly created."
# ─── the summary must *not* pollute STDOUT, must appear on STDERR ───
summary = "Analysis complete! Output sent to stdout."
stdout_lines = result.stdout.splitlines()
stderr_lines = result.stderr.splitlines()
assert summary not in stdout_lines, "Unexpected summary message found in STDOUT"
assert summary in stderr_lines, "Expected summary message not found in STDERR"
assert f"Output written to: {output_file.name}" not in stderr_lines
finally:
# Clean up any digest.txt file that might have been created during test
if output_file.exists():
output_file.unlink()
def _invoke_isolated_cli_runner(args: list[str]) -> Result:
"""Return a ``CliRunner`` that keeps ``stderr`` separate on Click 8.0-8.1."""
kwargs = {}
if "mix_stderr" in signature(CliRunner.__init__).parameters:
kwargs["mix_stderr"] = False # Click 8.0-8.1
runner = CliRunner(**kwargs)
return runner.invoke(main, args)