返回 last30days-skill
test_providers_v3.py
根目录 / tests / test_providers_v3.py
1 import json
2 import unittest
3 from typing import get_args
4
5 from lib import env
6 from lib import providers
7
8
9 class ProvidersV3Tests(unittest.TestCase):
10 def test_auto_prefers_gemini_with_google_key(self):
11 runtime, client = providers.resolve_runtime(
12 {"GOOGLE_API_KEY": "test", "LAST30DAYS_REASONING_PROVIDER": "auto"},
13 depth="default",
14 )
15 self.assertEqual("gemini", runtime.reasoning_provider)
16 self.assertEqual("gemini", client.name)
17 self.assertTrue(runtime.planner_model.startswith("gemini-3.1-"))
18
19 def test_auto_falls_back_to_openai(self):
20 runtime, client = providers.resolve_runtime(
21 {
22 "OPENAI_API_KEY": "test-key",
23 "OPENAI_AUTH_STATUS": "ok",
24 "LAST30DAYS_REASONING_PROVIDER": "auto",
25 },
26 depth="default",
27 )
28 self.assertEqual("openai", runtime.reasoning_provider)
29
30 def test_auto_falls_back_to_xai(self):
31 runtime, client = providers.resolve_runtime(
32 {"XAI_API_KEY": "test-key", "LAST30DAYS_REASONING_PROVIDER": "auto"},
33 depth="default",
34 )
35 self.assertEqual("xai", runtime.reasoning_provider)
36
37 def test_auto_returns_local_runtime_when_no_keys(self):
38 runtime, client = providers.resolve_runtime(
39 {"LAST30DAYS_REASONING_PROVIDER": "auto"},
40 depth="default",
41 )
42 self.assertEqual("local", runtime.reasoning_provider)
43 self.assertEqual("deterministic", runtime.planner_model)
44 self.assertEqual("local-score", runtime.rerank_model)
45 self.assertIsNone(client)
46
47 def test_explicit_gemini_without_key_still_raises(self):
48 with self.assertRaises(RuntimeError):
49 providers.resolve_runtime(
50 {"LAST30DAYS_REASONING_PROVIDER": "gemini"},
51 depth="default",
52 )
53
54 def test_explicit_openai_without_key_still_raises(self):
55 with self.assertRaises(RuntimeError):
56 providers.resolve_runtime(
57 {"LAST30DAYS_REASONING_PROVIDER": "openai"},
58 depth="default",
59 )
60
61 def test_explicit_xai_without_key_still_raises(self):
62 with self.assertRaises(RuntimeError):
63 providers.resolve_runtime(
64 {"LAST30DAYS_REASONING_PROVIDER": "xai"},
65 depth="default",
66 )
67
68 def test_codex_auth_is_not_supported_as_openai_provider_auth(self):
69 self.assertNotIn("codex", get_args(env.AuthSource))
70 self.assertFalse(hasattr(env, "AUTH_SOURCE_CODEX"))
71
72 def test_openai_provider_has_no_chatgpt_backend_route(self):
73 self.assertFalse(hasattr(providers, "CODEX_RESPONSES_URL"))
74 with self.assertRaises(TypeError):
75 providers.OpenAIClient("token", "codex", "acct")
76
77
78 class TestExtractJson(unittest.TestCase):
79 def test_direct_json(self):
80 result = providers.extract_json('{"scores": [1, 2]}')
81 self.assertEqual(result, {"scores": [1, 2]})
82
83 def test_json_in_markdown_fences(self):
84 text = '```json\n{"scores": [1, 2]}\n```'
85 result = providers.extract_json(text)
86 self.assertEqual(result, {"scores": [1, 2]})
87
88 def test_json_with_surrounding_text(self):
89 text = 'Here is the result:\n{"scores": [1]}\nDone.'
90 result = providers.extract_json(text)
91 self.assertEqual(result, {"scores": [1]})
92
93 def test_empty_text_raises(self):
94 with self.assertRaises(ValueError):
95 providers.extract_json("")
96
97 def test_no_json_raises(self):
98 with self.assertRaises(json.JSONDecodeError):
99 providers.extract_json("no json here at all")
100
101
102 class TestExtractOpenAIText(unittest.TestCase):
103 def test_output_text_field(self):
104 self.assertEqual("hello", providers.extract_openai_text({"output_text": "hello"}))
105
106 def test_choices_message_content(self):
107 payload = {"choices": [{"message": {"content": "world"}}]}
108 self.assertEqual("world", providers.extract_openai_text(payload))
109
110 def test_output_list_text(self):
111 payload = {"output": [{"text": "foo"}]}
112 self.assertEqual("foo", providers.extract_openai_text(payload))
113
114 def test_output_content_output_text_type(self):
115 payload = {"output": [{"content": [{"type": "output_text", "text": "bar"}]}]}
116 self.assertEqual("bar", providers.extract_openai_text(payload))
117
118 def test_output_string_item(self):
119 payload = {"output": ["direct string"]}
120 self.assertEqual("direct string", providers.extract_openai_text(payload))
121
122 def test_empty_payload_returns_empty(self):
123 self.assertEqual("", providers.extract_openai_text({}))
124
125
126 class TestExtractGeminiText(unittest.TestCase):
127 def test_standard_response(self):
128 payload = {"candidates": [{"content": {"parts": [{"text": "gemini says"}]}}]}
129 self.assertEqual("gemini says", providers.extract_gemini_text(payload))
130
131 def test_empty_candidates(self):
132 self.assertEqual("", providers.extract_gemini_text({"candidates": []}))
133
134 def test_empty_payload(self):
135 self.assertEqual("", providers.extract_gemini_text({}))
136
137
138 if __name__ == "__main__":
139 unittest.main()
140
140 lines PYTHON