generated from unai/python_boilerplate
308 lines
11 KiB
Python
308 lines
11 KiB
Python
"""Tests unitarios para el módulo config."""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clean_env(monkeypatch):
|
|
"""Limpia todas las variables de entorno relevantes antes de cada test."""
|
|
env_vars = [
|
|
"HOST",
|
|
"USERNAME",
|
|
"PASSWORD",
|
|
"PORT",
|
|
"UPDATE_INTERVAL",
|
|
"OUTPUT_FILE",
|
|
]
|
|
for var in env_vars:
|
|
monkeypatch.delenv(var, raising=False)
|
|
yield
|
|
|
|
|
|
class TestSettings:
|
|
"""Tests para la clase Settings."""
|
|
|
|
def test_settings_with_required_fields(self, monkeypatch):
|
|
"""Test: Settings se crea correctamente con campos obligatorios."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
# _env_file=None evita leer el archivo .env
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.host == "http://test.com"
|
|
assert settings.username == "user"
|
|
assert settings.password == "pass"
|
|
|
|
def test_settings_default_values(self, monkeypatch):
|
|
"""Test: Settings usa valores por defecto correctos."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.port == 8080
|
|
assert settings.update_interval == 3600
|
|
assert settings.output_file == "playlist.m3u"
|
|
|
|
def test_settings_custom_values(self, monkeypatch):
|
|
"""Test: Settings acepta valores personalizados."""
|
|
monkeypatch.setenv("HOST", "http://custom.com")
|
|
monkeypatch.setenv("USERNAME", "custom_user")
|
|
monkeypatch.setenv("PASSWORD", "custom_pass")
|
|
monkeypatch.setenv("PORT", "9090")
|
|
monkeypatch.setenv("UPDATE_INTERVAL", "7200")
|
|
monkeypatch.setenv("OUTPUT_FILE", "custom.m3u")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.host == "http://custom.com"
|
|
assert settings.username == "custom_user"
|
|
assert settings.password == "custom_pass"
|
|
assert settings.port == 9090
|
|
assert settings.update_interval == 7200
|
|
assert settings.output_file == "custom.m3u"
|
|
|
|
def test_settings_missing_required_host(self, monkeypatch):
|
|
"""Test: Settings falla sin HOST."""
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(_env_file=None)
|
|
|
|
assert "host" in str(exc_info.value).lower()
|
|
|
|
def test_settings_missing_required_username(self, monkeypatch):
|
|
"""Test: Settings falla sin USERNAME."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(_env_file=None)
|
|
|
|
assert "username" in str(exc_info.value).lower()
|
|
|
|
def test_settings_missing_required_password(self, monkeypatch):
|
|
"""Test: Settings falla sin PASSWORD."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Settings(_env_file=None)
|
|
|
|
assert "password" in str(exc_info.value).lower()
|
|
|
|
def test_settings_invalid_port_type(self, monkeypatch):
|
|
"""Test: Settings falla con PORT inválido."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("PORT", "invalid")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
with pytest.raises(ValidationError):
|
|
Settings(_env_file=None)
|
|
|
|
def test_settings_extra_fields_ignored(self, monkeypatch):
|
|
"""Test: Settings ignora campos extra (extra='ignore')."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("UNKNOWN_FIELD", "should_be_ignored")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
# No debe lanzar excepción
|
|
settings = Settings(_env_file=None)
|
|
assert not hasattr(settings, "unknown_field")
|
|
|
|
def test_settings_reads_env_file(self, tmp_path, monkeypatch):
|
|
"""Test: Settings puede leer desde archivo .env."""
|
|
# Crear archivo .env temporal
|
|
env_file = tmp_path / ".env"
|
|
env_file.write_text(
|
|
"HOST=http://from-env-file.com\nUSERNAME=envuser\nPASSWORD=envpass\n"
|
|
)
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=str(env_file))
|
|
|
|
assert settings.host == "http://from-env-file.com"
|
|
assert settings.username == "envuser"
|
|
assert settings.password == "envpass"
|
|
|
|
def test_settings_invalid_port_type(self, monkeypatch):
|
|
"""Test: Settings falla con PORT inválido."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("PORT", "invalid")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
with pytest.raises(ValidationError):
|
|
Settings()
|
|
|
|
def test_settings_extra_fields_ignored(self, monkeypatch):
|
|
"""Test: Settings ignora campos extra (extra='ignore')."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("UNKNOWN_FIELD", "should_be_ignored")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
# No debe lanzar excepción
|
|
settings = Settings()
|
|
assert not hasattr(settings, "unknown_field")
|
|
|
|
# ========================================
|
|
# Tests para include_text y exclude_text
|
|
# ========================================
|
|
|
|
def test_settings_include_text_default_empty_list(self, monkeypatch):
|
|
"""Test: include_text tiene valor por defecto lista vacía."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.include_text == []
|
|
assert isinstance(settings.include_text, list)
|
|
|
|
def test_settings_exclude_text_default_empty_list(self, monkeypatch):
|
|
"""Test: exclude_text tiene valor por defecto lista vacía."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.exclude_text == []
|
|
assert isinstance(settings.exclude_text, list)
|
|
|
|
def test_settings_include_text_from_env_json(self, monkeypatch):
|
|
"""Test: include_text acepta formato JSON desde variable de entorno."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("INCLUDE_TEXT", '["ESPN", "CNN"]')
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.include_text == ["ESPN", "CNN"]
|
|
|
|
def test_settings_exclude_text_from_env_json(self, monkeypatch):
|
|
"""Test: exclude_text acepta formato JSON desde variable de entorno."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("EXCLUDE_TEXT", '["Adult", "XXX"]')
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.exclude_text == ["Adult", "XXX"]
|
|
|
|
def test_settings_include_and_exclude_together(self, monkeypatch):
|
|
"""Test: include_text y exclude_text pueden usarse juntos."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("INCLUDE_TEXT", '["Sports", "News"]')
|
|
monkeypatch.setenv("EXCLUDE_TEXT", '["Adult"]')
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.include_text == ["Sports", "News"]
|
|
assert settings.exclude_text == ["Adult"]
|
|
|
|
def test_settings_include_text_single_value(self, monkeypatch):
|
|
"""Test: include_text acepta un solo valor en lista."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("INCLUDE_TEXT", '["OnlyThis"]')
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.include_text == ["OnlyThis"]
|
|
assert len(settings.include_text) == 1
|
|
|
|
def test_settings_exclude_text_single_value(self, monkeypatch):
|
|
"""Test: exclude_text acepta un solo valor en lista."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("EXCLUDE_TEXT", '["BlockThis"]')
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.exclude_text == ["BlockThis"]
|
|
assert len(settings.exclude_text) == 1
|
|
|
|
def test_settings_include_text_empty_json_array(self, monkeypatch):
|
|
"""Test: include_text acepta array JSON vacío."""
|
|
monkeypatch.setenv("HOST", "http://test.com")
|
|
monkeypatch.setenv("USERNAME", "user")
|
|
monkeypatch.setenv("PASSWORD", "pass")
|
|
monkeypatch.setenv("INCLUDE_TEXT", "[]")
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=None)
|
|
|
|
assert settings.include_text == []
|
|
|
|
def test_settings_from_env_file_with_filters(self, tmp_path, monkeypatch):
|
|
"""Test: Settings lee filtros desde archivo .env."""
|
|
env_file = tmp_path / ".env"
|
|
env_file.write_text(
|
|
'HOST=http://test.com\n'
|
|
'USERNAME=user\n'
|
|
'PASSWORD=pass\n'
|
|
'INCLUDE_TEXT=["HBO", "ESPN"]\n'
|
|
'EXCLUDE_TEXT=["Adult"]\n'
|
|
)
|
|
|
|
from m3u_list_builder.config import Settings
|
|
|
|
settings = Settings(_env_file=str(env_file))
|
|
|
|
assert settings.include_text == ["HBO", "ESPN"]
|
|
assert settings.exclude_text == ["Adult"]
|