mirror of
https://github.com/rommapp/romm.git
synced 2026-06-28 14:56:01 +00:00
Centralize the *_no_tags / *_no_ext / *_extension columns (derived from a file name) behind @validates hooks instead of computing them by hand at every write site: - Add pure helpers (compute_file_name_parts and friends) to models.base; the filesystem base handler now delegates to them. - Add @validates on Rom (fs_name), BaseAsset (file_name, inherited by all asset subclasses), and Firmware (file_name). - update_rom keeps the fs_name-derived columns in sync on bulk update(), which also fixes the rename path never updating fs_extension. - Drop the now-redundant computations at the scan/rename call sites. Also fix the migration backfill loop and a pre-existing list[str | None] type mismatch surfaced in scan_handler. Add tests for the helpers, the validators, and the update_rom bulk-sync path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
import pytest
|
|
|
|
from models.assets import Save
|
|
from models.base import compute_file_name_parts
|
|
from models.firmware import Firmware
|
|
from models.rom import Rom, compute_name_sort_key
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("file_name", "no_tags", "no_ext", "extension"),
|
|
[
|
|
("Sonic (USA) [!].md", "Sonic", "Sonic (USA) [!]", "md"),
|
|
("game.tar.gz", "game", "game", "tar.gz"),
|
|
("README", "README", "README", ""),
|
|
(
|
|
"Final Fantasy VII (Disc 1).bin",
|
|
"Final Fantasy VII",
|
|
"Final Fantasy VII (Disc 1)",
|
|
"bin",
|
|
),
|
|
],
|
|
)
|
|
def test_compute_file_name_parts(file_name, no_tags, no_ext, extension):
|
|
parts = compute_file_name_parts(file_name)
|
|
|
|
assert parts.no_tags == no_tags
|
|
assert parts.no_ext == no_ext
|
|
assert parts.extension == extension
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("name", "expected"),
|
|
[
|
|
("The Legend of Zelda 2", "legend of zelda 000000000002"),
|
|
("A Bug's Life", "bug's life"),
|
|
("Final Fantasy 10", "final fantasy 000000000010"),
|
|
(None, ""),
|
|
],
|
|
)
|
|
def test_compute_name_sort_key(name, expected):
|
|
assert compute_name_sort_key(name) == expected
|
|
|
|
|
|
def test_rom_validator_derives_fs_name_parts_on_construction():
|
|
rom = Rom(fs_name="The Legend of Zelda (USA) (Rev 1).z64")
|
|
|
|
assert rom.fs_name_no_tags == "The Legend of Zelda"
|
|
assert rom.fs_name_no_ext == "The Legend of Zelda (USA) (Rev 1)"
|
|
assert rom.fs_extension == "z64"
|
|
# The validator only fires on assignment; name was never set, so its
|
|
# derived column keeps the column default rather than being computed.
|
|
assert rom.name_sort_key is None
|
|
|
|
|
|
def test_rom_validator_resyncs_on_mutation():
|
|
rom = Rom(fs_name="old.zip", name="The Old Game")
|
|
assert rom.name_sort_key == "old game"
|
|
|
|
rom.fs_name = "Sonic (Europe).md"
|
|
rom.name = "A New Game 2"
|
|
|
|
assert rom.fs_name_no_tags == "Sonic"
|
|
assert rom.fs_extension == "md"
|
|
assert rom.name_sort_key == "new game 000000000002"
|
|
|
|
|
|
def test_asset_validator_derives_file_name_parts():
|
|
# Defined on the abstract BaseAsset, inherited by every asset subclass.
|
|
save = Save(file_name="Sonic [!] (proto).srm")
|
|
|
|
assert save.file_name_no_tags == "Sonic"
|
|
assert save.file_name_no_ext == "Sonic [!] (proto)"
|
|
assert save.file_extension == "srm"
|
|
|
|
|
|
def test_firmware_validator_derives_file_name_parts():
|
|
firmware = Firmware(file_name="bios (world).bin")
|
|
|
|
assert firmware.file_name_no_tags == "bios"
|
|
assert firmware.file_name_no_ext == "bios (world)"
|
|
assert firmware.file_extension == "bin"
|