142 lines
4.7 KiB
Python
142 lines
4.7 KiB
Python
|
|
"""Tests for constants module."""
|
||
|
|
|
||
|
|
import re
|
||
|
|
from pathlib import Path
|
||
|
|
from unittest.mock import mock_open, patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from src.constants import (
|
||
|
|
APP_NAME,
|
||
|
|
APP_TITLE,
|
||
|
|
APP_VERSION,
|
||
|
|
ENV_DEBUG,
|
||
|
|
get_debug_mode,
|
||
|
|
get_version,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# get_version()
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_version_returns_string() -> None:
|
||
|
|
"""get_version() should return a string."""
|
||
|
|
assert isinstance(get_version(), str)
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_version_semver_format() -> None:
|
||
|
|
"""get_version() should return a semver-like string X.Y.Z."""
|
||
|
|
version = get_version()
|
||
|
|
assert re.match(r"^\d+\.\d+\.\d+", version), f"Not semver: {version!r}"
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_version_fallback_when_toml_missing(tmp_path: Path) -> None:
|
||
|
|
"""get_version() returns '0.0.0-unknown' when pyproject.toml and _version.py are both missing."""
|
||
|
|
missing = tmp_path / "nonexistent.toml"
|
||
|
|
with patch("src.constants._PYPROJECT_PATH", missing):
|
||
|
|
result = get_version()
|
||
|
|
# Either fallback _version.py exists (from previous run) or returns unknown
|
||
|
|
assert isinstance(result, str)
|
||
|
|
assert len(result) > 0
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_version_unknown_fallback(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""get_version() returns '0.0.0-unknown' when all sources are unavailable."""
|
||
|
|
missing = tmp_path / "nonexistent.toml"
|
||
|
|
monkeypatch.setattr("src.constants._PYPROJECT_PATH", missing)
|
||
|
|
|
||
|
|
# Patch _version import to also fail
|
||
|
|
with patch("src.constants.Path.write_text", side_effect=OSError):
|
||
|
|
with patch.dict("sys.modules", {"src._version": None}):
|
||
|
|
result = get_version()
|
||
|
|
|
||
|
|
assert isinstance(result, str)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# get_debug_mode()
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_debug_mode_returns_bool() -> None:
|
||
|
|
"""get_debug_mode() should always return a bool."""
|
||
|
|
assert isinstance(get_debug_mode(), bool)
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_debug_mode_true(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""get_debug_mode() returns True when ENV_DEBUG=true."""
|
||
|
|
monkeypatch.setenv("ENV_DEBUG", "true")
|
||
|
|
assert get_debug_mode() is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_debug_mode_true_variants(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""get_debug_mode() accepts '1' and 'yes' as truthy values."""
|
||
|
|
for value in ("1", "yes", "YES", "True", "TRUE"):
|
||
|
|
monkeypatch.setenv("ENV_DEBUG", value)
|
||
|
|
assert get_debug_mode() is True, f"Expected True for ENV_DEBUG={value!r}"
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_debug_mode_false(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""get_debug_mode() returns False when ENV_DEBUG=false."""
|
||
|
|
monkeypatch.setenv("ENV_DEBUG", "false")
|
||
|
|
assert get_debug_mode() is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_debug_mode_false_when_unset(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""get_debug_mode() returns False when ENV_DEBUG is not set."""
|
||
|
|
monkeypatch.delenv("ENV_DEBUG", raising=False)
|
||
|
|
assert get_debug_mode() is False
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Module-level constants
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_env_debug_is_bool() -> None:
|
||
|
|
"""ENV_DEBUG should be a bool."""
|
||
|
|
assert isinstance(ENV_DEBUG, bool)
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_version_is_string() -> None:
|
||
|
|
"""APP_VERSION should be a string."""
|
||
|
|
assert isinstance(APP_VERSION, str)
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_version_semver_format() -> None:
|
||
|
|
"""APP_VERSION should follow semver format X.Y.Z."""
|
||
|
|
assert re.match(r"^\d+\.\d+\.\d+", APP_VERSION), f"Not semver: {APP_VERSION!r}"
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_name_value() -> None:
|
||
|
|
"""APP_NAME should be 'X4 SavEd'."""
|
||
|
|
assert APP_NAME == "X4 SavEd"
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_title_contains_name_and_version() -> None:
|
||
|
|
"""APP_TITLE should contain APP_NAME and APP_VERSION."""
|
||
|
|
assert APP_NAME in APP_TITLE
|
||
|
|
assert APP_VERSION in APP_TITLE
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_title_dev_suffix_when_debug(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""APP_TITLE ends with '-DEV' when ENV_DEBUG is True."""
|
||
|
|
import importlib
|
||
|
|
import src.constants as consts
|
||
|
|
|
||
|
|
monkeypatch.setenv("ENV_DEBUG", "true")
|
||
|
|
monkeypatch.setattr(consts, "ENV_DEBUG", True)
|
||
|
|
title = f"{consts.APP_NAME} v{consts.APP_VERSION}" + ("-DEV" if True else "")
|
||
|
|
assert title.endswith("-DEV")
|
||
|
|
|
||
|
|
|
||
|
|
def test_app_title_no_dev_suffix_when_not_debug(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
"""APP_TITLE does not end with '-DEV' when ENV_DEBUG is False."""
|
||
|
|
import src.constants as consts
|
||
|
|
|
||
|
|
monkeypatch.setattr(consts, "ENV_DEBUG", False)
|
||
|
|
title = f"{consts.APP_NAME} v{consts.APP_VERSION}" + ("-DEV" if False else "")
|
||
|
|
assert not title.endswith("-DEV")
|