267 lines
8.1 KiB
C#
267 lines
8.1 KiB
C#
using FrameProcessor.Configuration;
|
|
|
|
namespace FrameProcessor.Tests;
|
|
|
|
public class FramesOptionsValidatorTests
|
|
{
|
|
private readonly FramesOptionsValidator _validator = new();
|
|
|
|
[Fact]
|
|
public void NoFrames_IsValid()
|
|
{
|
|
var result = _validator.Validate(null, new FramesOptions());
|
|
|
|
Assert.True(result.Succeeded);
|
|
}
|
|
|
|
[Fact]
|
|
public void ValidFrame_Succeeds()
|
|
{
|
|
var options = new FramesOptions { Frames = { ValidFrame() } };
|
|
|
|
var result = _validator.Validate(null, options);
|
|
|
|
Assert.True(result.Succeeded, JoinFailures(result));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void Name_MissingOrBlank_Fails(string? badName)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Name = badName;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Name is required"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("living room")]
|
|
[InlineData("living/room")]
|
|
[InlineData("li:vingroom")]
|
|
public void Name_NotUrlSafe_Fails(string badName)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Name = badName;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("is not a valid frame name"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
public void Mac_Missing_Fails(string? badMac)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Mac = badMac;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Mac is required"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("ZZ:ZZ:ZZ:ZZ:ZZ:ZZ")]
|
|
[InlineData("AABBCC")]
|
|
[InlineData("not-a-mac")]
|
|
public void Mac_Unparseable_Fails(string badMac)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Mac = badMac;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("is not a valid MAC address"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Resolution_Missing_Fails()
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Resolution = null;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Resolution is required"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0, 1200)]
|
|
[InlineData(1600, 0)]
|
|
[InlineData(-1, 1200)]
|
|
[InlineData(1600, -1)]
|
|
public void Resolution_NonPositive_Fails(int width, int height)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Resolution = new ResolutionOptions { Width = width, Height = height };
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("must be positive"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData("LANDSCAPE")]
|
|
[InlineData("sideways")]
|
|
public void Orientation_Invalid_Fails(string? badOrientation)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Orientation = badOrientation;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Orientation"));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData("FloydSteinberg")]
|
|
[InlineData("ordered")]
|
|
public void Dithering_Invalid_Fails(string? badDithering)
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Dithering = badDithering;
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Dithering"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Palette_FewerThanTwoEntries_Fails()
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Palette = new List<PaletteEntryOptions>
|
|
{
|
|
new() { Name = "black", Color = "#000000", DeviceColor = "#000000" },
|
|
};
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("at least 2 entries"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Palette_EntryWithBadHex_Fails()
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Palette[0].Color = "not-a-color";
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Color 'not-a-color' is not a valid hex color"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Palette_EntryWithBadDeviceHex_Fails()
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Palette[1].DeviceColor = "zzzzzz";
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("DeviceColor 'zzzzzz' is not a valid hex color"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Palette_EntryMissingName_Fails()
|
|
{
|
|
var frame = ValidFrame();
|
|
frame.Palette[0].Name = "";
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Palette[0].Name is required"));
|
|
}
|
|
|
|
[Fact]
|
|
public void DuplicateName_Fails()
|
|
{
|
|
var a = ValidFrame();
|
|
var b = ValidFrame();
|
|
b.Mac = "11:22:33:44:55:66";
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { a, b } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("Name 'living-room' is a duplicate"));
|
|
}
|
|
|
|
[Fact]
|
|
public void DuplicateMac_DetectedAfterCanonicalization()
|
|
{
|
|
var a = ValidFrame();
|
|
a.Mac = "AA:BB:CC:DD:EE:FF";
|
|
var b = ValidFrame();
|
|
b.Name = "kitchen";
|
|
b.Mac = "aabbccddeeff";
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { a, b } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!, f => f.Contains("is a duplicate"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AllErrors_AreReportedTogether()
|
|
{
|
|
var frame = new FrameOptions
|
|
{
|
|
Name = "bad name",
|
|
Mac = "not-a-mac",
|
|
Resolution = null,
|
|
Orientation = "diagonal",
|
|
Dithering = "ordered",
|
|
Palette = new List<PaletteEntryOptions>(),
|
|
};
|
|
|
|
var result = _validator.Validate(null, new FramesOptions { Frames = { frame } });
|
|
|
|
Assert.False(result.Succeeded);
|
|
var failures = result.Failures!.ToList();
|
|
Assert.Contains(failures, f => f.Contains("Name"));
|
|
Assert.Contains(failures, f => f.Contains("Mac"));
|
|
Assert.Contains(failures, f => f.Contains("Resolution is required"));
|
|
Assert.Contains(failures, f => f.Contains("Orientation"));
|
|
Assert.Contains(failures, f => f.Contains("Dithering"));
|
|
Assert.Contains(failures, f => f.Contains("at least 2 entries"));
|
|
}
|
|
|
|
private static FrameOptions ValidFrame() => new()
|
|
{
|
|
Name = "living-room",
|
|
Mac = "AA:BB:CC:DD:EE:FF",
|
|
Resolution = new ResolutionOptions { Width = 1600, Height = 1200 },
|
|
Orientation = "landscape",
|
|
Dithering = "floyd-steinberg",
|
|
Palette = new List<PaletteEntryOptions>
|
|
{
|
|
new() { Name = "black", Color = "#1F2226", DeviceColor = "#000000" },
|
|
new() { Name = "white", Color = "#B9C7C9", DeviceColor = "#FFFFFF" },
|
|
},
|
|
};
|
|
|
|
private static string JoinFailures(Microsoft.Extensions.Options.ValidateOptionsResult result)
|
|
=> result.Failures is null ? string.Empty : string.Join("; ", result.Failures);
|
|
}
|