diff --git a/SabreTools.RedumpLib.Test/Web/UrlBuilderTests.cs b/SabreTools.RedumpLib.Test/Web/UrlBuilderTests.cs index 364ec8b..6fdea7f 100644 --- a/SabreTools.RedumpLib.Test/Web/UrlBuilderTests.cs +++ b/SabreTools.RedumpLib.Test/Web/UrlBuilderTests.cs @@ -7,6 +7,17 @@ namespace SabreTools.RedumpLib.Test.Web { public class UrlBuilderTests { + #region BuildAboutUrl + + [Fact] + public void BuildAboutUrl_Constant() + { + string actual = UrlBuilder.BuildAboutUrl(); + Assert.Equal("https://redump.info/about", actual); + } + + #endregion + #region BuildDiscUrl [Theory] @@ -15,13 +26,14 @@ namespace SabreTools.RedumpLib.Test.Web public void BuildDiscUrl_AlwaysPositive(int id, int expected) { string actual = UrlBuilder.BuildDiscUrl(id); - Assert.Equal($"https://redump.info/disc/{expected}/", actual); + Assert.Equal($"https://redump.info/disc/{expected}", actual); } [Theory] + [InlineData(null, "https://redump.info/disc/1")] [InlineData(DiscSubpath.Cuesheet, "https://redump.info/disc/1/cue")] - [InlineData(DiscSubpath.Edit, "https://redump.info/disc/1/edit/")] - [InlineData(null, "https://redump.info/disc/1/")] + [InlineData(DiscSubpath.Edit, "https://redump.info/disc/1/edit")] + [InlineData(DiscSubpath.SBI, "https://redump.info/disc/1/sbi")] public void BuildDiscUrl_Subpath_Builds(DiscSubpath? subpath, string expected) { string actual = UrlBuilder.BuildDiscUrl(1, subpath); @@ -36,29 +48,29 @@ namespace SabreTools.RedumpLib.Test.Web public void BuildDiscsUrl_DumperWithPages_Builds() { string actual = UrlBuilder.BuildDiscsUrl(dumper: "user", page: 3); - Assert.Equal("https://redump.info/discs/?dumper=user&page=3", actual); + Assert.Equal("https://redump.info/discs?dumper=user&page=3", actual); } [Fact] public void BuildDiscsUrl_DumperLastModifiedWithPages_Builds() { string actual = UrlBuilder.BuildDiscsUrl(dumper: "user", sort: SortCategory.Modified, order: SortDirection.Descending, page: 3); - Assert.Equal("https://redump.info/discs/?dumper=user&sort=modified&order=desc&page=3", actual); + Assert.Equal("https://redump.info/discs?dumper=user&sort=modified&order=desc&page=3", actual); } [Fact] public void BuildDiscsUrl_LastModifiedWithPages_Builds() { string actual = UrlBuilder.BuildDiscsUrl(sort: SortCategory.Modified, order: SortDirection.Descending, page: 3); - Assert.Equal("https://redump.info/discs/?sort=modified&order=desc&page=3", actual); + Assert.Equal("https://redump.info/discs?sort=modified&order=desc&page=3", actual); } [Theory] - [InlineData("", "https://redump.info/discs/?q=&page=3")] - [InlineData("simple", "https://redump.info/discs/?q=simple&page=3")] - [InlineData("search-format", "https://redump.info/discs/?q=search-format&page=3")] - [InlineData("invalid format", "https://redump.info/discs/?q=invalid format&page=3")] - [InlineData("extra/path", "https://redump.info/discs/?q=extra/path&page=3")] + [InlineData("", "https://redump.info/discs?q=&page=3")] + [InlineData("simple", "https://redump.info/discs?q=simple&page=3")] + [InlineData("search-format", "https://redump.info/discs?q=search-format&page=3")] + [InlineData("invalid format", "https://redump.info/discs?q=invalid format&page=3")] + [InlineData("extra/path", "https://redump.info/discs?q=extra/path&page=3")] public void BuildDiscsUrl_QuicksearchWithPages_Builds(string query, string expected) { string actual = UrlBuilder.BuildDiscsUrl(query: query, page: 3); @@ -71,11 +83,14 @@ namespace SabreTools.RedumpLib.Test.Web #region BuildDownloadsUrl - [Fact] - public void BuildDownloadsUrl_Constant() + [Theory] + [InlineData(null, "https://redump.info/downloads")] + [InlineData(true, "https://redump.info/downloads/database")] + [InlineData(false, "https://redump.info/downloads")] + public void BuildDownloadsUrl_Builds(bool? database, string expected) { - string actual = UrlBuilder.BuildDownloadsUrl(); - Assert.Equal("https://redump.info/downloads/", actual); + string actual = UrlBuilder.BuildDownloadsUrl(database); + Assert.Equal(expected, actual); } #endregion @@ -93,7 +108,18 @@ namespace SabreTools.RedumpLib.Test.Web Assert.Equal(expected, actual); } - [Fact] + [Theory] + [InlineData(PhysicalSystem.MicrosoftXboxBIOS, "https://redump.info/static/bios/Microsoft%20-%20Xbox%20-%20BIOS%20Images%20%289%29%20%282026-06-16%29.dat")] + [InlineData(PhysicalSystem.NintendoGameCubeBIOS, "https://redump.info/static/bios/Nintendo%20-%20GameCube%20-%20BIOS%20Images%20%2817%29%20%282026-06-16%29.dat")] + [InlineData(PhysicalSystem.SonyPlayStationBIOS, "https://redump.info/static/bios/Sony%20-%20PlayStation%20-%20BIOS%20Images%20%2824%29%20%282026-06-16%29.dat")] + [InlineData(PhysicalSystem.SonyPlayStation2BIOS, "https://redump.info/static/bios/Sony%20-%20PlayStation%202%20-%20BIOS%20Datfile%20%28140%29%20%282026-06-16%29.dat")] + public void BuildPackUrl_BIOSDatfile(PhysicalSystem system, string expected) + { + string actual = UrlBuilder.BuildPackUrl(PackType.Datfile, system); + Assert.Equal(expected, actual); + } + + [Fact] public void BuildPackUrl_InvalidPackType_Throws() { Assert.Throws(() => UrlBuilder.BuildPackUrl((PackType)int.MaxValue, PhysicalSystem.AcornArchimedesAndRiscPC)); @@ -108,17 +134,17 @@ namespace SabreTools.RedumpLib.Test.Web #endregion - // TODO: Implement more extensive queue tests - #region BuildQueueUrl [Fact] public void BuildQueueUrl_Constant() { string actual = UrlBuilder.BuildQueueUrl(); - Assert.Equal("https://redump.info/queue/?", actual); + Assert.Equal("https://redump.info/queue", actual); } + // TODO: Implement more extensive queue tests + #endregion #region BuildQueueDiscUrl diff --git a/SabreTools.RedumpLib/Web/UrlBuilder.cs b/SabreTools.RedumpLib/Web/UrlBuilder.cs index d64047e..37d7fcb 100644 --- a/SabreTools.RedumpLib/Web/UrlBuilder.cs +++ b/SabreTools.RedumpLib/Web/UrlBuilder.cs @@ -11,70 +11,6 @@ namespace SabreTools.RedumpLib.Web { #region Constants - /// - /// Redump site URL - /// - private const string SiteBaseUrl = "https://redump.info/"; - - #region Top-Level Paths - - /// - /// Path for about page - /// - private const string AboutPath = "about/"; - - /// - /// Path for BIOS datfile downloads - /// - private const string BiosPath = @"static/bios/{0}/"; - - /// - /// Path for cuesheet pack downloads - /// - private const string CuesPath = @"cues/{0}"; - - /// - /// Path for datfile downloads - /// - private const string DatfilePath = @"datfile/{0}"; - - /// - /// Path for individual disc pages - /// - private const string DiscPath = @"disc/{0}/"; - - /// - /// Path for multi-disc pages - /// - private const string DiscsPath = "discs/"; - - /// - /// Path for downloads page - /// - private const string DownloadsPath = "downloads/"; - - /// - /// Path for key pack downloads - /// - private const string KeysPath = @"keys/{0}"; - - /// - /// Path for discs queue - /// - private const string QueuePath = "queue/"; - - /// - /// Path for individual queue disc pages - /// - private const string QueueDiscPath = @"queue/{0}/"; - - /// - /// Path for SBI pack downloads - /// - private const string SbiPath = @"sbi/{0}"; - - #endregion - #region BIOS File Names /// @@ -108,50 +44,14 @@ namespace SabreTools.RedumpLib.Web /// public static string BuildAboutUrl() { - var sb = new StringBuilder(); - - sb.Append(SiteBaseUrl); - sb.Append(AboutPath); - - return sb.ToString(); - } - - /// - /// Build a /static/bios/ path URL - /// - /// System to retrieve static BIOS datfile for, required - /// Handles the non-BIOS variants of systems for compatibility - public static string BuildBiosUrl(PhysicalSystem system) - { - var sb = new StringBuilder(); - -#pragma warning disable IDE0072 // Add missing cases - string? filename = system switch + var ub = new UriBuilder { - PhysicalSystem.MicrosoftXbox => MicrosoftXboxBIOSFilename, - PhysicalSystem.MicrosoftXboxBIOS => MicrosoftXboxBIOSFilename, - - PhysicalSystem.NintendoGameCube => NintendoGameCubeBIOSFilename, - PhysicalSystem.NintendoGameCubeBIOS => NintendoGameCubeBIOSFilename, - - PhysicalSystem.SonyPlayStation => SonyPlayStationBIOSFilename, - PhysicalSystem.SonyPlayStationBIOS => SonyPlayStationBIOSFilename, - - PhysicalSystem.SonyPlayStation2 => SonyPlayStation2BIOSFilename, - PhysicalSystem.SonyPlayStation2BIOS => SonyPlayStation2BIOSFilename, - - _ => null, + Scheme = "https", + Host = "redump.info", + Path = "about", }; -#pragma warning restore IDE0072 // Add missing cases - // Ignore invalid BIOS systems - if (filename is null) - return string.Empty; - - sb.Append(SiteBaseUrl); - sb.AppendFormat(BiosPath, filename); - - return sb.ToString(); + return ub.ToString(); } /// @@ -159,23 +59,22 @@ namespace SabreTools.RedumpLib.Web /// /// Disc ID, required /// Disc page subpath, null to omit + /// TODO: Handle submit path? public static string BuildDiscUrl(int id, DiscSubpath? subpath = null) { - var sb = new StringBuilder(); - - sb.Append(SiteBaseUrl); - sb.AppendFormat(DiscPath, Math.Abs(id)); + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = $"disc/{Math.Abs(id)}", + }; switch (subpath) { - // Does not require trailing slash case DiscSubpath.Cuesheet: - sb.Append($"{subpath.ShortName()}"); - break; - - // Requires trailing slash case DiscSubpath.Edit: - sb.Append($"{subpath.ShortName()}/"); + case DiscSubpath.SBI: + ub.Path += $"/{subpath.ShortName()}"; break; // redump.org subpaths that don't have equivilent paths @@ -184,7 +83,6 @@ namespace SabreTools.RedumpLib.Web case DiscSubpath.Key: case DiscSubpath.LSD: case DiscSubpath.MD5: - case DiscSubpath.SBI: case DiscSubpath.SFV: case DiscSubpath.SHA1: case DiscSubpath.WIP: @@ -197,7 +95,7 @@ namespace SabreTools.RedumpLib.Web break; } - return sb.ToString(); + return ub.ToString(); } /// @@ -272,11 +170,287 @@ namespace SabreTools.RedumpLib.Web long? tracksMax = null, long? tracksMin = null) { - var sb = new StringBuilder(); + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = "discs", + Query = BuildDiscsQuery( + advanced, + barcode, + barcodeExact, + category, + comments, + contents, + dumper, + edc, + edition, + editionExact, + errorsMax, + errorsMin, + language, + letter, + media, + offset, + order, + page, + protection, + query, + region, + ringcode, + serial, + serialExact, + sort, + status, + system, + title, + titleExact, + titleForeign, + titleForeignExact, + tracksMax, + tracksMin + ), + }; - sb.Append(SiteBaseUrl); - sb.Append(DiscsPath); - sb.Append('?'); + return ub.ToString(); + } + + /// + /// Build a /downloads/ path URL + /// + /// Target database download + public static string BuildDownloadsUrl(bool? database = null) + { + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = "downloads", + }; + + if (database == true) + ub.Path += "/database"; + + return ub.ToString(); + } + + /// + /// Build a direct-download path URL + /// + /// Pack type + /// System for download + /// Does not check for invalid systems + /// TODO: Handle download_dat_variant? + public static string BuildPackUrl(PackType packType, PhysicalSystem system) + { + // Hack to support the static BIOS sets + if (packType == PackType.Datfile + && (system == PhysicalSystem.MicrosoftXboxBIOS + || system == PhysicalSystem.NintendoGameCubeBIOS + || system == PhysicalSystem.SonyPlayStationBIOS + || system == PhysicalSystem.SonyPlayStation2BIOS)) + { + return BuildBiosUrl(system); + } + + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + }; + + string systemName = system.ShortName() ?? string.Empty; + switch (packType) + { + case PackType.Cuesheets: ub.Path = $"cues/{systemName}"; break; + case PackType.Datfile: ub.Path = $"datfile/{systemName}"; break; + case PackType.Keys: ub.Path = $"keys/{systemName}"; break; + case PackType.Sbis: ub.Path = $"sbi/{systemName}"; break; + + // Unsupported + case PackType.DecryptedKeys: break; + case PackType.Gdis: break; + case PackType.Lsds: break; + default: throw new ArgumentOutOfRangeException(nameof(packType)); + } + + return ub.ToString(); + } + + /// + /// Build a /queue/ path URL + /// + /// Add disc ID to filter, null to omit + /// Set disc history status, null to omit + /// Add sorting direction, null to omit + /// Page number, null to omit + /// Add sorting type, null to omit + /// Add status to filter, null to omit + /// Add submitter name to filter, null to omit + /// Add submission type to filter, null to omit + /// Add system to filter, null to omit + /// Ordered according to site source code + public static string BuildQueueUrl( + long? discId = null, + bool? isDiscHistory = null, + SortDirection? order = null, + long? page = null, + SortCategory? sort = null, + DumpStatus? status = null, + string? submitter = null, + SubmissionType? subType = null, + PhysicalSystem? system = null) + { + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = "queue", + Query = BuildQueueQuery( + discId, + isDiscHistory, + order, + page, + sort, + status, + submitter, + subType, + system + ), + }; + + return ub.ToString(); + } + + /// + /// Build a /queue/ disc path URL + /// + /// Queue disc ID + public static string BuildQueueDiscUrl(int id) + { + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = $"queue/{Math.Abs(id)}/", + }; + + return ub.ToString(); + } + + /// + /// Build a /static/bios/ path URL + /// + /// System to retrieve static BIOS datfile for, required + /// Handles the non-BIOS variants of systems for compatibility + private static string BuildBiosUrl(PhysicalSystem system) + { +#pragma warning disable IDE0072 // Add missing cases + string? filename = system switch + { + PhysicalSystem.MicrosoftXbox => MicrosoftXboxBIOSFilename, + PhysicalSystem.MicrosoftXboxBIOS => MicrosoftXboxBIOSFilename, + + PhysicalSystem.NintendoGameCube => NintendoGameCubeBIOSFilename, + PhysicalSystem.NintendoGameCubeBIOS => NintendoGameCubeBIOSFilename, + + PhysicalSystem.SonyPlayStation => SonyPlayStationBIOSFilename, + PhysicalSystem.SonyPlayStationBIOS => SonyPlayStationBIOSFilename, + + PhysicalSystem.SonyPlayStation2 => SonyPlayStation2BIOSFilename, + PhysicalSystem.SonyPlayStation2BIOS => SonyPlayStation2BIOSFilename, + + _ => null, + }; +#pragma warning restore IDE0072 // Add missing cases + + // Ignore invalid BIOS systems + if (filename is null) + return string.Empty; + + var ub = new UriBuilder + { + Scheme = "https", + Host = "redump.info", + Path = $"static/bios/{filename}", + }; + + return ub.ToString(); + } + + /// + /// Build a /discs/ path query + /// + /// Set advanced search status, null to omit + /// Add barcode to filter, null to omit + /// Set exact barcode handling, null to omit + /// Add category to filter, null to omit + /// Add comments to filter, null to omit + /// Add contents to filter, null to omit + /// Add dumper name to filter, null to omit + /// Add EDC status to filter, null to omit + /// Add edition to filter, null to omit + /// Set exact edition handling, null to omit + /// Add maximum error count to filter, null to omit + /// Add minimum error count to filter, null to omit + /// Add language to filter, null to omit + /// Starts with upper-case letter or '#' for numbers, null to omit + /// Add media type to filter, null to omit + /// Add offset to filter, null to omit + /// Add sorting direction, null to omit + /// Page number, null to omit + /// Add protection to filter, null to omit + /// Generic text query to filter, null to omit + /// Add region to filter, null to omit + /// Add ringcode to filter, null to omit + /// Add serial to filter, null to omit + /// Set exact serial handling, null to omit + /// Add sorting type, null to omit + /// Add status to filter, null to omit + /// Add system to filter, null to omit + /// Add title to filter, null to omit + /// Set exact title handling, null to omit + /// Add foreign title to filter, null to omit + /// Set exact foreign title handling, null to omit + /// Add maximum track count to filter, null to omit + /// Add minimum track count to filter, null to omit + /// Ordered according to site source code + private static string BuildDiscsQuery( + bool? advanced, + string? barcode, + bool? barcodeExact, + DiscCategory? category, + string? comments, + string? contents, + string? dumper, + YesNo? edc, + string? edition, + bool? editionExact, + long? errorsMax, + long? errorsMin, + Language? language, + char? letter, + MediaType? media, + long? offset, + SortDirection? order, + long? page, + string? protection, + string? query, + Region? region, + string? ringcode, + string? serial, + bool? serialExact, + SortCategory? sort, + DumpStatus? status, + PhysicalSystem? system, + string? title, + bool? titleExact, + string? titleForeign, + bool? titleForeignExact, + long? tracksMax, + long? tracksMin) + { + var sb = new StringBuilder(); // System string? systemName = system.ShortName(); @@ -429,64 +603,7 @@ namespace SabreTools.RedumpLib.Web } /// - /// Build a /downloads/ path URL - /// - /// Target database download - public static string BuildDownloadsUrl(bool? database = null) - { - var sb = new StringBuilder(); - - sb.Append(SiteBaseUrl); - sb.Append(DownloadsPath); - - if (database == true) - sb.Append("database"); - - return sb.ToString(); - } - - /// - /// Build a direct-download path URL - /// - /// Pack type - /// System for download - /// Does not check for invalid systems - /// TODO: Handle download_dat_variant? - public static string BuildPackUrl(PackType packType, PhysicalSystem system) - { - // Hack to support the static BIOS sets - if (packType == PackType.Datfile - && (system == PhysicalSystem.MicrosoftXboxBIOS - || system == PhysicalSystem.NintendoGameCubeBIOS - || system == PhysicalSystem.SonyPlayStationBIOS - || system == PhysicalSystem.SonyPlayStation2BIOS)) - { - return BuildBiosUrl(system); - } - - var sb = new StringBuilder(); - - sb.Append(SiteBaseUrl); - - string systemName = system.ShortName() ?? string.Empty; - switch (packType) - { - case PackType.Cuesheets: sb.AppendFormat(CuesPath, systemName); break; - case PackType.Datfile: sb.AppendFormat(DatfilePath, systemName); break; - case PackType.DecryptedKeys: break; // Not supported - case PackType.Gdis: break; // Not supported - case PackType.Keys: sb.AppendFormat(KeysPath, systemName); break; - case PackType.Lsds: break; // Not supported - case PackType.Sbis: sb.AppendFormat(SbiPath, systemName); break; - - default: throw new ArgumentOutOfRangeException(nameof(packType)); - } - - return sb.ToString(); - } - - /// - /// Build a /queue/ path URL + /// Build a /queue/ path query /// /// Add disc ID to filter, null to omit /// Set disc history status, null to omit @@ -498,23 +615,19 @@ namespace SabreTools.RedumpLib.Web /// Add submission type to filter, null to omit /// Add system to filter, null to omit /// Ordered according to site source code - public static string BuildQueueUrl( - long? discId = null, - bool? isDiscHistory = null, - SortDirection? order = null, - long? page = null, - SortCategory? sort = null, - DumpStatus? status = null, - string? submitter = null, - SubmissionType? subType = null, - PhysicalSystem? system = null) + private static string BuildQueueQuery( + long? discId, + bool? isDiscHistory, + SortDirection? order, + long? page, + SortCategory? sort, + DumpStatus? status, + string? submitter, + SubmissionType? subType, + PhysicalSystem? system) { var sb = new StringBuilder(); - sb.Append(SiteBaseUrl); - sb.Append(QueuePath); - sb.Append('?'); - // Status string? statusName = status.LongName(); if (statusName is not null) @@ -579,20 +692,5 @@ namespace SabreTools.RedumpLib.Web return sb.ToString(); } - - /// - /// Build a /queue/ disc path URL - /// - /// Queue disc ID - /// TODO: Add form URLs, not just IDs - public static string BuildQueueDiscUrl(int id) - { - var sb = new StringBuilder(); - - sb.Append(SiteBaseUrl); - sb.AppendFormat(QueueDiscPath, Math.Abs(id)); - - return sb.ToString(); - } } }