using System.Text;
using AtomUI.Controls;
using Shouldly;
using Xunit;
namespace AtomUI.Controls.Shared.Tests.ImageLoading;
public class SvgContentValidatorTests
{
[Fact]
public void Same_Document_References_Inline_Css_And_Data_Raster_Are_Allowed()
{
var pngData = Convert.ToBase64String(ImageLoadingTestSupport.CreatePngHeader(2, 3));
var probe = ValidateSvg($$"""
""");
probe.Format.ShouldBe(ImageContentFormat.Svg);
probe.MediaType.ShouldBe("image/svg+xml");
probe.SvgMetadata.ShouldNotBeNull();
probe.SvgMetadata.ElementCount.ShouldBeGreaterThan(5);
probe.SvgMetadata.EmbeddedImageCount.ShouldBe(1);
probe.SvgMetadata.EmbeddedImageDecodedBytes.ShouldBe(24);
probe.SvgMetadata.EstimatedDecodedCost.ShouldBeGreaterThan(0);
}
[Theory]
[InlineData("image/svg+xml")]
[InlineData("application/xml")]
[InlineData("text/xml")]
[InlineData("application/octet-stream")]
[InlineData(null)]
public void Approved_Svg_Media_Types_Are_Accepted(string? mediaType)
{
ValidateSvg(
"",
mediaType)
.Format.ShouldBe(ImageContentFormat.Svg);
}
[Fact]
public void Compatible_Mode_Accepts_Duplicate_Ids()
{
var probe = ValidateSvg("""
""");
probe.Format.ShouldBe(ImageContentFormat.Svg);
}
[Fact]
public void Strict_Mode_Rejects_Duplicate_Ids()
{
AssertSvgFailure(
ImageLoadErrorCode.InvalidImageData,
"""
""",
configure: builder => builder.Svg.ConformanceMode = SvgConformanceMode.Strict);
}
[Fact]
public void Strict_Duplicate_Id_Does_Not_Mask_Unsafe_Content()
{
AssertSvgFailure(
ImageLoadErrorCode.UnsafeVectorContent,
"""
""",
configure: builder => builder.Svg.ConformanceMode = SvgConformanceMode.Strict);
}
[Fact]
public void Strict_Duplicate_Id_Does_Not_Mask_Reference_Complexity()
{
AssertSvgFailure(
ImageLoadErrorCode.VectorComplexityLimitExceeded,
"""
""",
configure: builder => builder.Svg.ConformanceMode = SvgConformanceMode.Strict);
}
[Theory]
[InlineData(SvgConformanceMode.Compatible)]
[InlineData(SvgConformanceMode.Strict)]
public void Duplicate_Id_Nested_References_Cannot_Bypass_Reference_Depth(SvgConformanceMode mode)
{
AssertSvgFailure(
ImageLoadErrorCode.VectorComplexityLimitExceeded,
"""
""",
configure: builder =>
{
builder.Svg.ConformanceMode = mode;
builder.Svg.MaxReferenceDepth = 1;
});
}
[Fact]
public void Compatible_Mode_Keeps_Duplicate_Id_Occurrences_As_Separate_Reference_Nodes()
{
var probe = ValidateSvg("""
""");
probe.SvgMetadata.ShouldNotBeNull();
probe.SvgMetadata.MaxReferenceDepth.ShouldBe(2);
}
[Fact]
public void Compatible_Mode_Counts_References_From_Every_Duplicate_Id_Occurrence()
{
AssertSvgFailure(
ImageLoadErrorCode.VectorComplexityLimitExceeded,
"""
""",
configure: builder => builder.Svg.MaxReferenceDepth = 1);
}
[Theory]
[InlineData(SvgConformanceMode.Compatible)]
[InlineData(SvgConformanceMode.Strict)]
public void Conformance_Mode_Does_Not_Change_Security_Rejection(SvgConformanceMode mode)
{
AssertSvgFailure(
ImageLoadErrorCode.UnsafeVectorContent,
"",
configure: builder => builder.Svg.ConformanceMode = mode);
}
[Theory]
[InlineData("]>")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
[InlineData("")]
public void Unsafe_Vector_Content_Is_Rejected(string svg)
{
AssertSvgFailure(ImageLoadErrorCode.UnsafeVectorContent, svg);
}
[Theory]
[InlineData("")]
[InlineData("")]
[InlineData("