Files
2026-07-27 09:40:27 -04:00

2951 lines
113 KiB
C#

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 = "<rom name=\"X\" size=\"50050629633\" crc=\"X\" md5=\"X\" sha1=\"X\" />",
},
};
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 = "<rom name=\"X\" size=\"25025314817\" crc=\"X\" md5=\"X\" sha1=\"X\" />",
},
};
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
/// <summary>
/// redump.info media type values that map to the combined media type
/// </summary>
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,
];
/// <summary>
/// Combined media type values that map to redump.info media type
/// </summary>
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,
];
/// <summary>
/// Check that every supported system has some set of MediaTypes supported
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
[Theory]
[MemberData(nameof(GeneratePhysicalSystemMappingTestData))]
public void MediaTypesTest(PhysicalSystem? physicalSystem)
{
var actual = physicalSystem?.MediaTypes ?? [PhysicalMediaType.NONE];
Assert.NotEmpty(actual);
}
/// <summary>
/// Check that both mappable and unmappable media types output correctly
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
[Theory]
[MemberData(nameof(GeneratePhysicalMediaTypeMappingTestData))]
public void ToPhysicalMediaTypeTest(PhysicalMediaType? mediaType, bool expectNull)
{
MediaType? actual = mediaType.ToMediaType();
Assert.Equal(expectNull, actual is null);
}
/// <summary>
/// Check that MediaType values all map to something appropriate
/// </summary>
/// <param name="discType">MediaType value to check</param>
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
[Theory]
[MemberData(nameof(GenerateMediaTypeMappingTestData))]
public void ToMediaTypeTest(MediaType? discType, bool expectNull)
{
PhysicalMediaType? actual = discType.ToPhysicalMediaType();
Assert.Equal(expectNull, actual is null);
}
/// <summary>
/// Generate a test set of PhysicalSystem values
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?> GeneratePhysicalSystemMappingTestData()
{
var testData = new TheoryData<PhysicalSystem?>() { null };
foreach (PhysicalSystem? physicalSystem in PhysicalSystem.AllSystems)
{
testData.Add(physicalSystem);
}
return testData;
}
/// <summary>
/// Generate a test set of MediaType values
/// </summary>
/// <returns>MemberData-compatible list of MediaType values</returns>
public static TheoryData<MediaType?, bool> GenerateMediaTypeMappingTestData()
{
var testData = new TheoryData<MediaType?, bool>() { { null, true } };
foreach (MediaType? discType in Enum.GetValues<MediaType>().Cast<MediaType?>())
{
if (_mappableMediaTypes.Contains(discType))
testData.Add(discType, false);
else
testData.Add(discType, true);
}
return testData;
}
/// <summary>
/// Generate a test set of mappable media types
/// </summary>
/// <returns>MemberData-compatible list of MediaTypes</returns>
public static TheoryData<PhysicalMediaType?, bool> GeneratePhysicalMediaTypeMappingTestData()
{
var testData = new TheoryData<PhysicalMediaType?, bool>() { { null, true } };
foreach (PhysicalMediaType? mediaType in Enum.GetValues<PhysicalMediaType>().Cast<PhysicalMediaType?>())
{
if (_mappablePhysicalMediaTypes.Contains(mediaType))
testData.Add(mediaType, false);
else
testData.Add(mediaType, true);
}
return testData;
}
#endregion
#region Disc Category
/// <summary>
/// Check that every DiscCategory has a long name provided
/// </summary>
/// <param name="discCategory">DiscCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every DiscCategory can be mapped from a string
/// </summary>
/// <param name="discCategory">DiscCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of DiscCategory values
/// </summary>
/// <returns>MemberData-compatible list of DiscCategory values</returns>
public static TheoryData<DiscCategory?, bool> GenerateDiscCategoryTestData()
{
var testData = new TheoryData<DiscCategory?, bool>() { { null, true } };
foreach (DiscCategory? discCategory in Enum.GetValues<DiscCategory>().Cast<DiscCategory?>())
{
testData.Add(discCategory, false);
}
return testData;
}
#endregion
#region Disc Subpath
/// <summary>
/// Check that every DiscSubpath has a long name provided
/// </summary>
/// <param name="discSubpath">DiscSubpath value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every DiscSubpath has a short name provided
/// </summary>
/// <param name="discSubpath">DiscSubpath value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every DiscSubpath that has a short name that is unique
/// </summary>
[Fact]
public void DiscSubpath_ShortName_NoDuplicates()
{
var fullDiscSubpaths = Enum.GetValues<DiscSubpath>().Cast<DiscSubpath>().ToList();
var filteredDiscSubpaths = new Dictionary<string, DiscSubpath?>();
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);
}
/// <summary>
/// Check that every DiscSubpath can be mapped from a string
/// </summary>
/// <param name="discSubpath">DiscSubpath value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of DiscSubpath values
/// </summary>
/// <returns>MemberData-compatible list of DiscSubpath values</returns>
public static TheoryData<DiscSubpath?, bool> GenerateDiscSubpathTestData()
{
var testData = new TheoryData<DiscSubpath?, bool>() { { null, true } };
foreach (DiscSubpath? discSubpath in Enum.GetValues<DiscSubpath>().Cast<DiscSubpath?>())
{
testData.Add(discSubpath, false);
}
return testData;
}
#endregion
#region Dump Status
/// <summary>
/// Check that every DumpStatus has a long name provided
/// </summary>
/// <param name="dumpStatus">DumpStatus value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every DumpStatus has a short name provided
/// </summary>
/// <param name="dumpStatus">DumpStatus value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every DumpStatus that has a short name that is unique
/// </summary>
[Fact]
public void DumpStatus_ShortName_NoDuplicates()
{
var fullDumpStatuses = Enum.GetValues<DumpStatus>().Cast<DumpStatus>().ToList();
var filteredDumpStatuses = new Dictionary<string, DumpStatus?>();
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);
}
/// <summary>
/// Check that every DumpStatus can be mapped from a string
/// </summary>
/// <param name="dumpStatus">DumpStatus value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of DumpStatus values
/// </summary>
/// <returns>MemberData-compatible list of DumpStatus values</returns>
public static TheoryData<DumpStatus?, bool> GenerateDumpStatusTestData()
{
var testData = new TheoryData<DumpStatus?, bool>() { { null, true } };
foreach (DumpStatus? dumpStatus in Enum.GetValues<DumpStatus>().Cast<DumpStatus?>())
{
testData.Add(dumpStatus, false);
}
return testData;
}
#endregion
#region Language Code
/// <summary>
/// Check that every LanguageCode can be mapped from a string
/// </summary>
/// <param name="lang">LanguageCode value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Ensure that every LanguageCode that has a standard/bibliographic ISO 639-2 code is unique
/// </summary>
[Fact]
public void LanguageCode_ThreeLetterCode_NoDuplicates()
{
var filteredLanguages = new Dictionary<string, LanguageCode?>();
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);
}
/// <summary>
/// Ensure that every LanguageCode that has a terminology ISO 639-2 code is unique
/// </summary>
[Fact]
public void LanguageCode_ThreeLetterCodeAlt_NoDuplicates()
{
var filteredLanguages = new Dictionary<string, LanguageCode?>();
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);
}
/// <summary>
/// Ensure that every LanguageCode that has an ISO 639-1 code is unique
/// </summary>
[Fact]
public void LanguageCode_TwoLetterCode_NoDuplicates()
{
var filteredLanguages = new Dictionary<string, LanguageCode?>();
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);
}
/// <summary>
/// Generate a test set of LanguageCode values
/// </summary>
/// <returns>MemberData-compatible list of LanguageCode values</returns>
public static TheoryData<LanguageCode?, bool> GenerateLanguageCodeTestData()
{
var testData = new TheoryData<LanguageCode?, bool>() { { null, true } };
foreach (LanguageCode? language in LanguageCode.AllLanguages)
{
testData.Add(language, false);
}
return testData;
}
#endregion
#region Media Type
/// <summary>
/// Check that every MediaType has a long name provided
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every MediaType has a short name provided
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every MediaType can be mapped from a string
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of DiscType values
/// </summary>
/// <returns>MemberData-compatible list of DiscType values</returns>
public static TheoryData<MediaType?, bool> GenerateMediaTypeTestData()
{
var testData = new TheoryData<MediaType?, bool>() { { null, true } };
foreach (MediaType? discType in Enum.GetValues<MediaType>().Cast<MediaType?>())
{
if (discType == MediaType.NONE)
testData.Add(discType, true);
else
testData.Add(discType, false);
}
return testData;
}
#endregion
#region Pack Type
/// <summary>
/// Check that every PackType has a long name provided
/// </summary>
/// <param name="packType">PackType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every PackType has a short name provided
/// </summary>
/// <param name="packType">PackType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every PackType that has a short name that is unique
/// </summary>
[Fact]
public void PackType_ShortName_NoDuplicates()
{
var fullPackTypes = Enum.GetValues<PackType>().Cast<PackType>().ToList();
var filteredPackTypes = new Dictionary<string, PackType?>();
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);
}
/// <summary>
/// Check that every PackType can be mapped from a string
/// </summary>
/// <param name="packType">PackType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of PackType values
/// </summary>
/// <returns>MemberData-compatible list of PackType values</returns>
public static TheoryData<PackType?, bool> GeneratePackTypeTestData()
{
var testData = new TheoryData<PackType?, bool>() { { null, true } };
foreach (PackType? packType in Enum.GetValues<PackType>().Cast<PackType?>())
{
testData.Add(packType, false);
}
return testData;
}
#endregion
#region Physical Media Type
[Fact]
public void PhysicalMediaType_ListMediaTypes()
{
var actual = Extensions.ListMediaTypes();
Assert.NotEmpty(actual);
}
/// <summary>
/// Check that every PhysicalMediaType has a long name provided
/// </summary>
/// <param name="mediaType">PhysicalMediaType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every PhysicalMediaType has a short name provided
/// </summary>
/// <param name="mediaType">PhysicalMediaType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every PhysicalMediaType can be mapped from a string
/// </summary>
/// <param name="mediaType">PhysicalMediaType value to check</param>
/// <param name="expectNone">True to expect a NONE value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of PhysicalMediaType values
/// </summary>
/// <returns>MemberData-compatible list of PhysicalMediaType values</returns>
public static TheoryData<PhysicalMediaType?, bool> GeneratePhysicalMediaTypeTestData()
{
var testData = new TheoryData<PhysicalMediaType?, bool>() { { null, true } };
foreach (PhysicalMediaType? mediaType in Enum.GetValues<PhysicalMediaType>().Cast<PhysicalMediaType?>())
{
testData.Add(mediaType, false);
}
return testData;
}
#endregion
#region Physical System
/// <summary>
/// PhysicalSystem values that are available
/// </summary>
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,
];
/// <summary>
/// PhysicalSystem values that are considered markers
/// </summary>
private static readonly PhysicalSystem?[] _markerSystems =
[
PhysicalSystem.MarkerArcadeEnd,
PhysicalSystem.MarkerComputerEnd,
PhysicalSystem.MarkerDiscBasedConsoleEnd,
PhysicalSystem.MarkerOtherEnd,
];
/// <summary>
/// Map of PhysicalSystem values to their corresponding categories
/// </summary>
private static readonly Dictionary<PhysicalSystem, SystemCategory> _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.IQBuildersLearningCDComputer] = 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.AppleII] = 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.SonyZN] = SystemCategory.Arcade,
[PhysicalSystem.TABAustriaQuizard] = SystemCategory.Arcade,
[PhysicalSystem.TsunamiTsuMoMultiGameMotionSystem] = SystemCategory.Arcade,
[PhysicalSystem.UltraCade] = SystemCategory.Arcade,
[PhysicalSystem.MarkerArcadeEnd] = SystemCategory.NONE,
// Other
[PhysicalSystem.AppleNewton] = SystemCategory.Other,
[PhysicalSystem.AquaplusPIECE] = SystemCategory.Other,
[PhysicalSystem.AudioCD] = SystemCategory.Other,
[PhysicalSystem.BDVideo] = SystemCategory.Other,
[PhysicalSystem.Cybiko] = 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.MiniDisc] = SystemCategory.Other,
[PhysicalSystem.MP3AudioDisc] = SystemCategory.Other,
[PhysicalSystem.NavisoftNaviken] = SystemCategory.Other,
[PhysicalSystem.OracleJ2ME] = 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.UHDBDVideo] = SystemCategory.Other,
[PhysicalSystem.VideoCD] = SystemCategory.Other,
[PhysicalSystem.MarkerOtherEnd] = SystemCategory.NONE,
};
/// <summary>
/// PhysicalSystem values that have cuesheet packs
/// </summary>
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,
];
/// <summary>
/// PhysicalSystem values that have dats
/// </summary>
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,
];
/// <summary>
/// PhysicalSystem values that have SBI packs
/// </summary>
private static readonly PhysicalSystem?[] _systemsWithSbis =
[
// Disc-Based Consoles
PhysicalSystem.SonyPlayStation,
// Computers
PhysicalSystem.AppleMacintosh,
PhysicalSystem.IBMPCcompatible,
];
/// <summary>
/// PhysicalSystem values that are considered detected by Windows
/// </summary>
private static readonly PhysicalSystem?[] _windowsDetectedSystems =
[
// Disc-Based Consoles
PhysicalSystem.CommodoreAmigaCD32,
PhysicalSystem.CommodoreAmigaCDTV,
PhysicalSystem.EnvizionsEVOSmartConsole,
PhysicalSystem.FujitsuFMTownsMarty,
PhysicalSystem.HasbroiONEducationalGamingSystem,
PhysicalSystem.IQBuildersLearningCDComputer, // TODO: Confirm this is Windows-readable
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.AppleII, // TODO: Confirm this is Windows-readable
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.SonyZN, // TODO: Confirm this is Windows-readable
PhysicalSystem.TABAustriaQuizard,
PhysicalSystem.TsunamiTsuMoMultiGameMotionSystem,
PhysicalSystem.UltraCade,
// Other
PhysicalSystem.AppleNewton, // TODO: Confirm this is Windows-readable
PhysicalSystem.AquaplusPIECE, // TODO: Confirm this is Windows-readable
PhysicalSystem.AudioCD,
PhysicalSystem.BDVideo,
PhysicalSystem.Cybiko,
PhysicalSystem.DVDAudio,
PhysicalSystem.DVDVideo,
PhysicalSystem.EnhancedCD,
PhysicalSystem.HDDVDVideo,
PhysicalSystem.MicrosoftPocketPC,
PhysicalSystem.MiniDisc, // TODO: Confirm this is Windows-readable
PhysicalSystem.MP3AudioDisc,
PhysicalSystem.NavisoftNaviken,
PhysicalSystem.OracleJ2ME,
PhysicalSystem.PalmOS,
PhysicalSystem.PhotoCD,
PhysicalSystem.Psion,
PhysicalSystem.RainbowDisc,
PhysicalSystem.SharpZaurus,
PhysicalSystem.SegaPrologue21MultimediaKaraokeSystem,
PhysicalSystem.SonyElectronicBook,
PhysicalSystem.TaoiKTV,
PhysicalSystem.TomyKissSite,
PhysicalSystem.UHDBDVideo,
PhysicalSystem.VideoCD,
];
/// <summary>
/// PhysicalSystem values that are considered XGD
/// </summary>
private static readonly PhysicalSystem?[] _xgdSystems =
[
PhysicalSystem.MicrosoftXbox,
PhysicalSystem.MicrosoftXbox360,
PhysicalSystem.MicrosoftXboxOne,
PhysicalSystem.MicrosoftXboxSeriesXS,
];
/// <summary>
/// Check that all systems detected by Windows are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateWindowsDetectedSystemsTestData))]
public void PhysicalSystem_DetectedByWindows(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem.DetectedByWindows();
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all marker systems are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateMarkerSystemsTestData))]
public void PhysicalSystem_IsMarker(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem?.IsMarker ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all XGD systems are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[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);
}
/// <summary>
/// Check that all systems are mapped to a category
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateCategoriesSystemTestData))]
public void PhysicalSystem_Category(PhysicalSystem? physicalSystem, SystemCategory expected)
{
SystemCategory actual = physicalSystem?.Category ?? SystemCategory.NONE;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all available systems are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateAvailableSystemsTestData))]
public void PhysicalSystem_IsAvailable(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem?.Available ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all systems with cuesheets are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateCuesheetSystemsTestData))]
public void PhysicalSystem_HasCues(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem?.HasCues ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all systems with DATs are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateDatSystemsTestData))]
public void PhysicalSystem_HasDat(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem?.HasDat ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all systems with SBIs are marked properly
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateSbiSystemsTestData))]
public void PhysicalSystem_HasSbi(PhysicalSystem? physicalSystem, bool expected)
{
bool actual = physicalSystem?.HasSbi ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that every PhysicalSystem can be mapped from a string
/// </summary>
/// <param name="physicalSystem">PhysicalSystem value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of PhysicalSystem values
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GeneratePhysicalSystemTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { 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;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that are available
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateAvailableSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_availableSystems.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values mapped to their categories
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, SystemCategory> GenerateCategoriesSystemTestData()
{
var testData = new TheoryData<PhysicalSystem?, SystemCategory>() { { null, SystemCategory.NONE } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
testData.Add(physicalSystem, _systemCategoryMap[physicalSystem]);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that have cuesheets
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateCuesheetSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_systemsWithCues.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that have DATs
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateDatSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_systemsWithDats.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that are considered markers
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateMarkerSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_markerSystems.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that have SBIs
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateSbiSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_systemsWithSbis.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that are detected by Windows
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateWindowsDetectedSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { null, false } };
foreach (PhysicalSystem physicalSystem in PhysicalSystem.AllSystems)
{
if (_windowsDetectedSystems.Contains(physicalSystem))
testData.Add(physicalSystem, true);
else
testData.Add(physicalSystem, false);
}
return testData;
}
/// <summary>
/// Generate a test set of PhysicalSystem values that are considered XGD
/// </summary>
/// <returns>MemberData-compatible list of PhysicalSystem values</returns>
public static TheoryData<PhysicalSystem?, bool> GenerateXGDSystemsTestData()
{
var testData = new TheoryData<PhysicalSystem?, bool>() { { 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
/// <summary>
/// Ensure that every RegionCode that has a short name that is unique
/// </summary>
[Fact]
public void RegionCode_ShortName_NoDuplicates()
{
var filteredRegions = new Dictionary<string, RegionCode?>();
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);
}
/// <summary>
/// Check that every RegionCode can be mapped from a string
/// </summary>
/// <param name="region">RegionCode value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of RegionCode values
/// </summary>
/// <returns>MemberData-compatible list of RegionCode values</returns>
public static TheoryData<RegionCode?, bool> GenerateRegionCodeTestData()
{
var testData = new TheoryData<RegionCode?, bool>() { { null, true } };
foreach (RegionCode? region in RegionCode.AllRegions)
{
testData.Add(region, false);
}
return testData;
}
#endregion
#region Site Code
/// <summary>
/// SiteCode values that are considered Boolean
/// </summary>
private static readonly SiteCode?[] _booleanSiteCodes =
[
SiteCode.PCMacHybrid,
SiteCode.PostgapType,
SiteCode.VCD,
];
/// <summary>
/// SiteCode values that are considered Comment
/// </summary>
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,
];
/// <summary>
/// SiteCode values that are considered Content
/// </summary>
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,
];
/// <summary>
/// SiteCode values that are considered Multiline
/// </summary>
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);
}
/// <summary>
/// Check that all boolean site codes are marked properly
/// </summary>
/// <param name="siteCode">SiteCode value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateBooleanSiteCodesTestData))]
public void SiteCode_IsBoolean(SiteCode? siteCode, bool expected)
{
bool actual = siteCode?.IsBoolean ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all comment site codes are marked properly
/// </summary>
/// <param name="siteCode">SiteCode value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateCommentSiteCodesTestData))]
public void SiteCode_IsCommentCode(SiteCode? siteCode, bool expected)
{
bool actual = siteCode?.IsCommentCode ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all content site codes are marked properly
/// </summary>
/// <param name="siteCode">SiteCode value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateContentSiteCodesTestData))]
public void SiteCode_IsContentCode(SiteCode? siteCode, bool expected)
{
bool actual = siteCode?.IsContentCode ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Check that all multiline site codes are marked properly
/// </summary>
/// <param name="siteCode">SiteCode value to check</param>
/// <param name="expected">The expected value to come from the check</param>
[Theory]
[MemberData(nameof(GenerateMultilineSiteCodesTestData))]
public void SiteCode_IsMultiLine(SiteCode? siteCode, bool expected)
{
bool actual = siteCode?.IsMultiLine ?? false;
Assert.Equal(expected, actual);
}
/// <summary>
/// Generate a test set of SiteCode values that are considered Boolean
/// </summary>
/// <returns>MemberData-compatible list of SiteCode values</returns>
public static TheoryData<SiteCode?, bool> GenerateBooleanSiteCodesTestData()
{
var testData = new TheoryData<SiteCode?, bool>() { { null, false } };
foreach (SiteCode siteCode in SiteCode.AllSiteCodes)
{
if (_booleanSiteCodes.Contains(siteCode))
testData.Add(siteCode, true);
else
testData.Add(siteCode, false);
}
return testData;
}
/// <summary>
/// Generate a test set of SiteCode values that are considered Comment
/// </summary>
/// <returns>MemberData-compatible list of SiteCode values</returns>
public static TheoryData<SiteCode?, bool> GenerateCommentSiteCodesTestData()
{
var testData = new TheoryData<SiteCode?, bool>() { { null, false } };
foreach (SiteCode siteCode in SiteCode.AllSiteCodes)
{
if (_commentSiteCodes.Contains(siteCode))
testData.Add(siteCode, true);
else
testData.Add(siteCode, false);
}
return testData;
}
/// <summary>
/// Generate a test set of SiteCode values that are considered Content
/// </summary>
/// <returns>MemberData-compatible list of SiteCode values</returns>
public static TheoryData<SiteCode?, bool> GenerateContentSiteCodesTestData()
{
var testData = new TheoryData<SiteCode?, bool>() { { null, false } };
foreach (SiteCode siteCode in SiteCode.AllSiteCodes)
{
if (_contentSiteCodes.Contains(siteCode))
testData.Add(siteCode, true);
else
testData.Add(siteCode, false);
}
return testData;
}
/// <summary>
/// Generate a test set of SiteCode values that are considered Multiline
/// </summary>
/// <returns>MemberData-compatible list of SiteCode values</returns>
public static TheoryData<SiteCode?, bool> GenerateMultilineSiteCodesTestData()
{
var testData = new TheoryData<SiteCode?, bool>() { { 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
/// <summary>
/// Check that every SortCategory has a long name provided
/// </summary>
/// <param name="sortCategory">SortCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every SortCategory has a short name provided
/// </summary>
/// <param name="sortCategory">SortCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every SortCategory that has a short name that is unique
/// </summary>
[Fact]
public void SortCategory_ShortName_NoDuplicates()
{
var fullSortCategorys = Enum.GetValues<SortCategory>().Cast<SortCategory>().ToList();
var filteredSortCategorys = new Dictionary<string, SortCategory?>();
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);
}
/// <summary>
/// Check that every SortCategory can be mapped from a string
/// </summary>
/// <param name="sortCategory">SortCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of SortCategory values
/// </summary>
/// <returns>MemberData-compatible list of SortCategory values</returns>
public static TheoryData<SortCategory?, bool> GenerateSortCategoryTestData()
{
var testData = new TheoryData<SortCategory?, bool>() { { null, true } };
foreach (SortCategory? sortCategory in Enum.GetValues<SortCategory>().Cast<SortCategory?>())
{
testData.Add(sortCategory, false);
}
return testData;
}
#endregion
#region Sort Direction
/// <summary>
/// Check that every SortDirection has a long name provided
/// </summary>
/// <param name="sortDirection">SortDirection value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every SortDirection has a short name provided
/// </summary>
/// <param name="sortDirection">SortDirection value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every SortDirection that has a short name that is unique
/// </summary>
[Fact]
public void SortDirection_ShortName_NoDuplicates()
{
var fullSortDirections = Enum.GetValues<SortDirection>().Cast<SortDirection>().ToList();
var filteredSortDirections = new Dictionary<string, SortDirection?>();
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);
}
/// <summary>
/// Check that every SortDirection can be mapped from a string
/// </summary>
/// <param name="sortDirection">SortDirection value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of SortDirection values
/// </summary>
/// <returns>MemberData-compatible list of SortDirection values</returns>
public static TheoryData<SortDirection?, bool> GenerateSortDirectionTestData()
{
var testData = new TheoryData<SortDirection?, bool>() { { null, true } };
foreach (SortDirection? sortDirection in Enum.GetValues<SortDirection>().Cast<SortDirection?>())
{
testData.Add(sortDirection, false);
}
return testData;
}
#endregion
#region Submission Type
/// <summary>
/// Check that every SubmissionType has a long name provided
/// </summary>
/// <param name="sortDirection">SubmissionType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Check that every SubmissionType has a short name provided
/// </summary>
/// <param name="sortDirection">SubmissionType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Ensure that every SubmissionType that has a short name that is unique
/// </summary>
[Fact]
public void SubmissionType_ShortName_NoDuplicates()
{
var fullSubmissionTypes = Enum.GetValues<SubmissionType>().Cast<SubmissionType>().ToList();
var filteredSubmissionTypes = new Dictionary<string, SubmissionType?>();
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);
}
/// <summary>
/// Check that every SubmissionType can be mapped from a string
/// </summary>
/// <param name="sortDirection">SubmissionType value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
}
/// <summary>
/// Generate a test set of SubmissionType values
/// </summary>
/// <returns>MemberData-compatible list of SubmissionType values</returns>
public static TheoryData<SubmissionType?, bool> GenerateSubmissionTypeTestData()
{
var testData = new TheoryData<SubmissionType?, bool>() { { null, true } };
foreach (SubmissionType? sortDirection in Enum.GetValues<SubmissionType>().Cast<SubmissionType?>())
{
testData.Add(sortDirection, false);
}
return testData;
}
#endregion
#region System Category
/// <summary>
/// Check that every SystemCategory has a long name provided
/// </summary>
/// <param name="systemCategory">SystemCategory value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Generate a test set of SystemCategory values
/// </summary>
/// <returns>MemberData-compatible list of SystemCategory values</returns>
public static TheoryData<SystemCategory?, bool> GenerateSystemCategoryTestData()
{
var testData = new TheoryData<SystemCategory?, bool>() { { null, true } };
foreach (SystemCategory? systemCategory in Enum.GetValues<SystemCategory>().Cast<SystemCategory?>())
{
if (systemCategory == SystemCategory.NONE)
testData.Add(systemCategory, true);
else
testData.Add(systemCategory, false);
}
return testData;
}
#endregion
#region Yes/No
/// <summary>
/// Check that every YesNo has a long name provided
/// </summary>
/// <param name="yesNo">YesNo value to check</param>
/// <param name="expectNull">True to expect a null value, false otherwise</param>
[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);
}
/// <summary>
/// Generate a test set of YesNo values
/// </summary>
/// <returns>MemberData-compatible list of YesNo values</returns>
public static TheoryData<YesNo?, bool> GenerateYesNoTestData()
{
var testData = new TheoryData<YesNo?, bool>() { { null, false } };
foreach (YesNo? yesNo in Enum.GetValues<YesNo>().Cast<YesNo?>())
{
testData.Add(yesNo, false);
}
return testData;
}
#endregion
}
}