using NUnit.Framework; using NcProgramManager.Cnc.Mazak; namespace NcProgramManager.Tests.Unit { [TestFixture] public class FtpListParserTests { // NormalizeDir [Test] public void NormalizeDir_Empty_ReturnsRoot() { Assert.That(FtpListParser.NormalizeDir(""), Is.EqualTo("/")); } [Test] public void NormalizeDir_Null_ReturnsRoot() { Assert.That(FtpListParser.NormalizeDir(null), Is.EqualTo("/")); } [Test] public void NormalizeDir_NoSlashes_AddsBoth() { Assert.That(FtpListParser.NormalizeDir("PRG"), Is.EqualTo("/PRG/")); } [Test] public void NormalizeDir_NoTrailingSlash_AddsTrailing() { Assert.That(FtpListParser.NormalizeDir("/a/b"), Is.EqualTo("/a/b/")); } [Test] public void NormalizeDir_AlreadyNormalized_Unchanged() { Assert.That(FtpListParser.NormalizeDir("/a/b/"), Is.EqualTo("/a/b/")); } // Parse - DOS/IIS format [Test] public void Parse_DosDir_DirectoryEntry() { var e = FtpListParser.Parse("07-18-26 10:00AM MYDIR", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("MYDIR")); Assert.That(e.IsDirectory, Is.True); Assert.That(e.Size, Is.EqualTo(-1)); Assert.That(e.FullPath, Is.EqualTo("/PRG/MYDIR")); } [Test] public void Parse_DosFile_FileEntryWithSize() { var e = FtpListParser.Parse("07-18-26 10:00AM 1234 O1000.EIA", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("O1000.EIA")); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(1234)); } // Parse - DOS/IIS format, T4 tolerances (24h time, 4-digit year, spaces) [Test] public void Parse_Dos24hTime_DirectoryEntry() { // 24h time, no AM/PM: _dosLine \s*(AM|PM)? optional absorbs this. var e = FtpListParser.Parse("07-18-26 22:00 NIGHTDIR", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("NIGHTDIR")); Assert.That(e.IsDirectory, Is.True); Assert.That(e.Size, Is.EqualTo(-1)); } [Test] public void Parse_Dos4DigitYear_FileEntryWithSize() { // 4-digit year: date group is \d{2}-\d{2}-\d{2,4}. var e = FtpListParser.Parse("07-18-2026 10:00AM 2048 O4000.EIA", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("O4000.EIA")); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(2048)); } [Test] public void Parse_DosFileNameWithSpaces_KeepsSpaces() { // name group is .+ (greedy to $) -> internal spaces preserved. var e = FtpListParser.Parse("07-18-26 10:00AM 128 MY PROG.EIA", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("MY PROG.EIA")); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(128)); } // Parse - Unix format [Test] public void Parse_UnixFileNameWithSpaces_KeepsSpaces() { // Unix name group is .+ -> internal spaces preserved. var e = FtpListParser.Parse("-rw-r--r-- 1 own grp 64 Jul 18 10:00 MY PROG", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("MY PROG")); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(64)); } [Test] public void Parse_UnixDir_DirectoryEntry() { var e = FtpListParser.Parse("drwxr-xr-x 1 own grp 4096 Jul 18 10:00 sub", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.IsDirectory, Is.True); Assert.That(e.Name, Is.EqualTo("sub")); } [Test] public void Parse_UnixFile_FileEntryWithSize() { var e = FtpListParser.Parse("-rw-r--r-- 1 own grp 512 Jul 18 10:00 O2000", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(512)); Assert.That(e.Name, Is.EqualTo("O2000")); } // Parse - skip '.' and '..' [Test] public void Parse_DotDir_ReturnsNull() { var e = FtpListParser.Parse("07-18-26 10:00AM .", "/PRG/"); Assert.That(e, Is.Null); } [Test] public void Parse_DotDotDir_ReturnsNull() { var e = FtpListParser.Parse("07-18-26 10:00AM ..", "/PRG/"); Assert.That(e, Is.Null); } // Parse - fallback (NLST bare name) [Test] public void Parse_BareName_FallbackFileEntry() { var e = FtpListParser.Parse("O3000", "/PRG/"); Assert.That(e, Is.Not.Null); Assert.That(e.Name, Is.EqualTo("O3000")); Assert.That(e.IsDirectory, Is.False); Assert.That(e.Size, Is.EqualTo(-1)); } // Parse - garbage/header multi-token line matches neither regex -> skip [Test] public void Parse_GarbageMultiToken_ReturnsNull() { // "total 8": DOS regex needs leading MM-DD-YY date (no); Unix perm group is // [dl-][rwxsStT-]{9} and 't' is not in [dl-] (no). Trimmed line has internal // whitespace -> T4 fallback returns null (not treated as bare NLST name). Assert.That(FtpListParser.Parse("total 8", "/PRG/"), Is.Null); } // Parse - whitespace/empty [Test] public void Parse_Whitespace_ReturnsNull() { Assert.That(FtpListParser.Parse(" ", "/PRG/"), Is.Null); } } }