using Ludarium.Application; namespace Ludarium.UnitTests; public sealed class SwitchLaunchPolicyTests { [Fact] public void SelectsUniqueReadOnlyBaseXciAndRejectsTicketUpdateAndDlc() { var candidates = new[] { Candidate("Animal Crossing ticket [01006F800232712C][v0].nsp", 124_112), Candidate("Animal Crossing update [01006F8002326800][v1769472].nsp", 4_332_291_043), Candidate("Happy Home Paradise [01006F80023273E8][v0].nsp", 624_384_208), Candidate("Animal Crossing New Horizons [01006F8002326000][v0].xci", 7_985_954_816), }; Assert.EndsWith(".xci", SwitchLaunchPolicy.SelectBaseGame(candidates)!.RelativePath); } [Fact] public void FailsClosedWhenTheBaseGameIsAmbiguousOrWritable() { var first = Candidate("Game A [0100000000000000][v0].xci", 2_000_000); var second = Candidate("Game B [0100000000010000][v0].xci", 3_000_000); Assert.Null(SwitchLaunchPolicy.SelectBaseGame([first, second])); Assert.Null(SwitchLaunchPolicy.SelectBaseGame([first with { SourceReadOnly = false }])); } [Fact] public void MapsOnlyContainedCatalogPaths() { Assert.Equal("Animal/Game [0100000000000000][v0].xci", SwitchLaunchPolicy.ToRuntimePath("roms/switch/Animal/Game [0100000000000000][v0].xci", "roms/switch")); Assert.Throws(() => SwitchLaunchPolicy.ToRuntimePath("roms/ps5/game.xci", "roms/switch")); } [Fact] public void CapabilityIsAvailableOnlyForOneQualifiedBaseGame() { var gameId = Guid.NewGuid(); var available = SwitchLaunchPolicy.EvaluateCapability(gameId, true, true, true, [Candidate("Game [0100000000000000][v0].xci", 2_000_000)]); var ambiguous = SwitchLaunchPolicy.EvaluateCapability(gameId, true, true, true, [Candidate("Game A [0100000000000000][v0].xci", 2_000_000), Candidate("Game B [0100000000010000][v0].xci", 3_000_000)]); Assert.True(available.Available); Assert.Equal(NativeRemotePlayState.Available, available.State); Assert.False(ambiguous.Available); Assert.Equal(NativeRemotePlayState.AmbiguousMapping, ambiguous.State); } [Theory] [InlineData(false, true, true, NativeRemotePlayState.UnsupportedPlatform)] [InlineData(true, false, true, NativeRemotePlayState.RuntimeUnavailable)] [InlineData(true, true, false, NativeRemotePlayState.MissingKeys)] public void CapabilityExplainsGlobalPrerequisites(bool isSwitch, bool runtime, bool keys, NativeRemotePlayState expected) { var capability = SwitchLaunchPolicy.EvaluateCapability(Guid.NewGuid(), isSwitch, runtime, keys, []); Assert.False(capability.Available); Assert.Equal(expected, capability.State); } [Fact] public void CapabilityDistinguishesAnUpdateWithoutItsBaseGameFromAmbiguity() { var capability = SwitchLaunchPolicy.EvaluateCapability(Guid.NewGuid(), true, true, true, [Candidate("Game update [0100000000000800][v131072].nsp", 4_000_000)]); Assert.False(capability.Available); Assert.Equal(NativeRemotePlayState.MissingBaseGame, capability.State); Assert.Contains("updates and DLC cannot start alone", capability.Message); } private static NativeLaunchCandidate Candidate(string path, long size) => new(Guid.NewGuid(), "roms/switch/" + path, size, true); }