markitect-main/tests/unit/llm/test_config.py

106 lines
3.2 KiB
Python
Raw Normal View History

"""Tests for markitect.llm.config."""
import os
from pathlib import Path
from unittest import mock
import pytest
from markitect.llm.config import (
LLMConfig,
resolve_api_key,
find_project_root,
load_config,
)
class TestResolveApiKey:
def test_explicit_key_wins(self):
key = resolve_api_key(explicit="sk-explicit")
assert key == "sk-explicit"
def test_env_var_fallback(self):
with mock.patch.dict(os.environ, {"MY_KEY": "sk-env"}):
key = resolve_api_key(explicit=None, env_var="MY_KEY")
assert key == "sk-env"
def test_env_var_stripped(self):
with mock.patch.dict(os.environ, {"MY_KEY": " sk-env \n"}):
key = resolve_api_key(explicit=None, env_var="MY_KEY")
assert key == "sk-env"
def test_file_fallback(self, tmp_path):
key_file = tmp_path / "key.txt"
key_file.write_text("sk-file\n")
key = resolve_api_key(
explicit=None,
env_var="NONEXISTENT_VAR_XYZ",
key_file_paths=[key_file],
)
assert key == "sk-file"
def test_file_skips_empty(self, tmp_path):
empty = tmp_path / "empty.txt"
empty.write_text("")
good = tmp_path / "good.txt"
good.write_text("sk-good")
key = resolve_api_key(
explicit=None,
env_var="NONEXISTENT_VAR_XYZ",
key_file_paths=[empty, good],
)
assert key == "sk-good"
def test_file_skips_missing(self, tmp_path):
missing = tmp_path / "no-such-file.txt"
key = resolve_api_key(
explicit=None,
env_var="NONEXISTENT_VAR_XYZ",
key_file_paths=[missing],
)
assert key is None
def test_returns_none_when_nothing_found(self):
key = resolve_api_key(
explicit=None,
env_var="NONEXISTENT_VAR_XYZ",
key_file_paths=[],
)
assert key is None
class TestFindProjectRoot:
def test_finds_root(self, tmp_path):
(tmp_path / "pyproject.toml").write_text("[project]")
sub = tmp_path / "a" / "b"
sub.mkdir(parents=True)
assert find_project_root(sub) == tmp_path
def test_returns_none_if_no_marker(self, tmp_path):
sub = tmp_path / "a" / "b"
sub.mkdir(parents=True)
# tmp_path itself won't have pyproject.toml
result = find_project_root(sub)
# Could be None or could find the real project root above;
# the important thing is it doesn't crash
assert result is None or (result / "pyproject.toml").exists()
class TestLoadConfig:
def test_returns_llmconfig(self):
cfg = load_config(provider="claude-code")
assert isinstance(cfg, LLMConfig)
assert cfg.provider == "claude-code"
def test_model_override(self):
cfg = load_config(model="my-model")
assert cfg.model == "my-model"
def test_explicit_key(self):
cfg = load_config(api_key="sk-test")
assert cfg.api_key == "sk-test"
def test_extra_overrides(self):
cfg = load_config(timeout_seconds=60)
assert cfg.timeout_seconds == 60