Files
riojoy/tests/RioJoy.Core.Tests/Hid/RioHidReportTests.cs
T
CydandClaude Fable 5 3b2af7b79a Phase 8A (1/2): de-Span the serial layer, swap JSON to Newtonsoft
Prepares RioJoy.Core for the net40 (Windows XP) target, which has no
System.Memory, ValueTask, or System.Text.Json:
- IRioTransport and the whole protocol/framing layer now use byte[] +
  Task (RioPacket.Payload, PacketParser/Builder, RioChecksum, replies,
  AnalogReport, RioHidReport). At 9600 baud Span bought nothing; the
  SerialPortTransport bridge copies disappear entirely.
- ConfigStore/OverlayTemplateStore switch to Newtonsoft 13 with the
  same conventions (indented, PascalCase, string enums, null-skipping);
  verified against the real STJ-written config.json and regions.json
  (load + round-trip). System.Memory and System.Text.Json packages
  dropped.

275 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:36:19 -05:00

86 lines
2.6 KiB
C#

using RioJoy.Core.Calibration;
using RioJoy.Core.Hid;
using RioJoy.Core.Mapping;
using Xunit;
namespace RioJoy.Core.Tests.Hid;
public class RioHidReportTests
{
[Fact]
public void DefaultReport_CentersAxesAndHat()
{
var report = new RioHidReport();
byte[] b = report.ToArray();
Assert.Equal(RioHidReport.Size, b.Length);
// Each axis = 16383 = 0x3FFF, little-endian.
for (int offset = 0; offset < 12; offset += 2)
{
Assert.Equal(0xFF, b[offset]);
Assert.Equal(0x3F, b[offset + 1]);
}
Assert.Equal(0x0F, b[12] & 0x0F); // hat centered/null
}
[Fact]
public void SetAxis_WritesLittleEndian_AndClamps()
{
var report = new RioHidReport();
report.SetAxis(JoyAxis.Z, 0x1234);
Assert.Equal(0x34, report.ToArray()[4]);
Assert.Equal(0x12, report.ToArray()[5]);
report.SetAxis(JoyAxis.Z, 70000); // over max → clamped to 32767
Assert.Equal(0xFF, report.ToArray()[4]);
Assert.Equal(0x7F, report.ToArray()[5]);
}
[Theory]
[InlineData(RioHat.Up, 0x00)]
[InlineData(RioHat.Right, 0x01)]
[InlineData(RioHat.Down, 0x02)]
[InlineData(RioHat.Left, 0x03)]
[InlineData(RioHat.Centered, 0x0F)]
public void SetHat_EncodesNibble(RioHat hat, int expected)
{
var report = new RioHidReport();
report.SetHat(hat);
Assert.Equal(expected, report.ToArray()[12] & 0x0F);
}
[Theory]
[InlineData(1, 13, 0x01)] // button 1 → byte 13 bit 0
[InlineData(8, 13, 0x80)] // button 8 → byte 13 bit 7
[InlineData(9, 14, 0x01)] // button 9 → byte 14 bit 0
[InlineData(96, 24, 0x80)] // button 96 → byte 24 bit 7
public void SetButton_SetsCorrectBit(int button, int byteIndex, int mask)
{
var report = new RioHidReport();
report.SetButton(button, pressed: true);
Assert.Equal(mask, report.ToArray()[byteIndex]);
report.SetButton(button, pressed: false);
Assert.Equal(0, report.ToArray()[byteIndex]);
}
[Fact]
public void SetButton_RejectsOutOfRange()
{
var report = new RioHidReport();
Assert.Throws<ArgumentOutOfRangeException>(() => report.SetButton(0, true));
Assert.Throws<ArgumentOutOfRangeException>(() => report.SetButton(97, true));
}
[Fact]
public void Buttons_ComposeIndependently()
{
var report = new RioHidReport();
report.SetButton(1, true);
report.SetButton(2, true);
report.SetButton(1, false);
Assert.Equal(0x02, report.ToArray()[13]); // only button 2 remains
}
}