using System.Buffers.Binary; using System.Text; using Ludarium.Application; using Ludarium.Domain; namespace Ludarium.UnitTests; /// /// Platform identification for the container formats the players actually accept. /// /// /// A disc or cartridge that classifies as Unknown never becomes a launch candidate, so a format the /// Dolphin policy or the browser matrix allows must also be identifiable here. These fixtures are /// synthesized from the documented on-media headers, not from copyrighted dumps. /// public sealed class PlatformIdentificationTests { [Fact] public void GameCubeDiscsAreIdentifiedByTheirMagicWordNotTheirDirectory() { var classification = ArtifactAnalysis.Classify("library/unsorted/Disc.iso", GameCubeDisc()); Assert.Equal(MediaType.DiscImage, classification.MediaType); Assert.Equal("gamecube", classification.Platform); Assert.Equal(Confidence.Deterministic, classification.Confidence); Assert.Contains(classification.Evidence, item => item.Kind == "signature" && item.Value == "GameCube disc"); Assert.Contains(classification.Evidence, item => item.Kind == "rom.gameCode" && item.Value == "GLZE"); Assert.Contains(classification.Evidence, item => item.Kind == "rom.region" && item.Value == "usa"); Assert.Contains(classification.Evidence, item => item.Kind == "rom.title" && item.Value == "LUDARIUM GAMECUBE FIXTURE"); } [Fact] public void WiiDiscsAreIdentifiedByTheirMagicWordNotTheirDirectory() { var classification = ArtifactAnalysis.Classify("library/unsorted/Disc.iso", WiiDisc()); Assert.Equal(MediaType.DiscImage, classification.MediaType); Assert.Equal("wii", classification.Platform); Assert.Equal(Confidence.Deterministic, classification.Confidence); Assert.Contains(classification.Evidence, item => item.Kind == "signature" && item.Value == "Wii disc"); } [Fact] public void ADiscMagicOverridesAMisleadingPlatformDirectory() { var classification = ArtifactAnalysis.Classify("roms/gamecube/Disc.iso", WiiDisc(), "gamecube"); Assert.Equal("wii", classification.Platform); Assert.Contains(classification.Evidence, item => item.Kind == "platform.conflict" && item.Value == "directory:gamecube;signature:wii"); } [Theory] [InlineData("roms/gamecube/Game.gcm", "gamecube")] [InlineData("roms/gamecube/Game.gcz", "gamecube")] [InlineData("roms/wii/Game.wia", "wii")] [InlineData("roms/wii/Game.rvz", "wii")] [InlineData("roms/wii/Game.wbfs", "wii")] public void EveryDolphinContainerFormatClassifiesAsAPlayableDiscImage(string path, string hint) { var classification = ArtifactAnalysis.Classify(path, [], hint); Assert.Equal(MediaType.DiscImage, classification.MediaType); Assert.Equal(hint, classification.Platform); Assert.True(classification.Supported); } [Fact] public void EveryFormatTheDolphinPolicyAcceptsIsIdentifiable() { foreach (var extension in NativeRemotePlayerRegistry.Dolphin.Extensions) { var classification = ArtifactAnalysis.Classify($"roms/wii/Game{extension}", [], "wii"); Assert.True(classification.Supported, $"{extension} is launchable in Dolphin but is not identified by the scanner."); } } [Fact] public void MegaDriveCartridgesAreIdentifiedAndSeparatedFromTheirVariants() { var genesis = ArtifactAnalysis.Classify("roms/unsorted/Game.md", SegaCartridge("SEGA MEGA DRIVE ")); var thirtyTwoX = ArtifactAnalysis.Classify("roms/unsorted/Game.32x", SegaCartridge("SEGA 32X ")); var segaCd = ArtifactAnalysis.Classify("roms/unsorted/Game.bin", SegaCartridge("SEGA SEGACD ")); Assert.Equal("genesis", genesis.Platform); Assert.Equal(MediaType.Rom, genesis.MediaType); Assert.Equal("sega32x", thirtyTwoX.Platform); Assert.Equal("segacd", segaCd.Platform); Assert.Contains(genesis.Evidence, item => item.Kind == "rom.internationalTitle" && item.Value == "LUDARIUM GENESIS FIXTURE"); } [Theory] [InlineData(0x40, "mastersystem")] [InlineData(0x30, "mastersystem")] [InlineData(0x50, "gamegear")] [InlineData(0x60, "gamegear")] [InlineData(0x70, "gamegear")] public void TheEightBitSegaRegionNibbleSeparatesMasterSystemFromGameGear(int region, string expected) { var classification = ArtifactAnalysis.Classify("roms/unsorted/Game.sms", SegaEightBit(region)); Assert.Equal(expected, classification.Platform); Assert.Equal(MediaType.Rom, classification.MediaType); Assert.Equal(Confidence.Deterministic, classification.Confidence); Assert.Contains(classification.Evidence, item => item.Kind == "rom.productCode" && item.Value == "50123"); Assert.Contains(classification.Evidence, item => item.Kind == "rom.revision" && item.Value == "1"); Assert.Contains(classification.Evidence, item => item.Kind == "rom.checksum" && item.Value == "1234"); } [Theory] [InlineData("megadrive", "genesis")] [InlineData("mega-drive", "genesis")] [InlineData("MD", "genesis")] [InlineData("sms", "mastersystem")] [InlineData("game-gear", "gamegear")] public void HardwareNamedDirectoriesResolveToTheCanonicalPlatform(string directory, string expected) { var hint = ArtifactAnalysis.InferPlatformHint("library", "/mnt/games", $"roms/{directory}/Game.md"); Assert.Equal(expected, hint); Assert.Equal(expected, ArtifactAnalysis.Classify($"roms/{directory}/Game.md", [], hint).Platform); } [Fact] public void PlatformValuesWrittenByEarlierVersionsStillResolve() { Assert.Equal("genesis", ArtifactAnalysis.CanonicalPlatform("sega-genesis")); Assert.Equal("mastersystem", ArtifactAnalysis.CanonicalPlatform("sms")); Assert.Equal("nes", ArtifactAnalysis.CanonicalPlatform("nes")); Assert.Null(ArtifactAnalysis.CanonicalPlatform(null)); } [Fact] public void ARawTrackIsOnlyADiscImageInsideADiscLibrary() { var disc = ArtifactAnalysis.Classify("roms/psx/Game/Game (Track 1).bin", [], "psx"); var installer = ArtifactAnalysis.Classify("PC/Some Game/data1.bin", [], "windows"); Assert.Equal(MediaType.DiscImage, disc.MediaType); Assert.Equal("psx", disc.Platform); // An installer payload must not be promoted to a disc image on the strength of its extension. Assert.Equal(MediaType.Unknown, installer.MediaType); } [Theory] [InlineData("roms/3ds/Game.3ds", "3ds")] [InlineData("roms/3ds/Game.cia", "3ds")] [InlineData("roms/wiiu/Game.wud", "wiiu")] [InlineData("roms/psvita/Game.vpk", "psvita")] public void FormatsForResearchedPlatformsAreIdentifiedEvenWithoutAPlayer(string path, string platform) { var classification = ArtifactAnalysis.Classify(path, []); Assert.Equal(platform, classification.Platform); Assert.True(classification.Supported); } private static byte[] GameCubeDisc() { var header = new byte[0x500]; Encoding.ASCII.GetBytes("GLZE").CopyTo(header, 0); Encoding.ASCII.GetBytes("01").CopyTo(header, 4); header[6] = 0; header[7] = 1; BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(0x1C), 0xC2339F3D); Encoding.ASCII.GetBytes("LUDARIUM GAMECUBE FIXTURE").CopyTo(header, 0x20); return header; } private static byte[] WiiDisc() { var header = new byte[0x500]; Encoding.ASCII.GetBytes("RLZP").CopyTo(header, 0); Encoding.ASCII.GetBytes("01").CopyTo(header, 4); BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(0x18), 0x5D1C9EA3); Encoding.ASCII.GetBytes("LUDARIUM WII FIXTURE").CopyTo(header, 0x20); return header; } private static byte[] SegaCartridge(string console) { var rom = new byte[0x200]; Encoding.ASCII.GetBytes(console.PadRight(16)[..16]).CopyTo(rom, 0x100); Encoding.ASCII.GetBytes("(C)LUDARIUM 2026".PadRight(16)).CopyTo(rom, 0x110); Encoding.ASCII.GetBytes("LUDARIUM GENESIS FIXTURE".PadRight(48)).CopyTo(rom, 0x120); Encoding.ASCII.GetBytes("LUDARIUM GENESIS FIXTURE".PadRight(48)).CopyTo(rom, 0x150); Encoding.ASCII.GetBytes("GM 00000000-00".PadRight(14)).CopyTo(rom, 0x180); Encoding.ASCII.GetBytes("JUE").CopyTo(rom, 0x1F0); return rom; } private static byte[] SegaEightBit(int region) { var rom = new byte[0x8000]; Encoding.ASCII.GetBytes("TMR SEGA").CopyTo(rom, 0x7FF0); rom[0x7FFA] = 0x34; // checksum, low byte rom[0x7FFB] = 0x12; // checksum, high byte rom[0x7FFC] = 0x23; // product code, low BCD pair rom[0x7FFD] = 0x01; // product code, high BCD pair rom[0x7FFE] = 0x51; // top product digit and revision 1 rom[0x7FFF] = (byte)(region | 0x0C); // region nibble plus a 32 KiB size nibble return rom; } }