Profile editor: - Cockpit-style encoder gauges centered over the Upper Middle MFD: Z left, X/Y right, and L/R/Rz arranged as a big "U". - [JoyStick] section surfaced as a vertical "Axis" toggle column (6 inverts + ZR mix), written back to the profile's calibration. - Tighten the panel layout (close gaps, trim empty border columns); colour the Secondary/Screen columns yellow; rename the "Joystick / Hat" board to "Joystick"; add an "Import .ini..." tray entry. - "RIO commands (live)" button group (all RioCommandCodes) fired at the live RIO. Serial-port handling: - Start dormant; only take the COM port for a profiled game (auto-switch) or while editing, so the native games can open the port without clashing. - Editor sessions hold the port but route keyboard/mouse/joystick to no-op sinks (NullInputSink), so button function can be checked without injecting input; RioRuntime.ButtonActivity drives a live cyan press indicator and lamp feedback still applies. - AutoSwitchWatcher.Reset() re-syncs the watcher after an editor session. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
69 lines
2.6 KiB
C#
69 lines
2.6 KiB
C#
using RioJoy.Core.Editing;
|
||
using RioJoy.Core.Mapping;
|
||
using Xunit;
|
||
|
||
namespace RioJoy.Core.Tests.Editing;
|
||
|
||
public class CockpitPanelTests
|
||
{
|
||
[Fact]
|
||
public void Covers_EveryValidAddress_ExactlyOnce()
|
||
{
|
||
List<int> addrs = CockpitPanel.Buttons().Select(b => b.Address).ToList();
|
||
|
||
// 0x00–0x47 buttons + 0x50–0x6F keypads = 104 valid addresses; 0x48–0x4F don't exist.
|
||
var expected = Enumerable.Range(0x00, 0x48).Concat(Enumerable.Range(0x50, 0x20)).ToHashSet();
|
||
Assert.Equal(expected.Count, addrs.Count); // no duplicates / no extras
|
||
Assert.Equal(expected, addrs.ToHashSet()); // exactly the valid set
|
||
Assert.DoesNotContain(0x48, addrs); // gap excluded
|
||
}
|
||
|
||
[Theory]
|
||
[InlineData(0x2F, "Upper Left MFD")]
|
||
[InlineData(0x20, "Upper Middle MFD")]
|
||
[InlineData(0x37, "Upper Right MFD")]
|
||
[InlineData(0x00, "Lower Right MFD")]
|
||
[InlineData(0x0F, "Lower Left MFD")]
|
||
[InlineData(0x38, "Throttle")]
|
||
[InlineData(0x10, "Secondary")]
|
||
[InlineData(0x18, "Screen")]
|
||
[InlineData(0x40, "Joystick")]
|
||
[InlineData(0x50, "Internal Keypad")]
|
||
[InlineData(0x6F, "External Keypad")]
|
||
public void Address_LandsInExpectedGroup(int address, string group)
|
||
{
|
||
PanelButton b = CockpitPanel.Buttons().Single(x => x.Address == address);
|
||
Assert.Equal(group, b.Group.Title);
|
||
}
|
||
|
||
[Fact]
|
||
public void Keypads_AreNotLampCapable()
|
||
{
|
||
foreach (PanelButton b in CockpitPanel.Buttons().Where(x => x.Group.Kind == PanelGroupKind.Keypad))
|
||
Assert.False(b.LampCapable);
|
||
// ...and everything else is.
|
||
foreach (PanelButton b in CockpitPanel.Buttons().Where(x => x.Group.Kind != PanelGroupKind.Keypad))
|
||
Assert.True(b.LampCapable);
|
||
}
|
||
|
||
[Fact]
|
||
public void Keypad_PhysicalLayout_MapsDigitsToAddresses()
|
||
{
|
||
// Internal keypad: top-left "1" -> 0x51, bottom-middle "0" -> 0x50, "C" -> 0x5C.
|
||
IReadOnlyList<PanelButton> all = CockpitPanel.Buttons();
|
||
PanelGroup pad = CockpitPanel.Groups.Single(g => g.Title == "Internal Keypad");
|
||
|
||
Assert.Equal(0x51, pad.Addresses[0]); // row0 col0 = "1"
|
||
Assert.Equal(0x5C, pad.Addresses[3]); // row0 col3 = "C"
|
||
Assert.Equal(0x50, pad.Addresses[13]); // row3 col1 = "0"
|
||
Assert.Equal(0x5F, pad.Addresses[15]); // row3 col3 = "F"
|
||
}
|
||
|
||
[Fact]
|
||
public void AllAddresses_AreValidRioAddresses()
|
||
{
|
||
foreach (PanelButton b in CockpitPanel.Buttons())
|
||
Assert.InRange(b.Address, 0, RioAddress.MaxAddress);
|
||
}
|
||
}
|