using System; using NUnit.Framework; using Moq; using FanucProgramManager.Cnc; using FanucProgramManager.Cnc.Models; using FanucProgramManager.Cnc.Heidenhain; namespace FanucProgramManager.Tests.Unit { [TestFixture] public class HeidenhainMachineTests { private HeidenhainConnectionConfig _config; private Mock _clientMock; private Mock _validatorMock; private HeidenhainMachine _machine; [SetUp] public void SetUp() { _config = new HeidenhainConnectionConfig { Name = "TestHeidenhain", IpAddress = "192.168.1.4", Port = 19000 }; _clientMock = new Mock(MockBehavior.Strict); // Always-ok validator so existing write tests are not affected by validation rules _validatorMock = new Mock(); _validatorMock.Setup(v => v.Validate(It.IsAny(), It.IsAny())) .Returns(ValidationResult.Ok()); // Internal constructor sets state = Connected immediately _machine = new HeidenhainMachine(_config, _clientMock.Object, _validatorMock.Object); } [TearDown] public void TearDown() { _clientMock.Setup(c => c.Disconnect()); _machine?.Dispose(); } // State on construction [Test] public void Constructor_WithInjectedClient_StateIsConnected() { Assert.That(_machine.State, Is.EqualTo(ConnectionState.Connected)); } // ReadProgramAsync [Test] public void ReadProgramAsync_ReceiveFileReturnsContent_ResultOk() { _clientMock.Setup(c => c.ReceiveFile("TNC:/nc_prog/O1234.H")).Returns("NC_CONTENT"); var result = _machine.ReadProgramAsync("TNC:/nc_prog/O1234.H").GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); Assert.That(result.Value, Is.EqualTo("NC_CONTENT")); _clientMock.Verify(c => c.ReceiveFile("TNC:/nc_prog/O1234.H"), Times.Once); } [Test] public void ReadProgramAsync_ReceiveFileReturnsNull_ResultIsFail() { _clientMock.Setup(c => c.ReceiveFile(It.IsAny())).Returns((string)null); var result = _machine.ReadProgramAsync("TNC:/nc_prog/MISSING.H").GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } // WriteProgramAsync [Test] public void WriteProgramAsync_WithName_AppendsDotHExtension() { _clientMock.Setup(c => c.SendFile("TNC:/nc_prog/O1234.H", "CONTENT")).Returns(true); var prog = new CncProgram { Name = "O1234", Content = "CONTENT" }; var result = _machine.WriteProgramAsync("TNC:/nc_prog/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); _clientMock.Verify(c => c.SendFile("TNC:/nc_prog/O1234.H", "CONTENT"), Times.Once); } [Test] public void WriteProgramAsync_NameAlreadyHasExtension_NoDoubleExtension() { _clientMock.Setup(c => c.SendFile("TNC:/nc_prog/O1234.H", "CONTENT")).Returns(true); var prog = new CncProgram { Name = "O1234.H", Content = "CONTENT" }; _machine.WriteProgramAsync("TNC:/nc_prog/", prog).GetAwaiter().GetResult(); _clientMock.Verify(c => c.SendFile("TNC:/nc_prog/O1234.H", "CONTENT"), Times.Once); _clientMock.Verify(c => c.SendFile(It.Is(s => s.EndsWith(".H.H")), It.IsAny()), Times.Never); } [Test] public void WriteProgramAsync_EmptyContent_FailsWithoutCallingSendFile() { var prog = new CncProgram { Name = "O1234", Content = "" }; var result = _machine.WriteProgramAsync("TNC:/nc_prog/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _clientMock.Verify(c => c.SendFile(It.IsAny(), It.IsAny()), Times.Never); } [Test] public void WriteProgramAsync_NullProgram_FailsWithoutCallingSendFile() { var result = _machine.WriteProgramAsync("TNC:/nc_prog/", null).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _clientMock.Verify(c => c.SendFile(It.IsAny(), It.IsAny()), Times.Never); } [Test] public void WriteProgramAsync_SendFileFails_ResultIsFail() { _clientMock.Setup(c => c.SendFile(It.IsAny(), It.IsAny())).Returns(false); var prog = new CncProgram { Name = "O1234", Content = "DATA" }; var result = _machine.WriteProgramAsync("TNC:/nc_prog/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } // ReadActiveProgramAsync [Test] public void ReadActiveProgramAsync_ReturnsFailNotSupported() { var result = _machine.ReadActiveProgramAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } } }