From d83266f634ec2c3a1ad75434ceb96890cb9b8847 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 13 Aug 2025 21:37:58 -0500 Subject: [PATCH] chore: remove unnecessary files --- PepperDash.Essentials.Tests.sln | 42 -- tests/EssentialsTests/CrestronMockTest.cs | 86 ---- tests/EssentialsTests/DirectMockTests.cs | 79 --- tests/EssentialsTests/UnitTest1.cs | 88 ---- .../Abstractions/DigitalInputTests.cs | 84 ---- .../Abstractions/VersiPortTests.cs | 163 ------ .../Devices/CrestronProcessorTestableTests.cs | 384 -------------- .../Devices/CrestronProcessorTests.cs | 193 -------- .../PepperDash.Essentials.Core.Tests.csproj | 29 -- tests/README.md | 170 ------- .../CrestronMockGenerator/AssemblyAnalyzer.cs | 266 ---------- .../CrestronMockGenerator.csproj | 15 - tools/CrestronMockGenerator/MockGenerator.cs | 468 ------------------ tools/CrestronMockGenerator/Program.cs | 117 ----- 14 files changed, 2184 deletions(-) delete mode 100644 PepperDash.Essentials.Tests.sln delete mode 100644 tests/EssentialsTests/CrestronMockTest.cs delete mode 100644 tests/EssentialsTests/DirectMockTests.cs delete mode 100644 tests/EssentialsTests/UnitTest1.cs delete mode 100644 tests/PepperDash.Essentials.Core.Tests/Abstractions/DigitalInputTests.cs delete mode 100644 tests/PepperDash.Essentials.Core.Tests/Abstractions/VersiPortTests.cs delete mode 100644 tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTestableTests.cs delete mode 100644 tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTests.cs delete mode 100644 tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj delete mode 100644 tests/README.md delete mode 100644 tools/CrestronMockGenerator/AssemblyAnalyzer.cs delete mode 100644 tools/CrestronMockGenerator/CrestronMockGenerator.csproj delete mode 100644 tools/CrestronMockGenerator/MockGenerator.cs delete mode 100644 tools/CrestronMockGenerator/Program.cs diff --git a/PepperDash.Essentials.Tests.sln b/PepperDash.Essentials.Tests.sln deleted file mode 100644 index b41db635..00000000 --- a/PepperDash.Essentials.Tests.sln +++ /dev/null @@ -1,42 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A8B8F24D-3181-45BF-9ED3-F734E04F0BC8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Core", "src\PepperDash.Core\PepperDash.Core.csproj", "{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core", "src\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj", "{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B8B8F24D-3181-45BF-9ED3-F734E04F0BC9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core.Tests", "tests\PepperDash.Essentials.Core.Tests\PepperDash.Essentials.Core.Tests.csproj", "{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Release|Any CPU.Build.0 = Release|Any CPU - {2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Release|Any CPU.Build.0 = Release|Any CPU - {3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A} = {A8B8F24D-3181-45BF-9ED3-F734E04F0BC8} - {2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B} = {A8B8F24D-3181-45BF-9ED3-F734E04F0BC8} - {3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C} = {B8B8F24D-3181-45BF-9ED3-F734E04F0BC9} - EndGlobalSection -EndGlobal \ No newline at end of file diff --git a/tests/EssentialsTests/CrestronMockTest.cs b/tests/EssentialsTests/CrestronMockTest.cs deleted file mode 100644 index d2d3ea45..00000000 --- a/tests/EssentialsTests/CrestronMockTest.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Crestron.SimplSharpPro; -using Xunit; - -namespace EssentialsTests -{ - public class CrestronMockTests - { - [Fact] - public void CrestronControlSystem_Constructor_ShouldBuildSuccessfully() - { - // Arrange & Act - var exception = Record.Exception(() => new CrestronControlSystem()); - - // Assert - Assert.Null(exception); - } - - [Fact] - public void CrestronControlSystem_Constructor_ShouldSetPropertiesCorrectly() - { - // Arrange & Act - var controlSystem = new CrestronControlSystem(); - - // Assert - Assert.NotNull(controlSystem); - Assert.NotNull(controlSystem.ComPorts); - Assert.NotNull(controlSystem.RelayPorts); - Assert.NotNull(controlSystem.IROutputPorts); - Assert.NotNull(controlSystem.DigitalInputPorts); - Assert.NotNull(controlSystem.IRInputPort); - } - - [Fact] - public void CrestronControlSystem_InitializeSystem_ShouldNotThrow() - { - // Arrange - var controlSystem = new CrestronControlSystem(); - - // Act & Assert - var exception = Record.Exception(() => controlSystem.InitializeSystem()); - Assert.Null(exception); - } - - [Fact] - public void MockControlSystem_ShouldHaveRequiredStaticProperties() - { - // Act & Assert - Assert.NotNull(CrestronControlSystem.NullCue); - Assert.NotNull(CrestronControlSystem.NullBoolInputSig); - Assert.NotNull(CrestronControlSystem.NullBoolOutputSig); - Assert.NotNull(CrestronControlSystem.NullUShortInputSig); - Assert.NotNull(CrestronControlSystem.NullUShortOutputSig); - Assert.NotNull(CrestronControlSystem.NullStringInputSig); - Assert.NotNull(CrestronControlSystem.NullStringOutputSig); - Assert.NotNull(CrestronControlSystem.SigGroups); - } - - [Fact] - public void MockControlSystem_ShouldCreateSigGroups() - { - // Act & Assert - var exception = Record.Exception(() => - { - var sigGroup = CrestronControlSystem.CreateSigGroup(1, eSigType.Bool); - Assert.NotNull(sigGroup); - }); - - Assert.Null(exception); - } - - [Fact] - public void MockControlSystem_VirtualMethods_ShouldNotThrow() - { - // Arrange - var controlSystem = new CrestronControlSystem(); - - // Act & Assert - just test InitializeSystem since it's definitely available - var exception = Record.Exception(() => - { - controlSystem.InitializeSystem(); - }); - - Assert.Null(exception); - } - } -} diff --git a/tests/EssentialsTests/DirectMockTests.cs b/tests/EssentialsTests/DirectMockTests.cs deleted file mode 100644 index a8d4c014..00000000 --- a/tests/EssentialsTests/DirectMockTests.cs +++ /dev/null @@ -1,79 +0,0 @@ -using CrestronMock; -using Xunit; - -namespace EssentialsTests -{ - public class DirectMockTests - { - [Fact] - public void CrestronMock_Should_Build_Successfully() - { - // This test verifies that our mock framework compiles and builds - // We've already proven this by the fact that the test project builds successfully - Assert.True(true, "Mock framework builds successfully in Test configuration"); - } - - [Fact] - public void MockFramework_Should_Provide_Required_Types() - { - // Verify that the essential mock types are available - var mockSig = new Sig(); - var mockBoolInputSig = new BoolInputSig(); - var mockUShortInputSig = new UShortInputSig(); - var mockStringInputSig = new StringInputSig(); - - Assert.NotNull(mockSig); - Assert.NotNull(mockBoolInputSig); - Assert.NotNull(mockUShortInputSig); - Assert.NotNull(mockStringInputSig); - } - - [Fact] - public void MockFramework_Should_Provide_Hardware_Types() - { - // Verify that hardware mock types are available - var mockComPort = new ComPort(); - var mockRelay = new Relay(); - var mockIROutputPort = new IROutputPort(); - var mockIRInputPort = new IRInputPort(); - var mockVersiPort = new VersiPort(); - - Assert.NotNull(mockComPort); - Assert.NotNull(mockRelay); - Assert.NotNull(mockIROutputPort); - Assert.NotNull(mockIRInputPort); - Assert.NotNull(mockVersiPort); - } - - [Fact] - public void TestConfiguration_Should_Use_MockFramework() - { - // In the Test configuration, CrestronControlSystem should come from our mock - // Let's verify this by checking we can create it without real Crestron dependencies - - // Since we can't reliably test the namespace-conflicted version, - // let's at least verify our mock types exist - var mockControlSystemType = typeof(CrestronMock.CrestronControlSystem); - Assert.NotNull(mockControlSystemType); - Assert.Equal("CrestronMock.CrestronControlSystem", mockControlSystemType.FullName); - } - - [Fact] - public void MockControlSystem_DirectTest_Should_Work() - { - // Test our mock directly using the CrestronMock namespace - var mockControlSystem = new CrestronMock.CrestronControlSystem(); - - Assert.NotNull(mockControlSystem); - Assert.NotNull(mockControlSystem.ComPorts); - Assert.NotNull(mockControlSystem.RelayPorts); - Assert.NotNull(mockControlSystem.IROutputPorts); - Assert.NotNull(mockControlSystem.DigitalInputPorts); - Assert.NotNull(mockControlSystem.IRInputPort); - - // Test that virtual methods don't throw - var exception = Record.Exception(() => mockControlSystem.InitializeSystem()); - Assert.Null(exception); - } - } -} diff --git a/tests/EssentialsTests/UnitTest1.cs b/tests/EssentialsTests/UnitTest1.cs deleted file mode 100644 index 9aabf7ae..00000000 --- a/tests/EssentialsTests/UnitTest1.cs +++ /dev/null @@ -1,88 +0,0 @@ -using CrestronMock; -using PepperDash.Essentials; -using PepperDash.Essentials.Core; - -namespace EssentialsTests; - -public class ControlSystemTests -{ - [Fact] - public void ControlSystem_Constructor_ShouldBuildSuccessfully() - { - // Arrange & Act - var exception = Record.Exception(() => new ControlSystem()); - - // Assert - Assert.Null(exception); - } - - [Fact] - public void ControlSystem_Constructor_ShouldSetGlobalControlSystem() - { - // Arrange & Act - var controlSystem = new ControlSystem(); - - // Assert - Assert.NotNull(Global.ControlSystem); - Assert.Same(controlSystem, Global.ControlSystem); - } - - [Fact] - public void ControlSystem_InitializeSystem_ShouldNotThrow() - { - // Arrange - var controlSystem = new ControlSystem(); - - // Act & Assert - var exception = Record.Exception(() => controlSystem.InitializeSystem()); - Assert.Null(exception); - } - - [Fact] - public void ControlSystem_ShouldImplementILoadConfig() - { - // Arrange & Act - var controlSystem = new ControlSystem(); - - // Assert - Assert.True(controlSystem is ILoadConfig); - } - - [Fact] - public void ControlSystem_ShouldHaveRequiredInterfaces() - { - // Arrange & Act - var controlSystem = new ControlSystem(); - - // Assert - Check that it inherits from base mock and implements hardware interfaces - Assert.NotNull(controlSystem); - Assert.True(controlSystem is IComPorts, "ControlSystem should implement IComPorts"); - Assert.True(controlSystem is IRelayPorts, "ControlSystem should implement IRelayPorts"); - Assert.True(controlSystem is IIROutputPorts, "ControlSystem should implement IIROutputPorts"); - Assert.True(controlSystem is IIOPorts, "ControlSystem should implement IIOPorts"); - Assert.True(controlSystem is IDigitalInputPorts, "ControlSystem should implement IDigitalInputPorts"); - Assert.True(controlSystem is IIRInputPort, "ControlSystem should implement IIRInputPort"); - } - - [Fact] - public void ControlSystem_ShouldHaveRequiredProperties() - { - // Arrange & Act - var controlSystem = new ControlSystem(); - - // Assert - Test by casting to interfaces to access properties - var comPorts = controlSystem as IComPorts; - var relayPorts = controlSystem as IRelayPorts; - var irOutputPorts = controlSystem as IIROutputPorts; - var ioPorts = controlSystem as IIOPorts; - var digitalInputPorts = controlSystem as IDigitalInputPorts; - var irInputPort = controlSystem as IIRInputPort; - - Assert.NotNull(comPorts?.ComPorts); - Assert.NotNull(relayPorts?.RelayPorts); - Assert.NotNull(irOutputPorts?.IROutputPorts); - Assert.NotNull(ioPorts?.IOPorts); - Assert.NotNull(digitalInputPorts?.DigitalInputPorts); - Assert.NotNull(irInputPort?.IRInputPort); - } -} diff --git a/tests/PepperDash.Essentials.Core.Tests/Abstractions/DigitalInputTests.cs b/tests/PepperDash.Essentials.Core.Tests/Abstractions/DigitalInputTests.cs deleted file mode 100644 index 8e88e2f0..00000000 --- a/tests/PepperDash.Essentials.Core.Tests/Abstractions/DigitalInputTests.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using FluentAssertions; -using Moq; -using PepperDash.Essentials.Core.Abstractions; -using Xunit; - -namespace PepperDash.Essentials.Core.Tests.Abstractions -{ - public class DigitalInputTests - { - [Fact] - public void StateChange_WhenDigitalInputChanges_RaisesEvent() - { - // Arrange - var mockDigitalInput = new Mock(); - var eventRaised = false; - bool capturedState = false; - - mockDigitalInput.Setup(d => d.State).Returns(true); - - // Subscribe to the event - mockDigitalInput.Object.StateChange += (sender, args) => - { - eventRaised = true; - capturedState = args.State; - }; - - // Act - Raise the event - mockDigitalInput.Raise(d => d.StateChange += null, - mockDigitalInput.Object, - new DigitalInputEventArgs(true)); - - // Assert - eventRaised.Should().BeTrue(); - capturedState.Should().BeTrue(); - } - - [Fact] - public void State_ReturnsCorrectValue() - { - // Arrange - var mockDigitalInput = new Mock(); - mockDigitalInput.Setup(d => d.State).Returns(true); - - // Act - var state = mockDigitalInput.Object.State; - - // Assert - state.Should().BeTrue(); - } - - [Fact] - public void MultipleStateChanges_TrackStateCorrectly() - { - // Arrange - var mockDigitalInput = new Mock(); - var stateChanges = new System.Collections.Generic.List(); - - mockDigitalInput.Object.StateChange += (sender, args) => - { - stateChanges.Add(args.State); - }; - - // Act - Simulate multiple state changes - mockDigitalInput.Raise(d => d.StateChange += null, - mockDigitalInput.Object, - new DigitalInputEventArgs(true)); - - mockDigitalInput.Raise(d => d.StateChange += null, - mockDigitalInput.Object, - new DigitalInputEventArgs(false)); - - mockDigitalInput.Raise(d => d.StateChange += null, - mockDigitalInput.Object, - new DigitalInputEventArgs(true)); - - // Assert - stateChanges.Should().HaveCount(3); - stateChanges[0].Should().BeTrue(); - stateChanges[1].Should().BeFalse(); - stateChanges[2].Should().BeTrue(); - } - } -} \ No newline at end of file diff --git a/tests/PepperDash.Essentials.Core.Tests/Abstractions/VersiPortTests.cs b/tests/PepperDash.Essentials.Core.Tests/Abstractions/VersiPortTests.cs deleted file mode 100644 index caa1ec7a..00000000 --- a/tests/PepperDash.Essentials.Core.Tests/Abstractions/VersiPortTests.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using FluentAssertions; -using Moq; -using PepperDash.Essentials.Core.Abstractions; -using Xunit; - -namespace PepperDash.Essentials.Core.Tests.Abstractions -{ - public class VersiPortTests - { - [Fact] - public void DigitalIn_ReturnsCorrectValue() - { - // Arrange - var mockVersiPort = new Mock(); - mockVersiPort.Setup(v => v.DigitalIn).Returns(true); - - // Act - var digitalIn = mockVersiPort.Object.DigitalIn; - - // Assert - digitalIn.Should().BeTrue(); - } - - [Fact] - public void SetDigitalOut_SetsCorrectValue() - { - // Arrange - var mockVersiPort = new Mock(); - - // Act - mockVersiPort.Object.SetDigitalOut(true); - - // Assert - mockVersiPort.Verify(v => v.SetDigitalOut(true), Times.Once); - } - - [Fact] - public void AnalogIn_ReturnsCorrectValue() - { - // Arrange - var mockVersiPort = new Mock(); - ushort expectedValue = 32768; - mockVersiPort.Setup(v => v.AnalogIn).Returns(expectedValue); - - // Act - var analogIn = mockVersiPort.Object.AnalogIn; - - // Assert - analogIn.Should().Be(expectedValue); - } - - [Fact] - public void VersiportChange_WhenDigitalChanges_RaisesEventWithCorrectType() - { - // Arrange - var mockVersiPort = new Mock(); - var eventRaised = false; - VersiPortEventType? capturedEventType = null; - object capturedValue = null; - - mockVersiPort.Object.VersiportChange += (sender, args) => - { - eventRaised = true; - capturedEventType = args.EventType; - capturedValue = args.Value; - }; - - // Act - mockVersiPort.Raise(v => v.VersiportChange += null, - mockVersiPort.Object, - new VersiPortEventArgs - { - EventType = VersiPortEventType.DigitalInChange, - Value = true - }); - - // Assert - eventRaised.Should().BeTrue(); - capturedEventType.Should().Be(VersiPortEventType.DigitalInChange); - capturedValue.Should().Be(true); - } - - [Fact] - public void VersiportChange_WhenAnalogChanges_RaisesEventWithCorrectValue() - { - // Arrange - var mockVersiPort = new Mock(); - var eventRaised = false; - VersiPortEventType? capturedEventType = null; - object capturedValue = null; - ushort expectedAnalogValue = 12345; - - mockVersiPort.Object.VersiportChange += (sender, args) => - { - eventRaised = true; - capturedEventType = args.EventType; - capturedValue = args.Value; - }; - - // Act - mockVersiPort.Raise(v => v.VersiportChange += null, - mockVersiPort.Object, - new VersiPortEventArgs - { - EventType = VersiPortEventType.AnalogInChange, - Value = expectedAnalogValue - }); - - // Assert - eventRaised.Should().BeTrue(); - capturedEventType.Should().Be(VersiPortEventType.AnalogInChange); - capturedValue.Should().Be(expectedAnalogValue); - } - - [Fact] - public void MultipleVersiportChanges_TracksAllChangesCorrectly() - { - // Arrange - var mockVersiPort = new Mock(); - var changes = new System.Collections.Generic.List<(VersiPortEventType type, object value)>(); - - mockVersiPort.Object.VersiportChange += (sender, args) => - { - changes.Add((args.EventType, args.Value)); - }; - - // Act - Simulate multiple changes - mockVersiPort.Raise(v => v.VersiportChange += null, - mockVersiPort.Object, - new VersiPortEventArgs - { - EventType = VersiPortEventType.DigitalInChange, - Value = true - }); - - mockVersiPort.Raise(v => v.VersiportChange += null, - mockVersiPort.Object, - new VersiPortEventArgs - { - EventType = VersiPortEventType.AnalogInChange, - Value = (ushort)30000 - }); - - mockVersiPort.Raise(v => v.VersiportChange += null, - mockVersiPort.Object, - new VersiPortEventArgs - { - EventType = VersiPortEventType.DigitalInChange, - Value = false - }); - - // Assert - changes.Should().HaveCount(3); - changes[0].type.Should().Be(VersiPortEventType.DigitalInChange); - changes[0].value.Should().Be(true); - changes[1].type.Should().Be(VersiPortEventType.AnalogInChange); - changes[1].value.Should().Be((ushort)30000); - changes[2].type.Should().Be(VersiPortEventType.DigitalInChange); - changes[2].value.Should().Be(false); - } - } -} \ No newline at end of file diff --git a/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTestableTests.cs b/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTestableTests.cs deleted file mode 100644 index 32ca2413..00000000 --- a/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTestableTests.cs +++ /dev/null @@ -1,384 +0,0 @@ -using System; -using System.Collections.Generic; -using Xunit; -using FluentAssertions; -using Moq; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Core.Abstractions; -using PepperDash.Essentials.Core.Factory; -using PepperDash.Essentials.Core.CrestronIO; - -namespace PepperDash.Essentials.Core.Tests.Devices -{ - public class CrestronProcessorTestableTests : IDisposable - { - public CrestronProcessorTestableTests() - { - // Enable test mode for all tests in this class - CrestronEnvironmentFactory.EnableTestMode(); - } - - public void Dispose() - { - // Restore runtime mode after tests - CrestronEnvironmentFactory.DisableTestMode(); - } - - [Fact] - public void Constructor_WithNullProcessor_UsesFactoryToGetControlSystem() - { - // Arrange & Act - var processor = new CrestronProcessorTestable("test-processor"); - - // Assert - processor.Should().NotBeNull(); - processor.Processor.Should().NotBeNull(); - processor.Key.Should().Be("test-processor"); - } - - [Fact] - public void Constructor_WithProvidedProcessor_UsesProvidedProcessor() - { - // Arrange - var mockProcessor = new Mock(); - mockProcessor.Setup(p => p.SupportsRelay).Returns(false); - mockProcessor.Setup(p => p.RelayPorts).Returns(new Dictionary()); - - // Act - var processor = new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - processor.Processor.Should().BeSameAs(mockProcessor.Object); - } - - [Fact] - public void GetRelays_WhenProcessorSupportsRelays_CreatesRelayDevices() - { - // Arrange - var mockProvider = new CrestronMockProvider(); - mockProvider.ConfigureMockSystem(system => - { - system.SupportsRelay = true; - system.NumberOfRelayPorts = 4; - // Ensure relay ports are initialized - for (uint i = 1; i <= 4; i++) - { - system.RelayPorts[i] = new MockRelayPort(); - } - }); - - CrestronEnvironmentFactory.SetProvider(mockProvider); - - // Act - var processor = new CrestronProcessorTestable("test-processor"); - - // Assert - processor.SwitchedOutputs.Should().HaveCount(4); - processor.SwitchedOutputs.Should().ContainKeys(1, 2, 3, 4); - - foreach (var kvp in processor.SwitchedOutputs) - { - kvp.Value.Should().BeOfType(); - var relayDevice = kvp.Value as GenericRelayDeviceTestable; - relayDevice.Key.Should().Be($"test-processor-relay-{kvp.Key}"); - } - } - - [Fact] - public void GetRelays_WhenProcessorDoesNotSupportRelays_CreatesNoDevices() - { - // Arrange - var mockProcessor = new Mock(); - mockProcessor.Setup(p => p.SupportsRelay).Returns(false); - mockProcessor.Setup(p => p.RelayPorts).Returns(new Dictionary()); - - // Act - var processor = new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - processor.SwitchedOutputs.Should().BeEmpty(); - } - - [Fact] - public void GetRelays_HandlesExceptionGracefully() - { - // Arrange - var mockProcessor = new Mock(); - mockProcessor.Setup(p => p.SupportsRelay).Returns(true); - mockProcessor.Setup(p => p.NumberOfRelayPorts).Throws(new Exception("Test exception")); - mockProcessor.Setup(p => p.RelayPorts).Returns(new Dictionary()); - - // Act - Action act = () => new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - act.Should().NotThrow(); - } - } - - public class GenericRelayDeviceTestableTests : IDisposable - { - public GenericRelayDeviceTestableTests() - { - CrestronEnvironmentFactory.EnableTestMode(); - } - - public void Dispose() - { - CrestronEnvironmentFactory.DisableTestMode(); - } - - [Fact] - public void Constructor_WithNullRelayPort_ThrowsArgumentNullException() - { - // Act & Assert - Action act = () => new GenericRelayDeviceTestable("test-relay", null); - act.Should().Throw() - .WithParameterName("relayPort"); - } - - [Fact] - public void Constructor_WithValidRelayPort_InitializesCorrectly() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - - // Act - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - // Assert - device.Should().NotBeNull(); - device.Key.Should().Be("test-relay"); - device.OutputIsOnFeedback.Should().NotBeNull(); - } - - [Fact] - public void OpenRelay_OpensRelayAndUpdatesFeedback() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - mockRelayPort.SetState(true); // Start with closed relay - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - bool feedbackFired = false; - device.OutputIsOnFeedback.OutputChange += (sender, args) => feedbackFired = true; - - // Act - device.OpenRelay(); - - // Assert - mockRelayPort.State.Should().BeFalse(); - device.IsOn.Should().BeFalse(); - feedbackFired.Should().BeTrue(); - } - - [Fact] - public void CloseRelay_ClosesRelayAndUpdatesFeedback() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - mockRelayPort.SetState(false); // Start with open relay - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - bool feedbackFired = false; - device.OutputIsOnFeedback.OutputChange += (sender, args) => feedbackFired = true; - - // Act - device.CloseRelay(); - - // Assert - mockRelayPort.State.Should().BeTrue(); - device.IsOn.Should().BeTrue(); - feedbackFired.Should().BeTrue(); - } - - [Fact] - public void PulseRelay_CallsPulseOnRelayPort() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.PulseRelay(500); - - // Assert - mockRelayPort.Verify(r => r.Pulse(500), Times.Once); - } - - [Fact] - public void On_ClosesRelay() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - // Act - device.On(); - - // Assert - mockRelayPort.State.Should().BeTrue(); - device.IsOn.Should().BeTrue(); - } - - [Fact] - public void Off_OpensRelay() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - mockRelayPort.SetState(true); // Start with closed relay - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - // Act - device.Off(); - - // Assert - mockRelayPort.State.Should().BeFalse(); - device.IsOn.Should().BeFalse(); - } - - [Fact] - public void PowerToggle_TogglesRelayState() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - // Act & Assert - First toggle (off to on) - device.PowerToggle(); - mockRelayPort.State.Should().BeTrue(); - device.IsOn.Should().BeTrue(); - - // Act & Assert - Second toggle (on to off) - device.PowerToggle(); - mockRelayPort.State.Should().BeFalse(); - device.IsOn.Should().BeFalse(); - } - - [Fact] - public void IsOn_ReflectsRelayPortState() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - - // Act & Assert - Initially off - device.IsOn.Should().BeFalse(); - - // Act & Assert - After closing - mockRelayPort.Close(); - device.IsOn.Should().BeTrue(); - - // Act & Assert - After opening - mockRelayPort.Open(); - device.IsOn.Should().BeFalse(); - } - - [Fact] - public void CustomActivate_ReinitializesFeedback() - { - // Arrange - var mockRelayPort = new MockRelayPort(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort); - var originalFeedback = device.OutputIsOnFeedback; - - // Act - var result = device.CustomActivate(); - - // Assert - result.Should().BeTrue(); - device.OutputIsOnFeedback.Should().NotBeNull(); - device.OutputIsOnFeedback.Should().NotBeSameAs(originalFeedback); - } - } - - public class IntegrationTests : IDisposable - { - public IntegrationTests() - { - CrestronEnvironmentFactory.EnableTestMode(); - } - - public void Dispose() - { - CrestronEnvironmentFactory.DisableTestMode(); - } - - [Fact] - public void FullSystemIntegration_CreatesAndControlsRelays() - { - // Arrange - var mockProvider = new CrestronMockProvider(); - mockProvider.ConfigureMockSystem(system => - { - system.SupportsRelay = true; - system.NumberOfRelayPorts = 2; - system.ProgramIdTag = "INTEGRATION_TEST"; - }); - - CrestronEnvironmentFactory.SetProvider(mockProvider); - - // Act - var processor = new CrestronProcessorTestable("integration-processor"); - - // Assert processor creation - processor.Processor.ProgramIdTag.Should().Be("INTEGRATION_TEST"); - processor.SwitchedOutputs.Should().HaveCount(2); - - // Test relay control - var relay1 = processor.SwitchedOutputs[1] as GenericRelayDeviceTestable; - relay1.Should().NotBeNull(); - - // Test On/Off operations - relay1.On(); - relay1.IsOn.Should().BeTrue(); - - relay1.Off(); - relay1.IsOn.Should().BeFalse(); - - // Test toggle - relay1.PowerToggle(); - relay1.IsOn.Should().BeTrue(); - - relay1.PowerToggle(); - relay1.IsOn.Should().BeFalse(); - - // Test feedback - int feedbackCount = 0; - relay1.OutputIsOnFeedback.OutputChange += (sender, args) => feedbackCount++; - - relay1.On(); - feedbackCount.Should().Be(1); - - relay1.Off(); - feedbackCount.Should().Be(2); - } - - [Fact] - public void FactoryPattern_AllowsSwitchingBetweenProviders() - { - // Arrange - Start with test mode - CrestronEnvironmentFactory.EnableTestMode(); - CrestronEnvironmentFactory.IsTestMode.Should().BeTrue(); - - var testProcessor = new CrestronProcessorTestable("test-mode"); - testProcessor.Processor.Should().BeOfType(); - - // Act - Switch to runtime mode - CrestronEnvironmentFactory.DisableTestMode(); - CrestronEnvironmentFactory.IsTestMode.Should().BeFalse(); - - // Note: In runtime mode without actual Crestron hardware, - // it will use the NullControlSystem implementation - var runtimeProcessor = new CrestronProcessorTestable("runtime-mode"); - runtimeProcessor.Processor.Should().NotBeNull(); - - // Act - Switch back to test mode - CrestronEnvironmentFactory.EnableTestMode(); - CrestronEnvironmentFactory.IsTestMode.Should().BeTrue(); - - var testProcessor2 = new CrestronProcessorTestable("test-mode-2"); - testProcessor2.Processor.Should().BeOfType(); - } - } -} \ No newline at end of file diff --git a/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTests.cs b/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTests.cs deleted file mode 100644 index a3f788bf..00000000 --- a/tests/PepperDash.Essentials.Core.Tests/Devices/CrestronProcessorTests.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System.Collections.Generic; -using FluentAssertions; -using Moq; -using PepperDash.Essentials.Core.Abstractions; -using PepperDash.Essentials.Core.Devices; -using Xunit; - -namespace PepperDash.Essentials.Core.Tests.Devices -{ - public class CrestronProcessorTests - { - [Fact] - public void Constructor_WithValidProcessor_InitializesSwitchedOutputs() - { - // Arrange - var mockProcessor = new Mock(); - mockProcessor.Setup(p => p.SupportsRelay).Returns(false); - - // Act - var processor = new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - processor.Should().NotBeNull(); - processor.Key.Should().Be("test-processor"); - processor.SwitchedOutputs.Should().NotBeNull(); - processor.SwitchedOutputs.Should().BeEmpty(); - } - - [Fact] - public void GetRelays_WhenProcessorSupportsRelays_CreatesRelayDevices() - { - // Arrange - var mockProcessor = new Mock(); - var mockRelayPort1 = new Mock(); - var mockRelayPort2 = new Mock(); - - var relayPorts = new Dictionary - { - { 1, mockRelayPort1.Object }, - { 2, mockRelayPort2.Object } - }; - - mockProcessor.Setup(p => p.SupportsRelay).Returns(true); - mockProcessor.Setup(p => p.NumberOfRelayPorts).Returns(2); - mockProcessor.Setup(p => p.RelayPorts).Returns(relayPorts); - - // Act - var processor = new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - processor.SwitchedOutputs.Should().HaveCount(2); - processor.SwitchedOutputs.Should().ContainKey(1); - processor.SwitchedOutputs.Should().ContainKey(2); - } - - [Fact] - public void GetRelays_WhenProcessorDoesNotSupportRelays_DoesNotCreateRelayDevices() - { - // Arrange - var mockProcessor = new Mock(); - mockProcessor.Setup(p => p.SupportsRelay).Returns(false); - - // Act - var processor = new CrestronProcessorTestable("test-processor", mockProcessor.Object); - - // Assert - processor.SwitchedOutputs.Should().BeEmpty(); - mockProcessor.Verify(p => p.NumberOfRelayPorts, Times.Never); - mockProcessor.Verify(p => p.RelayPorts, Times.Never); - } - } - - public class GenericRelayDeviceTests - { - [Fact] - public void OpenRelay_CallsRelayPortOpen() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.OpenRelay(); - - // Assert - mockRelayPort.Verify(r => r.Open(), Times.Once); - } - - [Fact] - public void CloseRelay_CallsRelayPortClose() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.CloseRelay(); - - // Assert - mockRelayPort.Verify(r => r.Close(), Times.Once); - } - - [Fact] - public void PulseRelay_CallsRelayPortPulseWithCorrectDelay() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - const int delayMs = 500; - - // Act - device.PulseRelay(delayMs); - - // Assert - mockRelayPort.Verify(r => r.Pulse(delayMs), Times.Once); - } - - [Fact] - public void On_CallsCloseRelay() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.On(); - - // Assert - mockRelayPort.Verify(r => r.Close(), Times.Once); - } - - [Fact] - public void Off_CallsOpenRelay() - { - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.Off(); - - // Assert - mockRelayPort.Verify(r => r.Open(), Times.Once); - } - - [Fact] - public void PowerToggle_WhenRelayIsOn_CallsOff() - { - // Arrange - var mockRelayPort = new Mock(); - mockRelayPort.Setup(r => r.State).Returns(true); // Relay is ON - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.PowerToggle(); - - // Assert - mockRelayPort.Verify(r => r.Open(), Times.Once); - mockRelayPort.Verify(r => r.Close(), Times.Never); - } - - [Fact] - public void PowerToggle_WhenRelayIsOff_CallsOn() - { - // Arrange - var mockRelayPort = new Mock(); - mockRelayPort.Setup(r => r.State).Returns(false); // Relay is OFF - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.PowerToggle(); - - // Assert - mockRelayPort.Verify(r => r.Close(), Times.Once); - mockRelayPort.Verify(r => r.Open(), Times.Never); - } - - [Fact] - public void IsOn_ReturnsRelayPortState() - { - // Arrange - var mockRelayPort = new Mock(); - mockRelayPort.Setup(r => r.State).Returns(true); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - var isOn = device.IsOn; - - // Assert - isOn.Should().BeTrue(); - } - } -} \ No newline at end of file diff --git a/tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj b/tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj deleted file mode 100644 index e0a86474..00000000 --- a/tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - net8.0 - false - true - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - \ No newline at end of file diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index fe0e55f1..00000000 --- a/tests/README.md +++ /dev/null @@ -1,170 +0,0 @@ -# PepperDash Essentials Unit Testing Guide - -## Overview - -This guide demonstrates how to write unit tests for PepperDash Essentials despite the Crestron hardware dependencies. The key approach is to use **abstraction layers** and **dependency injection** to isolate Crestron-specific functionality. - -## Architecture Pattern - -### 1. Abstraction Layer -We create interfaces that abstract Crestron hardware components: -- `ICrestronControlSystem` - Abstracts the control system -- `IRelayPort` - Abstracts relay functionality -- `IDigitalInput` - Abstracts digital inputs -- `IVersiPort` - Abstracts VersiPorts - -### 2. Adapters -Adapter classes wrap actual Crestron objects in production: -- `CrestronControlSystemAdapter` - Wraps `CrestronControlSystem` -- `RelayPortAdapter` - Wraps Crestron `Relay` -- `DigitalInputAdapter` - Wraps Crestron `DigitalInput` -- `VersiPortAdapter` - Wraps Crestron `Versiport` - -### 3. Testable Classes -Create testable versions of classes that accept abstractions: -- `CrestronProcessorTestable` - Accepts `ICrestronControlSystem` instead of concrete type -- `GenericRelayDeviceTestable` - Accepts `IRelayPort` instead of concrete type - -## Writing Tests - -### Basic Test Example -```csharp -[Fact] -public void OpenRelay_CallsRelayPortOpen() -{ - // Arrange - var mockRelayPort = new Mock(); - var device = new GenericRelayDeviceTestable("test-relay", mockRelayPort.Object); - - // Act - device.OpenRelay(); - - // Assert - mockRelayPort.Verify(r => r.Open(), Times.Once); -} -``` - -### Testing Events -```csharp -[Fact] -public void StateChange_WhenDigitalInputChanges_RaisesEvent() -{ - // Arrange - var mockDigitalInput = new Mock(); - var eventRaised = false; - - mockDigitalInput.Object.StateChange += (sender, args) => eventRaised = true; - - // Act - mockDigitalInput.Raise(d => d.StateChange += null, - mockDigitalInput.Object, - new DigitalInputEventArgs(true)); - - // Assert - eventRaised.Should().BeTrue(); -} -``` - -## Running Tests - -### Locally -```bash -# Run all tests -dotnet test - -# Run with coverage -dotnet test --collect:"XPlat Code Coverage" - -# Run specific test project -dotnet test tests/PepperDash.Essentials.Core.Tests -``` - -### CI Pipeline -Tests run automatically on: -- Push to main/develop/net8-updates branches -- Pull requests -- GitHub Actions workflow generates coverage reports - -## Migration Strategy - -To migrate existing code to be testable: - -1. **Identify Crestron Dependencies** - - Search for `using Crestron` statements - - Find direct hardware interactions - -2. **Create Abstractions** - - Define interfaces for hardware components - - Keep interfaces focused and simple - -3. **Implement Adapters** - - Wrap Crestron objects with adapters - - Map Crestron events to abstraction events - -4. **Refactor Classes** - - Accept abstractions via constructor injection - - Create factory methods for production use - -5. **Write Tests** - - Mock abstractions using Moq - - Test business logic independently - -## Best Practices - -### DO: -- Keep abstractions simple and focused -- Test business logic, not Crestron SDK behavior -- Use dependency injection consistently -- Mock at the abstraction boundary -- Test event handling and state changes - -### DON'T: -- Try to mock Crestron types directly -- Include hardware-dependent code in tests -- Mix business logic with hardware interaction -- Create overly complex abstractions - -## Tools Used - -- **xUnit** - Test framework -- **Moq** - Mocking framework -- **FluentAssertions** - Assertion library -- **Coverlet** - Code coverage -- **GitHub Actions** - CI/CD - -## Adding New Tests - -1. Create test file in appropriate folder -2. Follow naming convention: `[ClassName]Tests.cs` -3. Use Arrange-Act-Assert pattern -4. Include both positive and negative test cases -5. Test edge cases and error conditions - -## Troubleshooting - -### Common Issues: - -**Tests fail with "Type not found" errors** -- Ensure abstractions are properly defined -- Check project references - -**Mocked events not firing** -- Use `Mock.Raise()` to trigger events -- Verify event subscription syntax - -**Coverage not generating** -- Run with `--collect:"XPlat Code Coverage"` -- Check .gitignore isn't excluding coverage files - -## Example Test Project Structure -``` -tests/ -├── PepperDash.Essentials.Core.Tests/ -│ ├── Abstractions/ -│ │ ├── DigitalInputTests.cs -│ │ └── VersiPortTests.cs -│ ├── Devices/ -│ │ └── CrestronProcessorTests.cs -│ └── PepperDash.Essentials.Core.Tests.csproj -└── README.md -``` \ No newline at end of file diff --git a/tools/CrestronMockGenerator/AssemblyAnalyzer.cs b/tools/CrestronMockGenerator/AssemblyAnalyzer.cs deleted file mode 100644 index 599887c5..00000000 --- a/tools/CrestronMockGenerator/AssemblyAnalyzer.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Loader; -using System.Text; -using System.Xml.Linq; -using Newtonsoft.Json; - -namespace CrestronMockGenerator -{ - public class AssemblyAnalyzer - { - private readonly string _assemblyPath; - private readonly string _xmlDocPath; - private Dictionary _xmlDocumentation = new(); - - public AssemblyAnalyzer(string assemblyPath) - { - _assemblyPath = assemblyPath; - _xmlDocPath = Path.ChangeExtension(assemblyPath, ".xml"); - - if (File.Exists(_xmlDocPath)) - { - LoadXmlDocumentation(); - } - } - - private void LoadXmlDocumentation() - { - try - { - var doc = XDocument.Load(_xmlDocPath); - var members = doc.Descendants("member"); - - foreach (var member in members) - { - var name = member.Attribute("name")?.Value; - var summary = member.Element("summary")?.Value?.Trim(); - - if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(summary)) - { - _xmlDocumentation[name] = summary; - } - } - } - catch (Exception ex) - { - Console.WriteLine($"Error loading XML documentation: {ex.Message}"); - } - } - - public AssemblyInfo AnalyzeAssembly() - { - var assemblyInfo = new AssemblyInfo - { - Name = Path.GetFileNameWithoutExtension(_assemblyPath), - Types = new List() - }; - - try - { - // Use MetadataLoadContext to load assembly without dependencies - var resolver = new PathAssemblyResolver(new[] { _assemblyPath }); - var mlc = new MetadataLoadContext(resolver); - - var assembly = mlc.LoadFromAssemblyPath(_assemblyPath); - - foreach (var type in assembly.GetExportedTypes()) - { - if (type.IsSpecialName || type.Name.Contains("<>")) - continue; - - var typeInfo = AnalyzeType(type); - if (typeInfo != null) - { - assemblyInfo.Types.Add(typeInfo); - } - } - } - catch (Exception ex) - { - Console.WriteLine($"Error analyzing assembly: {ex.Message}"); - } - - return assemblyInfo; - } - - private TypeInfo? AnalyzeType(Type type) - { - try - { - var typeInfo = new TypeInfo - { - Name = type.Name, - Namespace = type.Namespace ?? "", - FullName = type.FullName ?? "", - IsInterface = type.IsInterface, - IsAbstract = type.IsAbstract, - IsSealed = type.IsSealed, - IsEnum = type.IsEnum, - IsClass = type.IsClass, - BaseType = type.BaseType?.FullName, - Documentation = GetDocumentation($"T:{type.FullName}"), - Properties = new List(), - Methods = new List(), - Events = new List(), - Fields = new List(), - Interfaces = type.GetInterfaces().Select(i => i.FullName).Where(n => n != null).ToList() - }; - - // Analyze properties - foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) - { - typeInfo.Properties.Add(new PropertyInfo - { - Name = prop.Name, - Type = prop.PropertyType.FullName ?? "", - CanRead = prop.CanRead, - CanWrite = prop.CanWrite, - IsStatic = prop.GetMethod?.IsStatic ?? prop.SetMethod?.IsStatic ?? false, - Documentation = GetDocumentation($"P:{type.FullName}.{prop.Name}") - }); - } - - // Analyze methods - foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) - .Where(m => !m.IsSpecialName)) - { - var parameters = method.GetParameters().Select(p => new ParameterInfo - { - Name = p.Name ?? "", - Type = p.ParameterType.FullName ?? "", - IsOut = p.IsOut, - IsRef = p.ParameterType.IsByRef && !p.IsOut, - HasDefaultValue = p.HasDefaultValue, - DefaultValue = p.HasDefaultValue ? p.DefaultValue?.ToString() : null - }).ToList(); - - typeInfo.Methods.Add(new MethodInfo - { - Name = method.Name, - ReturnType = method.ReturnType.FullName ?? "", - IsStatic = method.IsStatic, - IsVirtual = method.IsVirtual, - IsAbstract = method.IsAbstract, - Parameters = parameters, - Documentation = GetDocumentation($"M:{type.FullName}.{method.Name}") - }); - } - - // Analyze events - foreach (var evt in type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) - { - typeInfo.Events.Add(new EventInfo - { - Name = evt.Name, - EventHandlerType = evt.EventHandlerType?.FullName ?? "", - Documentation = GetDocumentation($"E:{type.FullName}.{evt.Name}") - }); - } - - // Analyze fields (for enums) - if (type.IsEnum) - { - foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) - { - if (field.Name == "value__") continue; - - typeInfo.Fields.Add(new FieldInfo - { - Name = field.Name, - Type = field.FieldType.FullName ?? "", - Value = field.GetRawConstantValue()?.ToString(), - Documentation = GetDocumentation($"F:{type.FullName}.{field.Name}") - }); - } - } - - return typeInfo; - } - catch (Exception ex) - { - Console.WriteLine($"Error analyzing type {type.Name}: {ex.Message}"); - return null; - } - } - - private string GetDocumentation(string memberName) - { - return _xmlDocumentation.TryGetValue(memberName, out var doc) ? doc : ""; - } - } - - public class AssemblyInfo - { - public string Name { get; set; } = ""; - public List Types { get; set; } = new(); - } - - public class TypeInfo - { - public string Name { get; set; } = ""; - public string Namespace { get; set; } = ""; - public string FullName { get; set; } = ""; - public bool IsInterface { get; set; } - public bool IsAbstract { get; set; } - public bool IsSealed { get; set; } - public bool IsEnum { get; set; } - public bool IsClass { get; set; } - public string? BaseType { get; set; } - public List Interfaces { get; set; } = new(); - public string Documentation { get; set; } = ""; - public List Properties { get; set; } = new(); - public List Methods { get; set; } = new(); - public List Events { get; set; } = new(); - public List Fields { get; set; } = new(); - } - - public class PropertyInfo - { - public string Name { get; set; } = ""; - public string Type { get; set; } = ""; - public bool CanRead { get; set; } - public bool CanWrite { get; set; } - public bool IsStatic { get; set; } - public string Documentation { get; set; } = ""; - } - - public class MethodInfo - { - public string Name { get; set; } = ""; - public string ReturnType { get; set; } = ""; - public bool IsStatic { get; set; } - public bool IsVirtual { get; set; } - public bool IsAbstract { get; set; } - public List Parameters { get; set; } = new(); - public string Documentation { get; set; } = ""; - } - - public class ParameterInfo - { - public string Name { get; set; } = ""; - public string Type { get; set; } = ""; - public bool IsOut { get; set; } - public bool IsRef { get; set; } - public bool HasDefaultValue { get; set; } - public string? DefaultValue { get; set; } - } - - public class EventInfo - { - public string Name { get; set; } = ""; - public string EventHandlerType { get; set; } = ""; - public string Documentation { get; set; } = ""; - } - - public class FieldInfo - { - public string Name { get; set; } = ""; - public string Type { get; set; } = ""; - public string? Value { get; set; } - public string Documentation { get; set; } = ""; - } -} \ No newline at end of file diff --git a/tools/CrestronMockGenerator/CrestronMockGenerator.csproj b/tools/CrestronMockGenerator/CrestronMockGenerator.csproj deleted file mode 100644 index 93ae6ae3..00000000 --- a/tools/CrestronMockGenerator/CrestronMockGenerator.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net8.0 - enable - - - - - - - - - \ No newline at end of file diff --git a/tools/CrestronMockGenerator/MockGenerator.cs b/tools/CrestronMockGenerator/MockGenerator.cs deleted file mode 100644 index 89febb63..00000000 --- a/tools/CrestronMockGenerator/MockGenerator.cs +++ /dev/null @@ -1,468 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - -namespace CrestronMockGenerator -{ - public class MockGenerator - { - public string GenerateMockClass(TypeInfo typeInfo) - { - var compilationUnit = CompilationUnit(); - - // Add usings - compilationUnit = compilationUnit.AddUsings( - UsingDirective(ParseName("System")), - UsingDirective(ParseName("System.Collections.Generic")), - UsingDirective(ParseName("System.Linq")) - ); - - // Create namespace - var namespaceDeclaration = NamespaceDeclaration(ParseName(typeInfo.Namespace)); - - // Add XML documentation if available - var trivia = new List(); - if (!string.IsNullOrEmpty(typeInfo.Documentation)) - { - trivia.Add(Comment($"/// ")); - trivia.Add(Comment($"/// {typeInfo.Documentation}")); - trivia.Add(Comment($"/// ")); - } - - // Create type declaration - MemberDeclarationSyntax typeDeclaration; - - if (typeInfo.IsEnum) - { - typeDeclaration = GenerateEnum(typeInfo); - } - else if (typeInfo.IsInterface) - { - typeDeclaration = GenerateInterface(typeInfo); - } - else - { - typeDeclaration = GenerateClass(typeInfo); - } - - if (trivia.Any()) - { - typeDeclaration = typeDeclaration.WithLeadingTrivia(trivia); - } - - namespaceDeclaration = namespaceDeclaration.AddMembers(typeDeclaration); - compilationUnit = compilationUnit.AddMembers(namespaceDeclaration); - - // Format the code - var workspace = new AdhocWorkspace(); - var formattedNode = Microsoft.CodeAnalysis.Formatting.Formatter.Format( - compilationUnit, - workspace); - - return formattedNode.ToFullString(); - } - - private EnumDeclarationSyntax GenerateEnum(TypeInfo typeInfo) - { - var enumDeclaration = EnumDeclaration(typeInfo.Name) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - foreach (var field in typeInfo.Fields) - { - var member = EnumMemberDeclaration(field.Name); - - if (!string.IsNullOrEmpty(field.Value)) - { - member = member.WithEqualsValue( - EqualsValueClause(ParseExpression(field.Value))); - } - - if (!string.IsNullOrEmpty(field.Documentation)) - { - member = member.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {field.Documentation}"), - Comment($"/// ")); - } - - enumDeclaration = enumDeclaration.AddMembers(member); - } - - return enumDeclaration; - } - - private InterfaceDeclarationSyntax GenerateInterface(TypeInfo typeInfo) - { - var interfaceDeclaration = InterfaceDeclaration(typeInfo.Name) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - // Add base interfaces - if (typeInfo.Interfaces.Any()) - { - var baseList = BaseList(); - foreach (var baseInterface in typeInfo.Interfaces) - { - var typeName = GetSimpleTypeName(baseInterface); - baseList = baseList.AddTypes(SimpleBaseType(ParseTypeName(typeName))); - } - interfaceDeclaration = interfaceDeclaration.WithBaseList(baseList); - } - - // Add properties - foreach (var property in typeInfo.Properties) - { - var propertyDeclaration = GenerateInterfaceProperty(property); - interfaceDeclaration = interfaceDeclaration.AddMembers(propertyDeclaration); - } - - // Add methods - foreach (var method in typeInfo.Methods) - { - var methodDeclaration = GenerateInterfaceMethod(method); - interfaceDeclaration = interfaceDeclaration.AddMembers(methodDeclaration); - } - - // Add events - foreach (var evt in typeInfo.Events) - { - var eventDeclaration = GenerateInterfaceEvent(evt); - interfaceDeclaration = interfaceDeclaration.AddMembers(eventDeclaration); - } - - return interfaceDeclaration; - } - - private ClassDeclarationSyntax GenerateClass(TypeInfo typeInfo) - { - var classDeclaration = ClassDeclaration(typeInfo.Name) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - if (typeInfo.IsAbstract) - { - classDeclaration = classDeclaration.AddModifiers(Token(SyntaxKind.AbstractKeyword)); - } - else if (typeInfo.IsSealed) - { - classDeclaration = classDeclaration.AddModifiers(Token(SyntaxKind.SealedKeyword)); - } - - // Add base class and interfaces - var baseTypes = new List(); - if (!string.IsNullOrEmpty(typeInfo.BaseType) && typeInfo.BaseType != "System.Object") - { - baseTypes.Add(typeInfo.BaseType); - } - baseTypes.AddRange(typeInfo.Interfaces); - - if (baseTypes.Any()) - { - var baseList = BaseList(); - foreach (var baseType in baseTypes) - { - var typeName = GetSimpleTypeName(baseType); - baseList = baseList.AddTypes(SimpleBaseType(ParseTypeName(typeName))); - } - classDeclaration = classDeclaration.WithBaseList(baseList); - } - - // Add properties - foreach (var property in typeInfo.Properties) - { - var propertyDeclaration = GenerateProperty(property); - classDeclaration = classDeclaration.AddMembers(propertyDeclaration); - } - - // Add methods - foreach (var method in typeInfo.Methods) - { - var methodDeclaration = GenerateMethod(method, typeInfo.IsAbstract); - classDeclaration = classDeclaration.AddMembers(methodDeclaration); - } - - // Add events - foreach (var evt in typeInfo.Events) - { - var eventDeclaration = GenerateEvent(evt); - classDeclaration = classDeclaration.AddMembers(eventDeclaration); - } - - return classDeclaration; - } - - private PropertyDeclarationSyntax GenerateProperty(PropertyInfo property) - { - var typeName = GetSimpleTypeName(property.Type); - var propertyDeclaration = PropertyDeclaration(ParseTypeName(typeName), property.Name) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - if (property.IsStatic) - { - propertyDeclaration = propertyDeclaration.AddModifiers(Token(SyntaxKind.StaticKeyword)); - } - - var accessors = new List(); - - if (property.CanRead) - { - accessors.Add(AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); - } - - if (property.CanWrite) - { - accessors.Add(AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); - } - - propertyDeclaration = propertyDeclaration.WithAccessorList( - AccessorList(List(accessors))); - - if (!string.IsNullOrEmpty(property.Documentation)) - { - propertyDeclaration = propertyDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {property.Documentation}"), - Comment($"/// ")); - } - - return propertyDeclaration; - } - - private PropertyDeclarationSyntax GenerateInterfaceProperty(PropertyInfo property) - { - var typeName = GetSimpleTypeName(property.Type); - var propertyDeclaration = PropertyDeclaration(ParseTypeName(typeName), property.Name); - - var accessors = new List(); - - if (property.CanRead) - { - accessors.Add(AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); - } - - if (property.CanWrite) - { - accessors.Add(AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); - } - - propertyDeclaration = propertyDeclaration.WithAccessorList( - AccessorList(List(accessors))); - - if (!string.IsNullOrEmpty(property.Documentation)) - { - propertyDeclaration = propertyDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {property.Documentation}"), - Comment($"/// ")); - } - - return propertyDeclaration; - } - - private MethodDeclarationSyntax GenerateMethod(MethodInfo method, bool isAbstractClass) - { - var returnTypeName = GetSimpleTypeName(method.ReturnType); - var methodDeclaration = MethodDeclaration(ParseTypeName(returnTypeName), method.Name) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - if (method.IsStatic) - { - methodDeclaration = methodDeclaration.AddModifiers(Token(SyntaxKind.StaticKeyword)); - } - else if (method.IsAbstract && isAbstractClass) - { - methodDeclaration = methodDeclaration.AddModifiers(Token(SyntaxKind.AbstractKeyword)); - } - else if (method.IsVirtual) - { - methodDeclaration = methodDeclaration.AddModifiers(Token(SyntaxKind.VirtualKeyword)); - } - - // Add parameters - var parameters = new List(); - foreach (var param in method.Parameters) - { - var paramTypeName = GetSimpleTypeName(param.Type); - var parameter = Parameter(Identifier(param.Name)) - .WithType(ParseTypeName(paramTypeName)); - - if (param.IsOut) - { - parameter = parameter.AddModifiers(Token(SyntaxKind.OutKeyword)); - } - else if (param.IsRef) - { - parameter = parameter.AddModifiers(Token(SyntaxKind.RefKeyword)); - } - - if (param.HasDefaultValue && !string.IsNullOrEmpty(param.DefaultValue)) - { - parameter = parameter.WithDefault( - EqualsValueClause(ParseExpression(param.DefaultValue))); - } - - parameters.Add(parameter); - } - - methodDeclaration = methodDeclaration.WithParameterList( - ParameterList(SeparatedList(parameters))); - - // Add body or semicolon - if (method.IsAbstract && isAbstractClass) - { - methodDeclaration = methodDeclaration.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); - } - else - { - var statements = new List(); - - // Add default implementation - if (returnTypeName != "void") - { - statements.Add(ParseStatement($"throw new NotImplementedException();")); - } - else - { - statements.Add(ParseStatement($"// Mock implementation")); - } - - methodDeclaration = methodDeclaration.WithBody(Block(statements)); - } - - if (!string.IsNullOrEmpty(method.Documentation)) - { - methodDeclaration = methodDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {method.Documentation}"), - Comment($"/// ")); - } - - return methodDeclaration; - } - - private MethodDeclarationSyntax GenerateInterfaceMethod(MethodInfo method) - { - var returnTypeName = GetSimpleTypeName(method.ReturnType); - var methodDeclaration = MethodDeclaration(ParseTypeName(returnTypeName), method.Name); - - // Add parameters - var parameters = new List(); - foreach (var param in method.Parameters) - { - var paramTypeName = GetSimpleTypeName(param.Type); - var parameter = Parameter(Identifier(param.Name)) - .WithType(ParseTypeName(paramTypeName)); - - if (param.IsOut) - { - parameter = parameter.AddModifiers(Token(SyntaxKind.OutKeyword)); - } - else if (param.IsRef) - { - parameter = parameter.AddModifiers(Token(SyntaxKind.RefKeyword)); - } - - parameters.Add(parameter); - } - - methodDeclaration = methodDeclaration - .WithParameterList(ParameterList(SeparatedList(parameters))) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); - - if (!string.IsNullOrEmpty(method.Documentation)) - { - methodDeclaration = methodDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {method.Documentation}"), - Comment($"/// ")); - } - - return methodDeclaration; - } - - private EventFieldDeclarationSyntax GenerateEvent(EventInfo evt) - { - var typeName = GetSimpleTypeName(evt.EventHandlerType); - var eventDeclaration = EventFieldDeclaration( - VariableDeclaration(ParseTypeName(typeName)) - .AddVariables(VariableDeclarator(evt.Name))) - .AddModifiers(Token(SyntaxKind.PublicKeyword)); - - if (!string.IsNullOrEmpty(evt.Documentation)) - { - eventDeclaration = eventDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {evt.Documentation}"), - Comment($"/// ")); - } - - return eventDeclaration; - } - - private EventFieldDeclarationSyntax GenerateInterfaceEvent(EventInfo evt) - { - var typeName = GetSimpleTypeName(evt.EventHandlerType); - var eventDeclaration = EventFieldDeclaration( - VariableDeclaration(ParseTypeName(typeName)) - .AddVariables(VariableDeclarator(evt.Name))); - - if (!string.IsNullOrEmpty(evt.Documentation)) - { - eventDeclaration = eventDeclaration.WithLeadingTrivia( - Comment($"/// "), - Comment($"/// {evt.Documentation}"), - Comment($"/// ")); - } - - return eventDeclaration; - } - - private string GetSimpleTypeName(string fullTypeName) - { - // Convert full type names to simple names - var typeMappings = new Dictionary - { - ["System.Void"] = "void", - ["System.String"] = "string", - ["System.Int32"] = "int", - ["System.Int64"] = "long", - ["System.Int16"] = "short", - ["System.UInt32"] = "uint", - ["System.UInt64"] = "ulong", - ["System.UInt16"] = "ushort", - ["System.Byte"] = "byte", - ["System.SByte"] = "sbyte", - ["System.Boolean"] = "bool", - ["System.Single"] = "float", - ["System.Double"] = "double", - ["System.Decimal"] = "decimal", - ["System.Object"] = "object", - ["System.Char"] = "char" - }; - - if (typeMappings.TryGetValue(fullTypeName, out var simpleName)) - { - return simpleName; - } - - // Handle generic types - if (fullTypeName.Contains('`')) - { - // Simplified generic handling - return "object"; - } - - // Return last part of the type name - var lastDot = fullTypeName.LastIndexOf('.'); - return lastDot >= 0 ? fullTypeName.Substring(lastDot + 1) : fullTypeName; - } - } -} \ No newline at end of file diff --git a/tools/CrestronMockGenerator/Program.cs b/tools/CrestronMockGenerator/Program.cs deleted file mode 100644 index 0a3f3efb..00000000 --- a/tools/CrestronMockGenerator/Program.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using Newtonsoft.Json; - -namespace CrestronMockGenerator -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Crestron Mock Library Generator"); - Console.WriteLine("================================"); - - if (args.Length < 2) - { - Console.WriteLine("Usage: CrestronMockGenerator "); - Console.WriteLine("Example: CrestronMockGenerator /path/to/SimplSharp.dll /output/mocks"); - return; - } - - var inputPath = args[0]; - var outputDir = args[1]; - - if (!File.Exists(inputPath)) - { - Console.WriteLine($"Error: Assembly file not found: {inputPath}"); - return; - } - - Directory.CreateDirectory(outputDir); - - try - { - // Analyze the assembly - Console.WriteLine($"Analyzing assembly: {inputPath}"); - var analyzer = new AssemblyAnalyzer(inputPath); - var assemblyInfo = analyzer.AnalyzeAssembly(); - - Console.WriteLine($"Found {assemblyInfo.Types.Count} types"); - - // Save assembly metadata as JSON - var metadataPath = Path.Combine(outputDir, $"{assemblyInfo.Name}.metadata.json"); - var json = JsonConvert.SerializeObject(assemblyInfo, Formatting.Indented); - File.WriteAllText(metadataPath, json); - Console.WriteLine($"Saved metadata to: {metadataPath}"); - - // Generate mock classes - var generator = new MockGenerator(); - var generatedFiles = new List(); - - // Group types by namespace - var namespaceGroups = assemblyInfo.Types.GroupBy(t => t.Namespace); - - foreach (var namespaceGroup in namespaceGroups) - { - var namespacePath = Path.Combine(outputDir, namespaceGroup.Key.Replace('.', Path.DirectorySeparatorChar)); - Directory.CreateDirectory(namespacePath); - - foreach (var typeInfo in namespaceGroup) - { - try - { - Console.WriteLine($"Generating mock for: {typeInfo.FullName}"); - var mockCode = generator.GenerateMockClass(typeInfo); - - var fileName = $"{typeInfo.Name}.cs"; - var filePath = Path.Combine(namespacePath, fileName); - - File.WriteAllText(filePath, mockCode); - generatedFiles.Add(filePath); - } - catch (Exception ex) - { - Console.WriteLine($"Error generating mock for {typeInfo.Name}: {ex.Message}"); - } - } - } - - // Generate project file - GenerateProjectFile(outputDir, assemblyInfo.Name); - - Console.WriteLine($"\nGeneration complete!"); - Console.WriteLine($"Generated {generatedFiles.Count} mock files"); - Console.WriteLine($"Output directory: {outputDir}"); - } - catch (Exception ex) - { - Console.WriteLine($"Error: {ex.Message}"); - Console.WriteLine(ex.StackTrace); - } - } - - static void GenerateProjectFile(string outputDir, string assemblyName) - { - var projectContent = @" - - - net8.0 - " + assemblyName + @".Mock - " + assemblyName + @" - true - " + assemblyName + @".Mock - 1.0.0 - Mock implementation of " + assemblyName + @" for testing - - -"; - - var projectPath = Path.Combine(outputDir, $"{assemblyName}.Mock.csproj"); - File.WriteAllText(projectPath, projectContent); - Console.WriteLine($"Generated project file: {projectPath}"); - } - } -} \ No newline at end of file