test: change methodology to have a mock assembly

This commit is contained in:
Sumanth Rayancha
2025-08-11 23:01:46 -04:00
parent 90b6f258f0
commit 4ee62088fa
9 changed files with 1826 additions and 2 deletions

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Essentials.Core.Abstractions;
using PepperDash.Essentials.Core.CrestronIO;
using PepperDash.Essentials.Core.Factory;
using Serilog.Events;
namespace PepperDash.Essentials.Core.Devices
@@ -16,11 +17,12 @@ namespace PepperDash.Essentials.Core.Devices
public ICrestronControlSystem Processor { get; private set; }
public CrestronProcessorTestable(string key, ICrestronControlSystem processor)
public CrestronProcessorTestable(string key, ICrestronControlSystem processor = null)
: base(key)
{
SwitchedOutputs = new Dictionary<uint, ISwitchedOutput>();
Processor = processor ?? throw new ArgumentNullException(nameof(processor));
// Use factory if processor not provided
Processor = processor ?? CrestronEnvironmentFactory.GetControlSystem();
GetRelays();
}

View File

@@ -0,0 +1,136 @@
using System;
using PepperDash.Essentials.Core.Abstractions;
namespace PepperDash.Essentials.Core.Factory
{
/// <summary>
/// Factory for creating Crestron environment dependencies
/// Allows switching between real Crestron libraries and mock implementations
/// </summary>
public static class CrestronEnvironmentFactory
{
private static ICrestronEnvironmentProvider _provider;
private static bool _isTestMode = false;
static CrestronEnvironmentFactory()
{
// Default to runtime provider
_provider = new CrestronRuntimeProvider();
}
/// <summary>
/// Enables test mode with mock implementations
/// </summary>
public static void EnableTestMode()
{
_isTestMode = true;
_provider = new CrestronMockProvider();
}
/// <summary>
/// Disables test mode and returns to runtime implementations
/// </summary>
public static void DisableTestMode()
{
_isTestMode = false;
_provider = new CrestronRuntimeProvider();
}
/// <summary>
/// Sets a custom provider for Crestron environment
/// </summary>
public static void SetProvider(ICrestronEnvironmentProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
/// <summary>
/// Gets whether the factory is in test mode
/// </summary>
public static bool IsTestMode => _isTestMode;
/// <summary>
/// Gets the current control system instance
/// </summary>
public static ICrestronControlSystem GetControlSystem()
{
return _provider.GetControlSystem();
}
/// <summary>
/// Creates a relay port
/// </summary>
public static IRelayPort CreateRelayPort(uint portNumber)
{
return _provider.CreateRelayPort(portNumber);
}
/// <summary>
/// Creates a digital input
/// </summary>
public static IDigitalInput CreateDigitalInput(uint portNumber)
{
return _provider.CreateDigitalInput(portNumber);
}
/// <summary>
/// Creates a versiport
/// </summary>
public static IVersiPort CreateVersiPort(uint portNumber)
{
return _provider.CreateVersiPort(portNumber);
}
/// <summary>
/// Gets console manager for debugging
/// </summary>
public static IConsoleManager GetConsoleManager()
{
return _provider.GetConsoleManager();
}
/// <summary>
/// Gets system information
/// </summary>
public static ISystemInfo GetSystemInfo()
{
return _provider.GetSystemInfo();
}
}
/// <summary>
/// Provider interface for Crestron environment dependencies
/// </summary>
public interface ICrestronEnvironmentProvider
{
ICrestronControlSystem GetControlSystem();
IRelayPort CreateRelayPort(uint portNumber);
IDigitalInput CreateDigitalInput(uint portNumber);
IVersiPort CreateVersiPort(uint portNumber);
IConsoleManager GetConsoleManager();
ISystemInfo GetSystemInfo();
}
/// <summary>
/// Console manager abstraction
/// </summary>
public interface IConsoleManager
{
void Print(string message);
void PrintLine(string message);
void RegisterCommand(string command, Action<string> handler, string help);
}
/// <summary>
/// System information abstraction
/// </summary>
public interface ISystemInfo
{
string ProgramName { get; }
string SerialNumber { get; }
string MacAddress { get; }
string IpAddress { get; }
string FirmwareVersion { get; }
DateTime SystemUpTime { get; }
}
}

View File

@@ -0,0 +1,265 @@
using System;
using System.Collections.Generic;
using PepperDash.Essentials.Core.Abstractions;
namespace PepperDash.Essentials.Core.Factory
{
/// <summary>
/// Mock provider for unit testing without Crestron hardware
/// </summary>
public class CrestronMockProvider : ICrestronEnvironmentProvider
{
private MockControlSystem _controlSystem;
public CrestronMockProvider()
{
_controlSystem = new MockControlSystem();
}
public ICrestronControlSystem GetControlSystem()
{
return _controlSystem;
}
public IRelayPort CreateRelayPort(uint portNumber)
{
if (!_controlSystem.RelayPorts.ContainsKey(portNumber))
{
_controlSystem.RelayPorts[portNumber] = new MockRelayPort();
}
return _controlSystem.RelayPorts[portNumber];
}
public IDigitalInput CreateDigitalInput(uint portNumber)
{
if (!_controlSystem.DigitalInputs.ContainsKey(portNumber))
{
_controlSystem.DigitalInputs[portNumber] = new MockDigitalInput();
}
return _controlSystem.DigitalInputs[portNumber];
}
public IVersiPort CreateVersiPort(uint portNumber)
{
if (!_controlSystem.VersiPorts.ContainsKey(portNumber))
{
_controlSystem.VersiPorts[portNumber] = new MockVersiPort();
}
return _controlSystem.VersiPorts[portNumber];
}
public IConsoleManager GetConsoleManager()
{
return new MockConsoleManager();
}
public ISystemInfo GetSystemInfo()
{
return new MockSystemInfo();
}
/// <summary>
/// Configures the mock control system for testing
/// </summary>
public void ConfigureMockSystem(Action<MockControlSystem> configure)
{
configure(_controlSystem);
}
}
/// <summary>
/// Mock implementation of control system for testing
/// </summary>
public class MockControlSystem : ICrestronControlSystem
{
public bool SupportsRelay { get; set; } = true;
public uint NumberOfRelayPorts { get; set; } = 8;
public Dictionary<uint, IRelayPort> RelayPorts { get; set; } = new Dictionary<uint, IRelayPort>();
public Dictionary<uint, IDigitalInput> DigitalInputs { get; set; } = new Dictionary<uint, IDigitalInput>();
public Dictionary<uint, IVersiPort> VersiPorts { get; set; } = new Dictionary<uint, IVersiPort>();
public string ProgramIdTag { get; set; } = "TEST_PROGRAM";
public string ControllerPrompt { get; set; } = "TEST>";
public bool SupportsEthernet { get; set; } = true;
public bool SupportsDigitalInput { get; set; } = true;
public uint NumberOfDigitalInputPorts { get; set; } = 8;
public bool SupportsVersiPort { get; set; } = true;
public uint NumberOfVersiPorts { get; set; } = 8;
public MockControlSystem()
{
// Initialize with default relay ports
for (uint i = 1; i <= NumberOfRelayPorts; i++)
{
RelayPorts[i] = new MockRelayPort();
}
// Initialize with default digital inputs
for (uint i = 1; i <= NumberOfDigitalInputPorts; i++)
{
DigitalInputs[i] = new MockDigitalInput();
}
// Initialize with default versiports
for (uint i = 1; i <= NumberOfVersiPorts; i++)
{
VersiPorts[i] = new MockVersiPort();
}
}
}
/// <summary>
/// Mock implementation of relay port for testing
/// </summary>
public class MockRelayPort : IRelayPort
{
private bool _state;
public bool State => _state;
public event EventHandler<bool> StateChanged;
public void Open()
{
_state = false;
StateChanged?.Invoke(this, _state);
}
public void Close()
{
_state = true;
StateChanged?.Invoke(this, _state);
}
public void Pulse(int delayMs)
{
Close();
System.Threading.Tasks.Task.Delay(delayMs).ContinueWith(_ => Open());
}
/// <summary>
/// Test helper to set state directly
/// </summary>
public void SetState(bool state)
{
_state = state;
StateChanged?.Invoke(this, _state);
}
}
/// <summary>
/// Mock implementation of digital input for testing
/// </summary>
public class MockDigitalInput : IDigitalInput
{
private bool _state;
public bool State => _state;
public event EventHandler<Abstractions.DigitalInputEventArgs> StateChange;
/// <summary>
/// Test helper to simulate input change
/// </summary>
public void SimulateStateChange(bool newState)
{
_state = newState;
StateChange?.Invoke(this, new Abstractions.DigitalInputEventArgs(newState));
}
}
/// <summary>
/// Mock implementation of versiport for testing
/// </summary>
public class MockVersiPort : IVersiPort
{
private bool _digitalIn;
private bool _digitalOut;
private ushort _analogIn;
public bool DigitalIn => _digitalIn;
public ushort AnalogIn => _analogIn;
public event EventHandler<Abstractions.VersiPortEventArgs> VersiportChange;
public void SetDigitalOut(bool value)
{
_digitalOut = value;
}
/// <summary>
/// Test helper to simulate digital input change
/// </summary>
public void SimulateDigitalInChange(bool value)
{
_digitalIn = value;
VersiportChange?.Invoke(this, new Abstractions.VersiPortEventArgs
{
EventType = Abstractions.VersiPortEventType.DigitalInChange,
Value = value
});
}
/// <summary>
/// Test helper to simulate analog input change
/// </summary>
public void SimulateAnalogInChange(ushort value)
{
_analogIn = value;
VersiportChange?.Invoke(this, new Abstractions.VersiPortEventArgs
{
EventType = Abstractions.VersiPortEventType.AnalogInChange,
Value = value
});
}
}
/// <summary>
/// Mock implementation of console manager for testing
/// </summary>
public class MockConsoleManager : IConsoleManager
{
public List<string> OutputLines { get; } = new List<string>();
public Dictionary<string, Action<string>> Commands { get; } = new Dictionary<string, Action<string>>();
public void Print(string message)
{
OutputLines.Add(message);
Console.Write(message);
}
public void PrintLine(string message)
{
OutputLines.Add(message);
Console.WriteLine(message);
}
public void RegisterCommand(string command, Action<string> handler, string help)
{
Commands[command] = handler;
}
/// <summary>
/// Test helper to execute a registered command
/// </summary>
public void ExecuteCommand(string command, string args)
{
if (Commands.TryGetValue(command, out var handler))
{
handler(args);
}
}
}
/// <summary>
/// Mock implementation of system info for testing
/// </summary>
public class MockSystemInfo : ISystemInfo
{
public string ProgramName { get; set; } = "TestProgram";
public string SerialNumber { get; set; } = "TEST123456";
public string MacAddress { get; set; } = "00:11:22:33:44:55";
public string IpAddress { get; set; } = "192.168.1.100";
public string FirmwareVersion { get; set; } = "1.0.0.0";
public DateTime SystemUpTime { get; set; } = DateTime.Now.AddHours(-1);
}
}

View File

@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using PepperDash.Essentials.Core.Abstractions;
#if !TEST_BUILD
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
#endif
namespace PepperDash.Essentials.Core.Factory
{
/// <summary>
/// Runtime provider that uses actual Crestron libraries
/// </summary>
public class CrestronRuntimeProvider : ICrestronEnvironmentProvider
{
private ICrestronControlSystem _controlSystem;
public ICrestronControlSystem GetControlSystem()
{
if (_controlSystem == null)
{
#if !TEST_BUILD
// In runtime, wrap the actual Crestron control system
// Note: This would need to be adapted based on the actual Crestron API
// For now, return a null implementation
#endif
{
// Return a null object pattern implementation for non-Crestron environments
_controlSystem = new NullControlSystem();
}
}
return _controlSystem;
}
public IRelayPort CreateRelayPort(uint portNumber)
{
#if !TEST_BUILD
var controlSystem = GetControlSystem();
if (controlSystem.RelayPorts.TryGetValue(portNumber, out var port))
{
return port;
}
#endif
return new NullRelayPort();
}
public IDigitalInput CreateDigitalInput(uint portNumber)
{
#if !TEST_BUILD
// Implementation would wrap actual Crestron digital input
// This is a simplified version
#endif
return new NullDigitalInput();
}
public IVersiPort CreateVersiPort(uint portNumber)
{
#if !TEST_BUILD
// Implementation would wrap actual Crestron versiport
// This is a simplified version
#endif
return new NullVersiPort();
}
public IConsoleManager GetConsoleManager()
{
#if !TEST_BUILD
return new CrestronConsoleManager();
#else
return new NullConsoleManager();
#endif
}
public ISystemInfo GetSystemInfo()
{
#if !TEST_BUILD
return new CrestronSystemInfo();
#else
return new NullSystemInfo();
#endif
}
#region Null Object Pattern Implementations
private class NullControlSystem : ICrestronControlSystem
{
public bool SupportsRelay => false;
public uint NumberOfRelayPorts => 0;
public Dictionary<uint, IRelayPort> RelayPorts => new Dictionary<uint, IRelayPort>();
public string ProgramIdTag => "NULL";
public string ControllerPrompt => "NULL>";
public bool SupportsEthernet => false;
public bool SupportsDigitalInput => false;
public uint NumberOfDigitalInputPorts => 0;
public bool SupportsVersiPort => false;
public uint NumberOfVersiPorts => 0;
}
private class NullRelayPort : IRelayPort
{
public bool State => false;
public void Open() { }
public void Close() { }
public void Pulse(int delayMs) { }
}
private class NullDigitalInput : IDigitalInput
{
public bool State => false;
public event EventHandler<Abstractions.DigitalInputEventArgs> StateChange;
}
private class NullVersiPort : IVersiPort
{
public bool DigitalIn => false;
public ushort AnalogIn => 0;
public void SetDigitalOut(bool value) { }
public event EventHandler<Abstractions.VersiPortEventArgs> VersiportChange;
}
private class NullConsoleManager : IConsoleManager
{
public void Print(string message) { }
public void PrintLine(string message) { }
public void RegisterCommand(string command, Action<string> handler, string help) { }
}
private class NullSystemInfo : ISystemInfo
{
public string ProgramName => "NULL";
public string SerialNumber => "000000";
public string MacAddress => "00:00:00:00:00:00";
public string IpAddress => "0.0.0.0";
public string FirmwareVersion => "0.0.0";
public DateTime SystemUpTime => DateTime.Now;
}
#endregion
#if !TEST_BUILD
private class CrestronConsoleManager : IConsoleManager
{
public void Print(string message)
{
CrestronConsole.Print(message);
}
public void PrintLine(string message)
{
CrestronConsole.PrintLine(message);
}
public void RegisterCommand(string command, Action<string> handler, string help)
{
CrestronConsole.AddNewConsoleCommand((s) => handler(s), command, help, ConsoleAccessLevelEnum.AccessOperator);
}
}
private class CrestronSystemInfo : ISystemInfo
{
public string ProgramName => "CrestronProgram";
public string SerialNumber => "000000";
public string MacAddress => "00:00:00:00:00:00";
public string IpAddress => "0.0.0.0";
public string FirmwareVersion => "1.0.0";
public DateTime SystemUpTime => DateTime.Now;
}
#endif
}
}