using Ludarium.Infrastructure; using System.Net; using System.Text; using System.Text.Json; namespace Ludarium.IntegrationTests; public sealed class GameCheatCatalogTests { [Fact] public void ParsesBoundedDescriptionAndCodePairs() { const string content = """ cheats = 3 cheat0_desc = "Infinite lives" cheat0_code = "1234:09" cheat0_enable = false cheat1_desc = "Unlock world" cheat1_code = "ABCD+EFGH" cheat2_desc = "Missing code is ignored" """; var cheats = GameCheatCatalog.Parse(content); Assert.Equal(2, cheats.Count); Assert.Equal(new GameCheat("Infinite lives", "1234:09"), cheats[0]); Assert.Equal(new GameCheat("Unlock world", "ABCD+EFGH"), cheats[1]); } [Fact] public async Task EmptyStatusDoesNotCauseAnExternalDownload() { var directory = Path.Combine(Path.GetTempPath(), "ludarium-cheat-tests", Guid.NewGuid().ToString("N")); var calls = 0; try { using var client = new HttpClient(new StubHandler(_ => { calls++; return new HttpResponseMessage(HttpStatusCode.InternalServerError); })); using var catalog = new GameCheatCatalog(directory, client); var status = await catalog.StatusAsync(CancellationToken.None); Assert.False(status.Cached); Assert.Equal(0, status.IndexedFiles); Assert.Equal(0, calls); } finally { if (Directory.Exists(directory)) Directory.Delete(directory, true); } } [Fact] public async Task RefreshesPinnedIndexAndReturnsOnlyAnExactPlatformTitleMatch() { var directory = Path.Combine(Path.GetTempPath(), "ludarium-cheat-tests", Guid.NewGuid().ToString("N")); try { var tree = Enumerable.Range(0, 100).Select(index => new { path = $"cht/Nintendo - Nintendo Entertainment System/{(index == 0 ? "Fixture Game" : $"Other {index}")}.cht", type = "blob", size = 120, sha = index.ToString("x40", System.Globalization.CultureInfo.InvariantCulture) }).ToArray(); var indexJson = JsonSerializer.Serialize(new { sha = GameCheatCatalog.Commit, truncated = false, tree }); var handler = new StubHandler(request => request.RequestUri!.Host == "api.github.com" ? new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(indexJson) } : new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("cheat0_desc = \"Infinite lives\"\ncheat0_code = \"1234:09\"") }); using var catalog = new GameCheatCatalog(directory, new HttpClient(handler)); var result = await catalog.FindAsync("Fixture Game", "nes", CancellationToken.None); Assert.True(result.Available); Assert.Equal(GameCheatCatalog.Version, result.Version); Assert.Equal(new GameCheat("Infinite lives", "1234:09"), Assert.Single(result.Cheats)); Assert.False((await catalog.FindAsync("Missing Game", "nes", CancellationToken.None)).Available); } finally { if (Directory.Exists(directory)) Directory.Delete(directory, true); } } private sealed class StubHandler(Func response) : HttpMessageHandler { protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(response(request)); } }