using System; using System.Collections.Generic; using System.Data; using System.Linq; using SabreTools.RedumpLib.Data; using SabreTools.RedumpLib.Data.Sections; using Xunit; namespace SabreTools.RedumpLib.Test.Data { public class ExtensionsTests { #region Non-Enumerable #region NormalizeDiscType [Fact] public void NormalizeDiscType_InvalidMedia_Untouched() { var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = null } }; si.NormalizeDiscType(); Assert.Null(si.DiscIdentity.Media); } [Fact] public void NormalizeDiscType_UnformattedType_Fixed() { MediaType expected = MediaType.CD; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = MediaType.CD }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.DVD5)] [InlineData(MediaType.DVD9)] public void NormalizeDiscType_DVD9_Fixed(MediaType type) { MediaType expected = MediaType.DVD9; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.DVD5)] [InlineData(MediaType.DVD9)] public void NormalizeDiscType_DVD5_Fixed(MediaType type) { MediaType expected = MediaType.DVD5; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD128_Fixed(MediaType type) { MediaType expected = MediaType.BD128; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak3 = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD100_Fixed(MediaType type) { MediaType expected = MediaType.BD100; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak2 = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD66PIC_Fixed(MediaType type) { MediaType expected = MediaType.BD66; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, DumpMetadata = new DumpMetadataSection { PICIdentifier = "BDU" }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD66Size_Fixed(MediaType type) { MediaType expected = MediaType.BD66; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, DumpMetadata = new DumpMetadataSection { Dat = "", }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD66PS5_Fixed(MediaType type) { MediaType expected = MediaType.BD66; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { System = PhysicalSystem.SonyPlayStation5, Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD50_Fixed(MediaType type) { MediaType expected = MediaType.BD50; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD33PIC_Fixed(MediaType type) { MediaType expected = MediaType.BD33; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DumpMetadata = new DumpMetadataSection { PICIdentifier = "BDU" }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD33Size_Fixed(MediaType type) { MediaType expected = MediaType.BD33; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DumpMetadata = new DumpMetadataSection { Dat = "", }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD33PS5_Fixed(MediaType type) { MediaType expected = MediaType.BD33; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { System = PhysicalSystem.SonyPlayStation5, Media = type, }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.BD25)] [InlineData(MediaType.BD33)] [InlineData(MediaType.BD50)] [InlineData(MediaType.BD66)] [InlineData(MediaType.BD100)] [InlineData(MediaType.BD128)] public void NormalizeDiscType_BD25_Fixed(MediaType type) { MediaType expected = MediaType.BD25; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.HDDVDSL)] [InlineData(MediaType.HDDVDDL)] public void NormalizeDiscType_HDDVDDL_Fixed(MediaType type) { MediaType expected = MediaType.HDDVDDL; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.HDDVDSL)] [InlineData(MediaType.HDDVDDL)] public void NormalizeDiscType_HDDVDSL_Fixed(MediaType type) { MediaType expected = MediaType.HDDVDSL; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.UMDSL)] [InlineData(MediaType.UMDDL)] public void NormalizeDiscType_UMDDL_Fixed(MediaType type) { MediaType expected = MediaType.UMDDL; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, DiscIdentifiers = new DiscIdentifiersSection { Layerbreak = 12345 }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } [Theory] [InlineData(MediaType.UMDSL)] [InlineData(MediaType.UMDDL)] public void NormalizeDiscType_UMDSL_Fixed(MediaType type) { MediaType expected = MediaType.UMDSL; var si = new SubmissionInfo { DiscIdentity = new DiscIdentitySection { Media = type }, }; si.NormalizeDiscType(); Assert.Equal(expected, si.DiscIdentity.Media); } #endregion #endregion #region Cross-Enumeration /// /// redump.info media type values that map to the combined media type /// private static readonly MediaType?[] _mappableMediaTypes = [ MediaType.NONE, MediaType.BD25, MediaType.BD33, MediaType.BD50, MediaType.BD66, MediaType.BD100, MediaType.BD128, MediaType.CD, MediaType.DVD5, MediaType.DVD9, MediaType.GDROM, MediaType.HDDVDSL, MediaType.HDDVDDL, MediaType.NintendoGameCubeGameDisc, MediaType.NintendoWiiOpticalDiscSL, MediaType.NintendoWiiOpticalDiscDL, MediaType.NintendoWiiUOpticalDiscSL, MediaType.UMDSL, MediaType.UMDDL, ]; /// /// Combined media type values that map to redump.info media type /// private static readonly PhysicalMediaType?[] _mappablePhysicalMediaTypes = [ PhysicalMediaType.NONE, PhysicalMediaType.BluRay, PhysicalMediaType.CDROM, PhysicalMediaType.DVD, PhysicalMediaType.GDROM, PhysicalMediaType.HDDVD, PhysicalMediaType.NintendoGameCubeGameDisc, PhysicalMediaType.NintendoWiiOpticalDisc, PhysicalMediaType.NintendoWiiUOpticalDisc, PhysicalMediaType.UMD, ]; /// /// Check that every supported system has some set of MediaTypes supported /// /// PhysicalSystem value to check [Theory] [MemberData(nameof(GeneratePhysicalSystemMappingTestData))] public void MediaTypesTest(PhysicalSystem? physicalSystem) { var actual = physicalSystem?.MediaTypes ?? [PhysicalMediaType.NONE]; Assert.NotEmpty(actual); } /// /// Check that both mappable and unmappable media types output correctly /// /// MediaType value to check /// True to expect a null mapping, false otherwise [Theory] [MemberData(nameof(GeneratePhysicalMediaTypeMappingTestData))] public void ToPhysicalMediaTypeTest(PhysicalMediaType? mediaType, bool expectNull) { MediaType? actual = mediaType.ToMediaType(); Assert.Equal(expectNull, actual is null); } /// /// Check that MediaType values all map to something appropriate /// /// MediaType value to check /// True to expect a null mapping, false otherwise [Theory] [MemberData(nameof(GenerateMediaTypeMappingTestData))] public void ToMediaTypeTest(MediaType? discType, bool expectNull) { PhysicalMediaType? actual = discType.ToPhysicalMediaType(); Assert.Equal(expectNull, actual is null); } /// /// Generate a test set of PhysicalSystem values /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GeneratePhysicalSystemMappingTestData() { var testData = new TheoryData() { null }; foreach (PhysicalSystem? physicalSystem in PhysicalSystem.AllSystems) { testData.Add(physicalSystem); } return testData; } /// /// Generate a test set of MediaType values /// /// MemberData-compatible list of MediaType values public static TheoryData GenerateMediaTypeMappingTestData() { var testData = new TheoryData() { { null, true } }; foreach (MediaType? discType in Enum.GetValues().Cast()) { if (_mappableMediaTypes.Contains(discType)) testData.Add(discType, false); else testData.Add(discType, true); } return testData; } /// /// Generate a test set of mappable media types /// /// MemberData-compatible list of MediaTypes public static TheoryData GeneratePhysicalMediaTypeMappingTestData() { var testData = new TheoryData() { { null, true } }; foreach (PhysicalMediaType? mediaType in Enum.GetValues().Cast()) { if (_mappablePhysicalMediaTypes.Contains(mediaType)) testData.Add(mediaType, false); else testData.Add(mediaType, true); } return testData; } #endregion #region Disc Category /// /// Check that every DiscCategory has a long name provided /// /// DiscCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDiscCategoryTestData))] public void DiscCategory_LongName(DiscCategory? discCategory, bool expectNull) { var actual = discCategory.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every DiscCategory can be mapped from a string /// /// DiscCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDiscCategoryTestData))] public void DiscCategory_ToDiscCategory(DiscCategory? discCategory, bool expectNull) { string? longName = discCategory.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToDiscCategory(); var actualSpaceless = longNameSpaceless.ToDiscCategory(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(discCategory, actualNormal); Assert.Equal(discCategory, actualSpaceless); } } /// /// Generate a test set of DiscCategory values /// /// MemberData-compatible list of DiscCategory values public static TheoryData GenerateDiscCategoryTestData() { var testData = new TheoryData() { { null, true } }; foreach (DiscCategory? discCategory in Enum.GetValues().Cast()) { testData.Add(discCategory, false); } return testData; } #endregion #region Disc Subpath /// /// Check that every DiscSubpath has a long name provided /// /// DiscSubpath value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDiscSubpathTestData))] public void DiscSubpath_LongName(DiscSubpath? discSubpath, bool expectNull) { var actual = discSubpath.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every DiscSubpath has a short name provided /// /// DiscSubpath value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDiscSubpathTestData))] public void DiscSubpath_ShortName(DiscSubpath? discSubpath, bool expectNull) { var actual = discSubpath.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every DiscSubpath that has a short name that is unique /// [Fact] public void DiscSubpath_ShortName_NoDuplicates() { var fullDiscSubpaths = Enum.GetValues().Cast().ToList(); var filteredDiscSubpaths = new Dictionary(); int totalCount = 0; foreach (DiscSubpath? discSubpath in fullDiscSubpaths) { var code = discSubpath.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredDiscSubpaths.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredDiscSubpaths[code] = discSubpath; totalCount++; } Assert.Equal(totalCount, filteredDiscSubpaths.Count); } /// /// Check that every DiscSubpath can be mapped from a string /// /// DiscSubpath value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDiscSubpathTestData))] public void DiscSubpath_ToDiscSubpath(DiscSubpath? discSubpath, bool expectNull) { string? longName = discSubpath.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToDiscSubpath(); var actualSpaceless = longNameSpaceless.ToDiscSubpath(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(discSubpath, actualNormal); Assert.Equal(discSubpath, actualSpaceless); } } /// /// Generate a test set of DiscSubpath values /// /// MemberData-compatible list of DiscSubpath values public static TheoryData GenerateDiscSubpathTestData() { var testData = new TheoryData() { { null, true } }; foreach (DiscSubpath? discSubpath in Enum.GetValues().Cast()) { testData.Add(discSubpath, false); } return testData; } #endregion #region Dump Status /// /// Check that every DumpStatus has a long name provided /// /// DumpStatus value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDumpStatusTestData))] public void DumpStatus_LongName(DumpStatus? dumpStatus, bool expectNull) { var actual = dumpStatus.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every DumpStatus has a short name provided /// /// DumpStatus value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDumpStatusTestData))] public void DumpStatus_ShortName(DumpStatus? dumpStatus, bool expectNull) { var actual = dumpStatus.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every DumpStatus that has a short name that is unique /// [Fact] public void DumpStatus_ShortName_NoDuplicates() { var fullDumpStatuses = Enum.GetValues().Cast().ToList(); var filteredDumpStatuses = new Dictionary(); int totalCount = 0; foreach (DumpStatus? dumpStatus in fullDumpStatuses) { var code = dumpStatus.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredDumpStatuses.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredDumpStatuses[code] = dumpStatus; totalCount++; } Assert.Equal(totalCount, filteredDumpStatuses.Count); } /// /// Check that every DumpStatus can be mapped from a string /// /// DumpStatus value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateDumpStatusTestData))] public void DumpStatus_ToDumpStatus(DumpStatus? dumpStatus, bool expectNull) { string? longName = dumpStatus.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); string? possibleInteger = $"{(int?)dumpStatus}"; var actualNormal = longName.ToDumpStatus(); var actualSpaceless = longNameSpaceless.ToDumpStatus(); var actualInteger = possibleInteger.ToDumpStatus(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); Assert.Null(actualInteger); } else { Assert.Equal(dumpStatus, actualNormal); Assert.Equal(dumpStatus, actualSpaceless); Assert.Equal(dumpStatus, actualInteger); } } /// /// Generate a test set of DumpStatus values /// /// MemberData-compatible list of DumpStatus values public static TheoryData GenerateDumpStatusTestData() { var testData = new TheoryData() { { null, true } }; foreach (DumpStatus? dumpStatus in Enum.GetValues().Cast()) { testData.Add(dumpStatus, false); } return testData; } #endregion #region Language Code /// /// Check that every LanguageCode can be mapped from a string /// /// LanguageCode value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateLanguageCodeTestData))] public void LanguageCode_ToLanguageCode(LanguageCode? lang, bool expectNull) { string? twoLetterCode = lang?.TwoLetterCode; string? threeLetterCode = lang?.ThreeLetterCode; string? threeLetterCodeAlt = lang?.ThreeLetterCodeAlt; var actualTwoLetterCode = twoLetterCode.ToLanguageCode(); var actualThreeLetterCode = threeLetterCode.ToLanguageCode(); var actualThreeLetterCodeAlt = threeLetterCodeAlt.ToLanguageCode(); if (expectNull) { Assert.Null(actualTwoLetterCode); Assert.Null(actualThreeLetterCode); Assert.Null(actualThreeLetterCodeAlt); } else { Assert.Equal(lang, actualThreeLetterCode); // Not guaranteed to exist if (twoLetterCode is not null) Assert.Equal(lang, actualTwoLetterCode); if (threeLetterCodeAlt is not null) Assert.Equal(lang, actualThreeLetterCodeAlt); } } /// /// Ensure that every LanguageCode that has a standard/bibliographic ISO 639-2 code is unique /// [Fact] public void LanguageCode_ThreeLetterCode_NoDuplicates() { var filteredLanguages = new Dictionary(); int totalCount = 0; foreach (LanguageCode? language in LanguageCode.AllLanguages) { var code = language.ThreeLetterCode; if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredLanguages.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredLanguages[code] = language; totalCount++; } Assert.Equal(totalCount, filteredLanguages.Count); } /// /// Ensure that every LanguageCode that has a terminology ISO 639-2 code is unique /// [Fact] public void LanguageCode_ThreeLetterCodeAlt_NoDuplicates() { var filteredLanguages = new Dictionary(); int totalCount = 0; foreach (LanguageCode? language in LanguageCode.AllLanguages) { var code = language.ThreeLetterCodeAlt; if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredLanguages.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredLanguages[code] = language; totalCount++; } Assert.Equal(totalCount, filteredLanguages.Count); } /// /// Ensure that every LanguageCode that has an ISO 639-1 code is unique /// [Fact] public void LanguageCode_TwoLetterCode_NoDuplicates() { var filteredLanguages = new Dictionary(); int totalCount = 0; foreach (LanguageCode? language in LanguageCode.AllLanguages) { var code = language.TwoLetterCode; if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredLanguages.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredLanguages[code] = language; totalCount++; } Assert.Equal(totalCount, filteredLanguages.Count); } /// /// Generate a test set of LanguageCode values /// /// MemberData-compatible list of LanguageCode values public static TheoryData GenerateLanguageCodeTestData() { var testData = new TheoryData() { { null, true } }; foreach (LanguageCode? language in LanguageCode.AllLanguages) { testData.Add(language, false); } return testData; } #endregion #region Media Type /// /// Check that every MediaType has a long name provided /// /// MediaType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateMediaTypeTestData))] public void DiscType_LongName(MediaType? mediaType, bool expectNull) { var actual = mediaType.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every MediaType has a short name provided /// /// MediaType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateMediaTypeTestData))] public void DiscType_ShortName(MediaType? mediaType, bool expectNull) { var actual = mediaType.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every MediaType can be mapped from a string /// /// MediaType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateMediaTypeTestData))] public void DiscType_ToMediaType(MediaType? mediaType, bool expectNull) { string? longName = mediaType.LongName(); string? longNameSpaceless = longName? .Replace(" ", string.Empty) .Replace("-", string.Empty); var actualNormal = longName.ToMediaType(); var actualSpaceless = longNameSpaceless.ToMediaType(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(mediaType, actualNormal); Assert.Equal(mediaType, actualSpaceless); } } /// /// Generate a test set of DiscType values /// /// MemberData-compatible list of DiscType values public static TheoryData GenerateMediaTypeTestData() { var testData = new TheoryData() { { null, true } }; foreach (MediaType? discType in Enum.GetValues().Cast()) { if (discType == MediaType.NONE) testData.Add(discType, true); else testData.Add(discType, false); } return testData; } #endregion #region Pack Type /// /// Check that every PackType has a long name provided /// /// PackType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePackTypeTestData))] public void PackType_LongName(PackType? packType, bool expectNull) { var actual = packType.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every PackType has a short name provided /// /// PackType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePackTypeTestData))] public void PackType_ShortName(PackType? packType, bool expectNull) { var actual = packType.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every PackType that has a short name that is unique /// [Fact] public void PackType_ShortName_NoDuplicates() { var fullPackTypes = Enum.GetValues().Cast().ToList(); var filteredPackTypes = new Dictionary(); int totalCount = 0; foreach (PackType? packType in fullPackTypes) { var code = packType.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredPackTypes.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredPackTypes[code] = packType; totalCount++; } Assert.Equal(totalCount, filteredPackTypes.Count); } /// /// Check that every PackType can be mapped from a string /// /// PackType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePackTypeTestData))] public void PackType_ToPackType(PackType? packType, bool expectNull) { string? longName = packType.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToPackType(); var actualSpaceless = longNameSpaceless.ToPackType(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(packType, actualNormal); Assert.Equal(packType, actualSpaceless); } } /// /// Generate a test set of PackType values /// /// MemberData-compatible list of PackType values public static TheoryData GeneratePackTypeTestData() { var testData = new TheoryData() { { null, true } }; foreach (PackType? packType in Enum.GetValues().Cast()) { testData.Add(packType, false); } return testData; } #endregion #region Physical Media Type [Fact] public void PhysicalMediaType_ListMediaTypes() { var actual = Extensions.ListMediaTypes(); Assert.NotEmpty(actual); } /// /// Check that every PhysicalMediaType has a long name provided /// /// PhysicalMediaType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePhysicalMediaTypeTestData))] public void PhysicalMediaType_LongName(PhysicalMediaType? mediaType, bool expectNull) { var actual = mediaType.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every PhysicalMediaType has a short name provided /// /// PhysicalMediaType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePhysicalMediaTypeTestData))] public void PhysicalMediaType_ShortName(PhysicalMediaType? mediaType, bool expectNull) { var actual = mediaType.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every PhysicalMediaType can be mapped from a string /// /// PhysicalMediaType value to check /// True to expect a NONE value, false otherwise [Theory] [MemberData(nameof(GeneratePhysicalMediaTypeTestData))] public void PhysicalMediaType_ToPhysicalMediaType(PhysicalMediaType? mediaType, bool expectNone) { string? longName = mediaType.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToPhysicalMediaType(); var actualSpaceless = longNameSpaceless.ToPhysicalMediaType(); if (expectNone) { Assert.Equal(PhysicalMediaType.NONE, actualNormal); Assert.Equal(PhysicalMediaType.NONE, actualSpaceless); } else { Assert.Equal(mediaType, actualNormal); Assert.Equal(mediaType, actualSpaceless); } } /// /// Generate a test set of PhysicalMediaType values /// /// MemberData-compatible list of PhysicalMediaType values public static TheoryData GeneratePhysicalMediaTypeTestData() { var testData = new TheoryData() { { null, true } }; foreach (PhysicalMediaType? mediaType in Enum.GetValues().Cast()) { testData.Add(mediaType, false); } return testData; } #endregion #region Physical System /// /// PhysicalSystem values that are available /// private static readonly PhysicalSystem?[] _availableSystems = [ // BIOS Sets PhysicalSystem.MicrosoftXboxBIOS, PhysicalSystem.NintendoGameCubeBIOS, PhysicalSystem.SonyPlayStationBIOS, PhysicalSystem.SonyPlayStation2BIOS, // Disc-Based Consoles PhysicalSystem.AtariJaguarCDInteractiveMultimediaSystem, PhysicalSystem.BandaiPlaydiaQuickInteractiveSystem, PhysicalSystem.AppleBandaiPippin, PhysicalSystem.CommodoreAmigaCD32, PhysicalSystem.CommodoreAmigaCDTV, PhysicalSystem.HasbroiONEducationalGamingSystem, PhysicalSystem.HasbroVideoNow, PhysicalSystem.HasbroVideoNowColor, PhysicalSystem.HasbroVideoNowJr, PhysicalSystem.HasbroVideoNowXP, PhysicalSystem.MattelFisherPriceiXL, PhysicalSystem.MattelHyperScan, PhysicalSystem.MemorexVisualInformationSystem, PhysicalSystem.MicrosoftXbox, PhysicalSystem.MicrosoftXbox360, PhysicalSystem.MicrosoftXboxOne, PhysicalSystem.MicrosoftXboxSeriesXS, PhysicalSystem.NECPCEngineCDTurboGrafxCD, PhysicalSystem.NECPCFXPCFXGA, PhysicalSystem.NintendoGameCube, PhysicalSystem.NintendoWii, PhysicalSystem.NintendoWiiU, PhysicalSystem.Panasonic3DOInteractiveMultiplayer, PhysicalSystem.PhilipsCDi, PhysicalSystem.PlaymajiPolymega, PhysicalSystem.SegaDreamcast, PhysicalSystem.SegaMegaCDSegaCD, PhysicalSystem.SegaSaturn, PhysicalSystem.SNKNeoGeoCD, PhysicalSystem.SonyPlayStation, PhysicalSystem.SonyPlayStation2, PhysicalSystem.SonyPlayStation3, PhysicalSystem.SonyPlayStation4, PhysicalSystem.SonyPlayStation5, PhysicalSystem.SonyPlayStationPortable, PhysicalSystem.VMLabsNUON, PhysicalSystem.VTechVFlashVSmilePro, PhysicalSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem, // Computers PhysicalSystem.AcornArchimedesAndRiscPC, PhysicalSystem.AppleMacintosh, PhysicalSystem.AtariSTSeries, PhysicalSystem.CommodoreAmigaCD, PhysicalSystem.FujitsuFMTownsSeries, PhysicalSystem.IBMPCcompatible, PhysicalSystem.NECPC88Series, PhysicalSystem.NECPC98Series, PhysicalSystem.SGIIndigoSeries, PhysicalSystem.SharpX68000, PhysicalSystem.SunMicrosystemsUltra, // Arcade PhysicalSystem.CapcomPlaySystemIII, PhysicalSystem.FunworldPhotoPlay, PhysicalSystem.FuRyuOmronPurikura, PhysicalSystem.IncredibleTechnologiesEagle, PhysicalSystem.KonamieAmusement, PhysicalSystem.KonamiFireBeat, PhysicalSystem.KonamiM2, PhysicalSystem.KonamiPython2, PhysicalSystem.KonamiSystem573, PhysicalSystem.KonamiSystemGV, PhysicalSystem.KonamiTwinkle, PhysicalSystem.MeritIndustriesMegaTouchION, PhysicalSystem.NamcoPurikura, PhysicalSystem.NamcoSegaNintendoTriforce, PhysicalSystem.NamcoSystem12, PhysicalSystem.NamcoSystem22, PhysicalSystem.NamcoSystem246, PhysicalSystem.NamcoSystem256, PhysicalSystem.PanasonicM2, PhysicalSystem.PCBasedArcade, PhysicalSystem.SegaALLS, PhysicalSystem.SegaChihiro, PhysicalSystem.SegaChihiroSatelliteTerminalPC, PhysicalSystem.SegaLindbergh, PhysicalSystem.SegaLindberghSatelliteTerminalPC, PhysicalSystem.SegaNaomi, PhysicalSystem.SegaNaomi2, PhysicalSystem.SegaNaomiSatelliteTerminalPC, PhysicalSystem.SegaNu, PhysicalSystem.SegaNu11, PhysicalSystem.SegaNu2, PhysicalSystem.SegaNuSX, PhysicalSystem.SegaRingEdge, PhysicalSystem.SegaRingEdge2, PhysicalSystem.SegaRingWide, PhysicalSystem.SegaTitanVideo, PhysicalSystem.TABAustriaQuizard, // Other PhysicalSystem.AudioCD, PhysicalSystem.BDVideo, PhysicalSystem.DatelPlayStationCheatDeviceUpdates, PhysicalSystem.DVDVideo, PhysicalSystem.EnhancedCD, PhysicalSystem.HDDVDVideo, PhysicalSystem.MicrosoftPocketPC, PhysicalSystem.MP3AudioDisc, PhysicalSystem.NavisoftNaviken, PhysicalSystem.PalmOS, PhysicalSystem.PhotoCD, PhysicalSystem.Psion, PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem, PhysicalSystem.SharpZaurus, PhysicalSystem.SonyElectronicBook, PhysicalSystem.TaoiKTV, PhysicalSystem.TomyKissSite, PhysicalSystem.VideoCD, ]; /// /// PhysicalSystem values that are considered markers /// private static readonly PhysicalSystem?[] _markerSystems = [ PhysicalSystem.MarkerArcadeEnd, PhysicalSystem.MarkerComputerEnd, PhysicalSystem.MarkerDiscBasedConsoleEnd, PhysicalSystem.MarkerOtherEnd, ]; /// /// Map of PhysicalSystem values to their corresponding categories /// private static readonly Dictionary _systemCategoryMap = new() { // BIOS [PhysicalSystem.MicrosoftXboxBIOS] = SystemCategory.NONE, [PhysicalSystem.NintendoGameCubeBIOS] = SystemCategory.NONE, [PhysicalSystem.SonyPlayStationBIOS] = SystemCategory.NONE, [PhysicalSystem.SonyPlayStation2BIOS] = SystemCategory.NONE, // Disc-Based Consoles [PhysicalSystem.AppleBandaiPippin] = SystemCategory.DiscBasedConsole, [PhysicalSystem.AtariJaguarCDInteractiveMultimediaSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.BandaiPlaydiaQuickInteractiveSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.CommodoreAmigaCD32] = SystemCategory.DiscBasedConsole, [PhysicalSystem.CommodoreAmigaCDTV] = SystemCategory.DiscBasedConsole, [PhysicalSystem.EnvizionsEVOSmartConsole] = SystemCategory.DiscBasedConsole, [PhysicalSystem.FujitsuFMTownsMarty] = SystemCategory.DiscBasedConsole, [PhysicalSystem.HasbroiONEducationalGamingSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.HasbroVideoNow] = SystemCategory.DiscBasedConsole, [PhysicalSystem.HasbroVideoNowColor] = SystemCategory.DiscBasedConsole, [PhysicalSystem.HasbroVideoNowJr] = SystemCategory.DiscBasedConsole, [PhysicalSystem.HasbroVideoNowXP] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MattelFisherPriceiXL] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MattelHyperScan] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MemorexVisualInformationSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MicrosoftXbox] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MicrosoftXbox360] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MicrosoftXboxOne] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MicrosoftXboxSeriesXS] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NECPCEngineCDTurboGrafxCD] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NECPCFXPCFXGA] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NintendoGameCube] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NintendoSonySuperNESCDROMSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NintendoWii] = SystemCategory.DiscBasedConsole, [PhysicalSystem.NintendoWiiU] = SystemCategory.DiscBasedConsole, [PhysicalSystem.Panasonic3DOInteractiveMultiplayer] = SystemCategory.DiscBasedConsole, [PhysicalSystem.PhilipsCDi] = SystemCategory.DiscBasedConsole, [PhysicalSystem.PlaymajiPolymega] = SystemCategory.DiscBasedConsole, [PhysicalSystem.PioneerLaserActive] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SegaDreamcast] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SegaMegaCDSegaCD] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SegaSaturn] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SNKNeoGeoCD] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStation] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStation2] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStation3] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStation4] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStation5] = SystemCategory.DiscBasedConsole, [PhysicalSystem.SonyPlayStationPortable] = SystemCategory.DiscBasedConsole, [PhysicalSystem.VMLabsNUON] = SystemCategory.DiscBasedConsole, [PhysicalSystem.VTechVFlashVSmilePro] = SystemCategory.DiscBasedConsole, [PhysicalSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem] = SystemCategory.DiscBasedConsole, [PhysicalSystem.MarkerDiscBasedConsoleEnd] = SystemCategory.NONE, // Computers [PhysicalSystem.AcornArchimedesAndRiscPC] = SystemCategory.Computer, [PhysicalSystem.AppleMacintosh] = SystemCategory.Computer, [PhysicalSystem.AtariSTSeries] = SystemCategory.Computer, [PhysicalSystem.Commodore64] = SystemCategory.Computer, [PhysicalSystem.CommodoreAmigaCD] = SystemCategory.Computer, [PhysicalSystem.FujitsuFMTownsSeries] = SystemCategory.Computer, [PhysicalSystem.IBMPCcompatible] = SystemCategory.Computer, [PhysicalSystem.MicrosoftMSX] = SystemCategory.Computer, [PhysicalSystem.NECPC88Series] = SystemCategory.Computer, [PhysicalSystem.NECPC98Series] = SystemCategory.Computer, [PhysicalSystem.SGIIndigoSeries] = SystemCategory.Computer, [PhysicalSystem.SharpX68000] = SystemCategory.Computer, [PhysicalSystem.SinclairZXSpectrum] = SystemCategory.Computer, [PhysicalSystem.SunMicrosystemsUltra] = SystemCategory.Computer, [PhysicalSystem.MarkerComputerEnd] = SystemCategory.NONE, // Arcade [PhysicalSystem.AmericanLaserGames3DO] = SystemCategory.Arcade, [PhysicalSystem.Atari3DO] = SystemCategory.Arcade, [PhysicalSystem.Atronic] = SystemCategory.Arcade, [PhysicalSystem.AUSCOMSystem1] = SystemCategory.Arcade, [PhysicalSystem.BallyGameMagic] = SystemCategory.Arcade, [PhysicalSystem.CapcomPlaySystemIII] = SystemCategory.Arcade, [PhysicalSystem.CDExpressCuboCD32] = SystemCategory.Arcade, [PhysicalSystem.FunworldPhotoPlay] = SystemCategory.Arcade, [PhysicalSystem.FuRyuOmronPurikura] = SystemCategory.Arcade, [PhysicalSystem.GlobalVRVarious] = SystemCategory.Arcade, [PhysicalSystem.GlobalVRVortek] = SystemCategory.Arcade, [PhysicalSystem.GlobalVRVortekV3] = SystemCategory.Arcade, [PhysicalSystem.ICEPCHardware] = SystemCategory.Arcade, [PhysicalSystem.IncredibleTechnologiesEagle] = SystemCategory.Arcade, [PhysicalSystem.IncredibleTechnologiesVarious] = SystemCategory.Arcade, [PhysicalSystem.JVLiTouch] = SystemCategory.Arcade, [PhysicalSystem.KonamieAmusement] = SystemCategory.Arcade, [PhysicalSystem.KonamiFireBeat] = SystemCategory.Arcade, [PhysicalSystem.KonamiM2] = SystemCategory.Arcade, [PhysicalSystem.KonamiPython] = SystemCategory.Arcade, [PhysicalSystem.KonamiPython2] = SystemCategory.Arcade, [PhysicalSystem.KonamiSystem573] = SystemCategory.Arcade, [PhysicalSystem.KonamiSystemGV] = SystemCategory.Arcade, [PhysicalSystem.KonamiTwinkle] = SystemCategory.Arcade, [PhysicalSystem.KonamiVarious] = SystemCategory.Arcade, [PhysicalSystem.MeritIndustriesBoardwalk] = SystemCategory.Arcade, [PhysicalSystem.MeritIndustriesMegaTouchForce] = SystemCategory.Arcade, [PhysicalSystem.MeritIndustriesMegaTouchION] = SystemCategory.Arcade, [PhysicalSystem.MeritIndustriesMegaTouchMaxx] = SystemCategory.Arcade, [PhysicalSystem.MeritIndustriesMegaTouchXL] = SystemCategory.Arcade, [PhysicalSystem.NamcoPurikura] = SystemCategory.Arcade, [PhysicalSystem.NamcoSegaNintendoTriforce] = SystemCategory.Arcade, [PhysicalSystem.NamcoSystem12] = SystemCategory.Arcade, [PhysicalSystem.NamcoSystem22] = SystemCategory.Arcade, [PhysicalSystem.NamcoSystem246] = SystemCategory.Arcade, [PhysicalSystem.NamcoSystem256] = SystemCategory.Arcade, [PhysicalSystem.NewJatreCDi] = SystemCategory.Arcade, [PhysicalSystem.NichibutsuHighRateSystem] = SystemCategory.Arcade, [PhysicalSystem.NichibutsuSuperCD] = SystemCategory.Arcade, [PhysicalSystem.NichibutsuXRateSystem] = SystemCategory.Arcade, [PhysicalSystem.PanasonicM2] = SystemCategory.Arcade, [PhysicalSystem.PCBasedArcade] = SystemCategory.Arcade, [PhysicalSystem.PhotoPlayVarious] = SystemCategory.Arcade, [PhysicalSystem.RawThrillsVarious] = SystemCategory.Arcade, [PhysicalSystem.SegaALLS] = SystemCategory.Arcade, [PhysicalSystem.SegaChihiro] = SystemCategory.Arcade, [PhysicalSystem.SegaChihiroSatelliteTerminalPC] = SystemCategory.Arcade, [PhysicalSystem.SegaEuropaR] = SystemCategory.Arcade, [PhysicalSystem.SegaLindbergh] = SystemCategory.Arcade, [PhysicalSystem.SegaLindberghSatelliteTerminalPC] = SystemCategory.Arcade, [PhysicalSystem.SegaNaomi] = SystemCategory.Arcade, [PhysicalSystem.SegaNaomi2] = SystemCategory.Arcade, [PhysicalSystem.SegaNaomiSatelliteTerminalPC] = SystemCategory.Arcade, [PhysicalSystem.SegaNu] = SystemCategory.Arcade, [PhysicalSystem.SegaNu11] = SystemCategory.Arcade, [PhysicalSystem.SegaNu2] = SystemCategory.Arcade, [PhysicalSystem.SegaNuSX] = SystemCategory.Arcade, [PhysicalSystem.SegaRingEdge] = SystemCategory.Arcade, [PhysicalSystem.SegaRingEdge2] = SystemCategory.Arcade, [PhysicalSystem.SegaRingWide] = SystemCategory.Arcade, [PhysicalSystem.SegaSystem32] = SystemCategory.Arcade, [PhysicalSystem.SegaTitanVideo] = SystemCategory.Arcade, [PhysicalSystem.SeibuCATSSystem] = SystemCategory.Arcade, [PhysicalSystem.TABAustriaQuizard] = SystemCategory.Arcade, [PhysicalSystem.TsunamiTsuMoMultiGameMotionSystem] = SystemCategory.Arcade, [PhysicalSystem.UltraCade] = SystemCategory.Arcade, [PhysicalSystem.MarkerArcadeEnd] = SystemCategory.NONE, // Other [PhysicalSystem.AudioCD] = SystemCategory.Other, [PhysicalSystem.BDVideo] = SystemCategory.Other, [PhysicalSystem.DatelPlayStationCheatDeviceUpdates] = SystemCategory.Other, [PhysicalSystem.DVDAudio] = SystemCategory.Other, [PhysicalSystem.DVDVideo] = SystemCategory.Other, [PhysicalSystem.EnhancedCD] = SystemCategory.Other, [PhysicalSystem.HDDVDVideo] = SystemCategory.Other, [PhysicalSystem.MicrosoftPocketPC] = SystemCategory.Other, [PhysicalSystem.MP3AudioDisc] = SystemCategory.Other, [PhysicalSystem.NavisoftNaviken] = SystemCategory.Other, [PhysicalSystem.PalmOS] = SystemCategory.Other, [PhysicalSystem.PhotoCD] = SystemCategory.Other, [PhysicalSystem.Psion] = SystemCategory.Other, [PhysicalSystem.RainbowDisc] = SystemCategory.Other, [PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem] = SystemCategory.Other, [PhysicalSystem.SharpZaurus] = SystemCategory.Other, [PhysicalSystem.SonyElectronicBook] = SystemCategory.Other, [PhysicalSystem.SuperAudioCD] = SystemCategory.Other, [PhysicalSystem.TaoiKTV] = SystemCategory.Other, [PhysicalSystem.TomyKissSite] = SystemCategory.Other, [PhysicalSystem.VideoCD] = SystemCategory.Other, [PhysicalSystem.MarkerOtherEnd] = SystemCategory.NONE, }; /// /// PhysicalSystem values that have cuesheet packs /// private static readonly PhysicalSystem?[] _systemsWithCues = [ // Disc-Based Consoles PhysicalSystem.AppleBandaiPippin, PhysicalSystem.AtariJaguarCDInteractiveMultimediaSystem, PhysicalSystem.BandaiPlaydiaQuickInteractiveSystem, PhysicalSystem.CommodoreAmigaCD32, PhysicalSystem.CommodoreAmigaCDTV, PhysicalSystem.HasbroiONEducationalGamingSystem, PhysicalSystem.HasbroVideoNow, PhysicalSystem.HasbroVideoNowColor, PhysicalSystem.HasbroVideoNowJr, PhysicalSystem.HasbroVideoNowXP, PhysicalSystem.MattelFisherPriceiXL, PhysicalSystem.MattelHyperScan, PhysicalSystem.MemorexVisualInformationSystem, PhysicalSystem.MicrosoftXbox, PhysicalSystem.MicrosoftXbox360, PhysicalSystem.NECPCEngineCDTurboGrafxCD, PhysicalSystem.NECPCFXPCFXGA, PhysicalSystem.Panasonic3DOInteractiveMultiplayer, PhysicalSystem.PhilipsCDi, PhysicalSystem.SegaDreamcast, PhysicalSystem.SegaMegaCDSegaCD, PhysicalSystem.SegaSaturn, PhysicalSystem.SNKNeoGeoCD, PhysicalSystem.SonyPlayStation, PhysicalSystem.SonyPlayStation2, PhysicalSystem.SonyPlayStation3, PhysicalSystem.VTechVFlashVSmilePro, // Computers PhysicalSystem.AcornArchimedesAndRiscPC, PhysicalSystem.AppleMacintosh, PhysicalSystem.AtariSTSeries, PhysicalSystem.CommodoreAmigaCD, PhysicalSystem.FujitsuFMTownsSeries, PhysicalSystem.IBMPCcompatible, PhysicalSystem.NECPC88Series, PhysicalSystem.NECPC98Series, PhysicalSystem.SGIIndigoSeries, PhysicalSystem.SharpX68000, PhysicalSystem.SunMicrosystemsUltra, // Arcade PhysicalSystem.CapcomPlaySystemIII, PhysicalSystem.FunworldPhotoPlay, PhysicalSystem.IncredibleTechnologiesEagle, PhysicalSystem.KonamieAmusement, PhysicalSystem.KonamiFireBeat, PhysicalSystem.KonamiM2, PhysicalSystem.KonamiSystem573, PhysicalSystem.KonamiSystemGV, PhysicalSystem.NamcoSegaNintendoTriforce, PhysicalSystem.NamcoSystem22, PhysicalSystem.NamcoSystem246, PhysicalSystem.NamcoSystem256, PhysicalSystem.PanasonicM2, PhysicalSystem.PCBasedArcade, PhysicalSystem.SegaChihiro, PhysicalSystem.SegaChihiroSatelliteTerminalPC, PhysicalSystem.SegaNaomi, PhysicalSystem.SegaNaomi2, PhysicalSystem.SegaNaomiSatelliteTerminalPC, PhysicalSystem.TABAustriaQuizard, // Other PhysicalSystem.AudioCD, PhysicalSystem.DatelPlayStationCheatDeviceUpdates, PhysicalSystem.EnhancedCD, PhysicalSystem.MicrosoftPocketPC, PhysicalSystem.MP3AudioDisc, PhysicalSystem.NavisoftNaviken, PhysicalSystem.PalmOS, PhysicalSystem.PhotoCD, PhysicalSystem.Psion, PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem, PhysicalSystem.SharpZaurus, PhysicalSystem.SonyElectronicBook, PhysicalSystem.TomyKissSite, PhysicalSystem.VideoCD, ]; /// /// PhysicalSystem values that have dats /// private static readonly PhysicalSystem?[] _systemsWithDats = [ // BIOS Sets PhysicalSystem.MicrosoftXboxBIOS, PhysicalSystem.NintendoGameCubeBIOS, PhysicalSystem.SonyPlayStationBIOS, PhysicalSystem.SonyPlayStation2BIOS, // Disc-Based Consoles PhysicalSystem.AppleBandaiPippin, PhysicalSystem.AtariJaguarCDInteractiveMultimediaSystem, PhysicalSystem.BandaiPlaydiaQuickInteractiveSystem, PhysicalSystem.CommodoreAmigaCD32, PhysicalSystem.CommodoreAmigaCDTV, PhysicalSystem.HasbroiONEducationalGamingSystem, PhysicalSystem.HasbroVideoNow, PhysicalSystem.HasbroVideoNowColor, PhysicalSystem.HasbroVideoNowJr, PhysicalSystem.HasbroVideoNowXP, PhysicalSystem.MattelFisherPriceiXL, PhysicalSystem.MattelHyperScan, PhysicalSystem.MemorexVisualInformationSystem, PhysicalSystem.MicrosoftXbox, PhysicalSystem.MicrosoftXbox360, PhysicalSystem.MicrosoftXboxOne, PhysicalSystem.MicrosoftXboxSeriesXS, PhysicalSystem.NECPCEngineCDTurboGrafxCD, PhysicalSystem.NECPCFXPCFXGA, PhysicalSystem.NintendoGameCube, PhysicalSystem.NintendoWii, PhysicalSystem.NintendoWiiU, PhysicalSystem.Panasonic3DOInteractiveMultiplayer, PhysicalSystem.PhilipsCDi, PhysicalSystem.PlaymajiPolymega, PhysicalSystem.SegaDreamcast, PhysicalSystem.SegaMegaCDSegaCD, PhysicalSystem.SegaSaturn, PhysicalSystem.SNKNeoGeoCD, PhysicalSystem.SonyPlayStation, PhysicalSystem.SonyPlayStation2, PhysicalSystem.SonyPlayStation3, PhysicalSystem.SonyPlayStation4, PhysicalSystem.SonyPlayStation5, PhysicalSystem.SonyPlayStationPortable, PhysicalSystem.VMLabsNUON, PhysicalSystem.VTechVFlashVSmilePro, PhysicalSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem, // Computers PhysicalSystem.AcornArchimedesAndRiscPC, PhysicalSystem.AppleMacintosh, PhysicalSystem.AtariSTSeries, PhysicalSystem.CommodoreAmigaCD, PhysicalSystem.FujitsuFMTownsSeries, PhysicalSystem.IBMPCcompatible, PhysicalSystem.NECPC88Series, PhysicalSystem.NECPC98Series, PhysicalSystem.SGIIndigoSeries, PhysicalSystem.SharpX68000, PhysicalSystem.SunMicrosystemsUltra, // Arcade PhysicalSystem.CapcomPlaySystemIII, PhysicalSystem.FunworldPhotoPlay, PhysicalSystem.FuRyuOmronPurikura, PhysicalSystem.IncredibleTechnologiesEagle, PhysicalSystem.KonamieAmusement, PhysicalSystem.KonamiFireBeat, PhysicalSystem.KonamiM2, PhysicalSystem.KonamiPython2, PhysicalSystem.KonamiSystem573, PhysicalSystem.KonamiSystemGV, PhysicalSystem.MeritIndustriesMegaTouchION, PhysicalSystem.NamcoPurikura, PhysicalSystem.NamcoSegaNintendoTriforce, PhysicalSystem.NamcoSystem22, PhysicalSystem.NamcoSystem246, PhysicalSystem.NamcoSystem256, PhysicalSystem.PanasonicM2, PhysicalSystem.PCBasedArcade, PhysicalSystem.SegaALLS, PhysicalSystem.SegaChihiro, PhysicalSystem.SegaChihiroSatelliteTerminalPC, PhysicalSystem.SegaLindbergh, PhysicalSystem.SegaLindberghSatelliteTerminalPC, PhysicalSystem.SegaNaomi, PhysicalSystem.SegaNaomi2, PhysicalSystem.SegaNaomiSatelliteTerminalPC, PhysicalSystem.SegaNu, PhysicalSystem.SegaNu11, PhysicalSystem.SegaNu2, PhysicalSystem.SegaNuSX, PhysicalSystem.SegaRingEdge, PhysicalSystem.SegaRingEdge2, PhysicalSystem.SegaRingWide, PhysicalSystem.TABAustriaQuizard, // Other PhysicalSystem.AudioCD, PhysicalSystem.BDVideo, PhysicalSystem.DatelPlayStationCheatDeviceUpdates, PhysicalSystem.DVDVideo, PhysicalSystem.EnhancedCD, PhysicalSystem.HDDVDVideo, PhysicalSystem.MicrosoftPocketPC, PhysicalSystem.MP3AudioDisc, PhysicalSystem.NavisoftNaviken, PhysicalSystem.PalmOS, PhysicalSystem.PhotoCD, PhysicalSystem.Psion, PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem, PhysicalSystem.SharpZaurus, PhysicalSystem.SonyElectronicBook, PhysicalSystem.TomyKissSite, PhysicalSystem.VideoCD, ]; /// /// PhysicalSystem values that have SBI packs /// private static readonly PhysicalSystem?[] _systemsWithSbis = [ // Disc-Based Consoles PhysicalSystem.SonyPlayStation, // Computers PhysicalSystem.AppleMacintosh, PhysicalSystem.IBMPCcompatible, ]; /// /// PhysicalSystem values that are considered detected by Windows /// private static readonly PhysicalSystem?[] _windowsDetectedSystems = [ // Disc-Based Consoles PhysicalSystem.CommodoreAmigaCD32, PhysicalSystem.CommodoreAmigaCDTV, PhysicalSystem.EnvizionsEVOSmartConsole, PhysicalSystem.FujitsuFMTownsMarty, PhysicalSystem.HasbroiONEducationalGamingSystem, PhysicalSystem.MattelFisherPriceiXL, PhysicalSystem.MattelHyperScan, PhysicalSystem.MemorexVisualInformationSystem, PhysicalSystem.MicrosoftXbox, PhysicalSystem.MicrosoftXbox360, PhysicalSystem.MicrosoftXboxOne, PhysicalSystem.MicrosoftXboxSeriesXS, PhysicalSystem.NECPCEngineCDTurboGrafxCD, PhysicalSystem.NECPCFXPCFXGA, PhysicalSystem.NintendoSonySuperNESCDROMSystem, PhysicalSystem.PlaymajiPolymega, PhysicalSystem.SegaDreamcast, PhysicalSystem.SegaMegaCDSegaCD, PhysicalSystem.SegaSaturn, PhysicalSystem.SNKNeoGeoCD, PhysicalSystem.SonyPlayStation, PhysicalSystem.SonyPlayStation2, PhysicalSystem.SonyPlayStation3, PhysicalSystem.SonyPlayStation4, PhysicalSystem.SonyPlayStation5, PhysicalSystem.SonyPlayStationPortable, PhysicalSystem.VMLabsNUON, PhysicalSystem.VTechVFlashVSmilePro, PhysicalSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem, // Computers PhysicalSystem.AcornArchimedesAndRiscPC, PhysicalSystem.AtariSTSeries, // TODO: Confirm this is Windows-readable PhysicalSystem.Commodore64, // TODO: Confirm this is Windows-readable PhysicalSystem.CommodoreAmigaCD, PhysicalSystem.FujitsuFMTownsSeries, PhysicalSystem.IBMPCcompatible, PhysicalSystem.MicrosoftMSX, // TODO: Confirm this is Windows-readable PhysicalSystem.NECPC88Series, PhysicalSystem.NECPC98Series, PhysicalSystem.SGIIndigoSeries, PhysicalSystem.SharpX68000, PhysicalSystem.SinclairZXSpectrum, // TODO: Confirm this is Windows-readable PhysicalSystem.SunMicrosystemsUltra, // TODO: Confirm this is Windows-readable // Arcade PhysicalSystem.Atronic, PhysicalSystem.AUSCOMSystem1, PhysicalSystem.BallyGameMagic, PhysicalSystem.CapcomPlaySystemIII, PhysicalSystem.CDExpressCuboCD32, PhysicalSystem.FunworldPhotoPlay, PhysicalSystem.FuRyuOmronPurikura, PhysicalSystem.GlobalVRVarious, PhysicalSystem.GlobalVRVortek, PhysicalSystem.GlobalVRVortekV3, PhysicalSystem.ICEPCHardware, PhysicalSystem.IncredibleTechnologiesEagle, PhysicalSystem.IncredibleTechnologiesVarious, PhysicalSystem.JVLiTouch, PhysicalSystem.KonamieAmusement, PhysicalSystem.KonamiFireBeat, PhysicalSystem.KonamiM2, PhysicalSystem.KonamiPython, PhysicalSystem.KonamiPython2, PhysicalSystem.KonamiSystem573, PhysicalSystem.KonamiSystemGV, PhysicalSystem.KonamiTwinkle, PhysicalSystem.KonamiVarious, PhysicalSystem.MeritIndustriesBoardwalk, PhysicalSystem.MeritIndustriesMegaTouchForce, PhysicalSystem.MeritIndustriesMegaTouchION, PhysicalSystem.MeritIndustriesMegaTouchMaxx, PhysicalSystem.MeritIndustriesMegaTouchXL, PhysicalSystem.NamcoPurikura, PhysicalSystem.NamcoSegaNintendoTriforce, PhysicalSystem.NamcoSystem12, PhysicalSystem.NamcoSystem22, PhysicalSystem.NamcoSystem246, PhysicalSystem.NamcoSystem256, PhysicalSystem.NichibutsuHighRateSystem, PhysicalSystem.NichibutsuSuperCD, PhysicalSystem.NichibutsuXRateSystem, PhysicalSystem.PCBasedArcade, PhysicalSystem.PhotoPlayVarious, PhysicalSystem.RawThrillsVarious, PhysicalSystem.SegaALLS, PhysicalSystem.SegaChihiro, PhysicalSystem.SegaChihiroSatelliteTerminalPC, PhysicalSystem.SegaEuropaR, PhysicalSystem.SegaLindbergh, PhysicalSystem.SegaLindberghSatelliteTerminalPC, PhysicalSystem.SegaNaomi, PhysicalSystem.SegaNaomi2, PhysicalSystem.SegaNaomiSatelliteTerminalPC, PhysicalSystem.SegaNu, PhysicalSystem.SegaNu11, PhysicalSystem.SegaNu2, PhysicalSystem.SegaNuSX, PhysicalSystem.SegaRingEdge, PhysicalSystem.SegaRingEdge2, PhysicalSystem.SegaRingWide, PhysicalSystem.SegaSystem32, PhysicalSystem.SegaTitanVideo, PhysicalSystem.SeibuCATSSystem, PhysicalSystem.TABAustriaQuizard, PhysicalSystem.TsunamiTsuMoMultiGameMotionSystem, PhysicalSystem.UltraCade, // Other PhysicalSystem.AudioCD, PhysicalSystem.BDVideo, PhysicalSystem.DVDAudio, PhysicalSystem.DVDVideo, PhysicalSystem.EnhancedCD, PhysicalSystem.HDDVDVideo, PhysicalSystem.MicrosoftPocketPC, PhysicalSystem.MP3AudioDisc, PhysicalSystem.NavisoftNaviken, PhysicalSystem.PalmOS, PhysicalSystem.PhotoCD, PhysicalSystem.Psion, PhysicalSystem.RainbowDisc, PhysicalSystem.SharpZaurus, PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem, PhysicalSystem.SonyElectronicBook, PhysicalSystem.TaoiKTV, PhysicalSystem.TomyKissSite, PhysicalSystem.VideoCD, ]; /// /// PhysicalSystem values that are considered XGD /// private static readonly PhysicalSystem?[] _xgdSystems = [ PhysicalSystem.MicrosoftXbox, PhysicalSystem.MicrosoftXbox360, PhysicalSystem.MicrosoftXboxOne, PhysicalSystem.MicrosoftXboxSeriesXS, ]; /// /// Check that all systems detected by Windows are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateWindowsDetectedSystemsTestData))] public void PhysicalSystem_DetectedByWindows(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem.DetectedByWindows(); Assert.Equal(expected, actual); } /// /// Check that all marker systems are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateMarkerSystemsTestData))] public void PhysicalSystem_IsMarker(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem?.IsMarker ?? false; Assert.Equal(expected, actual); } /// /// Check that all XGD systems are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateXGDSystemsTestData))] public void PhysicalSystem_IsXGD(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem.IsXGD(); Assert.Equal(expected, actual); } [Fact] public void PhysicalSystem_ListPhysicalSystem() { var actual = Extensions.ListSystems(); Assert.NotEmpty(actual); } /// /// Check that all systems are mapped to a category /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateCategoriesSystemTestData))] public void PhysicalSystem_Category(PhysicalSystem? physicalSystem, SystemCategory expected) { SystemCategory actual = physicalSystem?.Category ?? SystemCategory.NONE; Assert.Equal(expected, actual); } /// /// Check that all available systems are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateAvailableSystemsTestData))] public void PhysicalSystem_IsAvailable(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem?.Available ?? false; Assert.Equal(expected, actual); } /// /// Check that all systems with cuesheets are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateCuesheetSystemsTestData))] public void PhysicalSystem_HasCues(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem?.HasCues ?? false; Assert.Equal(expected, actual); } /// /// Check that all systems with DATs are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateDatSystemsTestData))] public void PhysicalSystem_HasDat(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem?.HasDat ?? false; Assert.Equal(expected, actual); } /// /// Check that all systems with SBIs are marked properly /// /// PhysicalSystem value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateSbiSystemsTestData))] public void PhysicalSystem_HasSbi(PhysicalSystem? physicalSystem, bool expected) { bool actual = physicalSystem?.HasSbi ?? false; Assert.Equal(expected, actual); } /// /// Check that every PhysicalSystem can be mapped from a string /// /// PhysicalSystem value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GeneratePhysicalSystemTestData))] public void PhysicalSystem_ToPhysicalSystem(PhysicalSystem? physicalSystem, bool expectNull) { string? longName = physicalSystem?.Name; string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToPhysicalSystem(); var actualSpaceless = longNameSpaceless.ToPhysicalSystem(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(physicalSystem, actualNormal); Assert.Equal(physicalSystem, actualSpaceless); } } /// /// Generate a test set of PhysicalSystem values /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GeneratePhysicalSystemTestData() { var testData = new TheoryData() { { null, true } }; foreach (PhysicalSystem? physicalSystem in PhysicalSystem.AllSystems) { // We want to skip all markers for this if (physicalSystem.IsMarker) continue; testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that are available /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateAvailableSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_availableSystems.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values mapped to their categories /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateCategoriesSystemTestData() { var testData = new TheoryData() { { null, SystemCategory.NONE } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { testData.Add(physicalSystem, _systemCategoryMap[physicalSystem]); } return testData; } /// /// Generate a test set of PhysicalSystem values that have cuesheets /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateCuesheetSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_systemsWithCues.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that have DATs /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateDatSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_systemsWithDats.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that are considered markers /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateMarkerSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_markerSystems.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that have SBIs /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateSbiSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_systemsWithSbis.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that are detected by Windows /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateWindowsDetectedSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_windowsDetectedSystems.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } /// /// Generate a test set of PhysicalSystem values that are considered XGD /// /// MemberData-compatible list of PhysicalSystem values public static TheoryData GenerateXGDSystemsTestData() { var testData = new TheoryData() { { null, false } }; foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems) { if (_xgdSystems.Contains(physicalSystem)) testData.Add(physicalSystem, true); else testData.Add(physicalSystem, false); } return testData; } #endregion #region Region /// /// Ensure that every RegionCode that has a short name that is unique /// [Fact] public void RegionCode_ShortName_NoDuplicates() { var filteredRegions = new Dictionary(); int totalCount = 0; foreach (RegionCode? region in RegionCode.AllRegions) { var code = region.Code; if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredRegions.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredRegions[code] = region; totalCount++; } Assert.Equal(totalCount, filteredRegions.Count); } /// /// Check that every RegionCode can be mapped from a string /// /// RegionCode value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateRegionCodeTestData))] public void RegionCode_ToRegionCode(RegionCode? region, bool expectNull) { string? longName = region?.Name; string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToRegionCode(); var actualSpaceless = longNameSpaceless.ToRegionCode(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(region, actualNormal); Assert.Equal(region, actualSpaceless); } } /// /// Generate a test set of RegionCode values /// /// MemberData-compatible list of RegionCode values public static TheoryData GenerateRegionCodeTestData() { var testData = new TheoryData() { { null, true } }; foreach (RegionCode? region in RegionCode.AllRegions) { testData.Add(region, false); } return testData; } #endregion #region Site Code /// /// SiteCode values that are considered Boolean /// private static readonly SiteCode?[] _booleanSiteCodes = [ SiteCode.PCMacHybrid, SiteCode.PostgapType, SiteCode.VCD, ]; /// /// SiteCode values that are considered Comment /// private static readonly SiteCode?[] _commentSiteCodes = [ // Identifying Info SiteCode.AdditionalBCAData, SiteCode.AlternativeTitle, SiteCode.AlternativeForeignTitle, SiteCode.BBFCRegistrationNumber, SiteCode.CompatibleOS, SiteCode.CoverID, SiteCode.DiscHologramID, SiteCode.DiscID, SiteCode.DiscTitleNonLatin, SiteCode.DMIHash, SiteCode.DNASDiscID, SiteCode.EditionNonLatin, SiteCode.Filename, SiteCode.Genre, SiteCode.HighSierraVolumeDescriptor, SiteCode.InternalName, SiteCode.InternalSerialName, SiteCode.ISBN, SiteCode.ISSN, SiteCode.Multisession, SiteCode.PCMacHybrid, SiteCode.PFIHash, SiteCode.PostgapType, SiteCode.PPN, SiteCode.Protection, SiteCode.RingPerfectAudioOffset, SiteCode.Series, SiteCode.SSHash, SiteCode.SSVersion, SiteCode.SteamAppID, SiteCode.TitleID, SiteCode.VCD, SiteCode.VFCCode, SiteCode.VolumeLabel, SiteCode.XeMID, SiteCode.XMID, // Publisher / Company IDs SiteCode.TwoKGamesID, SiteCode.AcclaimID, SiteCode.AccoladeID, SiteCode.ActivisionID, SiteCode.BandaiID, SiteCode.BethesdaID, SiteCode.CDProjektID, SiteCode.DiceMultimedia, SiteCode.DisneyInteractiveID, SiteCode.EidosID, SiteCode.ElectronicArtsID, SiteCode.FocusMultimedia, SiteCode.FoxInteractiveID, SiteCode.GSPSoftware, SiteCode.GTInteractiveID, SiteCode.InterplayID, SiteCode.JASRACID, SiteCode.KingRecordsID, SiteCode.KoeiID, SiteCode.KonamiID, SiteCode.LucasArtsID, SiteCode.MicrosoftID, SiteCode.NaganoID, SiteCode.NamcoID, SiteCode.NipponIchiSoftwareID, SiteCode.OriginID, SiteCode.PonyCanyonID, SiteCode.SegaID, SiteCode.SelenID, SiteCode.SierraID, SiteCode.TaitoID, SiteCode.UbisoftID, SiteCode.ValveID, ]; /// /// SiteCode values that are considered Content /// private static readonly SiteCode?[] _contentSiteCodes = [ SiteCode.Applications, SiteCode.Extras, SiteCode.GameFootage, SiteCode.Games, SiteCode.NetYarozeGames, SiteCode.Patches, SiteCode.PlayableDemos, SiteCode.RollingDemos, SiteCode.Savegames, SiteCode.SteamSimSidDepotID, SiteCode.SteamCsmCsdDepotID, SiteCode.TechDemos, SiteCode.Videos, ]; /// /// SiteCode values that are considered Multiline /// private static readonly SiteCode?[] _multilineSiteCodes = [ SiteCode.Extras, SiteCode.Filename, SiteCode.Games, SiteCode.GameFootage, SiteCode.HighSierraVolumeDescriptor, SiteCode.Multisession, SiteCode.NetYarozeGames, SiteCode.Patches, SiteCode.PlayableDemos, SiteCode.RollingDemos, SiteCode.Savegames, SiteCode.SteamSimSidDepotID, SiteCode.SteamCsmCsdDepotID, SiteCode.TechDemos, SiteCode.Videos, ]; [Fact] public void SiteCode_ListSiteCodes() { var actual = Extensions.ListSiteCodes(); Assert.NotEmpty(actual); } /// /// Check that all boolean site codes are marked properly /// /// SiteCode value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateBooleanSiteCodesTestData))] public void SiteCode_IsBoolean(SiteCode? siteCode, bool expected) { bool actual = siteCode?.IsBoolean ?? false; Assert.Equal(expected, actual); } /// /// Check that all comment site codes are marked properly /// /// SiteCode value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateCommentSiteCodesTestData))] public void SiteCode_IsCommentCode(SiteCode? siteCode, bool expected) { bool actual = siteCode?.IsCommentCode ?? false; Assert.Equal(expected, actual); } /// /// Check that all content site codes are marked properly /// /// SiteCode value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateContentSiteCodesTestData))] public void SiteCode_IsContentCode(SiteCode? siteCode, bool expected) { bool actual = siteCode?.IsContentCode ?? false; Assert.Equal(expected, actual); } /// /// Check that all multiline site codes are marked properly /// /// SiteCode value to check /// The expected value to come from the check [Theory] [MemberData(nameof(GenerateMultilineSiteCodesTestData))] public void SiteCode_IsMultiLine(SiteCode? siteCode, bool expected) { bool actual = siteCode?.IsMultiLine ?? false; Assert.Equal(expected, actual); } /// /// Generate a test set of SiteCode values that are considered Boolean /// /// MemberData-compatible list of SiteCode values public static TheoryData GenerateBooleanSiteCodesTestData() { var testData = new TheoryData() { { null, false } }; foreach (SiteCode siteCode in SiteCode.AllSiteCodes) { if (_booleanSiteCodes.Contains(siteCode)) testData.Add(siteCode, true); else testData.Add(siteCode, false); } return testData; } /// /// Generate a test set of SiteCode values that are considered Comment /// /// MemberData-compatible list of SiteCode values public static TheoryData GenerateCommentSiteCodesTestData() { var testData = new TheoryData() { { null, false } }; foreach (SiteCode siteCode in SiteCode.AllSiteCodes) { if (_commentSiteCodes.Contains(siteCode)) testData.Add(siteCode, true); else testData.Add(siteCode, false); } return testData; } /// /// Generate a test set of SiteCode values that are considered Content /// /// MemberData-compatible list of SiteCode values public static TheoryData GenerateContentSiteCodesTestData() { var testData = new TheoryData() { { null, false } }; foreach (SiteCode siteCode in SiteCode.AllSiteCodes) { if (_contentSiteCodes.Contains(siteCode)) testData.Add(siteCode, true); else testData.Add(siteCode, false); } return testData; } /// /// Generate a test set of SiteCode values that are considered Multiline /// /// MemberData-compatible list of SiteCode values public static TheoryData GenerateMultilineSiteCodesTestData() { var testData = new TheoryData() { { null, false } }; foreach (SiteCode siteCode in SiteCode.AllSiteCodes) { if (_multilineSiteCodes.Contains(siteCode)) testData.Add(siteCode, true); else testData.Add(siteCode, false); } return testData; } #endregion #region Sort Category /// /// Check that every SortCategory has a long name provided /// /// SortCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortCategoryTestData))] public void SortCategory_LongName(SortCategory? sortCategory, bool expectNull) { var actual = sortCategory.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every SortCategory has a short name provided /// /// SortCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortCategoryTestData))] public void SortCategory_ShortName(SortCategory? sortCategory, bool expectNull) { var actual = sortCategory.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every SortCategory that has a short name that is unique /// [Fact] public void SortCategory_ShortName_NoDuplicates() { var fullSortCategorys = Enum.GetValues().Cast().ToList(); var filteredSortCategorys = new Dictionary(); int totalCount = 0; foreach (SortCategory? sortCategory in fullSortCategorys) { var code = sortCategory.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredSortCategorys.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredSortCategorys[code] = sortCategory; totalCount++; } Assert.Equal(totalCount, filteredSortCategorys.Count); } /// /// Check that every SortCategory can be mapped from a string /// /// SortCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortCategoryTestData))] public void SortCategory_ToSortCategory(SortCategory? sortCategory, bool expectNull) { string? longName = sortCategory.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToSortCategory(); var actualSpaceless = longNameSpaceless.ToSortCategory(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(sortCategory, actualNormal); Assert.Equal(sortCategory, actualSpaceless); } } /// /// Generate a test set of SortCategory values /// /// MemberData-compatible list of SortCategory values public static TheoryData GenerateSortCategoryTestData() { var testData = new TheoryData() { { null, true } }; foreach (SortCategory? sortCategory in Enum.GetValues().Cast()) { testData.Add(sortCategory, false); } return testData; } #endregion #region Sort Direction /// /// Check that every SortDirection has a long name provided /// /// SortDirection value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortDirectionTestData))] public void SortDirection_LongName(SortDirection? sortDirection, bool expectNull) { var actual = sortDirection.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every SortDirection has a short name provided /// /// SortDirection value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortDirectionTestData))] public void SortDirection_ShortName(SortDirection? sortDirection, bool expectNull) { var actual = sortDirection.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every SortDirection that has a short name that is unique /// [Fact] public void SortDirection_ShortName_NoDuplicates() { var fullSortDirections = Enum.GetValues().Cast().ToList(); var filteredSortDirections = new Dictionary(); int totalCount = 0; foreach (SortDirection? sortDirection in fullSortDirections) { var code = sortDirection.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredSortDirections.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredSortDirections[code] = sortDirection; totalCount++; } Assert.Equal(totalCount, filteredSortDirections.Count); } /// /// Check that every SortDirection can be mapped from a string /// /// SortDirection value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSortDirectionTestData))] public void SortDirection_ToSortDirection(SortDirection? sortDirection, bool expectNull) { string? longName = sortDirection.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToSortDirection(); var actualSpaceless = longNameSpaceless.ToSortDirection(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(sortDirection, actualNormal); Assert.Equal(sortDirection, actualSpaceless); } } /// /// Generate a test set of SortDirection values /// /// MemberData-compatible list of SortDirection values public static TheoryData GenerateSortDirectionTestData() { var testData = new TheoryData() { { null, true } }; foreach (SortDirection? sortDirection in Enum.GetValues().Cast()) { testData.Add(sortDirection, false); } return testData; } #endregion #region Submission Type /// /// Check that every SubmissionType has a long name provided /// /// SubmissionType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSubmissionTypeTestData))] public void SubmissionType_LongName(SubmissionType? sortDirection, bool expectNull) { var actual = sortDirection.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Check that every SubmissionType has a short name provided /// /// SubmissionType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSubmissionTypeTestData))] public void SubmissionType_ShortName(SubmissionType? sortDirection, bool expectNull) { var actual = sortDirection.ShortName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Ensure that every SubmissionType that has a short name that is unique /// [Fact] public void SubmissionType_ShortName_NoDuplicates() { var fullSubmissionTypes = Enum.GetValues().Cast().ToList(); var filteredSubmissionTypes = new Dictionary(); int totalCount = 0; foreach (SubmissionType? sortDirection in fullSubmissionTypes) { var code = sortDirection.ShortName(); if (string.IsNullOrEmpty(code)) continue; // Throw if the code already exists if (filteredSubmissionTypes.ContainsKey(code)) throw new DuplicateNameException($"Code {code} already in dictionary"); filteredSubmissionTypes[code] = sortDirection; totalCount++; } Assert.Equal(totalCount, filteredSubmissionTypes.Count); } /// /// Check that every SubmissionType can be mapped from a string /// /// SubmissionType value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSubmissionTypeTestData))] public void SubmissionType_ToSubmissionType(SubmissionType? sortDirection, bool expectNull) { string? longName = sortDirection.LongName(); string? longNameSpaceless = longName?.Replace(" ", string.Empty); var actualNormal = longName.ToSubmissionType(); var actualSpaceless = longNameSpaceless.ToSubmissionType(); if (expectNull) { Assert.Null(actualNormal); Assert.Null(actualSpaceless); } else { Assert.Equal(sortDirection, actualNormal); Assert.Equal(sortDirection, actualSpaceless); } } /// /// Generate a test set of SubmissionType values /// /// MemberData-compatible list of SubmissionType values public static TheoryData GenerateSubmissionTypeTestData() { var testData = new TheoryData() { { null, true } }; foreach (SubmissionType? sortDirection in Enum.GetValues().Cast()) { testData.Add(sortDirection, false); } return testData; } #endregion #region System Category /// /// Check that every SystemCategory has a long name provided /// /// SystemCategory value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateSystemCategoryTestData))] public void SystemCategory_LongName(SystemCategory? systemCategory, bool expectNull) { var actual = systemCategory.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } /// /// Generate a test set of SystemCategory values /// /// MemberData-compatible list of SystemCategory values public static TheoryData GenerateSystemCategoryTestData() { var testData = new TheoryData() { { null, true } }; foreach (SystemCategory? systemCategory in Enum.GetValues().Cast()) { if (systemCategory == SystemCategory.NONE) testData.Add(systemCategory, true); else testData.Add(systemCategory, false); } return testData; } #endregion #region Yes/No /// /// Check that every YesNo has a long name provided /// /// YesNo value to check /// True to expect a null value, false otherwise [Theory] [MemberData(nameof(GenerateYesNoTestData))] public void YesNo_LongName(YesNo? yesNo, bool expectNull) { string actual = yesNo.LongName(); if (expectNull) Assert.Null(actual); else Assert.NotNull(actual); } [Theory] [InlineData(true, YesNo.Yes)] [InlineData(false, YesNo.No)] [InlineData(null, YesNo.NULL)] public void YesNo_ToYesNo_Boolean(bool? value, YesNo? expected) { YesNo? actual = value.ToYesNo(); Assert.Equal(expected, actual); } [Theory] [InlineData("True", YesNo.Yes)] [InlineData("true", YesNo.Yes)] [InlineData("Yes", YesNo.Yes)] [InlineData("yes", YesNo.Yes)] [InlineData("False", YesNo.No)] [InlineData("false", YesNo.No)] [InlineData("No", YesNo.No)] [InlineData("no", YesNo.No)] [InlineData("INVALID", YesNo.NULL)] [InlineData(null, YesNo.NULL)] public void YesNo_ToYesNo_String(string? value, YesNo? expected) { YesNo? actual = value.ToYesNo(); Assert.Equal(expected, actual); } /// /// Generate a test set of YesNo values /// /// MemberData-compatible list of YesNo values public static TheoryData GenerateYesNoTestData() { var testData = new TheoryData() { { null, false } }; foreach (YesNo? yesNo in Enum.GetValues().Cast()) { testData.Add(yesNo, false); } return testData; } #endregion } }