返回 last30days-skill
test_cli_competitors.py
根目录 / tests / test_cli_competitors.py
1 """CLI parsing and validation for --competitors / --competitors-list."""
2
3 from __future__ import annotations
4
5 import io
6 import unittest
7 from contextlib import redirect_stderr
8
9 import last30days as cli
10
11
12 def _parse(*argv: str):
13 parser = cli.build_parser()
14 args, _extra = parser.parse_known_args(argv)
15 return args
16
17
18 class CompetitorsCliTests(unittest.TestCase):
19 def test_flag_absent_returns_disabled(self):
20 args = _parse("Kanye West")
21 enabled, count, explicit = cli.resolve_competitors_args(args)
22 self.assertFalse(enabled)
23 self.assertEqual(count, 0)
24 self.assertEqual(explicit, [])
25
26 def test_bare_flag_defaults_to_two(self):
27 args = _parse("Kanye West", "--competitors")
28 enabled, count, explicit = cli.resolve_competitors_args(args)
29 self.assertTrue(enabled)
30 self.assertEqual(count, 2)
31 self.assertEqual(explicit, [])
32
33 def test_explicit_three_still_supported(self):
34 args = _parse("OpenAI", "--competitors", "3")
35 enabled, count, _explicit = cli.resolve_competitors_args(args)
36 self.assertTrue(enabled)
37 self.assertEqual(count, 3)
38
39 def test_explicit_count(self):
40 args = _parse("OpenAI", "--competitors", "4")
41 enabled, count, explicit = cli.resolve_competitors_args(args)
42 self.assertTrue(enabled)
43 self.assertEqual(count, 4)
44 self.assertEqual(explicit, [])
45
46 def test_explicit_list_preferred_over_discovery(self):
47 args = _parse(
48 "OpenAI",
49 "--competitors",
50 "--competitors-list",
51 "Anthropic,xAI,Google Gemini",
52 )
53 enabled, count, explicit = cli.resolve_competitors_args(args)
54 self.assertTrue(enabled)
55 self.assertEqual(count, 3)
56 self.assertEqual(explicit, ["Anthropic", "xAI", "Google Gemini"])
57
58 def test_explicit_list_without_flag_implies_enabled(self):
59 args = _parse("OpenAI", "--competitors-list", "Anthropic,xAI")
60 enabled, count, explicit = cli.resolve_competitors_args(args)
61 self.assertTrue(enabled)
62 self.assertEqual(count, 2)
63 self.assertEqual(explicit, ["Anthropic", "xAI"])
64
65 def test_list_whitespace_normalized(self):
66 args = _parse("OpenAI", "--competitors-list", " Anthropic , xAI , Gemini ")
67 _enabled, count, explicit = cli.resolve_competitors_args(args)
68 self.assertEqual(count, 3)
69 self.assertEqual(explicit, ["Anthropic", "xAI", "Gemini"])
70
71 def test_zero_count_rejected(self):
72 args = _parse("Topic", "--competitors", "0")
73 with self.assertRaises(SystemExit) as cm, redirect_stderr(io.StringIO()) as err:
74 cli.resolve_competitors_args(args)
75 self.assertEqual(cm.exception.code, 2)
76 self.assertIn("--competitors must be >= 1", err.getvalue())
77
78 def test_negative_count_rejected(self):
79 args = _parse("Topic", "--competitors", "-1")
80 with self.assertRaises(SystemExit), redirect_stderr(io.StringIO()):
81 cli.resolve_competitors_args(args)
82
83 def test_over_max_count_clamps_with_warning(self):
84 args = _parse("Topic", "--competitors", "99")
85 err = io.StringIO()
86 with redirect_stderr(err):
87 enabled, count, explicit = cli.resolve_competitors_args(args)
88 self.assertTrue(enabled)
89 self.assertEqual(count, cli.COMPETITORS_MAX)
90 self.assertEqual(explicit, [])
91 self.assertIn("clamping", err.getvalue())
92
93 def test_overlong_list_clamps_with_warning(self):
94 args = _parse(
95 "Topic",
96 "--competitors-list",
97 "A,B,C,D,E,F,G,H",
98 )
99 err = io.StringIO()
100 with redirect_stderr(err):
101 enabled, count, explicit = cli.resolve_competitors_args(args)
102 self.assertTrue(enabled)
103 self.assertEqual(count, cli.COMPETITORS_MAX)
104 self.assertEqual(len(explicit), cli.COMPETITORS_MAX)
105 self.assertIn("clamping to", err.getvalue())
106
107 def test_list_count_mismatch_warns(self):
108 args = _parse(
109 "Topic",
110 "--competitors",
111 "5",
112 "--competitors-list",
113 "A,B",
114 )
115 err = io.StringIO()
116 with redirect_stderr(err):
117 enabled, count, explicit = cli.resolve_competitors_args(args)
118 self.assertTrue(enabled)
119 self.assertEqual(count, 2)
120 self.assertEqual(explicit, ["A", "B"])
121 self.assertIn("--competitors=5 ignored", err.getvalue())
122
123 def test_empty_list_rejected(self):
124 args = _parse("Topic", "--competitors-list", ",, ,")
125 with self.assertRaises(SystemExit) as cm, redirect_stderr(io.StringIO()):
126 cli.resolve_competitors_args(args)
127 self.assertEqual(cm.exception.code, 2)
128
129 if __name__ == "__main__":
130 unittest.main()
131
131 lines PYTHON