@@ -181,6 +181,125 @@ def test_filter_by_search_term_with_multiple_terms(platform: Platform):
181181 assert actual_rom_ids_single == expected_rom_ids_single
182182
183183
184+ def test_sibling_roms_empty_fs_name_no_tags_not_matched (platform : Platform ):
185+ """ROMs with empty fs_name_no_tags should NOT be matched as siblings.
186+
187+ Japanese ROMs often have names starting with region tags (e.g., "(Japan) Sonic Jam.iso"),
188+ which results in an empty fs_name_no_tags. Without a guard, all such ROMs on the same
189+ platform would incorrectly be matched as siblings of each other.
190+ """
191+ rom1 = db_rom_handler .add_rom (
192+ Rom (
193+ platform_id = platform .id ,
194+ name = "(Japan) Game A" ,
195+ slug = "japan-game-a" ,
196+ fs_name = "(Japan) Game A.iso" ,
197+ fs_name_no_tags = "" , # Empty due to leading region tag
198+ fs_name_no_ext = "(Japan) Game A" ,
199+ fs_extension = "iso" ,
200+ fs_path = f"{ platform .slug } /roms" ,
201+ )
202+ )
203+ rom2 = db_rom_handler .add_rom (
204+ Rom (
205+ platform_id = platform .id ,
206+ name = "(Japan) Game B" ,
207+ slug = "japan-game-b" ,
208+ fs_name = "(Japan) Game B.iso" ,
209+ fs_name_no_tags = "" , # Empty due to leading region tag
210+ fs_name_no_ext = "(Japan) Game B" ,
211+ fs_extension = "iso" ,
212+ fs_path = f"{ platform .slug } /roms" ,
213+ )
214+ )
215+
216+ loaded_rom1 = db_rom_handler .get_rom (rom1 .id )
217+ loaded_rom2 = db_rom_handler .get_rom (rom2 .id )
218+ assert loaded_rom1 is not None
219+ assert loaded_rom2 is not None
220+
221+ # ROMs with empty fs_name_no_tags should NOT be siblings of each other
222+ sibling_ids1 = {s .id for s in loaded_rom1 .sibling_roms }
223+ sibling_ids2 = {s .id for s in loaded_rom2 .sibling_roms }
224+ assert rom2 .id not in sibling_ids1
225+ assert rom1 .id not in sibling_ids2
226+
227+
228+ def test_sibling_roms_nonempty_fs_name_no_tags_matched (platform : Platform ):
229+ """ROMs with matching non-empty fs_name_no_tags SHOULD be matched as siblings.
230+
231+ For example, "Sonic Jam (USA).iso" and "Sonic Jam (Japan).iso" both have
232+ fs_name_no_tags = "Sonic Jam" and should be considered siblings.
233+ """
234+ rom1 = db_rom_handler .add_rom (
235+ Rom (
236+ platform_id = platform .id ,
237+ name = "Sonic Jam (USA)" ,
238+ slug = "sonic-jam-usa" ,
239+ fs_name = "Sonic Jam (USA).iso" ,
240+ fs_name_no_tags = "Sonic Jam" ,
241+ fs_name_no_ext = "Sonic Jam (USA)" ,
242+ fs_extension = "iso" ,
243+ fs_path = f"{ platform .slug } /roms" ,
244+ )
245+ )
246+ rom2 = db_rom_handler .add_rom (
247+ Rom (
248+ platform_id = platform .id ,
249+ name = "Sonic Jam (Japan)" ,
250+ slug = "sonic-jam-japan" ,
251+ fs_name = "Sonic Jam (Japan).iso" ,
252+ fs_name_no_tags = "Sonic Jam" ,
253+ fs_name_no_ext = "Sonic Jam (Japan)" ,
254+ fs_extension = "iso" ,
255+ fs_path = f"{ platform .slug } /roms" ,
256+ )
257+ )
258+
259+ loaded_rom1 = db_rom_handler .get_rom (rom1 .id )
260+ loaded_rom2 = db_rom_handler .get_rom (rom2 .id )
261+ assert loaded_rom1 is not None
262+ assert loaded_rom2 is not None
263+
264+ # ROMs with same non-empty fs_name_no_tags should be siblings
265+ sibling_ids1 = {s .id for s in loaded_rom1 .sibling_roms }
266+ sibling_ids2 = {s .id for s in loaded_rom2 .sibling_roms }
267+ assert rom2 .id in sibling_ids1
268+ assert rom1 .id in sibling_ids2
269+
270+
271+ def test_group_by_meta_id_with_empty_fs_name_no_tags (platform : Platform ):
272+ """ROMs with empty fs_name_no_tags should each get their own group when using
273+ group_by_meta_id, not be grouped into a single catch-all group.
274+
275+ Without the fix, all unmatched ROMs with empty fs_name_no_tags would be
276+ grouped under "fs-<platform_id>-" and only 1 would be shown.
277+ """
278+ rom_names = ["(Japan) Game A" , "(Japan) Game B" , "(Japan) Game C" ]
279+ for name in rom_names :
280+ db_rom_handler .add_rom (
281+ Rom (
282+ platform_id = platform .id ,
283+ name = name ,
284+ slug = name .lower ().replace (" " , "-" ).replace ("(" , "" ).replace (")" , "" ),
285+ fs_name = f"{ name } .iso" ,
286+ fs_name_no_tags = "" , # Empty due to leading region tag
287+ fs_name_no_ext = name ,
288+ fs_extension = "iso" ,
289+ fs_path = f"{ platform .slug } /roms" ,
290+ )
291+ )
292+
293+ roms = db_rom_handler .get_roms_scalar (
294+ platform_ids = [platform .id ],
295+ order_by = "name" ,
296+ order_dir = "asc" ,
297+ group_by_meta_id = True ,
298+ )
299+ # All 3 ROMs should be shown, not collapsed into 1
300+ assert len (roms ) == len (rom_names )
301+
302+
184303def test_natural_sort_order (platform : Platform ):
185304 """Numbers in names should sort numerically, not lexicographically."""
186305 for name in ["Game 10" , "Game 2" , "Game 1" ]:
0 commit comments