Add majority of data extensions tests, fix minor issues

This commit is contained in:
Matt Nadareski
2026-03-21 20:09:10 -04:00
parent 8bec2087eb
commit 5544ab0b8a
16 changed files with 910 additions and 11 deletions

View File

@@ -0,0 +1,141 @@
using SabreTools.Data.Models.Atari7800;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class Atari7800CartExtensionsTests
{
[Theory]
[InlineData((AudioDevice)0, "POKEY - none, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
// POKEY
[InlineData(AudioDevice.Pokey440, "POKEY - @440, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
[InlineData(AudioDevice.Pokey450, "POKEY - @450, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
[InlineData(AudioDevice.Pokey450Plus440, "POKEY - @450+@440, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
[InlineData(AudioDevice.Pokey800, "POKEY - @800, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
[InlineData(AudioDevice.Pokey4000, "POKEY - @4000, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
[InlineData((AudioDevice)0x0007, "Unknown 7, No YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
// YM2151
[InlineData(AudioDevice.YM2151460, "POKEY - none, YM2151 @460, No COVOX @430, No ADPCM Audio Stream @420")]
// COVOX
[InlineData(AudioDevice.COVOX430, "POKEY - none, No YM2151 @460, COVOX @430, No ADPCM Audio Stream @420")]
// ADPCM
[InlineData(AudioDevice.ADPCMAudioStream420, "POKEY - none, No YM2151 @460, No COVOX @430, ADPCM Audio Stream @420")]
public void FromAudioDeviceTest(AudioDevice audio, string expected)
{
string actual = audio.FromAudioDevice();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData((CartType)0, "N/A")]
[InlineData(CartType.PokeyAt4000, "pokey at $4000")]
[InlineData(CartType.SupergameBankSwitched, "supergame bank switched")]
[InlineData(CartType.SupergameRamAt4000, "supergame ram at $4000")]
[InlineData(CartType.RomAt4000, "rom at $4000")]
[InlineData(CartType.Bank6At4000, "bank 6 at $4000")]
[InlineData(CartType.BankedRam, "banked ram")]
[InlineData(CartType.PokeyAt450, "pokey at $450")]
[InlineData(CartType.MirrorRamAt4000, "mirror ram at $4000")]
[InlineData(CartType.ActivisionBanking, "activision banking")]
[InlineData(CartType.AbsoluteBanking, "absolute banking")]
[InlineData(CartType.PokeyAt440, "pokey at $440")]
[InlineData(CartType.Ym2151At460461, "ym2151 at $460/$461")]
[InlineData(CartType.Souper, "souper")]
[InlineData(CartType.Banksets, "banksets")]
[InlineData(CartType.HaltBankedRam, "halt banked ram")]
[InlineData(CartType.PokeyAt800, "pokey@800")]
public void FromCartTypeTest(CartType type, string expected)
{
string actual = type.FromCartType();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(ControllerType.None, "none")]
[InlineData(ControllerType.Joystick, "7800 joystick")]
[InlineData(ControllerType.Lightgun, "lightgun")]
[InlineData(ControllerType.Paddle, "paddle")]
[InlineData(ControllerType.Trakball, "trakball")]
[InlineData(ControllerType.VcsJoystick, "2600 joystick")]
[InlineData(ControllerType.VcsDriving, "2600 driving")]
[InlineData(ControllerType.VcsKeypad, "2600 keypad")]
[InlineData(ControllerType.STMouse, "ST mouse")]
[InlineData(ControllerType.AmigaMouse, "Amiga mouse")]
[InlineData(ControllerType.AtariVoxSaveKey, "AtariVox/SaveKey")]
[InlineData(ControllerType.SNES2Atari, "SNES2Atari")]
[InlineData(ControllerType.Mega7800, "Mega7800")]
public void FromControllerTypeTest(ControllerType type, string expected)
{
string actual = type.FromControllerType();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(Interrupt.None, "None")]
[InlineData(Interrupt.Pokey1, "POKEY 1 (@450 | @800 | @4000)")]
[InlineData(Interrupt.Pokey2, "POKEY 2 (@440)")]
[InlineData(Interrupt.YM2151, "YM2151")]
public void FromInterruptTest(Interrupt interrupt, string expected)
{
string actual = interrupt.FromInterrupt();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(Mapper.Linear, "Linear")]
[InlineData(Mapper.SuperGame, "SuperGame")]
[InlineData(Mapper.Activision, "Activision")]
[InlineData(Mapper.Absolute, "Absolute")]
[InlineData(Mapper.Souper, "Souper")]
public void FromMapperTest(Mapper mapper, string expected)
{
string actual = mapper.FromMapper();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(MapperOptions.SuperGameNone, "Option at @4000 - none, Standard ROM")]
[InlineData(MapperOptions.SuperGame16KRAM, "Option at @4000 - 16K RAM, Standard ROM")]
[InlineData(MapperOptions.SuperGame8KEXRAMA8, "Option at @4000 - 8K EXRAM/A8, Standard ROM")]
[InlineData(MapperOptions.SuperGame32KEXRAMM2, "Option at @4000 - 32K EXRAM/M2, Standard ROM")]
[InlineData(MapperOptions.SuperGameEXROM, "Option at @4000 - EXROM, Standard ROM")]
[InlineData(MapperOptions.SuperGameEXFIX, "Option at @4000 - EXFIX, Standard ROM")]
[InlineData(MapperOptions.SuperGame32KEXRAMX2, "Option at @4000 - 32k EXRAM/X2, Standard ROM")]
[InlineData(MapperOptions.BanksetRom, "Option at @4000 - none, Bankset ROM")]
public void FromMapperOptionsTest(MapperOptions options, string expected)
{
string actual = options.FromMapperOptions();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(SaveDevice.None, "None")]
[InlineData(SaveDevice.HSC, "HSC")]
[InlineData(SaveDevice.SaveKeyAtariVox, "SaveKey/AtariVox")]
public void FromSaveDeviceTest(SaveDevice device, string expected)
{
string actual = device.FromSaveDevice();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(SlotPassthroughDevice.None, "None")]
[InlineData(SlotPassthroughDevice.XM, "XM")]
public void FromSlotPassthroughDeviceTest(SlotPassthroughDevice device, string expected)
{
string actual = device.FromSlotPassthroughDevice();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData((TVType)0, "NTSC, Component, Single-region")]
[InlineData(TVType.PAL, "PAL, Component, Single-region")]
[InlineData(TVType.Composite, "NTSC, Composite, Single-region")]
[InlineData(TVType.MultiRegion, "NTSC, Component, Multi-region")]
public void FromTVTypeTest(TVType type, string expected)
{
string actual = type.FromTVType();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,18 @@
using SabreTools.Data.Models.AtariLynx;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class AtariLynxCartExtensionsTests
{
[Theory]
[InlineData(Rotation.NoRotation, "No rotation (horizontal, buttons right)")]
[InlineData(Rotation.RotateLeft, "Rotate left (vertical, buttons down)")]
[InlineData(Rotation.RotateRight, "Rotate right (vertical, buttons up)")]
public void FromRotationTest(Rotation rotation, string expected)
{
string actual = rotation.FromRotation();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,65 @@
using System.IO;
using SabreTools.Data.Models.CDROM;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class CDROMExtensionsTests
{
[Theory]
[InlineData(new byte[0], SectorMode.UNKNOWN)]
[InlineData(new byte[] { 0x00 }, SectorMode.MODE0)]
[InlineData(new byte[] { 0x01 }, SectorMode.MODE1)]
[InlineData(new byte[] { 0x02 }, SectorMode.UNKNOWN)]
[InlineData(new byte[] { 0x02, 0x00, 0x00, 0x00 }, SectorMode.MODE2_FORM1)]
[InlineData(new byte[] { 0x02, 0x00, 0x00, 0x20 }, SectorMode.MODE2_FORM2)]
[InlineData(new byte[] { 0x03 }, SectorMode.UNKNOWN)]
public void GetSectorModeTest(byte[] bytes, SectorMode expected)
{
var stream = new MemoryStream(bytes);
SectorMode actual = stream.GetSectorMode();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(SectorMode.UNKNOWN, 2336)]
[InlineData(SectorMode.MODE0, 2336)]
[InlineData(SectorMode.MODE1, 2048)]
[InlineData(SectorMode.MODE2, 2336)]
[InlineData(SectorMode.MODE2_FORM1, 2048)]
[InlineData(SectorMode.MODE2_FORM2, 2324)]
public void GetUserDataSizeTest(SectorMode mode, long expected)
{
long actual = mode.GetUserDataSize();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(SectorMode.UNKNOWN, 2064)]
[InlineData(SectorMode.MODE0, 2064)]
[InlineData(SectorMode.MODE1, 2064)]
[InlineData(SectorMode.MODE2, 2064)]
[InlineData(SectorMode.MODE2_FORM1, 2072)]
[InlineData(SectorMode.MODE2_FORM2, 2072)]
public void GetUserDataEndTest(SectorMode mode, long expected)
{
long actual = mode.GetUserDataEnd();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(SectorMode.UNKNOWN, 16)]
[InlineData(SectorMode.MODE0, 16)]
[InlineData(SectorMode.MODE1, 16)]
[InlineData(SectorMode.MODE2, 16)]
[InlineData(SectorMode.MODE2_FORM1, 24)]
[InlineData(SectorMode.MODE2_FORM2, 24)]
public void GetUserDataStart(SectorMode mode, long expected)
{
long actual = mode.GetUserDataStart();
Assert.Equal(expected, actual);
}
// TODO: Figure out how to add ISO9660Stream tests
}
}

View File

@@ -0,0 +1,17 @@
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class CFBExtensionsTests
{
[Theory]
[InlineData(null, null)]
[InlineData(new byte[0], "")]
// TODO: Create more artifical tests
public void DecodeStreamNameTest(byte[]? bytes, string? expected)
{
string? actual = bytes.DecodeStreamName();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,138 @@
using SabreTools.Data.Models.ISO9660;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class ISO9660ExtensionsTests
{
[Fact]
public void GetLogicalBlockSize_Generic_SectorLength()
{
VolumeDescriptor vd = new GenericVolumeDescriptor();
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(sectorLength, actual);
}
[Fact]
public void GetLogicalBlockSize_PVD_ValidBothEndian_ValidBlockSize_BlockSize()
{
VolumeDescriptor vd = new PrimaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2048, 2048)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_PVD_ValidBothEndian_InvalidBlockSize_SectorLength()
{
VolumeDescriptor vd = new PrimaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2352, 2352)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(4096, actual);
}
[Fact]
public void GetLogicalBlockSize_PVD_InvalidBothEndian_ValidLE_LEValue()
{
VolumeDescriptor vd = new PrimaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2048, -1)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_PVD_InvalidBothEndian_ValidBE_BEValue()
{
VolumeDescriptor vd = new PrimaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(-1, 2048)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_PVD_InvalidBothEndian_BothInvalid_SectorLength()
{
VolumeDescriptor vd = new PrimaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(-1, -2)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(sectorLength, actual);
}
[Fact]
public void GetLogicalBlockSize_SVD_ValidBothEndian_ValidBlockSize_BlockSize()
{
VolumeDescriptor vd = new SupplementaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2048, 2048)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_SVD_ValidBothEndian_InvalidBlockSize_SectorLength()
{
VolumeDescriptor vd = new SupplementaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2352, 2352)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(4096, actual);
}
[Fact]
public void GetLogicalBlockSize_SVD_InvalidBothEndian_ValidLE_LEValue()
{
VolumeDescriptor vd = new SupplementaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(2048, -1)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_SVD_InvalidBothEndian_ValidBE_BEValue()
{
VolumeDescriptor vd = new SupplementaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(-1, 2048)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(2048, actual);
}
[Fact]
public void GetLogicalBlockSize_SVD_InvalidBothEndian_BothInvalid_SectorLength()
{
VolumeDescriptor vd = new SupplementaryVolumeDescriptor
{
LogicalBlockSize = new BothInt16(-1, -2)
};
short sectorLength = 4096;
short actual = vd.GetLogicalBlockSize(sectorLength);
Assert.Equal(sectorLength, actual);
}
}
}

View File

@@ -0,0 +1,156 @@
using SabreTools.Data.Models.InstallShieldCabinet;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class InstallShieldCabinetExtensionsTests
{
#region IsCompressed
[Fact]
public void IsCompressed_Null_True()
{
FileDescriptor? fd = null;
bool actual = fd.IsCompressed();
Assert.True(actual);
}
[Fact]
public void IsCompressed_Compressed_True()
{
FileDescriptor? fd = new FileDescriptor { Flags = FileFlags.FILE_COMPRESSED };
bool actual = fd.IsCompressed();
Assert.True(actual);
}
[Fact]
public void IsCompressed_NotCompressed_False()
{
FileDescriptor? fd = new FileDescriptor { Flags = 0 };
bool actual = fd.IsCompressed();
Assert.False(actual);
}
#endregion
#region IsInvalid
[Fact]
public void IsInvalid_Null_True()
{
FileDescriptor? fd = null;
bool actual = fd.IsInvalid();
Assert.True(actual);
}
[Fact]
public void IsInvalid_Invalid_True()
{
FileDescriptor? fd = new FileDescriptor { Flags = FileFlags.FILE_INVALID };
bool actual = fd.IsInvalid();
Assert.True(actual);
}
[Fact]
public void IsInvalid_Valid_False()
{
FileDescriptor? fd = new FileDescriptor { Flags = 0 };
bool actual = fd.IsInvalid();
Assert.False(actual);
}
#endregion
#region IsObfuscated
[Fact]
public void IsObfuscated_Null_False()
{
FileDescriptor? fd = null;
bool actual = fd.IsObfuscated();
Assert.False(actual);
}
[Fact]
public void IsObfuscated_Obfuscated_True()
{
FileDescriptor? fd = new FileDescriptor { Flags = FileFlags.FILE_OBFUSCATED };
bool actual = fd.IsObfuscated();
Assert.True(actual);
}
[Fact]
public void IsObfuscated_NotObfuscated_False()
{
FileDescriptor? fd = new FileDescriptor { Flags = 0 };
bool actual = fd.IsObfuscated();
Assert.False(actual);
}
#endregion
#region IsSplit
[Fact]
public void IsSplit_Null_False()
{
FileDescriptor? fd = null;
bool actual = fd.IsSplit();
Assert.False(actual);
}
[Fact]
public void IsSplit_Split_True()
{
FileDescriptor? fd = new FileDescriptor { Flags = FileFlags.FILE_SPLIT };
bool actual = fd.IsSplit();
Assert.True(actual);
}
[Fact]
public void IsSplit_NotSplitFalse()
{
FileDescriptor? fd = new FileDescriptor { Flags = 0 };
bool actual = fd.IsSplit();
Assert.False(actual);
}
#endregion
#region GetMajorVersion
[Fact]
public void GetMajorVersion_NullCabinet_NegativeOne()
{
Cabinet? cabinet = null;
int actual = cabinet.GetMajorVersion();
Assert.Equal(-1, actual);
}
[Fact]
public void GetMajorVersion_NullHeader_NegativeOne()
{
CommonHeader? cabinet = null;
int actual = cabinet.GetMajorVersion();
Assert.Equal(-1, actual);
}
[Theory]
[InlineData(0x00000000, 0)]
[InlineData(0x00000004, 4)]
[InlineData(0x01000000, 0)]
[InlineData(0x01004000, 4)]
[InlineData(0x02000000, 0)]
[InlineData(0x02000190, 4)]
[InlineData(0x04000000, 0)]
[InlineData(0x04000190, 4)]
public void GetMajorVersionTest(uint version, int expected)
{
CommonHeader? cabinet = new CommonHeader { Version = version };
int actual = cabinet.GetMajorVersion();
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,206 @@
using SabreTools.Data.Models.NES;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class NESCartExtensionsTests
{
[Theory]
[InlineData(ConsoleType.StandardSystem, "Nintendo Entertainment System/Family Computer")]
[InlineData(ConsoleType.VSUnisystem, "VS Unisystem")]
[InlineData(ConsoleType.PlayChoice10, "PlayChoice-10 (8 KB of Hint Screen data stored after CHR data)")]
[InlineData(ConsoleType.ExtendedConsoleType, "Extended Console Type")]
public void FromConsoleTypeTest(ConsoleType type, string expected)
{
string actual = type.FromConsoleType();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(CPUPPUTiming.RP2C02, "RP2C02 (NTSC NES)")]
[InlineData(CPUPPUTiming.RP2C07, "RP2C07 (Licensed PAL NES)")]
[InlineData(CPUPPUTiming.MultipleRegion, "Multiple-region")]
[InlineData(CPUPPUTiming.UA6538, "UA6538 (Dendy)")]
public void FromCPUPPUTimingTest(CPUPPUTiming timing, string expected)
{
string actual = timing.FromCPUPPUTiming();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(DefaultExpansionDevice.Unspecified, "Unspecified")]
[InlineData(DefaultExpansionDevice.StandardControllers, "Standard NES/Famicom controllers")]
[InlineData(DefaultExpansionDevice.NESFourScore, "NES Four Score/Satellite with two additional standard controllers")]
[InlineData(DefaultExpansionDevice.FamicomFourPlayersAdapter, "Famicom Four Players Adapter with two additional standard controllers using the 'simple' protocol")]
[InlineData(DefaultExpansionDevice.VsSystem4016, "Vs. System (1P via $4016)")]
[InlineData(DefaultExpansionDevice.VsSystem4017, "Vs. System (1P via $4017)")]
[InlineData(DefaultExpansionDevice.Reserved06, "Reserved (0x06)")]
[InlineData(DefaultExpansionDevice.VsZapper, "Vs. Zapper")]
[InlineData(DefaultExpansionDevice.Zapper4017, "Zapper ($4017)")]
[InlineData(DefaultExpansionDevice.TwoZappers, "Two Zappers")]
[InlineData(DefaultExpansionDevice.BandaiHyperShotLightgun, "Bandai Hyper Shot Lightgun")]
[InlineData(DefaultExpansionDevice.PowerPadSideA, "Power Pad Side A")]
[InlineData(DefaultExpansionDevice.PowerPadSideB, "Power Pad Side B")]
[InlineData(DefaultExpansionDevice.FamilyTrainerSideA, "Family Trainer Side A")]
[InlineData(DefaultExpansionDevice.FamilyTrainerSideB, "Family Trainer Side B")]
[InlineData(DefaultExpansionDevice.ArkanoidVausControllerNES, "Arkanoid Vaus Controller (NES)")]
[InlineData(DefaultExpansionDevice.ArkanoidVausControllerFamicom, "Arkanoid Vaus Controller (Famicom)")]
[InlineData(DefaultExpansionDevice.TwoVausControllersPlusFamicomDataRecorder, "Two Vaus Controllers plus Famicom Data Recorder")]
[InlineData(DefaultExpansionDevice.KonamiHyperShotController, "Konami Hyper Shot Controller")]
[InlineData(DefaultExpansionDevice.CoconutsPachinkoController, "Coconuts Pachinko Controller")]
[InlineData(DefaultExpansionDevice.ExcitingBoxingPunchingBag, "Exciting Boxing Punching Bag (Blowup Doll)")]
[InlineData(DefaultExpansionDevice.JissenMahjongController, "Jissen Mahjong Controller")]
[InlineData(DefaultExpansionDevice.YonezawaPartyTap, "米澤 (Yonezawa) Party Tap")]
[InlineData(DefaultExpansionDevice.OekaKidsTablet, "Oeka Kids Tablet")]
[InlineData(DefaultExpansionDevice.SunsoftBarcodeBattler, "Sunsoft Barcode Battler")]
[InlineData(DefaultExpansionDevice.MiraclePianoKeyboard, "Miracle Piano Keyboard")]
[InlineData(DefaultExpansionDevice.PokkunMoguraaTapTapMat, "Pokkun Moguraa Tap-tap Mat (Whack-a-Mole Mat and Mallet)")]
[InlineData(DefaultExpansionDevice.TopRider, "Top Rider (Inflatable Bicycle)")]
[InlineData(DefaultExpansionDevice.DoubleFisted, "Double-Fisted (Requires or allows use of two controllers by one player)")]
[InlineData(DefaultExpansionDevice.Famicom3DSystem, "Famicom 3D System")]
[InlineData(DefaultExpansionDevice.DoremikkoKeyboard, "Doremikko Keyboard")]
[InlineData(DefaultExpansionDevice.ROBGyromite, "R.O.B. Gyromite")]
[InlineData(DefaultExpansionDevice.FamicomDataRecorder, "Famicom Data Recorder ('silent' keyboard)")]
[InlineData(DefaultExpansionDevice.ASCIITurboFile, "ASCII Turbo File")]
[InlineData(DefaultExpansionDevice.IGSStorageBattleBox, "IGS Storage Battle Box")]
[InlineData(DefaultExpansionDevice.FamilyBASICKeyboardPlusFamicomDataRecorder, "Family BASIC Keyboard plus Famicom Data Recorder")]
[InlineData(DefaultExpansionDevice.DongdaPECKeyboard, "东达 (Dōngdá) PEC Keyboard")]
[InlineData(DefaultExpansionDevice.BitCorpBit79Keyboard, "普澤 (Pǔzé, a.k.a. Bit Corp.) Bit-79 Keyboard")]
[InlineData(DefaultExpansionDevice.SuborKeyboard, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusMacroWinnersMouse, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Macro Winners Mouse")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusSuborMouse4016, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Subor Mouse via $4016")]
[InlineData(DefaultExpansionDevice.SNESMouse4016, "SNES Mouse ($4016)")]
[InlineData(DefaultExpansionDevice.Multicart, "Multicart")]
[InlineData(DefaultExpansionDevice.TwoSNESControllers, "Two SNES controllers replacing the two standard NES controllers")]
[InlineData(DefaultExpansionDevice.RacerMateBicycle, "RacerMate Bicycle")]
[InlineData(DefaultExpansionDevice.UForce, "U-Force")]
[InlineData(DefaultExpansionDevice.ROBStackUp, "R.O.B. Stack-Up")]
[InlineData(DefaultExpansionDevice.CityPatrolmanLightgun, "City Patrolman Lightgun")]
[InlineData(DefaultExpansionDevice.SharpC1CassetteInterface, "Sharp C1 Cassette Interface")]
[InlineData(DefaultExpansionDevice.StandardControllerWithSwappedInputs, "Standard Controller with swapped Left-Right/Up-Down/B-A")]
[InlineData(DefaultExpansionDevice.ExcaliburSudokuPad, "Excalibur Sudoku Pad")]
[InlineData(DefaultExpansionDevice.ABLPinball, "ABL Pinball")]
[InlineData(DefaultExpansionDevice.GoldenNuggetCasinoExtraButtons, "Golden Nugget Casino extra buttons")]
[InlineData(DefaultExpansionDevice.KedaKeyboard, "科达 (Kēdá) Keyboard")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusSuborMouse4017, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Subor Mouse via $4017")]
[InlineData(DefaultExpansionDevice.PortTestController, "Port test controller")]
[InlineData(DefaultExpansionDevice.BandaiMultiGamePlayerGamepad, "Bandai Multi Game Player Gamepad buttons")]
[InlineData(DefaultExpansionDevice.VenomTVDanceMat, "Venom TV Dance Mat")]
[InlineData(DefaultExpansionDevice.LGTVRemoteControl, "LG TV Remote Control")]
[InlineData(DefaultExpansionDevice.FamicomNetworkController, "Famicom Network Controller")]
[InlineData(DefaultExpansionDevice.KingFishingController, "King Fishing Controller")]
[InlineData(DefaultExpansionDevice.CroakyKaraokeController, "Croaky Karaoke Controller")]
[InlineData(DefaultExpansionDevice.KingwonKeyboard, "科王 (Kēwáng, a.k.a. Kingwon) Keyboard")]
[InlineData(DefaultExpansionDevice.ZechengKeyboard, "泽诚 (Zéchéng) Keyboard")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusL90RotatedPS2Mouse4017, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus L90-rotated PS/2 mouse in $4017")]
[InlineData(DefaultExpansionDevice.PS2KeyboardInUM6578PS2PortPS2Mouse4017, "PS/2 Keyboard in UM6578 PS/2 port, PS/2 Mouse via $4017")]
[InlineData(DefaultExpansionDevice.PS2MouseInUM6578PS2Port, "PS/2 Mouse in UM6578 PS/2 port")]
[InlineData(DefaultExpansionDevice.YuxingMouse4016, "裕兴 (Yùxìng) Mouse via $4016")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusYuxingMouse4016, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus 裕兴 (Yùxìng) Mouse mouse in $4016")]
[InlineData(DefaultExpansionDevice.GigggleTVPump, "Gigggle TV Pump")]
[InlineData(DefaultExpansionDevice.BBKKeyboardPlusR90RotatedPS2Mouse4017, "步步高 (Bùbùgāo, a.k.a. BBK) Keyboard plus R90-rotated PS/2 mouse in $4017")]
[InlineData(DefaultExpansionDevice.MagicalCooking, "Magical Cooking")]
[InlineData(DefaultExpansionDevice.SNESMouse4017, "SNES Mouse ($4017)")]
[InlineData(DefaultExpansionDevice.Zapper4016, "Zapper ($4016)")]
[InlineData(DefaultExpansionDevice.ArkanoidVausControllerPrototype, "Arkanoid Vaus Controller (Prototype)")]
[InlineData(DefaultExpansionDevice.TVMahjongGameController, "TV 麻雀 Game (TV Mahjong Game) Controller")]
[InlineData(DefaultExpansionDevice.MahjongGekitouDensetsuController, "麻雀激闘伝説 (Mahjong Gekitou Densetsu) Controller")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusXInvertedPS2Mouse4017, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus X-inverted PS/2 mouse in $4017")]
[InlineData(DefaultExpansionDevice.IBMPCXTKeyboard, "IBM PC/XT Keyboard")]
[InlineData(DefaultExpansionDevice.SuborKeyboardPlusMegaBookMouse, "小霸王 (Xiǎobàwáng, a.k.a. Subor) Keyboard plus Mega Book Mouse")]
public void FromDefaultExpansionDeviceTest(DefaultExpansionDevice device, string expected)
{
string actual = device.FromDefaultExpansionDevice();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(ExtendedConsoleType.RegularSystem, "Regular NES/Famicom/Dendy")]
[InlineData(ExtendedConsoleType.NintendoVsSystem, "Nintendo Vs. System")]
[InlineData(ExtendedConsoleType.Playchoice10, "Playchoice 10")]
[InlineData(ExtendedConsoleType.RegularFamicloneDecimalMode, "Regular Famiclone, but with CPU that supports Decimal Mode")]
[InlineData(ExtendedConsoleType.RegularNESWithEPSM, "Regular NES/Famicom with EPSM module or plug-through cartridge")]
[InlineData(ExtendedConsoleType.VRTechnologyVT01, "V.R. Technology VT01 with red/cyan STN palette")]
[InlineData(ExtendedConsoleType.VRTechnologyVT02, "V.R. Technology VT02")]
[InlineData(ExtendedConsoleType.VRTechnologyVT03, "V.R. Technology VT03")]
[InlineData(ExtendedConsoleType.VRTechnologyVT09, "V.R. Technology VT09")]
[InlineData(ExtendedConsoleType.VRTechnologyVT32, "V.R. Technology VT32")]
[InlineData(ExtendedConsoleType.VRTechnologyVT369, "V.R. Technology VT369")]
[InlineData(ExtendedConsoleType.UMCUM6578, "UMC UM6578")]
[InlineData(ExtendedConsoleType.FamicomNetworkSystem, "Famicom Network System")]
[InlineData(ExtendedConsoleType.ReservedD, "Reserved (0x0D)")]
[InlineData(ExtendedConsoleType.ReservedE, "Reserved (0x0E)")]
[InlineData(ExtendedConsoleType.ReservedF, "Reserved (0x0F)")]
public void FromExtendedConsoleTypeTest(ExtendedConsoleType type, string expected)
{
string actual = type.FromExtendedConsoleType();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(NametableArrangement.Vertical, "Vertical")]
[InlineData(NametableArrangement.Horizontal, "Horizontal")]
public void FromNametableArrangementTest(NametableArrangement arrangement, string expected)
{
string actual = arrangement.FromNametableArrangement();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(TVSystem.NTSC, "NTSC")]
[InlineData(TVSystem.PAL, "PAL")]
public void FromTVSystemTest(TVSystem system, string expected)
{
string actual = system.FromTVSystem();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(TVSystemExtended.NTSC, "NTSC")]
[InlineData(TVSystemExtended.DualCompatible1, "Dual-compatible (0x01)")]
[InlineData(TVSystemExtended.PAL, "PAL")]
[InlineData(TVSystemExtended.DualCompatible3, "Dual-compatible (0x03)")]
public void FromTVSystemExtendedTest(TVSystemExtended system, string expected)
{
string actual = system.FromTVSystemExtended();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(VsHardwareType.VsUnisystem, "Vs. Unisystem (normal)")]
[InlineData(VsHardwareType.VsUnisystemRBIBaseballProtection, "Vs. Unisystem (RBI Baseball protection)")]
[InlineData(VsHardwareType.VsUnisystemTKOBoxingProtection, "Vs. Unisystem (TKO Boxing protection)")]
[InlineData(VsHardwareType.VsUnisystemSuperXeviousProtection, "Vs. Unisystem (Super Xevious protection)")]
[InlineData(VsHardwareType.VsUnisystemVsIceClimberJapanProtection, "Vs. Unisystem (Vs. Ice Climber Japan protection)")]
[InlineData(VsHardwareType.VsDualSystem, "Vs. Dual System (normal)")]
[InlineData(VsHardwareType.VsDualSystemRaidOnBungelingBayProtection, "Vs. Dual System (Raid on Bungeling Bay protection)")]
public void FromVsHardwareTypeTest(VsHardwareType type, string expected)
{
string actual = type.FromVsHardwareType();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(VsSystemType.AnyRP2C03RC2C03Variant, "Any RP2C03/RC2C03 variant")]
[InlineData(VsSystemType.Reserved1, "Reserved (0x01)")]
[InlineData(VsSystemType.RP2C040001, "RP2C04-0001")]
[InlineData(VsSystemType.RP2C040002, "RP2C04-0002")]
[InlineData(VsSystemType.RP2C040003, "RP2C04-0003")]
[InlineData(VsSystemType.RP2C040004, "RP2C04-0004")]
[InlineData(VsSystemType.Reserved6, "Reserved (0x06)")]
[InlineData(VsSystemType.Reserved7, "Reserved (0x07)")]
[InlineData(VsSystemType.RC2C0501, "RC2C05-01 (signature unknown)")]
[InlineData(VsSystemType.RC2C0502, "RC2C05-02 ($2002 AND $3F =$3D)")]
[InlineData(VsSystemType.RC2C0503, "RC2C05-03 ($2002 AND $1F =$1C)")]
[InlineData(VsSystemType.RC2C0504, "RC2C05-04 ($2002 AND $1F =$1B)")]
[InlineData(VsSystemType.ReservedC, "Reserved (0x0C)")]
[InlineData(VsSystemType.ReservedD, "Reserved (0x0D)")]
[InlineData(VsSystemType.ReservedE, "Reserved (0x0E)")]
[InlineData(VsSystemType.ReservedF, "Reserved (0x0F)")]
public void FromVsSystemTypeTest(VsSystemType type, string expected)
{
string actual = type.FromVsSystemType();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using SabreTools.Data.Models.NewExecutable;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class NewExecutableExtensionsTests
{
#region IsIntegerType
[Fact]
public void IsIntegerType_RTIE_HighBitSet_True()
{
var entry = new ResourceTypeInformationEntry { TypeID = 0xFFFF };
bool actual = entry.IsIntegerType();
Assert.True(actual);
}
[Fact]
public void IsIntegerType_RTIE_HighBitClear_False()
{
var entry = new ResourceTypeInformationEntry { TypeID = 0x0000 };
bool actual = entry.IsIntegerType();
Assert.False(actual);
}
[Fact]
public void IsIntegerType_RTRE_HighBitSet_True()
{
var entry = new ResourceTypeResourceEntry { ResourceID = 0xFFFF };
bool actual = entry.IsIntegerType();
Assert.True(actual);
}
[Fact]
public void IsIntegerType_RTRE_HighBitClear_False()
{
var entry = new ResourceTypeResourceEntry { ResourceID = 0x0000 };
bool actual = entry.IsIntegerType();
Assert.False(actual);
}
#endregion
#region GetEntryType
[Theory]
[InlineData(0x00, SegmentEntryType.Unused)]
[InlineData(0x01, SegmentEntryType.FixedSegment)]
[InlineData(0xAA, SegmentEntryType.FixedSegment)]
[InlineData(0xFE, SegmentEntryType.FixedSegment)]
[InlineData(0xFF, SegmentEntryType.MoveableSegment)]
public void GetEntryTypeTest(byte segmentIndicator, SegmentEntryType expected)
{
var entry = new EntryTableBundle { SegmentIndicator = segmentIndicator };
SegmentEntryType actual = entry.GetEntryType();
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,59 @@
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class WiseScriptExtensionsTests
{
[Theory]
// Defined functions
[InlineData("f0", "Add Directory to PATH")]
[InlineData("f1", "Add to AUTOEXEC.BAT")]
[InlineData("f2", "Add to CONFIG.SYS")]
[InlineData("f3", "Add to SYSTEM.INI")]
[InlineData("f8", "Read INI Value")]
[InlineData("f9", "Get Registry Key Value")]
[InlineData("f10", "Register Font")]
[InlineData("f11", "Win32 System Directory")]
[InlineData("f12", "Check Configuration")]
[InlineData("f13", "Search for File")]
[InlineData("f15", "Read/Write Binary File")]
[InlineData("f16", "Set Variable")]
[InlineData("f17", "Get Environment Variable")]
[InlineData("f19", "Check if File/Dir Exists")]
[InlineData("f20", "Set File Attributes")]
[InlineData("f21", "Set Files/Buffers")]
[InlineData("f22", "Find File in Path")]
[InlineData("f23", "Check Disk Space")]
[InlineData("f25", "Insert Line Into Text File")]
[InlineData("f27", "Parse String")]
[InlineData("f28", "Exit Installation")]
[InlineData("f29", "Self-Register OCXs/DLLs")]
[InlineData("f30", "Install DirectX Components")]
[InlineData("f31", "Wizard Block")]
[InlineData("f33", "Read/Update Text File")]
[InlineData("f34", "Post to HTTP Server")]
[InlineData("f35", "Prompt for Filename")]
[InlineData("f36", "Start/Stop Service")]
[InlineData("f38", "Check HTTP Connection")]
// Undefined functions
[InlineData("f4", "UNDEFINED f4")]
[InlineData("f5", "UNDEFINED f5")]
[InlineData("f6", "UNDEFINED f6")]
[InlineData("f7", "UNDEFINED f7")]
[InlineData("f14", "UNDEFINED f14")]
[InlineData("f18", "UNDEFINED f18")]
[InlineData("f24", "UNDEFINED f24")]
[InlineData("f26", "UNDEFINED f26")]
[InlineData("f32", "UNDEFINED f32")]
[InlineData("f37", "UNDEFINED f37")]
// External DLL
[InlineData(null, null)]
[InlineData("f99", "UNDEFINED f99")]
[InlineData("func", "External: func")]
public void FromWiseFunctionIdTest(string? functionId, string? expected)
{
string? actual = functionId.FromWiseFunctionId();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -0,0 +1,20 @@
using System.Linq;
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class XZExtensionsTests
{
[Fact]
public void VariableLengthIntegerTest()
{
ulong expected = 123456789;
byte[] encoded = expected.EncodeVariableLength();
Assert.True(encoded.SequenceEqual<byte>([0x95, 0x9A, 0xEF, 0x3A]));
ulong actual = encoded.DecodeVariableLength(maxSize: 16, out int length);
Assert.Equal(expected, actual);
Assert.Equal(4, length);
}
}
}

View File

@@ -0,0 +1,17 @@
using Xunit;
namespace SabreTools.Data.Extensions.Test
{
public class XboxExecutableExtensionsTests
{
[Theory]
[InlineData(0x00000000, "0000-000")]
[InlineData(0x4142000F, "AB-015")]
[InlineData(0x3132F000, "12-61440")]
public void ToFormattedXBETitleIDTest(uint value, string expected)
{
string actual = value.ToFormattedXBETitleID();
Assert.Equal(expected, actual);
}
}
}

View File

@@ -12,7 +12,7 @@ namespace SabreTools.Data.Extensions
{
string[] devices = new string[4];
byte pokey = (byte)((byte)audio & 0x0F);
byte pokey = (byte)((byte)audio & 0x07);
devices[0] = pokey switch
{
0 => "POKEY - none",
@@ -24,7 +24,7 @@ namespace SabreTools.Data.Extensions
_ => $"Unknown {pokey}",
};
byte ym2151 = (byte)(((byte)audio >> 1) & 0x01);
byte ym2151 = (byte)(((byte)audio >> 3) & 0x01);
devices[1] = ym2151 switch
{
0 => "No YM2151 @460",
@@ -32,7 +32,7 @@ namespace SabreTools.Data.Extensions
_ => $"Unknown {ym2151}",
};
byte covox = (byte)(((byte)audio >> 2) & 0x01);
byte covox = (byte)(((byte)audio >> 4) & 0x01);
devices[2] = covox switch
{
0 => "No COVOX @430",
@@ -40,7 +40,7 @@ namespace SabreTools.Data.Extensions
_ => $"Unknown {covox}",
};
byte adpcm = (byte)(((byte)audio >> 3) & 0x01);
byte adpcm = (byte)(((byte)audio >> 5) & 0x01);
devices[3] = adpcm switch
{
0 => "No ADPCM Audio Stream @420",
@@ -239,7 +239,7 @@ namespace SabreTools.Data.Extensions
{
string[] romOptions = new string[2];
byte option4000 = (byte)((byte)options & 0x0F);
byte option4000 = (byte)((byte)options & 0x07);
romOptions[0] = option4000 switch
{
0 => "Option at @4000 - none",

View File

@@ -155,13 +155,13 @@ namespace SabreTools.Data.Extensions
/// <summary>
/// Convert a <see cref="NametableArrangement"/> value to string
/// </summary>
public static string FromNametableArrangement(this NametableArrangement type)
public static string FromNametableArrangement(this NametableArrangement arrangement)
{
return type switch
return arrangement switch
{
NametableArrangement.Vertical => "Vertical",
NametableArrangement.Horizontal => "Horizontal",
_ => $"Unknown {(byte)type}",
_ => $"Unknown {(byte)arrangement}",
};
}

View File

@@ -3,6 +3,7 @@ using SabreTools.Data.Models.COFF;
namespace SabreTools.Data.Extensions
{
// TODO: Add tests
public static class PortableExecutableExtensions
{
/// <summary>

View File

@@ -8,7 +8,7 @@ namespace SabreTools.Data.Extensions
/// <summary>
/// Convert a UInt32 to a formatted XBE title ID
/// </summary>
public static string? ToFormattedXBETitleID(this uint value)
public static string ToFormattedXBETitleID(this uint value)
{
// Convert to a byte array
byte[] data = BitConverter.GetBytes(value);

View File

@@ -29,7 +29,7 @@ namespace SabreTools.Wrappers
if (AlternativeTitleIDs is null)
return null;
return Array.ConvertAll(AlternativeTitleIDs, ba => ba.ToFormattedXBETitleID() ?? "[NULL]");
return Array.ConvertAll(AlternativeTitleIDs, ba => ba.ToFormattedXBETitleID());
}
}
@@ -74,7 +74,7 @@ namespace SabreTools.Wrappers
public uint TitleID => Certificate?.TitleID ?? 0;
/// <inheritdoc cref="Certificate.TitleID"/>
public string? TitleIDString => TitleID.ToFormattedXBETitleID();
public string TitleIDString => TitleID.ToFormattedXBETitleID();
/// <inheritdoc cref="Certificate.TitleName"/>
public string? TitleName