- TargetFrameworks net48;net40. net48 keeps x64 + ViGEm + System.IO.Ports package; net40 adds Microsoft.Bcl.Async + System.ValueTuple and uses the in-box SerialPort. - Compat/TaskCompat bridges Task.Run/Delay/WhenAny/WhenAll (TaskEx on net40) and SemaphoreSlim.WaitAsync (net40 blocks briefly - trivial at 9600 baud). - IReadOnlyList/IReadOnlyDictionary -> IList/IDictionary throughout (net40 predates the IReadOnly* interfaces and the Bcl backport cannot make arrays implement them). - HashCode.Combine replaced with a manual combine (Bcl.HashCode has no net40 build); Marshal.SizeOf<T> -> typeof form; ViGEmJoystickSink gated #if !NET40. HidFeederJoystickSink stays on both flavors - it will drive RioGamepadXP.sys on XP via the same contract. Both TFMs build; 275 tests green on net48. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
79 lines
2.5 KiB
C#
79 lines
2.5 KiB
C#
using RioJoy.Core.Editing;
|
|
using Xunit;
|
|
|
|
namespace RioJoy.Core.Tests.Editing;
|
|
|
|
public class SheetLayoutTests
|
|
{
|
|
[Theory]
|
|
[InlineData("0F", 0x0F)]
|
|
[InlineData("50", 0x50)]
|
|
[InlineData("6F", 0x6F)]
|
|
[InlineData("00", 0x00)]
|
|
public void AddressFromText_ParsesHexCells(string text, int expected)
|
|
{
|
|
Assert.Equal(expected, SheetLayout.AddressFromText(text));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("HOME")]
|
|
[InlineData("RIO_0")]
|
|
[InlineData("70")] // > 0x6F
|
|
[InlineData("M U")]
|
|
[InlineData("0")] // single digit
|
|
public void AddressFromText_RejectsNonAddresses(string text)
|
|
{
|
|
Assert.Null(SheetLayout.AddressFromText(text));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0x00, SheetSection.Contacts)]
|
|
[InlineData(0x10, SheetSection.Secondary)]
|
|
[InlineData(0x18, SheetSection.Screen)]
|
|
[InlineData(0x2F, SheetSection.Letters)]
|
|
[InlineData(0x38, SheetSection.Throttle)]
|
|
[InlineData(0x40, SheetSection.Joystick)]
|
|
[InlineData(0x50, SheetSection.Keypad)]
|
|
[InlineData(0x6F, SheetSection.ExtKeypad)]
|
|
public void SectionForAddress_Classifies(int address, SheetSection expected)
|
|
{
|
|
Assert.Equal(expected, SheetLayout.SectionForAddress(address));
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_BuildsCellsWithGridPositions()
|
|
{
|
|
const string csv =
|
|
"\"\",\"IsLit\",\"\",\"\",\"0F\"\n" +
|
|
"\"\",\"\",\"\",\"\",\"HOME\"";
|
|
|
|
IList<SheetCell> cells = SheetLayout.Parse(csv);
|
|
|
|
SheetCell addr = Assert.Single(cells, c => c.Text == "0F");
|
|
Assert.Equal(0x0F, addr.Address);
|
|
Assert.Equal(SheetSection.Contacts, addr.Section);
|
|
Assert.Equal(0, addr.Row);
|
|
Assert.Equal(4, addr.Col);
|
|
|
|
SheetCell key = Assert.Single(cells, c => c.Text == "HOME");
|
|
Assert.Null(key.Address);
|
|
Assert.Equal(1, key.Row);
|
|
Assert.Equal(4, key.Col);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_RealSheet_HasFullAddressMap()
|
|
{
|
|
IList<SheetCell> cells = SheetLayout.Load(
|
|
TestRepo.CustomBackground("config-sheet.csv"));
|
|
|
|
// Every RIO address 0x00..0x6F that exists should appear exactly once as a cell.
|
|
var addresses = cells.Where(c => c.Address is not null).Select(c => c.Address!.Value).ToHashSet();
|
|
Assert.Contains(0x00, addresses);
|
|
Assert.Contains(0x2F, addresses); // a letter button
|
|
Assert.Contains(0x50, addresses); // keypad
|
|
Assert.Contains(0x6F, addresses); // ext keypad
|
|
Assert.True(addresses.Count >= 100, $"expected most of the address map, got {addresses.Count}");
|
|
}
|
|
}
|