Files
last30days-skill/tests/test_models.py
T
Jeffrey Sperling 036bcd2ae3 Address review feedback: deduplicate query_type, clean unused imports, fix defaults
- Remove duplicate detect_query_type from query.py (divergent 5-type version);
  canonical 7-type version lives in query_type.py
- Fix reddit.py import to use query_type.detect_query_type
- Clean unused STOPWORDS/SYNONYMS/tokenize imports from youtube_yt, instagram,
  tiktok, scrapecreators_x, bird_x after relevance consolidation
- Fix _relevance_filter default from 0.7 to 0.0 (items without relevance
  should not silently pass the filter)
- Remove --dateafter from yt-dlp (returns 0 results for evergreen topics)
- Remove restrictSearchableAttributes from HN search (misses Ask/Show HN)
- Lower HN points filter from >5 to >2 (avoids filtering niche posts)
- Add error logging to select_openai_model HTTP failures
- Remove mise.toml and internal planning doc from repo
- Update module docstrings to describe current purpose, not migration history
- Update tests to import from canonical relevance module
2026-03-11 18:40:07 -07:00

208 lines
6.8 KiB
Python

"""Tests for models module."""
import sys
import unittest
from pathlib import Path
# Add lib to path
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
from lib import models
class TestParseVersion(unittest.TestCase):
def test_simple_version(self):
result = models.parse_version("gpt-5")
self.assertEqual(result, (5,))
def test_minor_version(self):
result = models.parse_version("gpt-5.2")
self.assertEqual(result, (5, 2))
def test_patch_version(self):
result = models.parse_version("gpt-5.2.1")
self.assertEqual(result, (5, 2, 1))
def test_no_version(self):
result = models.parse_version("custom-model")
self.assertIsNone(result)
class TestIsSearchCapableModel(unittest.TestCase):
def test_gpt5_is_capable(self):
"""gpt-5 supports web_search when reasoning is not set to 'minimal'.
Per OpenAI docs, gpt-5 with reasoning effort="minimal" does NOT
support web_search. We never set reasoning params (our usage is
tool invocation + JSON extraction only), so gpt-5 is safe here.
"""
self.assertTrue(models.is_search_capable_model("gpt-5"))
def test_gpt52_is_capable(self):
self.assertTrue(models.is_search_capable_model("gpt-5.2"))
def test_gpt5_mini_is_capable(self):
self.assertTrue(models.is_search_capable_model("gpt-5-mini"))
def test_gpt41_mini_is_capable(self):
self.assertTrue(models.is_search_capable_model("gpt-4.1-mini"))
def test_gpt4o_is_capable(self):
self.assertTrue(models.is_search_capable_model("gpt-4o"))
def test_gpt4o_mini_not_capable(self):
"""gpt-4o-mini does not support web_search with domain filtering."""
self.assertFalse(models.is_search_capable_model("gpt-4o-mini"))
def test_nano_not_capable(self):
"""nano models don't support web_search."""
self.assertFalse(models.is_search_capable_model("gpt-4.1-nano"))
self.assertFalse(models.is_search_capable_model("gpt-5-nano"))
def test_gpt4_not_capable(self):
self.assertFalse(models.is_search_capable_model("gpt-4"))
def test_codex_not_capable(self):
self.assertFalse(models.is_search_capable_model("gpt-5.1-codex"))
def test_backward_compat_alias(self):
"""is_mainline_openai_model still works as alias."""
self.assertTrue(models.is_mainline_openai_model("gpt-5"))
class TestSelectOpenAIModel(unittest.TestCase):
def setUp(self):
from lib import cache
cache.MODEL_CACHE_FILE.unlink(missing_ok=True)
def test_pinned_policy(self):
result = models.select_openai_model(
"fake-key",
policy="pinned",
pin="gpt-5.1"
)
self.assertEqual(result, "gpt-5.1")
def test_prefers_mini_over_mainline(self):
"""Mini models should be preferred for cost-efficiency."""
mock_models = [
{"id": "gpt-5.2", "created": 1704067200},
{"id": "gpt-5-mini", "created": 1704067200},
{"id": "gpt-5.1", "created": 1701388800},
]
result = models.select_openai_model(
"fake-key",
policy="auto",
mock_models=mock_models
)
self.assertEqual(result, "gpt-5-mini")
def test_prefers_newer_generation_mini(self):
"""gpt-5-mini should beat gpt-4.1-mini (newer generation)."""
mock_models = [
{"id": "gpt-4.1-mini", "created": 1701388800},
{"id": "gpt-5-mini", "created": 1704067200},
{"id": "gpt-4.1", "created": 1698710400},
]
result = models.select_openai_model(
"fake-key",
policy="auto",
mock_models=mock_models
)
self.assertEqual(result, "gpt-5-mini")
def test_falls_back_to_mainline_when_no_mini(self):
"""Without mini models, mainline models are selected."""
mock_models = [
{"id": "gpt-5.2", "created": 1704067200},
{"id": "gpt-4.1", "created": 1698710400},
]
result = models.select_openai_model(
"fake-key",
policy="auto",
mock_models=mock_models
)
self.assertEqual(result, "gpt-5.2")
def test_filters_unsupported_variants(self):
"""Nano, codex, preview models should be excluded."""
mock_models = [
{"id": "gpt-5-nano", "created": 1704067200},
{"id": "gpt-5.1-codex", "created": 1704067200},
{"id": "gpt-4o-mini", "created": 1704067200},
{"id": "gpt-4.1-mini", "created": 1698710400},
]
result = models.select_openai_model(
"fake-key",
policy="auto",
mock_models=mock_models
)
self.assertEqual(result, "gpt-4.1-mini")
class TestSelectXAIModel(unittest.TestCase):
def test_latest_policy(self):
result = models.select_xai_model(
"fake-key",
policy="latest"
)
self.assertEqual(result, "grok-4-1-fast-non-reasoning")
def test_stable_policy(self):
# Clear cache first to avoid interference
from lib import cache
cache.MODEL_CACHE_FILE.unlink(missing_ok=True)
result = models.select_xai_model(
"fake-key",
policy="stable"
)
self.assertEqual(result, "grok-4-1-fast-non-reasoning")
def test_pinned_policy(self):
result = models.select_xai_model(
"fake-key",
policy="pinned",
pin="grok-3"
)
self.assertEqual(result, "grok-3")
class TestGetModels(unittest.TestCase):
def setUp(self):
from lib import cache
cache.MODEL_CACHE_FILE.unlink(missing_ok=True)
def test_no_keys_returns_none(self):
config = {}
result = models.get_models(config)
self.assertIsNone(result["openai"])
self.assertIsNone(result["xai"])
def test_openai_key_only(self):
config = {"OPENAI_API_KEY": "sk-test"}
mock_models = [
{"id": "gpt-5.2", "created": 1704067200},
{"id": "gpt-5-mini", "created": 1704067200},
]
result = models.get_models(config, mock_openai_models=mock_models)
self.assertEqual(result["openai"], "gpt-5-mini")
self.assertIsNone(result["xai"])
def test_both_keys(self):
config = {
"OPENAI_API_KEY": "sk-test",
"XAI_API_KEY": "xai-test",
}
mock_openai = [
{"id": "gpt-5.2", "created": 1704067200},
{"id": "gpt-5-mini", "created": 1704067200},
]
mock_xai = [{"id": "grok-4-1-fast-non-reasoning", "created": 1704067200}]
result = models.get_models(config, mock_openai, mock_xai)
self.assertEqual(result["openai"], "gpt-5-mini")
self.assertEqual(result["xai"], "grok-4-1-fast-non-reasoning")
if __name__ == "__main__":
unittest.main()