mirror of
https://github.com/rommapp/romm.git
synced 2026-05-04 00:01:30 +08:00
312 lines
11 KiB
Python
312 lines
11 KiB
Python
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
import socketio
|
|
|
|
from endpoints.sockets.scan import ScanStats, _should_scan_rom
|
|
from handler.filesystem.roms_handler import FSRomsHandler
|
|
from handler.metadata.base_handler import UniversalPlatformSlug as UPS
|
|
from handler.scan_handler import ScanType
|
|
from models.rom import Rom
|
|
|
|
|
|
def test_scan_stats():
|
|
stats = ScanStats()
|
|
assert stats.scanned_platforms == 0
|
|
assert stats.new_platforms == 0
|
|
assert stats.identified_platforms == 0
|
|
assert stats.scanned_roms == 0
|
|
assert stats.new_roms == 0
|
|
assert stats.identified_roms == 0
|
|
assert stats.scanned_firmware == 0
|
|
assert stats.new_firmware == 0
|
|
|
|
stats.scanned_platforms += 1
|
|
stats.new_platforms += 1
|
|
stats.identified_platforms += 1
|
|
stats.scanned_roms += 1
|
|
stats.new_roms += 1
|
|
stats.identified_roms += 1
|
|
stats.scanned_firmware += 1
|
|
stats.new_firmware += 1
|
|
|
|
assert stats.scanned_platforms == 1
|
|
assert stats.new_platforms == 1
|
|
assert stats.identified_platforms == 1
|
|
assert stats.scanned_roms == 1
|
|
assert stats.new_roms == 1
|
|
assert stats.identified_roms == 1
|
|
assert stats.scanned_firmware == 1
|
|
assert stats.new_firmware == 1
|
|
|
|
|
|
async def test_merging_scan_stats():
|
|
stats = ScanStats(
|
|
scanned_platforms=1,
|
|
new_platforms=2,
|
|
identified_platforms=3,
|
|
scanned_roms=4,
|
|
new_roms=5,
|
|
identified_roms=6,
|
|
scanned_firmware=7,
|
|
new_firmware=8,
|
|
)
|
|
|
|
await stats.update(
|
|
socket_manager=Mock(spec=socketio.AsyncRedisManager),
|
|
scanned_platforms=stats.scanned_platforms + 10,
|
|
new_platforms=stats.new_platforms + 11,
|
|
identified_platforms=stats.identified_platforms + 12,
|
|
scanned_roms=stats.scanned_roms + 13,
|
|
new_roms=stats.new_roms + 14,
|
|
identified_roms=stats.identified_roms + 15,
|
|
scanned_firmware=stats.scanned_firmware + 16,
|
|
new_firmware=stats.new_firmware + 17,
|
|
)
|
|
|
|
assert stats.scanned_platforms == 11
|
|
assert stats.new_platforms == 13
|
|
assert stats.identified_platforms == 15
|
|
assert stats.scanned_roms == 17
|
|
assert stats.new_roms == 19
|
|
assert stats.identified_roms == 21
|
|
assert stats.scanned_firmware == 23
|
|
assert stats.new_firmware == 25
|
|
|
|
|
|
class TestShouldScanRom:
|
|
def test_new_platforms_scan_with_no_rom(self):
|
|
"""NEW_PLATFORMS should scan when rom is None"""
|
|
result = _should_scan_rom(ScanType.NEW_PLATFORMS, None, [], ["igdb"])
|
|
assert result is True
|
|
|
|
def test_new_platforms_scan_with_existing_rom(self, rom: Rom):
|
|
"""NEW_PLATFORMS should not scan when rom exists"""
|
|
result = _should_scan_rom(ScanType.NEW_PLATFORMS, rom, [], ["igdb"])
|
|
assert result is False
|
|
|
|
# Test QUICK scan type
|
|
def test_quick_scan_with_no_rom(self):
|
|
"""QUICK should scan when rom is None"""
|
|
result = _should_scan_rom(ScanType.QUICK, None, [], ["igdb"])
|
|
assert result is True
|
|
|
|
def test_quick_scan_with_existing_rom(self, rom: Rom):
|
|
"""QUICK should not scan when rom exists"""
|
|
result = _should_scan_rom(ScanType.QUICK, rom, [], ["igdb"])
|
|
assert result is False
|
|
|
|
# Test COMPLETE scan type
|
|
def test_complete_scan_always_scans(self, rom: Rom):
|
|
"""COMPLETE should always scan regardless of rom state"""
|
|
assert _should_scan_rom(ScanType.COMPLETE, None, [], ["igdb"]) is True
|
|
assert _should_scan_rom(ScanType.COMPLETE, rom, [], ["igdb"]) is True
|
|
assert _should_scan_rom(ScanType.COMPLETE, rom, [2, 3], ["igdb"]) is True
|
|
|
|
# Test HASHES scan type
|
|
def test_hashes_scan_always_scans(self, rom: Rom):
|
|
"""HASHES should always scan regardless of rom state"""
|
|
assert _should_scan_rom(ScanType.HASHES, None, [], ["igdb"]) is True
|
|
assert _should_scan_rom(ScanType.HASHES, rom, [], ["igdb"]) is True
|
|
assert _should_scan_rom(ScanType.HASHES, rom, [2, 3], ["igdb"]) is True
|
|
|
|
# Test UNMATCHED scan type
|
|
def test_unmatched_scan_with_no_rom(self):
|
|
"""UNMATCHED should not scan when rom is None"""
|
|
result = _should_scan_rom(ScanType.UNMATCHED, None, [], ["igdb"])
|
|
assert result is False
|
|
|
|
def test_unmatched_scan_with_unmatched_rom(self, rom: Rom):
|
|
"""UNMATCHED should scan when rom is unmatched"""
|
|
rom.igdb_id = None
|
|
rom.moby_id = None
|
|
rom.ss_id = None
|
|
rom.ra_id = None
|
|
rom.launchbox_id = None
|
|
result = _should_scan_rom(ScanType.UNMATCHED, rom, [], ["igdb"])
|
|
assert result is True
|
|
|
|
def test_unmatched_scan_with_identified_rom(self, rom: Rom):
|
|
"""UNMATCHED should also scan when rom is identified"""
|
|
rom.igdb_id = 1
|
|
result = _should_scan_rom(ScanType.UNMATCHED, rom, [], ["moby"])
|
|
assert result is True
|
|
|
|
# Test UPDATE scan type
|
|
def test_update_scan_with_no_rom(self):
|
|
"""UPDATE should not scan when rom is None"""
|
|
result = _should_scan_rom(ScanType.UPDATE, None, [], ["igdb"])
|
|
assert result is False
|
|
|
|
def test_update_scan_with_identified_rom(self, rom: Rom):
|
|
"""UPDATE should scan when rom is identified"""
|
|
rom.igdb_id = 1
|
|
result = _should_scan_rom(ScanType.UPDATE, rom, [], ["igdb"])
|
|
assert result is True
|
|
|
|
def test_update_scan_with_unmatched_rom(self, rom: Rom):
|
|
"""UPDATE should not scan when rom is not identified"""
|
|
rom.igdb_id = None
|
|
rom.moby_id = None
|
|
rom.ss_id = None
|
|
rom.ra_id = None
|
|
rom.launchbox_id = None
|
|
result = _should_scan_rom(ScanType.UPDATE, rom, [], ["igdb"])
|
|
assert result is False
|
|
|
|
# Test rom_ids parameter
|
|
def test_scan_when_rom_id_in_list(self, rom: Rom):
|
|
"""Should scan when rom.id is in roms_ids list regardless of scan type"""
|
|
rom.id = 1
|
|
roms_ids = [1, 2, 3]
|
|
|
|
# Test with different scan types
|
|
for scan_type in [
|
|
ScanType.QUICK,
|
|
ScanType.UNMATCHED,
|
|
ScanType.UPDATE,
|
|
]:
|
|
result = _should_scan_rom(scan_type, rom, roms_ids, ["igdb"])
|
|
assert result is True
|
|
|
|
def test_no_scan_when_rom_id_not_in_list(self, rom: Rom):
|
|
"""Should follow normal rules when rom.id is not in roms_ids list"""
|
|
rom.id = 4
|
|
roms_ids = [1, 2, 3]
|
|
|
|
# These should not scan because rom exists and id not in list
|
|
assert (
|
|
_should_scan_rom(ScanType.NEW_PLATFORMS, rom, roms_ids, ["igdb"]) is False
|
|
)
|
|
assert _should_scan_rom(ScanType.QUICK, rom, roms_ids, ["igdb"]) is False
|
|
assert _should_scan_rom(ScanType.UPDATE, rom, roms_ids, ["igdb"]) is False
|
|
assert _should_scan_rom(ScanType.UNMATCHED, rom, roms_ids, ["igdb"]) is True
|
|
|
|
# Edge cases
|
|
def test_empty_roms_ids_list(self, rom: Rom):
|
|
"""Test behavior with empty roms_ids list"""
|
|
rom.id = 1
|
|
rom.igdb_id = 1
|
|
|
|
assert _should_scan_rom(ScanType.UPDATE, rom, [], ["igdb"]) is True
|
|
assert _should_scan_rom(ScanType.NEW_PLATFORMS, rom, [], ["igdb"]) is False
|
|
|
|
def test_rom_id_type_conversion(self, rom: Rom):
|
|
"""Test that rom.id (int) is properly compared with roms_ids (list of strings)"""
|
|
rom.id = 123
|
|
roms_ids = [123, 456]
|
|
|
|
# This should scan because 123 should match "123"
|
|
result = _should_scan_rom(ScanType.QUICK, rom, roms_ids, ["igdb"])
|
|
assert result is True
|
|
|
|
@pytest.mark.parametrize(
|
|
"scan_type,rom_exists,is_identified,rom_in_list,expected",
|
|
[
|
|
# Comprehensive test matrix
|
|
(ScanType.NEW_PLATFORMS, False, None, False, False),
|
|
(ScanType.NEW_PLATFORMS, True, True, False, False),
|
|
(ScanType.NEW_PLATFORMS, True, True, True, True),
|
|
(ScanType.QUICK, False, None, False, False),
|
|
(ScanType.QUICK, True, True, False, False),
|
|
(ScanType.COMPLETE, False, None, False, True),
|
|
(ScanType.COMPLETE, True, False, False, True),
|
|
(ScanType.HASHES, False, None, False, True),
|
|
(ScanType.HASHES, True, False, False, True),
|
|
(ScanType.UNMATCHED, True, False, False, True),
|
|
(ScanType.UNMATCHED, True, True, False, False),
|
|
(ScanType.UPDATE, True, True, False, True),
|
|
],
|
|
)
|
|
def test_comprehensive_scenarios(
|
|
self,
|
|
scan_type,
|
|
rom_exists,
|
|
is_identified,
|
|
rom_in_list,
|
|
expected,
|
|
):
|
|
"""Test comprehensive scenarios with different combinations"""
|
|
rom: Rom = Mock(spec=Rom)
|
|
roms_ids = []
|
|
|
|
if rom_exists:
|
|
rom.id = 1
|
|
if is_identified:
|
|
rom.igdb_id = 1
|
|
else:
|
|
rom.igdb_id = None
|
|
rom.moby_id = None
|
|
rom.ss_id = None
|
|
rom.ra_id = None
|
|
rom.launchbox_id = None
|
|
|
|
if rom_in_list:
|
|
roms_ids = [1]
|
|
|
|
result = _should_scan_rom(scan_type, rom, roms_ids, ["igdb"])
|
|
assert result is expected
|
|
|
|
|
|
class TestGetPico8CoverUrl:
|
|
"""Tests for the PICO-8 cover art URL helper on FSRomsHandler."""
|
|
|
|
@pytest.fixture
|
|
def handler(self):
|
|
return FSRomsHandler()
|
|
|
|
def test_returns_file_url_for_pico8_cartridge(self, handler: FSRomsHandler):
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug=UPS.PICO,
|
|
fs_name="mygame.p8.png",
|
|
fs_path="pico/roms",
|
|
)
|
|
expected = "file://pico/roms/mygame.p8.png"
|
|
assert url == expected
|
|
|
|
def test_returns_none_for_non_pico8_platform(self, handler: FSRomsHandler):
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug="snes",
|
|
fs_name="mygame.p8.png",
|
|
fs_path="snes/roms",
|
|
)
|
|
assert url is None
|
|
|
|
def test_returns_none_for_plain_p8_text_file(self, handler: FSRomsHandler):
|
|
"""Plain .p8 files are text-only and have no embedded PNG image."""
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug=UPS.PICO,
|
|
fs_name="mygame.p8",
|
|
fs_path="pico/roms",
|
|
)
|
|
assert url is None
|
|
|
|
def test_returns_none_for_unrelated_extension(self, handler: FSRomsHandler):
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug=UPS.PICO,
|
|
fs_name="mygame.zip",
|
|
fs_path="pico/roms",
|
|
)
|
|
assert url is None
|
|
|
|
def test_url_starts_with_file_scheme(self, handler: FSRomsHandler):
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug=UPS.PICO,
|
|
fs_name="cart.p8.png",
|
|
fs_path="pico/roms",
|
|
)
|
|
assert url is not None
|
|
assert url.startswith("file://")
|
|
|
|
def test_url_contains_fs_path_and_name(self, handler: FSRomsHandler):
|
|
fs_path = "pico/roms"
|
|
fs_name = "celeste.p8.png"
|
|
url = handler.get_pico8_cover_url(
|
|
platform_slug=UPS.PICO,
|
|
fs_name=fs_name,
|
|
fs_path=fs_path,
|
|
)
|
|
assert url is not None
|
|
assert fs_path in url
|
|
assert fs_name in url
|