namespace OpenNest.Desktop.Tests;
///
/// Post processors load from a Posts directory one DLL at a time: a DLL that fails is
/// reported and the others still load, and the materials they provide are registered.
///
public sealed class PostProcessorLoaderTests : IDisposable
{
private readonly string directory = Path.Combine(Path.GetTempPath(), "OpenNestDesktopTests", Guid.NewGuid().ToString("N"));
public PostProcessorLoaderTests() => Directory.CreateDirectory(directory);
public void Dispose()
{
try { Directory.Delete(directory, recursive: true); } catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) { }
}
[Fact]
public void Load_IsolatesAFailingDllReportsItAndRegistersTheOthersMaterials()
{
// This test assembly is a post plug-in (it holds MaterialPost); the broken DLL is not .NET at all.
File.Copy(typeof(MaterialPost).Assembly.Location, Path.Combine(directory, "Good.Posts.dll"));
File.WriteAllText(Path.Combine(directory, "Broken.Posts.dll"), "not an assembly");
File.WriteAllText(Path.Combine(directory, "Readme.txt"), "ignored");
var result = PostProcessorLoader.Load(directory);
var failure = Assert.Single(result.Failures);
Assert.StartsWith("Broken.Posts.dll: ", failure);
Assert.Contains(result.PostProcessors, post => post.Name == MaterialPost.PostName);
Assert.Contains("Unobtainium", PostProcessorMaterials.Names, StringComparer.Ordinal);
Assert.Contains("aluminum 5052", PostProcessorMaterials.Names, StringComparer.Ordinal);
}
[Fact]
public void Load_WithoutAPostsDirectory_LoadsNothing()
{
var result = PostProcessorLoader.Load(Path.Combine(directory, "missing"));
Assert.Empty(result.PostProcessors);
Assert.Empty(result.Failures);
}
[Fact]
public void Materials_AreAddedOnceIgnoringCaseAndBlanksInNameOrder()
{
PostProcessorMaterials.AddFrom(new MaterialPost(["zz Order B", "ZZ ORDER a", " ", "zz order b"]));
var names = PostProcessorMaterials.Names.Where(n => n.StartsWith("zz", StringComparison.OrdinalIgnoreCase)).ToList();
Assert.Equal(["ZZ ORDER a", "zz Order B"], names);
Assert.DoesNotContain(" ", PostProcessorMaterials.Names);
}
internal sealed class MaterialPost : IPostProcessor, IMaterialProvidingPostProcessor
{
public const string PostName = "Material Test Post";
private readonly IReadOnlyList materials;
public MaterialPost() : this(["Unobtainium", "aluminum 5052"])
{
}
public MaterialPost(IReadOnlyList materials) => this.materials = materials;
public string Name => PostName;
public string Author => "Tests";
public string Description => "Provides materials.";
public IEnumerable GetMaterialNames() => materials;
public void Post(Nest nest, Stream outputStream) { }
public void Post(Nest nest, string outputFile) { }
}
}