11import datetime
22import sqlite3
33import unittest
4- from unittest .mock import patch
4+ from unittest .mock import Mock , patch
5+
6+ from click .testing import CliRunner
57
68from tests import load_resource
9+ from tibiawikisql import __main__ as cli_module
10+ from tibiawikisql import generation as generation_module
711from tibiawikisql .api import Article
8- from tibiawikisql .generation import (
9- WEAPON_PROFICIENCY_NAME_ARTICLE ,
10- WEAPON_PROFICIENCY_TABLES_ARTICLE ,
11- generate_item_proficiency_perks ,
12- wiki_client ,
13- )
12+ from tibiawikisql .generation import WEAPON_PROFICIENCY_NAME_ARTICLE , WEAPON_PROFICIENCY_TABLES_ARTICLE
1413from tibiawikisql .schema import ItemProficiencyPerkTable , ItemTable
14+ from tibiawikisql .tasks .item_proficiency_perks import generate_item_proficiency_perks
15+ from tibiawikisql .tasks .loot_statistics import generate_loot_statistics
1516
1617
1718class TestGeneration (unittest .TestCase ):
@@ -46,11 +47,18 @@ def test_generate_item_proficiency_perks(self):
4647 )
4748 data_store = {"items_map" : {"amber axe" : 1 , "amber cudgel" : 2 }}
4849
49- with (
50- patch .object (wiki_client , "get_article" , side_effect = [mapping_article , tables_article ]),
51- patch ("tibiawikisql.generation.click.echo" ) as mock_echo ,
52- ):
53- generate_item_proficiency_perks (self .conn , data_store )
50+ wiki_client = Mock ()
51+ wiki_client .get_article .side_effect = [mapping_article , tables_article ]
52+ mock_echo = Mock ()
53+ generate_item_proficiency_perks (
54+ self .conn ,
55+ data_store ,
56+ wiki_client = wiki_client ,
57+ mapping_article_title = WEAPON_PROFICIENCY_NAME_ARTICLE ,
58+ tables_article_title = WEAPON_PROFICIENCY_TABLES_ARTICLE ,
59+ timed = generation_module .timed ,
60+ echo = mock_echo ,
61+ )
5462
5563 rows = self .conn .execute (
5664 "SELECT item_id, proficiency_level, skill_image, icon, effect "
@@ -91,11 +99,18 @@ def test_generate_item_proficiency_perks_warn_and_continue(self):
9199 )
92100 data_store = {"items_map" : {"amber axe" : 1 , "amber cudgel" : 2 }}
93101
94- with (
95- patch .object (wiki_client , "get_article" , side_effect = [mapping_article , tables_article ]),
96- patch ("tibiawikisql.generation.click.echo" ) as mock_echo ,
97- ):
98- generate_item_proficiency_perks (self .conn , data_store )
102+ wiki_client = Mock ()
103+ wiki_client .get_article .side_effect = [mapping_article , tables_article ]
104+ mock_echo = Mock ()
105+ generate_item_proficiency_perks (
106+ self .conn ,
107+ data_store ,
108+ wiki_client = wiki_client ,
109+ mapping_article_title = WEAPON_PROFICIENCY_NAME_ARTICLE ,
110+ tables_article_title = WEAPON_PROFICIENCY_TABLES_ARTICLE ,
111+ timed = generation_module .timed ,
112+ echo = mock_echo ,
113+ )
99114
100115 rows = self .conn .execute (
101116 "SELECT item_id, proficiency_level, skill_image, icon, effect FROM item_proficiency_perk" ,
@@ -118,20 +133,31 @@ def get_article_side_effect(title: str) -> Article | None:
118133 return mapping_article
119134 return None
120135
121- with (
122- patch .object (wiki_client , "get_article" , side_effect = get_article_side_effect ) as mock_get_article ,
123- patch ("tibiawikisql.generation.click.echo" ) as mock_echo ,
124- ):
125- generate_item_proficiency_perks (self .conn , data_store )
136+ wiki_client = Mock ()
137+ wiki_client .get_article .side_effect = get_article_side_effect
138+ mock_echo = Mock ()
139+ generate_item_proficiency_perks (
140+ self .conn ,
141+ data_store ,
142+ wiki_client = wiki_client ,
143+ mapping_article_title = WEAPON_PROFICIENCY_NAME_ARTICLE ,
144+ tables_article_title = WEAPON_PROFICIENCY_TABLES_ARTICLE ,
145+ timed = generation_module .timed ,
146+ echo = mock_echo ,
147+ )
126148
127149 rows = self .conn .execute ("SELECT COUNT(*) FROM item_proficiency_perk" ).fetchone ()
128150 self .assertEqual (0 , rows [0 ])
129151 self .assertEqual (
130- [WEAPON_PROFICIENCY_NAME_ARTICLE , WEAPON_PROFICIENCY_TABLES_ARTICLE ],
131- [call .args [0 ] for call in mock_get_article .call_args_list ],
152+ [
153+ WEAPON_PROFICIENCY_NAME_ARTICLE ,
154+ WEAPON_PROFICIENCY_TABLES_ARTICLE ,
155+ ],
156+ [call .args [0 ] for call in wiki_client .get_article .call_args_list ],
132157 )
133158 messages = " " .join (call .args [0 ] for call in mock_echo .call_args_list if call .args )
134159 self .assertIn ("Could not fetch weapon proficiency pages" , messages )
160+ self .assertIn (WEAPON_PROFICIENCY_TABLES_ARTICLE , messages )
135161
136162 def test_generate_item_proficiency_perks_case_insensitive_section_match (self ):
137163 timestamp = datetime .datetime .fromisoformat ("2024-01-01T00:00:00+00:00" )
@@ -154,13 +180,122 @@ def test_generate_item_proficiency_perks_case_insensitive_section_match(self):
154180 )
155181 data_store = {"items_map" : {"stale bread of ancientness" : 3 }}
156182
157- with (
158- patch .object (wiki_client , "get_article" , side_effect = [mapping_article , tables_article ]),
159- patch ("tibiawikisql.generation.click.echo" ),
160- ):
161- generate_item_proficiency_perks (self .conn , data_store )
183+ wiki_client = Mock ()
184+ wiki_client .get_article .side_effect = [mapping_article , tables_article ]
185+ generate_item_proficiency_perks (
186+ self .conn ,
187+ data_store ,
188+ wiki_client = wiki_client ,
189+ mapping_article_title = WEAPON_PROFICIENCY_NAME_ARTICLE ,
190+ tables_article_title = WEAPON_PROFICIENCY_TABLES_ARTICLE ,
191+ timed = generation_module .timed ,
192+ echo = Mock (),
193+ )
162194
163195 rows = self .conn .execute (
164196 "SELECT item_id, proficiency_level, skill_image, icon, effect FROM item_proficiency_perk" ,
165197 ).fetchall ()
166198 self .assertEqual ([(3 , 1 , "Club Skill Bonus" , None , "+1 Club Fighting" )], [tuple (row ) for row in rows ])
199+
200+
201+ class TestGenerationOrchestration (unittest .TestCase ):
202+ def setUp (self ):
203+ self .conn = sqlite3 .connect (":memory:" )
204+
205+ def tearDown (self ):
206+ self .conn .close ()
207+
208+ def test_skip_category_excludes_fetch_and_parse (self ):
209+ with (
210+ patch ("tibiawikisql.generation.fetch_category_entries" , return_value = []) as mock_fetch ,
211+ patch .object (generation_module .wiki_client , "get_articles" , return_value = []) as mock_get_articles ,
212+ patch ("tibiawikisql.generation.POST_TASKS" , ()),
213+ ):
214+ generation_module .generate (self .conn , skip_categories = ("achievements" ,))
215+
216+ fetched_categories = [call .args [0 ] for call in mock_fetch .call_args_list ]
217+ self .assertNotIn ("Achievements" , fetched_categories )
218+ self .assertEqual (len (generation_module .CATEGORIES ) - 1 , len (mock_get_articles .call_args_list ))
219+
220+ def test_hard_dependencies_auto_skip_categories (self ):
221+ with (
222+ patch ("tibiawikisql.generation.fetch_category_entries" , return_value = []) as mock_fetch ,
223+ patch .object (generation_module .wiki_client , "get_articles" , return_value = []),
224+ patch ("tibiawikisql.generation.POST_TASKS" , ()),
225+ patch ("tibiawikisql.generation.click.echo" ) as mock_echo ,
226+ ):
227+ generation_module .generate (self .conn , skip_categories = ("items" ,))
228+
229+ fetched_categories = [call .args [0 ] for call in mock_fetch .call_args_list ]
230+ self .assertNotIn ("Objects" , fetched_categories )
231+ self .assertNotIn ("Keys" , fetched_categories )
232+ messages = " " .join (call .args [0 ] for call in mock_echo .call_args_list if call .args )
233+ self .assertIn ("Skipping category 'keys'" , messages )
234+
235+ def test_post_tasks_are_gated_by_enabled_categories (self ):
236+ gated_task = Mock ()
237+ always_task = Mock ()
238+ post_tasks = (
239+ generation_module .PostTask ("needs_items" , lambda * _ : gated_task (), dependencies = ("items" ,)),
240+ generation_module .PostTask ("always_runs" , lambda * _ : always_task ()),
241+ )
242+ with (
243+ patch ("tibiawikisql.generation.fetch_category_entries" , return_value = []),
244+ patch .object (generation_module .wiki_client , "get_articles" , return_value = []),
245+ patch ("tibiawikisql.generation.POST_TASKS" , post_tasks ),
246+ patch ("tibiawikisql.generation.click.echo" ) as mock_echo ,
247+ ):
248+ generation_module .generate (self .conn , skip_categories = ("items" ,))
249+
250+ gated_task .assert_not_called ()
251+ always_task .assert_called_once_with ()
252+ messages = " " .join (call .args [0 ] for call in mock_echo .call_args_list if call .args )
253+ self .assertIn ("Skipping task 'needs_items'" , messages )
254+
255+ def test_generate_loot_statistics_early_return_without_maps (self ):
256+ wiki_client = Mock ()
257+ generate_loot_statistics (
258+ self .conn ,
259+ {},
260+ wiki_client = wiki_client ,
261+ progress_bar = generation_module .progress_bar ,
262+ article_label = generation_module .article_label ,
263+ timed = generation_module .timed ,
264+ echo = Mock (),
265+ )
266+ wiki_client .get_articles .assert_not_called ()
267+
268+
269+ class TestGenerateCommand (unittest .TestCase ):
270+ def setUp (self ):
271+ self .runner = CliRunner ()
272+
273+ def test_skip_category_option_is_passed_to_generate (self ):
274+ with patch ("tibiawikisql.__main__.generation.generate" ) as mock_generate :
275+ result = self .runner .invoke (
276+ cli_module .cli ,
277+ [
278+ "generate" ,
279+ "--db-name" ,
280+ ":memory:" ,
281+ "--skip-category" ,
282+ "achievements" ,
283+ "--skip-category" ,
284+ "items" ,
285+ ],
286+ )
287+ self .assertEqual (0 , result .exit_code , result .output )
288+ self .assertEqual (("achievements" , "items" ), mock_generate .call_args .kwargs ["skip_categories" ])
289+
290+ def test_skip_category_rejects_invalid_value (self ):
291+ result = self .runner .invoke (
292+ cli_module .cli ,
293+ [
294+ "generate" ,
295+ "--skip-category" ,
296+ "invalid-category" ,
297+ ],
298+ )
299+ self .assertNotEqual (0 , result .exit_code )
300+ self .assertIn ("Invalid value" , result .output )
301+ self .assertIn ("--skip-category" , result .output )
0 commit comments