Tighten configuration and export handling

This commit is contained in:
Кокос Артем Николаевич
2026-05-22 17:41:56 +07:00
parent 8bc8181ce3
commit 2db0ab1f0b
20 changed files with 423 additions and 350 deletions

View File

@@ -1,22 +1,44 @@
import os
import sys
from io import StringIO
from unittest import mock
from redmine_reporter.cli import main
from redmine_reporter.config import Config
import pytest
from redmine_reporter.cli import main, parse_date_range
VALID_ENV = {
"REDMINE_URL": "https://red.eltex.loc",
"REDMINE_API_KEY": "token",
}
# Config читает env при импорте -- патчим класс напрямую.
# fetch_issues_with_spent_time импортируется в cli.py через "from .client import ...",
# поэтому мокать нужно имя в модуле cli, а не в client.
@mock.patch.multiple(
Config,
REDMINE_URL="https://red.eltex.loc",
REDMINE_API_KEY=None,
REDMINE_USER="x",
REDMINE_PASSWORD="y",
@pytest.mark.parametrize(
"date_arg, expected",
[
("2026-01-01--2026-01-31", ("2026-01-01", "2026-01-31")),
(" 2026-01-01 -- 2026-01-31 ", ("2026-01-01", "2026-01-31")),
],
)
def test_parse_date_range_valid(date_arg, expected):
assert parse_date_range(date_arg) == expected
@pytest.mark.parametrize(
"date_arg",
[
"20260101-20260131",
"2026-1-01--2026-01-31",
"2026-02-30--2026-03-01",
"2026-02-01--2026-01-31",
],
)
def test_parse_date_range_invalid(date_arg):
with pytest.raises(ValueError):
parse_date_range(date_arg)
@mock.patch.dict(os.environ, VALID_ENV, clear=True)
@mock.patch("redmine_reporter.cli.fetch_issues_with_spent_time")
def test_cli_smoke_empty(mock_fetch):
"""Пустой список задач -- выход 0, сообщение о 0 задачах."""
@@ -31,13 +53,7 @@ def test_cli_smoke_empty(mock_fetch):
assert "Total issues: 0" in captured.getvalue()
@mock.patch.multiple(
Config,
REDMINE_URL="https://red.eltex.loc",
REDMINE_API_KEY=None,
REDMINE_USER="x",
REDMINE_PASSWORD="y",
)
@mock.patch.dict(os.environ, VALID_ENV, clear=True)
@mock.patch("redmine_reporter.cli.fetch_issues_with_spent_time")
def test_cli_returns_zero_on_no_entries(mock_fetch):
"""None от fetch (нет time entries) -- выход 0."""
@@ -46,32 +62,21 @@ def test_cli_returns_zero_on_no_entries(mock_fetch):
assert code == 0
@mock.patch.multiple(
Config,
REDMINE_URL="",
REDMINE_API_KEY=None,
REDMINE_USER=None,
REDMINE_PASSWORD=None,
)
@mock.patch.dict(os.environ, {}, clear=True)
def test_cli_config_error():
"""Невалидный конфиг -- выход 1."""
code = main(["--date", "2026-01-01--2026-01-31"])
assert code == 1
@mock.patch.dict(os.environ, VALID_ENV, clear=True)
def test_cli_invalid_date_format():
"""Неверный формат даты -- выход 1."""
code = main(["--date", "20260101-20260131"])
assert code == 1
@mock.patch.multiple(
Config,
REDMINE_URL="https://red.eltex.loc",
REDMINE_API_KEY=None,
REDMINE_USER="x",
REDMINE_PASSWORD="y",
)
@mock.patch.dict(os.environ, VALID_ENV, clear=True)
@mock.patch("redmine_reporter.cli.fetch_issues_with_spent_time")
def test_cli_unknown_output_extension(mock_fetch, tmp_path):
"""Неизвестное расширение файла -- выход 1."""
@@ -81,13 +86,7 @@ def test_cli_unknown_output_extension(mock_fetch, tmp_path):
assert code == 1
@mock.patch.multiple(
Config,
REDMINE_URL="https://red.eltex.loc",
REDMINE_API_KEY=None,
REDMINE_USER="x",
REDMINE_PASSWORD="y",
)
@mock.patch.dict(os.environ, VALID_ENV, clear=True)
@mock.patch("redmine_reporter.cli.fetch_issues_with_spent_time")
def test_cli_output_without_extension(mock_fetch, tmp_path):
"""Файл без расширения -- выход 1 с подсказкой."""