Add test coverage for CLI commands, Flask routes, and shared DB methods
74 new tests across 3 files: - test_cli.py: CLI help, version, config, report generation, wg/viz/pipeline subcommands - test_web.py: All public pages, admin pages (dev/prod), API JSON endpoints, CSV export, 404s - test_db_shared.py: rated_count, gap_count, false_positive_names, category_counts, source_counts, draft_author_count_map, search_gaps, search_authors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
157
tests/test_cli.py
Normal file
157
tests/test_cli.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""Tests for CLI commands using Click's CliRunner."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from ietf_analyzer.cli import main
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def runner():
|
||||
return CliRunner()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config(tmp_path):
|
||||
"""Patch Config.load to return a config pointing at a temp DB."""
|
||||
from ietf_analyzer.config import Config
|
||||
|
||||
cfg = Config(
|
||||
data_dir=str(tmp_path),
|
||||
db_path=str(tmp_path / "test.db"),
|
||||
)
|
||||
with patch("ietf_analyzer.cli.Config.load", return_value=cfg):
|
||||
yield cfg
|
||||
|
||||
|
||||
# ── Help & version ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "IETF Draft Analyzer" in result.output
|
||||
|
||||
|
||||
def test_version(runner, mock_config):
|
||||
result = runner.invoke(main, ["--version"])
|
||||
assert result.exit_code == 0
|
||||
assert "0.3.0" in result.output
|
||||
|
||||
|
||||
def test_unknown_command(runner, mock_config):
|
||||
result = runner.invoke(main, ["nonexistent-command"])
|
||||
assert result.exit_code != 0
|
||||
|
||||
|
||||
# ── config command ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_config_show(runner, mock_config):
|
||||
result = runner.invoke(main, ["config", "--show"])
|
||||
assert result.exit_code == 0
|
||||
assert "data_dir" in result.output
|
||||
|
||||
|
||||
def test_config_show_default(runner, mock_config):
|
||||
"""config without --show or --set also prints config."""
|
||||
result = runner.invoke(main, ["config"])
|
||||
assert result.exit_code == 0
|
||||
assert "data_dir" in result.output
|
||||
|
||||
|
||||
# ── report subcommands ────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_report_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["report", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "overview" in result.output
|
||||
|
||||
|
||||
def test_report_overview(runner, mock_config, seeded_db):
|
||||
"""report overview should run and produce a file."""
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["report", "overview"])
|
||||
assert result.exit_code == 0
|
||||
assert "Report saved" in result.output
|
||||
|
||||
|
||||
def test_report_landscape(runner, mock_config, seeded_db):
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["report", "landscape"])
|
||||
assert result.exit_code == 0
|
||||
assert "Report saved" in result.output
|
||||
|
||||
|
||||
def test_report_timeline(runner, mock_config, seeded_db):
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["report", "timeline"])
|
||||
assert result.exit_code == 0
|
||||
assert "Report saved" in result.output
|
||||
|
||||
|
||||
def test_report_ideas(runner, mock_config, seeded_db):
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["report", "ideas"])
|
||||
assert result.exit_code == 0
|
||||
assert "Report saved" in result.output
|
||||
|
||||
|
||||
def test_report_authors(runner, mock_config, seeded_db):
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["report", "authors"])
|
||||
assert result.exit_code == 0
|
||||
assert "Report saved" in result.output
|
||||
|
||||
|
||||
# ── export command ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_export_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["export", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "json" in result.output
|
||||
|
||||
|
||||
# ── wg commands ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_wg_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["wg", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "list" in result.output
|
||||
|
||||
|
||||
def test_wg_list(runner, mock_config, seeded_db):
|
||||
mock_config.db_path = seeded_db.config.db_path
|
||||
mock_config.data_dir = seeded_db.config.data_dir
|
||||
result = runner.invoke(main, ["wg", "list"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
# ── viz commands ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_viz_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["viz", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "landscape" in result.output
|
||||
|
||||
|
||||
# ── pipeline commands ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_pipeline_help(runner, mock_config):
|
||||
result = runner.invoke(main, ["pipeline", "--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "generate" in result.output
|
||||
Reference in New Issue
Block a user