Files
ssh-access-tui/outlook-bulk-sender/BulkArchiveMailer.Core.Tests/ArchiveScannerTests.cs
T
redlineoandClaude Sonnet 5 6e823954a3 Fix hidden add/remove template buttons, add per-template login filter
The add/remove template buttons sat directly below the fixed-height
list with only 6px of margin to the tab's bottom edge - enough on this
dev machine but not on the operator's real one (different DPI/font
scale), so the buttons rendered off the visible area. Moved them above
the list instead (visibility no longer depends on how much space is
left at the bottom) and gave the whole "Шаблоны" tab substantially
more vertical room throughout.

Also added an optional per-template login regex filter
(MailTemplateDefinition.LoginPattern): once a file's suffix matches a
template, its login must also match that template's pattern (if any)
or the row surfaces as a clear Error in the preview instead of
silently going through - addresses "непонятно что будет работать".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 12:23:54 +03:00

153 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BulkArchiveMailer.Core;
using Xunit;
namespace BulkArchiveMailer.Core.Tests
{
/// <summary>
/// ArchiveScanner.Scan touches the real file system (Directory.Exists/
/// EnumerateFiles), so these tests set up a throwaway folder under
/// Path.GetTempPath() per test and delete it afterwards (IDisposable),
/// rather than mocking - the existing precedent in this test project
/// (SendLogStoreTests-equivalent file-based tests) already treats this
/// as an acceptable pattern for .NET file-system-touching code.
/// </summary>
public class ArchiveScannerTests : IDisposable
{
private readonly string tempDir;
public ArchiveScannerTests()
{
tempDir = Path.Combine(Path.GetTempPath(), "BulkArchiveMailerTests_" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
}
public void Dispose()
{
try
{
if (Directory.Exists(tempDir))
{
Directory.Delete(tempDir, recursive: true);
}
}
catch
{
// Best-effort cleanup only - never fail a passing test over
// a locked/leftover temp file.
}
}
private static void WriteArchive(string path) => File.WriteAllBytes(path, new byte[] { 1, 2, 3 });
[Fact]
public void Scan_LoginMatchesTemplateLoginPattern_IsReady()
{
var filePath = Path.Combine(tempDir, "a-makarov_ssh_access.7z");
WriteArchive(filePath);
var templates = new List<MailTemplateDefinition>
{
new MailTemplateDefinition
{
DisplayName = "SSH-доступ (только a-*)",
FileSuffix = "ssh_access",
Subject = "Доступ — {Login}",
BodyHtml = "<p>{Login}</p>",
LoginPattern = "^a-.*",
},
};
var result = ArchiveScanner.Scan(tempDir, "redlab.lo", templates);
var job = Assert.Single(result.Jobs);
Assert.Equal(SendStatus.Ready, job.Status);
Assert.Equal("a-makarov", job.Login);
Assert.Equal("a.makarov@redlab.lo", job.Email);
Assert.Empty(result.UnrecognizedFiles);
}
[Fact]
public void Scan_LoginDoesNotMatchTemplateLoginPattern_IsErrorInUnrecognized()
{
var filePath = Path.Combine(tempDir, "b-petrov_ssh_access.7z");
WriteArchive(filePath);
var templates = new List<MailTemplateDefinition>
{
new MailTemplateDefinition
{
DisplayName = "SSH-доступ (только a-*)",
FileSuffix = "ssh_access",
Subject = "Доступ — {Login}",
BodyHtml = "<p>{Login}</p>",
LoginPattern = "^a-.*",
},
};
var result = ArchiveScanner.Scan(tempDir, "redlab.lo", templates);
Assert.Empty(result.Jobs);
var row = Assert.Single(result.UnrecognizedFiles);
Assert.Equal(SendStatus.Error, row.Status);
Assert.Contains("b-petrov", row.ErrorMessage);
Assert.Contains("SSH-доступ (только a-*)", row.ErrorMessage);
Assert.Contains("^a-.*", row.ErrorMessage);
}
[Fact]
public void Scan_EmptyLoginPattern_MatchesAnyLogin_UnchangedLegacyBehavior()
{
var filePath = Path.Combine(tempDir, "z-unrelated_ssh_access.7z");
WriteArchive(filePath);
var templates = new List<MailTemplateDefinition>
{
new MailTemplateDefinition
{
DisplayName = "SSH-доступ",
FileSuffix = "ssh_access",
Subject = "Доступ — {Login}",
BodyHtml = "<p>{Login}</p>",
LoginPattern = "",
},
};
var result = ArchiveScanner.Scan(tempDir, "redlab.lo", templates);
var job = Assert.Single(result.Jobs);
Assert.Equal(SendStatus.Ready, job.Status);
Assert.Equal("z-unrelated", job.Login);
}
[Fact]
public void Scan_InvalidLoginPatternRegex_TreatedAsNoMatchRatherThanThrowing()
{
var filePath = Path.Combine(tempDir, "a-makarov_ssh_access.7z");
WriteArchive(filePath);
var templates = new List<MailTemplateDefinition>
{
new MailTemplateDefinition
{
DisplayName = "SSH-доступ (битый regex)",
FileSuffix = "ssh_access",
Subject = "Доступ — {Login}",
BodyHtml = "<p>{Login}</p>",
// Unbalanced group - not a valid regex.
LoginPattern = "(a-",
},
};
var result = ArchiveScanner.Scan(tempDir, "redlab.lo", templates);
Assert.Empty(result.Jobs);
var row = Assert.Single(result.UnrecognizedFiles);
Assert.Equal(SendStatus.Error, row.Status);
}
}
}