using RioJoy.Core.Mapping; namespace RioJoy.Core.Tests.Mapping; /// /// Records every routed output as an ordered, human-readable log so tests can /// assert both what happened and in what order. /// internal sealed class RecordingSink : IInputSink, IJoystickSink, ILampSink, IRioCommandSink { private readonly List _log = new(); /// Direct access for single-threaded tests. public List Log { get { lock (_log) return _log; } } /// Thread-safe copy for assertions while the link thread writes. public string[] Snapshot() { lock (_log) return _log.ToArray(); } private void Add(string entry) { lock (_log) _log.Add(entry); } public void KeyDown(byte virtualKey, bool extended) => Add($"KeyDown(0x{virtualKey:X2},ext={extended})"); public void KeyUp(byte virtualKey, bool extended) => Add($"KeyUp(0x{virtualKey:X2},ext={extended})"); public void MouseMove(int dx, int dy) => Add($"MouseMove({dx},{dy})"); public void MouseButton(MouseButton button, bool down) => Add($"MouseButton({button},{down})"); public void SetButton(int button, bool pressed) => Add($"Joy({button},{pressed})"); public void SetHat(RioHat position) => Add($"Hat({position})"); public void SetAxis(RioJoy.Core.Calibration.JoyAxis axis, int value) => Add($"Axis({axis},{value})"); public void SetLamp(int address, byte lampState) => Add($"Lamp(0x{address:X2},0x{lampState:X2})"); public void Execute(RioCommandCode command) => Add($"Cmd({command})"); }