test: initial attempt at tests with Claude Code

This commit is contained in:
Sumanth Rayancha
2025-08-11 22:21:14 -04:00
parent e1e32cea6f
commit 90b6f258f0
11 changed files with 1211 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro;
namespace PepperDash.Essentials.Core.Abstractions
{
/// <summary>
/// Adapter that wraps actual Crestron Control System for production use
/// </summary>
public class CrestronControlSystemAdapter : ICrestronControlSystem
{
private readonly CrestronControlSystem _controlSystem;
private readonly Dictionary<uint, IRelayPort> _relayPorts;
public CrestronControlSystemAdapter(CrestronControlSystem controlSystem)
{
_controlSystem = controlSystem ?? throw new ArgumentNullException(nameof(controlSystem));
_relayPorts = new Dictionary<uint, IRelayPort>();
if (_controlSystem.SupportsRelay)
{
for (uint i = 1; i <= (uint)_controlSystem.NumberOfRelayPorts; i++)
{
_relayPorts[i] = new RelayPortAdapter(_controlSystem.RelayPorts[i]);
}
}
}
public bool SupportsRelay => _controlSystem.SupportsRelay;
public uint NumberOfRelayPorts => (uint)_controlSystem.NumberOfRelayPorts;
public Dictionary<uint, IRelayPort> RelayPorts => _relayPorts;
public string ProgramIdTag => "TestProgram"; // Simplified for now
public string ControllerPrompt => _controlSystem.ControllerPrompt;
public bool SupportsEthernet => _controlSystem.SupportsEthernet;
public bool SupportsDigitalInput => _controlSystem.SupportsDigitalInput;
public uint NumberOfDigitalInputPorts => (uint)_controlSystem.NumberOfDigitalInputPorts;
public bool SupportsVersiPort => _controlSystem.SupportsVersiport;
public uint NumberOfVersiPorts => (uint)_controlSystem.NumberOfVersiPorts;
}
/// <summary>
/// Adapter for Crestron relay port
/// </summary>
public class RelayPortAdapter : IRelayPort
{
private readonly Crestron.SimplSharpPro.Relay _relay;
public RelayPortAdapter(Crestron.SimplSharpPro.Relay relay)
{
_relay = relay ?? throw new ArgumentNullException(nameof(relay));
}
public void Open() => _relay.Open();
public void Close() => _relay.Close();
public void Pulse(int delayMs)
{
// Crestron Relay.Pulse() doesn't take parameters
// We'll just call the basic Pulse method
_relay.Close();
System.Threading.Thread.Sleep(delayMs);
_relay.Open();
}
public bool State => _relay.State;
}
/// <summary>
/// Adapter for Crestron digital input
/// </summary>
public class DigitalInputAdapter : IDigitalInput
{
private readonly Crestron.SimplSharpPro.DigitalInput _digitalInput;
public DigitalInputAdapter(Crestron.SimplSharpPro.DigitalInput digitalInput)
{
_digitalInput = digitalInput ?? throw new ArgumentNullException(nameof(digitalInput));
_digitalInput.StateChange += OnStateChange;
}
public bool State => _digitalInput.State;
public event EventHandler<DigitalInputEventArgs> StateChange;
private void OnStateChange(DigitalInput digitalInput, Crestron.SimplSharpPro.DigitalInputEventArgs args)
{
StateChange?.Invoke(this, new Abstractions.DigitalInputEventArgs(args.State));
}
}
/// <summary>
/// Adapter for Crestron VersiPort
/// </summary>
public class VersiPortAdapter : IVersiPort
{
private readonly Crestron.SimplSharpPro.Versiport _versiPort;
public VersiPortAdapter(Crestron.SimplSharpPro.Versiport versiPort)
{
_versiPort = versiPort ?? throw new ArgumentNullException(nameof(versiPort));
_versiPort.VersiportChange += OnVersiportChange;
}
public bool DigitalIn => _versiPort.DigitalIn;
public void SetDigitalOut(bool value) => _versiPort.DigitalOut = value;
public ushort AnalogIn => _versiPort.AnalogIn;
public event EventHandler<VersiPortEventArgs> VersiportChange;
private void OnVersiportChange(Versiport port, VersiportEventArgs args)
{
var eventType = args.Event == eVersiportEvent.DigitalInChange
? VersiPortEventType.DigitalInChange
: VersiPortEventType.AnalogInChange;
VersiportChange?.Invoke(this, new Abstractions.VersiPortEventArgs
{
EventType = eventType,
Value = args.Event == eVersiportEvent.DigitalInChange ? (object)port.DigitalIn : port.AnalogIn
});
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.Core.Abstractions
{
/// <summary>
/// Abstraction for Crestron Control System to enable unit testing
/// </summary>
public interface ICrestronControlSystem
{
bool SupportsRelay { get; }
uint NumberOfRelayPorts { get; }
Dictionary<uint, IRelayPort> RelayPorts { get; }
string ProgramIdTag { get; }
string ControllerPrompt { get; }
bool SupportsEthernet { get; }
bool SupportsDigitalInput { get; }
uint NumberOfDigitalInputPorts { get; }
bool SupportsVersiPort { get; }
uint NumberOfVersiPorts { get; }
}
/// <summary>
/// Abstraction for relay port
/// </summary>
public interface IRelayPort
{
void Open();
void Close();
void Pulse(int delayMs);
bool State { get; }
}
/// <summary>
/// Abstraction for digital input
/// </summary>
public interface IDigitalInput
{
bool State { get; }
event EventHandler<DigitalInputEventArgs> StateChange;
}
public class DigitalInputEventArgs : EventArgs
{
public bool State { get; set; }
public DigitalInputEventArgs(bool state)
{
State = state;
}
}
/// <summary>
/// Abstraction for VersiPort
/// </summary>
public interface IVersiPort
{
bool DigitalIn { get; }
void SetDigitalOut(bool value);
ushort AnalogIn { get; }
event EventHandler<VersiPortEventArgs> VersiportChange;
}
public class VersiPortEventArgs : EventArgs
{
public VersiPortEventType EventType { get; set; }
public object Value { get; set; }
}
public enum VersiPortEventType
{
DigitalInChange,
AnalogInChange
}
}

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Essentials.Core.Abstractions;
using PepperDash.Essentials.Core.CrestronIO;
using Serilog.Events;
namespace PepperDash.Essentials.Core.Devices
{
/// <summary>
/// Testable version of CrestronProcessor that uses abstractions
/// </summary>
public class CrestronProcessorTestable : Device, ISwitchedOutputCollection
{
public Dictionary<uint, ISwitchedOutput> SwitchedOutputs { get; private set; }
public ICrestronControlSystem Processor { get; private set; }
public CrestronProcessorTestable(string key, ICrestronControlSystem processor)
: base(key)
{
SwitchedOutputs = new Dictionary<uint, ISwitchedOutput>();
Processor = processor ?? throw new ArgumentNullException(nameof(processor));
GetRelays();
}
/// <summary>
/// Creates a GenericRelayDevice for each relay on the processor and adds them to the SwitchedOutputs collection
/// </summary>
void GetRelays()
{
try
{
if (Processor.SupportsRelay)
{
for (uint i = 1; i <= Processor.NumberOfRelayPorts; i++)
{
if (Processor.RelayPorts.ContainsKey(i))
{
var relay = new GenericRelayDeviceTestable(
string.Format("{0}-relay-{1}", this.Key, i),
Processor.RelayPorts[i]);
SwitchedOutputs.Add(i, relay);
}
}
}
}
catch (Exception e)
{
Debug.LogMessage(LogEventLevel.Debug, this, "Error Getting Relays from processor:\n '{0}'", e);
}
}
}
/// <summary>
/// Testable version of GenericRelayDevice
/// </summary>
public class GenericRelayDeviceTestable : Device, ISwitchedOutput
{
private readonly IRelayPort _relayPort;
public GenericRelayDeviceTestable(string key, IRelayPort relayPort)
: base(key)
{
_relayPort = relayPort ?? throw new ArgumentNullException(nameof(relayPort));
OutputIsOnFeedback = new BoolFeedback(() => IsOn);
}
public void OpenRelay()
{
_relayPort.Open();
OutputIsOnFeedback.FireUpdate();
}
public void CloseRelay()
{
_relayPort.Close();
OutputIsOnFeedback.FireUpdate();
}
public void PulseRelay(int delayMs)
{
_relayPort.Pulse(delayMs);
}
public void On()
{
CloseRelay();
}
public void Off()
{
OpenRelay();
}
public void PowerToggle()
{
if (IsOn)
Off();
else
On();
}
public bool IsOn => _relayPort.State;
public BoolFeedback OutputIsOnFeedback { get; private set; }
public override bool CustomActivate()
{
OutputIsOnFeedback = new BoolFeedback(() => IsOn);
return base.CustomActivate();
}
}
}