Skip to content

Commit 959d2df

Browse files
Cover the small zero-coverage types and exclude submodule sources
The shared-infrastructure guard sources are covered by the submodule's own tests and are excluded from this repository's metric. New tests cover the Brushes pattern factories in both overload forms, the LinearGeometry polyline surface including segment enumeration, lengths, shoelace areas, winding containment, distance queries and sub-path extraction, path normalization including the positive-winding lobe selection for self-intersecting contours, the native-to-public error type mapping, the window option defaults, the shader diagnostic and compilation exception surface, and the native type name attribute.
1 parent 0e4ebc5 commit 959d2df

8 files changed

Lines changed: 404 additions & 2 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Drawing.Processing.Backends.Native;
5+
6+
namespace SixLabors.ImageSharp.Drawing.Tests.Processing.Backends;
7+
8+
public class NativeTypeNameAttributeTests
9+
{
10+
[Fact]
11+
public void Constructor_StoresNativeName()
12+
=> Assert.Equal("WGPUBool", new NativeTypeNameAttribute("WGPUBool").Name);
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Drawing.Processing.Backends;
5+
using SixLabors.ImageSharp.Drawing.Processing.Backends.Native;
6+
7+
namespace SixLabors.ImageSharp.Drawing.Tests.Processing.Backends;
8+
9+
public class WebGPUErrorTypeMapperTests
10+
{
11+
[Fact]
12+
public void ToPublic_MapsEveryNativeClassification()
13+
{
14+
Assert.Equal(WebGPUErrorType.NoError, WebGPUErrorTypeMapper.ToPublic(WGPUErrorType.NoError));
15+
Assert.Equal(WebGPUErrorType.Validation, WebGPUErrorTypeMapper.ToPublic(WGPUErrorType.Validation));
16+
Assert.Equal(WebGPUErrorType.OutOfMemory, WebGPUErrorTypeMapper.ToPublic(WGPUErrorType.OutOfMemory));
17+
Assert.Equal(WebGPUErrorType.Internal, WebGPUErrorTypeMapper.ToPublic(WGPUErrorType.Internal));
18+
Assert.Equal(WebGPUErrorType.Unknown, WebGPUErrorTypeMapper.ToPublic(WGPUErrorType.Unknown));
19+
Assert.Equal(WebGPUErrorType.Unknown, WebGPUErrorTypeMapper.ToPublic((WGPUErrorType)int.MaxValue));
20+
}
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Drawing.Processing.Backends;
5+
6+
namespace SixLabors.ImageSharp.Drawing.Tests.Processing.Backends;
7+
8+
public class WebGPUShaderDiagnosticTests
9+
{
10+
[Fact]
11+
public void Constructor_StoresAllValues()
12+
{
13+
WebGPUShaderDiagnostic diagnostic = new(WebGPUShaderDiagnosticSeverity.Error, "bad shader", 4, 7);
14+
15+
Assert.Equal(WebGPUShaderDiagnosticSeverity.Error, diagnostic.Severity);
16+
Assert.Equal("bad shader", diagnostic.Message);
17+
Assert.Equal(4, diagnostic.Line);
18+
Assert.Equal(7, diagnostic.Column);
19+
}
20+
21+
[Fact]
22+
public void CompilationException_ExposesMessageAndDiagnostics()
23+
{
24+
WebGPUShaderDiagnostic[] diagnostics =
25+
[
26+
new(WebGPUShaderDiagnosticSeverity.Warning, "first", 1, 2),
27+
new(WebGPUShaderDiagnosticSeverity.Error, "second", 3, 4),
28+
];
29+
30+
WebGPUShaderCompilationException exception = new("compilation failed", diagnostics);
31+
32+
Assert.Equal("compilation failed", exception.Message);
33+
Assert.Equal(2, exception.Diagnostics.Count);
34+
Assert.Equal("second", exception.Diagnostics[1].Message);
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Drawing.Processing.Backends;
5+
6+
namespace SixLabors.ImageSharp.Drawing.Tests.Processing.Backends;
7+
8+
public class WebGPUWindowOptionsTests
9+
{
10+
[Fact]
11+
public void Defaults_MatchDocumentedInitialConfiguration()
12+
{
13+
WebGPUWindowOptions options = new();
14+
15+
Assert.Equal("ImageSharp.Drawing WebGPU", options.Title);
16+
Assert.Equal(new Size(1280, 720), options.Size);
17+
Assert.Equal(new Point(50, 50), options.Position);
18+
Assert.True(options.IsVisible);
19+
Assert.Equal(0, options.FramesPerSecond);
20+
Assert.Equal(0, options.UpdatesPerSecond);
21+
Assert.False(options.IsEventDriven);
22+
Assert.Equal(WebGPUWindowState.Normal, options.WindowState);
23+
Assert.Equal(WebGPUWindowBorder.Resizable, options.WindowBorder);
24+
Assert.False(options.IsTopMost);
25+
Assert.Equal(WebGPUPresentMode.Fifo, options.PresentMode);
26+
Assert.Equal(WebGPUTextureFormat.Rgba8Unorm, options.Format);
27+
}
28+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Drawing.Processing;
5+
6+
namespace SixLabors.ImageSharp.Drawing.Tests.Processing;
7+
8+
public class BrushesTests
9+
{
10+
public static TheoryData<string> PatternFactoryNames { get; } = new()
11+
{
12+
nameof(Brushes.Horizontal),
13+
nameof(Brushes.Min),
14+
nameof(Brushes.Vertical),
15+
nameof(Brushes.ForwardDiagonal),
16+
nameof(Brushes.BackwardDiagonal),
17+
nameof(Brushes.Cross),
18+
nameof(Brushes.DiagonalCross),
19+
};
20+
21+
[Fact]
22+
public void Solid_CreatesBrushWithColor()
23+
{
24+
SolidBrush brush = Brushes.Solid(Color.Red);
25+
26+
Assert.Equal(Color.Red, brush.Color);
27+
}
28+
29+
[Theory]
30+
[MemberData(nameof(PatternFactoryNames))]
31+
public void PatternFactories_SingleColor_UseTransparentBackground(string name)
32+
{
33+
PatternBrush brush = InvokePatternFactory(name, Color.Red, null);
34+
35+
Assert.Contains(Color.Red, brush.Pattern.Data);
36+
Assert.Contains(Color.Transparent, brush.Pattern.Data);
37+
}
38+
39+
[Theory]
40+
[MemberData(nameof(PatternFactoryNames))]
41+
public void PatternFactories_TwoColors_UseBothColors(string name)
42+
{
43+
PatternBrush brush = InvokePatternFactory(name, Color.Red, Color.Blue);
44+
45+
Assert.Contains(Color.Red, brush.Pattern.Data);
46+
Assert.Contains(Color.Blue, brush.Pattern.Data);
47+
Assert.DoesNotContain(Color.Transparent, brush.Pattern.Data);
48+
}
49+
50+
private static PatternBrush InvokePatternFactory(string name, Color foreColor, Color? backColor)
51+
=> (name, backColor) switch
52+
{
53+
(nameof(Brushes.Horizontal), null) => Brushes.Horizontal(foreColor),
54+
(nameof(Brushes.Horizontal), _) => Brushes.Horizontal(foreColor, backColor.Value),
55+
(nameof(Brushes.Min), null) => Brushes.Min(foreColor),
56+
(nameof(Brushes.Min), _) => Brushes.Min(foreColor, backColor.Value),
57+
(nameof(Brushes.Vertical), null) => Brushes.Vertical(foreColor),
58+
(nameof(Brushes.Vertical), _) => Brushes.Vertical(foreColor, backColor.Value),
59+
(nameof(Brushes.ForwardDiagonal), null) => Brushes.ForwardDiagonal(foreColor),
60+
(nameof(Brushes.ForwardDiagonal), _) => Brushes.ForwardDiagonal(foreColor, backColor.Value),
61+
(nameof(Brushes.BackwardDiagonal), null) => Brushes.BackwardDiagonal(foreColor),
62+
(nameof(Brushes.BackwardDiagonal), _) => Brushes.BackwardDiagonal(foreColor, backColor.Value),
63+
(nameof(Brushes.Cross), null) => Brushes.Cross(foreColor),
64+
(nameof(Brushes.Cross), _) => Brushes.Cross(foreColor, backColor.Value),
65+
(nameof(Brushes.DiagonalCross), null) => Brushes.DiagonalCross(foreColor),
66+
(nameof(Brushes.DiagonalCross), _) => Brushes.DiagonalCross(foreColor, backColor.Value),
67+
_ => throw new ArgumentOutOfRangeException(nameof(name)),
68+
};
69+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Numerics;
5+
6+
namespace SixLabors.ImageSharp.Drawing.Tests.Shapes;
7+
8+
public class LinearGeometryTests
9+
{
10+
private static LinearGeometry CreateLPolyline()
11+
=> LinearGeometry.CreateOpenPolyline(
12+
[
13+
new PointF(0, 0),
14+
new PointF(10, 0),
15+
new PointF(10, 10),
16+
]);
17+
18+
private static LinearGeometry CreateClosedSquare()
19+
{
20+
PointF[] points =
21+
[
22+
new PointF(0, 0),
23+
new PointF(10, 0),
24+
new PointF(10, 10),
25+
new PointF(0, 10),
26+
];
27+
RectangleF bounds = RectangleF.FromLTRB(0, 0, 10, 10);
28+
29+
return new LinearGeometry(
30+
new LinearGeometryInfo
31+
{
32+
Bounds = bounds,
33+
ContourCount = 1,
34+
PointCount = points.Length,
35+
SegmentCount = points.Length,
36+
},
37+
[new LinearContour
38+
{
39+
PointStart = 0,
40+
PointCount = points.Length,
41+
Bounds = bounds,
42+
SegmentStart = 0,
43+
SegmentCount = points.Length,
44+
IsClosed = true,
45+
}
46+
],
47+
points);
48+
}
49+
50+
[Fact]
51+
public void CreateOpenPolyline_PopulatesInfoAndContours()
52+
{
53+
LinearGeometry geometry = CreateLPolyline();
54+
55+
Assert.Equal(1, geometry.Info.ContourCount);
56+
Assert.Equal(3, geometry.Info.PointCount);
57+
Assert.Equal(2, geometry.Info.SegmentCount);
58+
Assert.Equal(RectangleF.FromLTRB(0, 0, 10, 10), geometry.Info.Bounds);
59+
60+
LinearContour contour = Assert.Single(geometry.Contours);
61+
Assert.False(contour.IsClosed);
62+
Assert.Equal(3, geometry.Points.Count);
63+
}
64+
65+
[Fact]
66+
public void CreateOpenPolyline_AppliesScale()
67+
{
68+
LinearGeometry geometry = LinearGeometry.CreateOpenPolyline(
69+
[new PointF(1, 2), new PointF(3, 4)],
70+
new Vector2(2, 10));
71+
72+
Assert.Equal(new PointF(2, 20), geometry.Points[0]);
73+
Assert.Equal(new PointF(6, 40), geometry.Points[1]);
74+
}
75+
76+
[Fact]
77+
public void CreateOpenPolyline_FewerThanTwoPoints_Throws()
78+
=> Assert.Throws<ArgumentOutOfRangeException>(() => LinearGeometry.CreateOpenPolyline([new PointF(0, 0)]));
79+
80+
[Fact]
81+
public void GetSegments_YieldsEachSegmentInOrder()
82+
{
83+
LinearGeometry geometry = CreateLPolyline();
84+
List<(PointF Start, PointF End)> segments = [];
85+
86+
SegmentEnumerator enumerator = geometry.GetSegments();
87+
while (enumerator.MoveNext())
88+
{
89+
segments.Add((enumerator.Current.Start, enumerator.Current.End));
90+
}
91+
92+
Assert.Equal(
93+
[
94+
(new PointF(0, 0), new PointF(10, 0)),
95+
(new PointF(10, 0), new PointF(10, 10)),
96+
],
97+
segments);
98+
}
99+
100+
[Fact]
101+
public void ComputeLength_SumsSegmentLengths()
102+
=> Assert.Equal(20F, CreateLPolyline().ComputeLength());
103+
104+
[Fact]
105+
public void ComputeArea_OpenRunWithThreePoints_UsesShoelaceOfPointRun()
106+
=> Assert.Equal(50F, CreateLPolyline().ComputeArea());
107+
108+
[Fact]
109+
public void ComputeArea_ClosedSquare_ReturnsEnclosedArea()
110+
=> Assert.Equal(100F, CreateClosedSquare().ComputeArea());
111+
112+
[Fact]
113+
public void Contains_OpenContour_NeverContains()
114+
{
115+
LinearGeometry geometry = CreateLPolyline();
116+
117+
Assert.False(geometry.Contains(new PointF(9, 1), IntersectionRule.NonZero));
118+
Assert.False(geometry.Contains(new PointF(9, 1), IntersectionRule.EvenOdd));
119+
}
120+
121+
[Theory]
122+
[InlineData(5, 5, true)]
123+
[InlineData(0, 0, true)]
124+
[InlineData(15, 5, false)]
125+
[InlineData(-1, 5, false)]
126+
public void Contains_ClosedContour_UsesWinding(float x, float y, bool expected)
127+
{
128+
LinearGeometry geometry = CreateClosedSquare();
129+
130+
Assert.Equal(expected, geometry.Contains(new PointF(x, y), IntersectionRule.NonZero));
131+
Assert.Equal(expected, geometry.Contains(new PointF(x, y), IntersectionRule.EvenOdd));
132+
}
133+
134+
[Theory]
135+
[InlineData(0, 0, 0)]
136+
[InlineData(5, 5, 0)]
137+
[InlineData(15, 10, 5)]
138+
[InlineData(20, 10, 10)]
139+
public void TryGetPathPointAtDistance_WithinLength_ReturnsPointOnPolyline(float distance, float x, float y)
140+
{
141+
LinearGeometry geometry = CreateLPolyline();
142+
143+
Assert.True(geometry.TryGetPathPointAtDistance(distance, out PathPoint pathPoint));
144+
Assert.Equal(new PointF(x, y), pathPoint.Point);
145+
}
146+
147+
[Fact]
148+
public void TryGetPathPointAtDistance_BeyondOpenPolyline_ReturnsFalse()
149+
{
150+
LinearGeometry geometry = CreateLPolyline();
151+
152+
Assert.False(geometry.TryGetPathPointAtDistance(25, out _));
153+
Assert.False(geometry.TryGetPathPointAtDistance(-1, out _));
154+
Assert.False(geometry.TryGetPathPointAtDistance(float.NaN, out _));
155+
}
156+
157+
[Fact]
158+
public void TryGetPathPointAtDistanceUnbounded_ExtrapolatesAlongEndTangent()
159+
{
160+
LinearGeometry geometry = CreateLPolyline();
161+
162+
Assert.True(geometry.TryGetPathPointAtDistanceUnbounded(25, out PathPoint pathPoint));
163+
Assert.Equal(new PointF(10, 15), pathPoint.Point);
164+
}
165+
166+
[Fact]
167+
public void TryGetPathPointAtDistanceUnbounded_NegativeDistance_ExtrapolatesBeforeStart()
168+
{
169+
LinearGeometry geometry = CreateLPolyline();
170+
171+
Assert.True(geometry.TryGetPathPointAtDistanceUnbounded(-5, out PathPoint pathPoint));
172+
Assert.Equal(new PointF(-5, 0), pathPoint.Point);
173+
}
174+
175+
[Fact]
176+
public void TryGetSegment_ReturnsSubPathBetweenDistances()
177+
{
178+
LinearGeometry geometry = CreateLPolyline();
179+
180+
Assert.True(geometry.TryGetSegment(5, 15, false, out IPath segment));
181+
Assert.Equal(RectangleF.FromLTRB(5, 0, 10, 5), segment.Bounds);
182+
}
183+
}

0 commit comments

Comments
 (0)