1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using Xunit;
7 
8 namespace System.Drawing.Drawing2D.Tests
9 {
10     public class CustomLineCapTests
11     {
Ctor_Path_Path_LineCap_Float_TestData()12         public static IEnumerable<object[]> Ctor_Path_Path_LineCap_Float_TestData()
13         {
14             yield return new object[] { new GraphicsPath(), null, LineCap.Flat, 0f, LineCap.Flat };
15             yield return new object[] { new GraphicsPath(), null, LineCap.Square, 1f, LineCap.Square };
16             yield return new object[] { new GraphicsPath(), null, LineCap.Round, -1f, LineCap.Round };
17             yield return new object[] { new GraphicsPath(), null, LineCap.Triangle, float.MaxValue, LineCap.Triangle };
18             // All of these "anchor" values yield a "Flat" LineCap.
19             yield return new object[] { new GraphicsPath(), null, LineCap.NoAnchor, 0f, LineCap.Flat };
20             yield return new object[] { new GraphicsPath(), null, LineCap.SquareAnchor, 0f, LineCap.Flat };
21             yield return new object[] { new GraphicsPath(), null, LineCap.DiamondAnchor, 0f, LineCap.Flat };
22             yield return new object[] { new GraphicsPath(), null, LineCap.ArrowAnchor, 0f, LineCap.Flat };
23 
24             // Boxy cap
25             GraphicsPath strokePath = new GraphicsPath();
26             strokePath.AddRectangle(new Rectangle(0, 0, 10, 10));
27             yield return new object[] { null, strokePath, LineCap.Square, 0f, LineCap.Square };
28 
29             // Hook-shaped cap
30             strokePath = new GraphicsPath();
31             strokePath.AddLine(new Point(0, 0), new Point(0, 5));
32             strokePath.AddLine(new Point(0, 5), new Point(5, 1));
33             strokePath.AddLine(new Point(5, 1), new Point(3, 1));
34             yield return new object[] { null, strokePath, LineCap.Flat, 0f, LineCap.Flat };
35 
36             // Fill path -- Must intercept the Y-axis.
37             GraphicsPath fillPath = new GraphicsPath();
38             fillPath.AddLine(new Point(-5, -10), new Point(0, 10));
39             fillPath.AddLine(new Point(0, 10), new Point(5, -10));
40             fillPath.AddLine(new Point(5, -10), new Point(-5, -10));
41             yield return new object[] { fillPath, null, LineCap.Flat, 0f, LineCap.Flat };
42         }
43 
44         [ActiveIssue(20884, TestPlatforms.AnyUnix)]
45         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
46         [MemberData(nameof(Ctor_Path_Path_LineCap_Float_TestData))]
Ctor_Path_Path_LineCap_Float(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap, float baseInset, LineCap expectedCap)47         public void Ctor_Path_Path_LineCap_Float(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap, float baseInset, LineCap expectedCap)
48         {
49             using (fillPath)
50             using (strokePath)
51             using (CustomLineCap customLineCap = new CustomLineCap(fillPath, strokePath, baseCap, baseInset))
52             {
53                 Assert.Equal(expectedCap, customLineCap.BaseCap);
54                 Assert.Equal(baseInset, customLineCap.BaseInset);
55                 Assert.Equal(LineJoin.Miter, customLineCap.StrokeJoin);
56                 Assert.Equal(1f, customLineCap.WidthScale);
57             }
58         }
59 
60         [ActiveIssue(20884, TestPlatforms.AnyUnix)]
61         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
62         // These values are outside the valid range of the LineCap enum.
63         [InlineData(LineCap.Flat - 1)]
64         [InlineData(LineCap.Custom + 1)]
Ctor_InvalidLineCap_ReturnsFlat(LineCap baseCap)65         public void Ctor_InvalidLineCap_ReturnsFlat(LineCap baseCap)
66         {
67             using (GraphicsPath fillPath = new GraphicsPath())
68             using (GraphicsPath strokePath = new GraphicsPath())
69             using (CustomLineCap customLineCap = new CustomLineCap(fillPath, strokePath, baseCap, 0f))
70             {
71                 Assert.Equal(LineCap.Flat, customLineCap.BaseCap);
72             }
73         }
74 
75         [ActiveIssue(20884, TestPlatforms.AnyUnix)]
76         [ConditionalFact(Helpers.GdiplusIsAvailable)]
Ctor_FillPath_Incomplete_ThrowsArgumentException()77         public void Ctor_FillPath_Incomplete_ThrowsArgumentException()
78         {
79             using (GraphicsPath fillPath = new GraphicsPath())
80             {
81                 fillPath.AddLine(new Point(0, -10), new Point(0, 10));
82                 AssertExtensions.Throws<ArgumentException>(null, () => new CustomLineCap(fillPath, null));
83             }
84         }
85 
86         [ActiveIssue(20884, TestPlatforms.AnyUnix)]
87         [ConditionalFact(Helpers.GdiplusIsAvailable)]
Ctor_FillPath_DoesNotCrossYAxis_ThrowsNotImplementedException()88         public void Ctor_FillPath_DoesNotCrossYAxis_ThrowsNotImplementedException()
89         {
90             // Closed fillPath, but does not cross the Y-axis.
91             using (GraphicsPath fillPath = new GraphicsPath())
92             {
93                 fillPath.AddLine(new Point(-5, 5), new Point(5, 5));
94                 fillPath.AddLine(new Point(5, 5), new Point(5, 1));
95                 fillPath.AddLine(new Point(5, 1), new Point(-5, 5));
96                 Assert.Throws<NotImplementedException>(() => new CustomLineCap(fillPath, null));
97             }
98         }
99 
100         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
101         [InlineData(LineCap.Square, LineCap.Square)]
102         [InlineData(LineCap.Round, LineCap.Round)]
103         [InlineData(LineCap.Triangle, LineCap.Triangle)]
SetThenGetStrokeCaps_Success(LineCap startCap, LineCap endCap)104         public void SetThenGetStrokeCaps_Success(LineCap startCap, LineCap endCap)
105         {
106             using (GraphicsPath strokePath = new GraphicsPath())
107             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
108             {
109                 customLineCap.SetStrokeCaps(startCap, endCap);
110                 customLineCap.GetStrokeCaps(out LineCap retrievedStartCap, out LineCap retrievedEndCap);
111 
112                 Assert.Equal(startCap, retrievedStartCap);
113                 Assert.Equal(endCap, retrievedEndCap);
114             }
115         }
116 
117         [ActiveIssue(20884, TestPlatforms.AnyUnix)]
118         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
119         [InlineData(LineCap.SquareAnchor, LineCap.SquareAnchor)]
120         [InlineData(LineCap.Custom, LineCap.Custom)]
121         [InlineData(LineCap.Square, LineCap.Custom)]
122         [InlineData(LineCap.Custom, LineCap.SquareAnchor)]
123         [InlineData(LineCap.Flat - 1, LineCap.Flat)] // Below valid enum range
124         [InlineData(LineCap.Custom + 1, LineCap.Flat)] // Above valid enum range
SetStrokeCaps_InvalidLineCap_ThrowsArgumentException(LineCap startCap, LineCap endCap)125         public void SetStrokeCaps_InvalidLineCap_ThrowsArgumentException(LineCap startCap, LineCap endCap)
126         {
127             using (GraphicsPath strokePath = new GraphicsPath())
128             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
129             {
130                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.SetStrokeCaps(startCap, endCap));
131 
132                 // start and end cap should be unchanged.
133                 customLineCap.GetStrokeCaps(out LineCap retrievedStartCap, out LineCap retrievedEndCap);
134                 Assert.Equal(LineCap.Flat, retrievedStartCap);
135                 Assert.Equal(LineCap.Flat, retrievedEndCap);
136             }
137         }
138 
139         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
140         [InlineData(LineJoin.Miter)] // Default value
141         [InlineData(LineJoin.Bevel)]
142         [InlineData(LineJoin.Round)]
143         [InlineData(LineJoin.MiterClipped)]
144         // Invalid (non-enum) values are allowed. Their values are stored and returned unchanged.
145         [InlineData(LineJoin.Miter - 1)]
146         [InlineData(LineJoin.MiterClipped + 1)]
StrokeJoin_SetThenGet_Success(LineJoin lineJoin)147         public void StrokeJoin_SetThenGet_Success(LineJoin lineJoin)
148         {
149             using (GraphicsPath strokePath = new GraphicsPath())
150             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
151             {
152                 customLineCap.StrokeJoin = lineJoin;
153                 Assert.Equal(lineJoin, customLineCap.StrokeJoin);
154             }
155         }
156 
157         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
158         [InlineData(LineCap.Flat)] // Default value
159         [InlineData(LineCap.Square)]
160         [InlineData(LineCap.Round)]
161         [InlineData(LineCap.Triangle)]
BaseCap_SetThenGet_Success(LineCap baseCap)162         public void BaseCap_SetThenGet_Success(LineCap baseCap)
163         {
164             using (GraphicsPath strokePath = new GraphicsPath())
165             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
166             {
167                 customLineCap.BaseCap = baseCap;
168                 Assert.Equal(baseCap, customLineCap.BaseCap);
169             }
170         }
171 
172         [InlineData(LineCap.NoAnchor)]
173         [InlineData(LineCap.SquareAnchor)]
174         [InlineData(LineCap.RoundAnchor)]
175         [InlineData(LineCap.DiamondAnchor)]
176         [InlineData(LineCap.Custom)]
177         [InlineData(LineCap.Flat - 1)]
178         [InlineData(LineCap.Custom + 1)]
BaseCap_Set_InvalidLineCap_ThrowsArgumentException(LineCap baseCap)179         public void BaseCap_Set_InvalidLineCap_ThrowsArgumentException(LineCap baseCap)
180         {
181             using (GraphicsPath strokePath = new GraphicsPath())
182             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
183             {
184                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.BaseCap = baseCap);
185                 Assert.Equal(LineCap.Flat, customLineCap.BaseCap);
186             }
187         }
188 
189         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
190         [InlineData(0f)]
191         [InlineData(1f)]
192         [InlineData(10f)]
193         [InlineData(10000f)]
194         [InlineData(-1f)]
195         [InlineData(-10f)]
196         [InlineData(-10000f)]
197         [InlineData(float.MaxValue)]
198         [InlineData(float.MinValue)]
199         [InlineData(float.PositiveInfinity)]
200         [InlineData(float.NegativeInfinity)]
201         [InlineData(float.NaN)]
BaseInset_SetThenGet_Success(float value)202         public void BaseInset_SetThenGet_Success(float value)
203         {
204             using (GraphicsPath strokePath = new GraphicsPath())
205             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
206             {
207                 customLineCap.BaseInset = value;
208                 Assert.Equal(value, customLineCap.BaseInset);
209             }
210         }
211 
212         [ConditionalTheory(Helpers.GdiplusIsAvailable)]
213         [InlineData(0f)]
214         [InlineData(1f)]
215         [InlineData(10f)]
216         [InlineData(10000f)]
217         [InlineData(-1f)]
218         [InlineData(-10f)]
219         [InlineData(-10000f)]
220         [InlineData(float.MaxValue)]
221         [InlineData(float.MinValue)]
222         [InlineData(float.PositiveInfinity)]
223         [InlineData(float.NegativeInfinity)]
224         [InlineData(float.NaN)]
WidthScale_SetThenGet_Success(float value)225         public void WidthScale_SetThenGet_Success(float value)
226         {
227             using (GraphicsPath strokePath = new GraphicsPath())
228             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
229             {
230                 customLineCap.WidthScale = value;
231                 Assert.Equal(value, customLineCap.WidthScale);
232             }
233         }
234 
235         [ConditionalFact(Helpers.GdiplusIsAvailable)]
Disposed_MembersThrow()236         public void Disposed_MembersThrow()
237         {
238             using (GraphicsPath strokePath = new GraphicsPath())
239             using (CustomLineCap customLineCap = new CustomLineCap(null, strokePath))
240             {
241                 customLineCap.Dispose();
242                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.StrokeJoin);
243                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.BaseCap);
244                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.BaseInset);
245                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.WidthScale);
246                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.Clone());
247                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.SetStrokeCaps(LineCap.Flat, LineCap.Flat));
248                 AssertExtensions.Throws<ArgumentException>(null, () => customLineCap.GetStrokeCaps(out LineCap startCap, out LineCap endCap));
249             }
250         }
251     }
252 }
253