Fix stale test assertions and truthsocial pytest dependency

- test_models: update xAI model expectations to grok-4-1-fast (matching
  current XAI_POLICY_MAP)
- test_openai_reddit: update fallback order assertion to gpt-4.1 (matching
  current MODEL_FALLBACK_ORDER)
- test_codex_auth: expect 'reddit' not 'web' when no API keys (Reddit
  is available via public JSON fallback)
- test_truthsocial: convert from pytest-style classes to unittest.TestCase,
  fix import path to use sys.path.insert pattern (matching all other tests)
This commit is contained in:
Jeffrey Sperling
2026-03-11 15:56:14 -07:00
parent b38703e53d
commit 9ca84e495e
4 changed files with 84 additions and 75 deletions
+2 -1
View File
@@ -140,7 +140,8 @@ class TestGetAvailableSourcesWithAuth(unittest.TestCase):
"XAI_API_KEY": None, "XAI_API_KEY": None,
} }
result = env.get_available_sources(config) result = env.get_available_sources(config)
self.assertEqual(result, "web") # Reddit is available via public JSON fallback even without OpenAI auth
self.assertEqual(result, "reddit")
class TestParseCodexStream(unittest.TestCase): class TestParseCodexStream(unittest.TestCase):
+4 -4
View File
@@ -84,7 +84,7 @@ class TestSelectXAIModel(unittest.TestCase):
"fake-key", "fake-key",
policy="latest" policy="latest"
) )
self.assertEqual(result, "grok-4-latest") self.assertEqual(result, "grok-4-1-fast")
def test_stable_policy(self): def test_stable_policy(self):
# Clear cache first to avoid interference # Clear cache first to avoid interference
@@ -94,7 +94,7 @@ class TestSelectXAIModel(unittest.TestCase):
"fake-key", "fake-key",
policy="stable" policy="stable"
) )
self.assertEqual(result, "grok-4") self.assertEqual(result, "grok-4-1-fast")
def test_pinned_policy(self): def test_pinned_policy(self):
result = models.select_xai_model( result = models.select_xai_model(
@@ -125,10 +125,10 @@ class TestGetModels(unittest.TestCase):
"XAI_API_KEY": "xai-test", "XAI_API_KEY": "xai-test",
} }
mock_openai = [{"id": "gpt-5.2", "created": 1704067200}] mock_openai = [{"id": "gpt-5.2", "created": 1704067200}]
mock_xai = [{"id": "grok-4-latest", "created": 1704067200}] mock_xai = [{"id": "grok-4-1-fast", "created": 1704067200}]
result = models.get_models(config, mock_openai, mock_xai) result = models.get_models(config, mock_openai, mock_xai)
self.assertEqual(result["openai"], "gpt-5.2") self.assertEqual(result["openai"], "gpt-5.2")
self.assertEqual(result["xai"], "grok-4-latest") self.assertEqual(result["xai"], "grok-4-1-fast")
if __name__ == "__main__": if __name__ == "__main__":
+3 -3
View File
@@ -68,9 +68,9 @@ class TestModelFallbackOrder(unittest.TestCase):
"""Fallback list should include gpt-4o.""" """Fallback list should include gpt-4o."""
self.assertIn("gpt-4o", MODEL_FALLBACK_ORDER) self.assertIn("gpt-4o", MODEL_FALLBACK_ORDER)
def test_gpt4o_is_first(self): def test_gpt41_is_first(self):
"""gpt-4o should be the first fallback option.""" """gpt-4.1 should be the first fallback option."""
self.assertEqual(MODEL_FALLBACK_ORDER[0], "gpt-4o") self.assertEqual(MODEL_FALLBACK_ORDER[0], "gpt-4.1")
if __name__ == "__main__": if __name__ == "__main__":
+75 -67
View File
@@ -1,129 +1,133 @@
"""Tests for Truth Social source module.""" """Tests for Truth Social source module."""
import pytest import sys
import unittest
from pathlib import Path
from unittest.mock import patch, MagicMock from unittest.mock import patch, MagicMock
from scripts.lib import truthsocial sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
from lib import truthsocial
class TestStripHtml: class TestStripHtml(unittest.TestCase):
"""Test HTML tag stripping.""" """Test HTML tag stripping."""
def test_basic_paragraph(self): def test_basic_paragraph(self):
assert truthsocial._strip_html("<p>Hello world</p>") == "Hello world" self.assertEqual(truthsocial._strip_html("<p>Hello world</p>"), "Hello world")
def test_br_tags(self): def test_br_tags(self):
assert truthsocial._strip_html("Line 1<br>Line 2") == "Line 1\nLine 2" self.assertEqual(truthsocial._strip_html("Line 1<br>Line 2"), "Line 1\nLine 2")
assert truthsocial._strip_html("Line 1<br/>Line 2") == "Line 1\nLine 2" self.assertEqual(truthsocial._strip_html("Line 1<br/>Line 2"), "Line 1\nLine 2")
assert truthsocial._strip_html("Line 1<br />Line 2") == "Line 1\nLine 2" self.assertEqual(truthsocial._strip_html("Line 1<br />Line 2"), "Line 1\nLine 2")
def test_nested_tags(self): def test_nested_tags(self):
assert truthsocial._strip_html("<p>Hello <a href='#'>world</a></p>") == "Hello world" self.assertEqual(truthsocial._strip_html("<p>Hello <a href='#'>world</a></p>"), "Hello world")
def test_empty_string(self): def test_empty_string(self):
assert truthsocial._strip_html("") == "" self.assertEqual(truthsocial._strip_html(""), "")
def test_no_tags(self): def test_no_tags(self):
assert truthsocial._strip_html("plain text") == "plain text" self.assertEqual(truthsocial._strip_html("plain text"), "plain text")
def test_entities_preserved(self): def test_entities_preserved(self):
assert truthsocial._strip_html("<p>&amp; test</p>") == "&amp; test" self.assertEqual(truthsocial._strip_html("<p>&amp; test</p>"), "&amp; test")
class TestExtractCoreSubject: class TestExtractCoreSubject(unittest.TestCase):
"""Test query preprocessing.""" """Test query preprocessing."""
def test_strips_question_prefix(self): def test_strips_question_prefix(self):
assert truthsocial._extract_core_subject("what are people saying about tariffs") == "tariffs" self.assertEqual(truthsocial._extract_core_subject("what are people saying about tariffs"), "tariffs")
def test_strips_noise_words(self): def test_strips_noise_words(self):
assert truthsocial._extract_core_subject("latest trending crypto news") == "crypto" self.assertEqual(truthsocial._extract_core_subject("latest trending crypto news"), "crypto")
def test_preserves_core_topic(self): def test_preserves_core_topic(self):
assert truthsocial._extract_core_subject("tariffs") == "tariffs" self.assertEqual(truthsocial._extract_core_subject("tariffs"), "tariffs")
def test_strips_trailing_punctuation(self): def test_strips_trailing_punctuation(self):
assert truthsocial._extract_core_subject("what is bitcoin?") == "bitcoin" self.assertEqual(truthsocial._extract_core_subject("what is bitcoin?"), "bitcoin")
class TestParseDate: class TestParseDate(unittest.TestCase):
"""Test date parsing from Mastodon status.""" """Test date parsing from Mastodon status."""
def test_iso_date(self): def test_iso_date(self):
assert truthsocial._parse_date({"created_at": "2026-03-09T12:00:00.000Z"}) == "2026-03-09" self.assertEqual(truthsocial._parse_date({"created_at": "2026-03-09T12:00:00.000Z"}), "2026-03-09")
def test_missing_date(self): def test_missing_date(self):
assert truthsocial._parse_date({}) is None self.assertIsNone(truthsocial._parse_date({}))
def test_short_date(self): def test_short_date(self):
assert truthsocial._parse_date({"created_at": "short"}) is None self.assertIsNone(truthsocial._parse_date({"created_at": "short"}))
def test_none_value(self): def test_none_value(self):
assert truthsocial._parse_date({"created_at": None}) is None self.assertIsNone(truthsocial._parse_date({"created_at": None}))
class TestDepthConfig: class TestDepthConfig(unittest.TestCase):
"""Test depth configuration.""" """Test depth configuration."""
def test_all_depths_exist(self): def test_all_depths_exist(self):
assert "quick" in truthsocial.DEPTH_CONFIG self.assertIn("quick", truthsocial.DEPTH_CONFIG)
assert "default" in truthsocial.DEPTH_CONFIG self.assertIn("default", truthsocial.DEPTH_CONFIG)
assert "deep" in truthsocial.DEPTH_CONFIG self.assertIn("deep", truthsocial.DEPTH_CONFIG)
def test_depth_ordering(self): def test_depth_ordering(self):
assert truthsocial.DEPTH_CONFIG["quick"] < truthsocial.DEPTH_CONFIG["default"] self.assertLess(truthsocial.DEPTH_CONFIG["quick"], truthsocial.DEPTH_CONFIG["default"])
assert truthsocial.DEPTH_CONFIG["default"] < truthsocial.DEPTH_CONFIG["deep"] self.assertLess(truthsocial.DEPTH_CONFIG["default"], truthsocial.DEPTH_CONFIG["deep"])
class TestSearchTruthSocial: class TestSearchTruthSocial(unittest.TestCase):
"""Test search function auth handling.""" """Test search function auth handling."""
def test_no_config_returns_error(self): def test_no_config_returns_error(self):
result = truthsocial.search_truthsocial("test", "2026-02-09", "2026-03-09") result = truthsocial.search_truthsocial("test", "2026-02-09", "2026-03-09")
assert result["statuses"] == [] self.assertEqual(result["statuses"], [])
assert "not configured" in result["error"] self.assertIn("not configured", result["error"])
def test_empty_token_returns_error(self): def test_empty_token_returns_error(self):
result = truthsocial.search_truthsocial( result = truthsocial.search_truthsocial(
"test", "2026-02-09", "2026-03-09", "test", "2026-02-09", "2026-03-09",
config={"TRUTHSOCIAL_TOKEN": ""}, config={"TRUTHSOCIAL_TOKEN": ""},
) )
assert result["statuses"] == [] self.assertEqual(result["statuses"], [])
assert "not configured" in result["error"] self.assertIn("not configured", result["error"])
@patch("scripts.lib.truthsocial.http.request") @patch("lib.truthsocial.http.request")
def test_401_returns_token_expired(self, mock_request): def test_401_returns_token_expired(self, mock_request):
from scripts.lib.http import HTTPError from lib.http import HTTPError
mock_request.side_effect = HTTPError("Unauthorized", status_code=401) mock_request.side_effect = HTTPError("Unauthorized", status_code=401)
result = truthsocial.search_truthsocial( result = truthsocial.search_truthsocial(
"test", "2026-02-09", "2026-03-09", "test", "2026-02-09", "2026-03-09",
config={"TRUTHSOCIAL_TOKEN": "expired_token"}, config={"TRUTHSOCIAL_TOKEN": "expired_token"},
) )
assert result["statuses"] == [] self.assertEqual(result["statuses"], [])
assert "expired" in result["error"] self.assertIn("expired", result["error"])
@patch("scripts.lib.truthsocial.http.request") @patch("lib.truthsocial.http.request")
def test_403_returns_access_denied(self, mock_request): def test_403_returns_access_denied(self, mock_request):
from scripts.lib.http import HTTPError from lib.http import HTTPError
mock_request.side_effect = HTTPError("Forbidden", status_code=403) mock_request.side_effect = HTTPError("Forbidden", status_code=403)
result = truthsocial.search_truthsocial( result = truthsocial.search_truthsocial(
"test", "2026-02-09", "2026-03-09", "test", "2026-02-09", "2026-03-09",
config={"TRUTHSOCIAL_TOKEN": "blocked_token"}, config={"TRUTHSOCIAL_TOKEN": "blocked_token"},
) )
assert result["statuses"] == [] self.assertEqual(result["statuses"], [])
assert "Cloudflare" in result["error"] self.assertIn("Cloudflare", result["error"])
@patch("scripts.lib.truthsocial.http.request") @patch("lib.truthsocial.http.request")
def test_429_returns_rate_limited(self, mock_request): def test_429_returns_rate_limited(self, mock_request):
from scripts.lib.http import HTTPError from lib.http import HTTPError
mock_request.side_effect = HTTPError("Too Many Requests", status_code=429) mock_request.side_effect = HTTPError("Too Many Requests", status_code=429)
result = truthsocial.search_truthsocial( result = truthsocial.search_truthsocial(
"test", "2026-02-09", "2026-03-09", "test", "2026-02-09", "2026-03-09",
config={"TRUTHSOCIAL_TOKEN": "rate_limited_token"}, config={"TRUTHSOCIAL_TOKEN": "rate_limited_token"},
) )
assert result["statuses"] == [] self.assertEqual(result["statuses"], [])
assert "rate limited" in result["error"] self.assertIn("rate limited", result["error"])
@patch("scripts.lib.truthsocial.http.request") @patch("lib.truthsocial.http.request")
def test_successful_search(self, mock_request): def test_successful_search(self, mock_request):
mock_request.return_value = { mock_request.return_value = {
"statuses": [ "statuses": [
@@ -142,13 +146,13 @@ class TestSearchTruthSocial:
"tariffs", "2026-02-09", "2026-03-09", "tariffs", "2026-02-09", "2026-03-09",
config={"TRUTHSOCIAL_TOKEN": "valid_token"}, config={"TRUTHSOCIAL_TOKEN": "valid_token"},
) )
assert len(result["statuses"]) == 1 self.assertEqual(len(result["statuses"]), 1)
# Verify bearer token was passed # Verify bearer token was passed
call_args = mock_request.call_args call_args = mock_request.call_args
assert call_args[1]["headers"]["Authorization"] == "Bearer valid_token" self.assertEqual(call_args[1]["headers"]["Authorization"], "Bearer valid_token")
class TestParseTruthSocialResponse: class TestParseTruthSocialResponse(unittest.TestCase):
"""Test response parsing.""" """Test response parsing."""
def test_basic_post(self): def test_basic_post(self):
@@ -166,21 +170,21 @@ class TestParseTruthSocialResponse:
] ]
} }
items = truthsocial.parse_truthsocial_response(response) items = truthsocial.parse_truthsocial_response(response)
assert len(items) == 1 self.assertEqual(len(items), 1)
item = items[0] item = items[0]
assert item["handle"] == "testuser" self.assertEqual(item["handle"], "testuser")
assert item["display_name"] == "Test User" self.assertEqual(item["display_name"], "Test User")
assert item["text"] == "Hello from Truth Social" # HTML stripped self.assertEqual(item["text"], "Hello from Truth Social")
assert item["url"] == "https://truthsocial.com/@testuser/456" self.assertEqual(item["url"], "https://truthsocial.com/@testuser/456")
assert item["date"] == "2026-03-09" self.assertEqual(item["date"], "2026-03-09")
assert item["engagement"]["likes"] == 100 self.assertEqual(item["engagement"]["likes"], 100)
assert item["engagement"]["reposts"] == 50 self.assertEqual(item["engagement"]["reposts"], 50)
assert item["engagement"]["replies"] == 25 self.assertEqual(item["engagement"]["replies"], 25)
assert item["relevance"] > 0 self.assertGreater(item["relevance"], 0)
def test_empty_response(self): def test_empty_response(self):
items = truthsocial.parse_truthsocial_response({"statuses": []}) items = truthsocial.parse_truthsocial_response({"statuses": []})
assert items == [] self.assertEqual(items, [])
def test_missing_fields(self): def test_missing_fields(self):
response = { response = {
@@ -192,10 +196,10 @@ class TestParseTruthSocialResponse:
] ]
} }
items = truthsocial.parse_truthsocial_response(response) items = truthsocial.parse_truthsocial_response(response)
assert len(items) == 1 self.assertEqual(len(items), 1)
assert items[0]["handle"] == "" self.assertEqual(items[0]["handle"], "")
assert items[0]["text"] == "" self.assertEqual(items[0]["text"], "")
assert items[0]["engagement"]["likes"] == 0 self.assertEqual(items[0]["engagement"]["likes"], 0)
def test_relevance_ordering(self): def test_relevance_ordering(self):
response = { response = {
@@ -206,8 +210,8 @@ class TestParseTruthSocialResponse:
] ]
} }
items = truthsocial.parse_truthsocial_response(response) items = truthsocial.parse_truthsocial_response(response)
assert items[0]["relevance"] >= items[1]["relevance"] self.assertGreaterEqual(items[0]["relevance"], items[1]["relevance"])
assert items[1]["relevance"] >= items[2]["relevance"] self.assertGreaterEqual(items[1]["relevance"], items[2]["relevance"])
def test_html_stripping_in_parse(self): def test_html_stripping_in_parse(self):
response = { response = {
@@ -222,5 +226,9 @@ class TestParseTruthSocialResponse:
] ]
} }
items = truthsocial.parse_truthsocial_response(response) items = truthsocial.parse_truthsocial_response(response)
assert "<" not in items[0]["text"] self.assertNotIn("<", items[0]["text"])
assert ">" not in items[0]["text"] self.assertNotIn(">", items[0]["text"])
if __name__ == "__main__":
unittest.main()