namespace PS.IPAM.Tests.Mocks; using System.Management.Automation; using System.Management.Automation.Host; using System.Reflection; /// /// Helper class for testing PowerShell cmdlets. /// public class CmdletTestHelper : IDisposable where T : PSCmdlet, new() { private readonly T _cmdlet; private readonly List _output = new(); private readonly List _errors = new(); private bool _disposed; public CmdletTestHelper() { _cmdlet = new T(); } /// /// Gets the cmdlet instance for setting parameters. /// public T Cmdlet => _cmdlet; /// /// Gets the output objects written by the cmdlet. /// public IReadOnlyList Output => _output.AsReadOnly(); /// /// Gets the errors written by the cmdlet. /// public IReadOnlyList Errors => _errors.AsReadOnly(); /// /// Gets whether any errors were written. /// public bool HasErrors => _errors.Count > 0; /// /// Invokes the cmdlet and captures output. /// public void Invoke() { // Use reflection to call the protected ProcessRecord method var processMethod = typeof(T).GetMethod("ProcessRecord", BindingFlags.NonPublic | BindingFlags.Instance); if (processMethod == null) { throw new InvalidOperationException("ProcessRecord method not found on cmdlet."); } // Set up a mock command runtime to capture output var runtime = new MockCommandRuntime(_output, _errors); var runtimeProperty = typeof(Cmdlet).GetProperty("CommandRuntime", BindingFlags.Public | BindingFlags.Instance); runtimeProperty?.SetValue(_cmdlet, runtime); // Invoke the method try { processMethod.Invoke(_cmdlet, null); } catch (TargetInvocationException ex) when (ex.InnerException != null) { // Unwrap the exception throw ex.InnerException; } } public void Dispose() { if (!_disposed) { _disposed = true; } } } /// /// Mock implementation of ICommandRuntime for capturing cmdlet output. /// This is a minimal implementation that only handles the methods we need for testing. /// internal class MockCommandRuntime : ICommandRuntime { private readonly List _output; private readonly List _errors; public MockCommandRuntime(List output, List errors) { _output = output; _errors = errors; } public PSHost Host => null!; public PSTransactionContext CurrentPSTransaction => null!; public bool ShouldContinue(string query, string caption) => true; public bool ShouldContinue(string query, string caption, ref bool yesToAll, ref bool noToAll) => true; public bool ShouldProcess(string target) => true; public bool ShouldProcess(string target, string action) => true; public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption) => true; public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption, out ShouldProcessReason shouldProcessReason) { shouldProcessReason = ShouldProcessReason.None; return true; } public bool TransactionAvailable() => false; public void ThrowTerminatingError(ErrorRecord errorRecord) => throw errorRecord.Exception; public void WriteCommandDetail(string text) { } public void WriteDebug(string text) { } public void WriteError(ErrorRecord errorRecord) => _errors.Add(errorRecord); public void WriteObject(object sendToPipeline) => _output.Add(sendToPipeline); public void WriteObject(object sendToPipeline, bool enumerateCollection) { if (enumerateCollection && sendToPipeline is System.Collections.IEnumerable enumerable) { foreach (var item in enumerable) { _output.Add(item); } } else { _output.Add(sendToPipeline); } } public void WriteProgress(ProgressRecord progressRecord) { } public void WriteProgress(long sourceId, ProgressRecord progressRecord) { } public void WriteVerbose(string text) { } public void WriteWarning(string text) { } }