using System; using NUnit.Framework; using Moq; using NcProgramManager.Cnc; using NcProgramManager.Cnc.Models; using NcProgramManager.Cnc.Fagor; namespace NcProgramManager.Tests.Unit { [TestFixture] public class FagorMachineTests { private FagorConnectionConfig _config; private Mock _ftpMock; private Mock _validatorMock; private FagorMachine _machine; [SetUp] public void SetUp() { _config = new FagorConnectionConfig { Name = "TestFagor", IpAddress = "192.168.1.2", Port = 21, ProgramDirectory = "/Users/Prg/", ProgramExtension = ".nc" }; _ftpMock = 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()); _machine = new FagorMachine(_config, _ftpMock.Object, _validatorMock.Object); } [TearDown] public void TearDown() { _machine?.Dispose(); } // ConnectAsync [Test] public void ConnectAsync_PingTrue_StateConnectedAndResultOk() { _ftpMock.Setup(f => f.Ping()).Returns(true); var result = _machine.ConnectAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); Assert.That(result.Value, Is.True); Assert.That(_machine.State, Is.EqualTo(ConnectionState.Connected)); } [Test] public void ConnectAsync_PingFalse_StateFaultedAndResultFail() { _ftpMock.Setup(f => f.Ping()).Returns(false); var result = _machine.ConnectAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); Assert.That(_machine.State, Is.EqualTo(ConnectionState.Faulted)); } // ReadProgramAsync [Test] public void ReadProgramAsync_FullPath_CallsDownloadFileWithPath() { _ftpMock.Setup(f => f.Ping()).Returns(true); _ftpMock.Setup(f => f.DownloadFile("/Users/Prg/PROG1.nc")).Returns("CONTENT"); _machine.ConnectAsync().GetAwaiter().GetResult(); var result = _machine.ReadProgramAsync("/Users/Prg/PROG1.nc").GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); Assert.That(result.Value, Is.EqualTo("CONTENT")); _ftpMock.Verify(f => f.DownloadFile("/Users/Prg/PROG1.nc"), Times.Once); } [Test] public void ReadProgramAsync_ShortName_ResolvesWithDirectoryAndExtension() { _ftpMock.Setup(f => f.Ping()).Returns(true); _ftpMock.Setup(f => f.DownloadFile("/Users/Prg/PROG1.nc")).Returns("DATA"); _machine.ConnectAsync().GetAwaiter().GetResult(); _machine.ReadProgramAsync("PROG1").GetAwaiter().GetResult(); _ftpMock.Verify(f => f.DownloadFile("/Users/Prg/PROG1.nc"), Times.Once); } // WriteProgramAsync [Test] public void WriteProgramAsync_ValidContent_CallsUploadFile() { _ftpMock.Setup(f => f.Ping()).Returns(true); _ftpMock.Setup(f => f.UploadFile(It.IsAny(), "CONTENT")); _machine.ConnectAsync().GetAwaiter().GetResult(); var prog = new CncProgram { Name = "PROG1", Content = "CONTENT" }; var result = _machine.WriteProgramAsync("/Users/Prg/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); _ftpMock.Verify(f => f.UploadFile(It.IsAny(), "CONTENT"), Times.Once); } [Test] public void WriteProgramAsync_EmptyContent_FailsWithoutCallingUploadFile() { _ftpMock.Setup(f => f.Ping()).Returns(true); _machine.ConnectAsync().GetAwaiter().GetResult(); var prog = new CncProgram { Name = "PROG1", Content = "" }; var result = _machine.WriteProgramAsync("/Users/Prg/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _ftpMock.Verify(f => f.UploadFile(It.IsAny(), It.IsAny()), Times.Never); } [Test] public void WriteProgramAsync_NullProgram_FailsWithoutCallingUploadFile() { _ftpMock.Setup(f => f.Ping()).Returns(true); _machine.ConnectAsync().GetAwaiter().GetResult(); var result = _machine.WriteProgramAsync("/Users/Prg/", null).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _ftpMock.Verify(f => f.UploadFile(It.IsAny(), It.IsAny()), Times.Never); } // DeleteProgramAsync [Test] public void DeleteProgramAsync_ValidPath_CallsDeleteFile() { _ftpMock.Setup(f => f.Ping()).Returns(true); _ftpMock.Setup(f => f.DeleteFile("/Users/Prg/PROG1.nc")); _machine.ConnectAsync().GetAwaiter().GetResult(); var result = _machine.DeleteProgramAsync("/Users/Prg/PROG1.nc").GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); _ftpMock.Verify(f => f.DeleteFile("/Users/Prg/PROG1.nc"), Times.Once); } // ReadActiveProgramAsync [Test] public void ReadActiveProgramAsync_ReturnsFailNotSupported() { var result = _machine.ReadActiveProgramAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } // SelectMainProgramAsync [Test] public void SelectMainProgramAsync_ReturnsFailNotSupported() { var result = _machine.SelectMainProgramAsync("/Users/Prg/PROG1.nc").GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } // Validator-real tests (NcProgramValidator with CncManufacturer.Fagor) [Test] public void WriteProgramAsync_NameTooLong_ValidationFails() { var realMachine = new FagorMachine(_config, _ftpMock.Object, new NcProgramValidator(CncManufacturer.Fagor)); try { _ftpMock.Setup(f => f.Ping()).Returns(true); realMachine.ConnectAsync().GetAwaiter().GetResult(); var prog = new CncProgram { Name = new string('A', 25), Content = "G00 X10" }; var result = realMachine.WriteProgramAsync("/Users/Prg/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _ftpMock.Verify(f => f.UploadFile(It.IsAny(), It.IsAny()), Times.Never); } finally { realMachine.Dispose(); } } [Test] public void WriteProgramAsync_NameContainsTilde_ValidationFails() { var realMachine = new FagorMachine(_config, _ftpMock.Object, new NcProgramValidator(CncManufacturer.Fagor)); try { _ftpMock.Setup(f => f.Ping()).Returns(true); realMachine.ConnectAsync().GetAwaiter().GetResult(); var prog = new CncProgram { Name = "MAƱANA", Content = "G00 X10" }; var result = realMachine.WriteProgramAsync("/Users/Prg/", prog).GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); _ftpMock.Verify(f => f.UploadFile(It.IsAny(), It.IsAny()), Times.Never); } finally { realMachine.Dispose(); } } } }