using System; using NUnit.Framework; using NcProgramManager.Cnc.Models; using NcProgramManager.Cnc.Mazak; using NcProgramManager.Tests.Integration.Stubs; namespace NcProgramManager.Tests.Integration { [TestFixture] [Category("Integration")] public class MazakMachineIntegrationTests { private FtpServerStub _stub; private MazakMachine _machine; private const string ProgramDir = "/PRG/"; [SetUp] public void SetUp() { _stub = new FtpServerStub(); var config = new MazakConnectionConfig { Name = "MazakIntegration", IpAddress = "127.0.0.1", Port = _stub.Port, Username = "user", Password = "pass", ProgramDirectory = ProgramDir, RequestTimeout = TimeSpan.FromSeconds(5) }; _machine = new MazakMachine(config); } [TearDown] public void TearDown() { _machine?.Dispose(); _stub?.Dispose(); } [Test] public void ConnectAsync_StubListens_ResultOk() { var result = _machine.ConnectAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.True); Assert.That(_machine.State, Is.EqualTo(ConnectionState.Connected)); } [Test] public void WriteThenRead_ProgramRoundTripsSamePathNoExtension() { _machine.ConnectAsync().GetAwaiter().GetResult(); // Bare identifier "1234"; Mazak validator is passthrough but use clean EIA text. const string identifier = "1234"; string content = "O1234\nG00 X10\nM30"; var prog = new CncProgram { Name = identifier, Content = content }; // Write target == ResolvePath(identifier) == ProgramDir + identifier (verbatim, no extension) var writeResult = _machine.WriteProgramAsync(identifier, prog).GetAwaiter().GetResult(); Assert.That(writeResult.Success, Is.True); string storedPath = ProgramDir + identifier; Assert.That(_stub.Files.ContainsKey(storedPath), Is.True, "File should be stored verbatim at " + storedPath); Assert.That(_stub.Files.ContainsKey(storedPath + ".EIA"), Is.False, "File must NOT be stored with an appended extension"); // Read SAME bare identifier -> ResolvePath resolves to the same target (ISS-020 symmetry) var readResult = _machine.ReadProgramAsync(identifier).GetAwaiter().GetResult(); Assert.That(readResult.Success, Is.True); Assert.That(readResult.Value, Is.EqualTo(content), "Read content must match written content for the same identifier (ResolvePath symmetry)"); } [Test] public void WriteThenDelete_ProgramRemoved_SubsequentReadFails() { _machine.ConnectAsync().GetAwaiter().GetResult(); const string identifier = "1234"; string content = "O1234\nG00 X10\nM30"; var prog = new CncProgram { Name = identifier, Content = content }; var writeResult = _machine.WriteProgramAsync(identifier, prog).GetAwaiter().GetResult(); Assert.That(writeResult.Success, Is.True); string storedPath = ProgramDir + identifier; Assert.That(_stub.Files.ContainsKey(storedPath), Is.True); // ISS-020 symmetry: delete the SAME bare identifier used for write. // ResolvePath(identifier) -> storedPath, so write/delete/read all align. var deleteResult = _machine.DeleteProgramAsync(identifier).GetAwaiter().GetResult(); Assert.That(deleteResult.Success, Is.True); Assert.That(_stub.Files.ContainsKey(storedPath), Is.False); var readResult = _machine.ReadProgramAsync(identifier).GetAwaiter().GetResult(); Assert.That(readResult.Success, Is.False, "Read after delete must fail / not found"); } [Test] public void ReadProgramAsync_FileNotInStub_ResultFail() { _machine.ConnectAsync().GetAwaiter().GetResult(); var result = _machine.ReadProgramAsync("9999").GetAwaiter().GetResult(); Assert.That(result.Success, Is.False); } [Test] [Category("Hardware")] public void Hardware_ConnectAsync_RealMachine() { string ip = HardwareTestHelper.GetIpOrSkip("MAZAK_TEST_IP"); var config = new MazakConnectionConfig { Name = "MazakHardware", IpAddress = ip, Port = 21, Username = Environment.GetEnvironmentVariable("MAZAK_USER") ?? "user", Password = Environment.GetEnvironmentVariable("MAZAK_PASS") ?? "pass", ProgramDirectory = "/PRG/", RequestTimeout = TimeSpan.FromSeconds(10) }; using (var machine = new MazakMachine(config)) { var result = machine.ConnectAsync().GetAwaiter().GetResult(); Assert.That(result.Success, Is.True, "ConnectAsync failed: " + string.Join("; ", result.Errors)); } } } }