Explorar el Código

Add tests for the Line element

Marcin Ziąbek hace 2 meses
padre
commit
121ac0fe11

+ 53 - 0
Source/QuestPDF.LayoutTests/LineTests.cs

@@ -0,0 +1,53 @@
+namespace QuestPDF.LayoutTests;
+
+public class LineTests
+{
+    [Test]
+    public void VerticalLineRequiresSpaceEqualToItsThickness()
+    {
+        LayoutTest
+            .HavingSpaceOfSize(5, 100)
+            .ForContent(content =>
+            {
+                content.Shrink().LineVertical(10);
+            })
+            .ExpectLayoutException("The line thickness is greater than the available horizontal space.");
+    }
+    
+    [Test]
+    public void HorizontalLineRequiresSpaceEqualToItsThickness()
+    {
+        LayoutTest
+            .HavingSpaceOfSize(100, 5)
+            .ForContent(content =>
+            {
+                content.Shrink().LineHorizontal(10);
+            })
+            .ExpectLayoutException("The line thickness is greater than the available vertical space.");
+    }
+    
+    #region Stateful
+    
+    [Test]
+    public void CheckRenderingState()
+    {
+        LayoutTest
+            .HavingSpaceOfSize(240, 100)
+            .ForContent(content =>
+            {
+                content.ShrinkVertical().Mock("a").LineHorizontal(2);
+            })
+            .ExpectDrawResult(document =>
+            {
+                document
+                    .Page()
+                    .RequiredAreaSize(0, 2)
+                    .Content(page =>
+                    {
+                        page.Mock("a").Position(0, 0).Size(240, 2).State(true);
+                    });
+            });
+    }
+    
+    #endregion
+}

+ 256 - 0
Source/QuestPDF.UnitTests/LineTests.cs

@@ -0,0 +1,256 @@
+using System;
+using NUnit.Framework;
+using QuestPDF.Elements;
+using QuestPDF.Fluent;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests;
+
+public class LineTests
+{
+    #region Line Types
+    
+    [Test]
+    public void VerticalLineTypeIsSetCorrectly()
+    {
+        var container = EmptyContainer.Create();
+        container.LineVertical(2);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Type, Is.EqualTo(LineType.Vertical));
+        Assert.That(line?.Thickness, Is.EqualTo(2));
+    }
+    
+    [Test]
+    public void HorizontalLineTypeIsSetCorrectly()
+    {
+        var container = EmptyContainer.Create();
+        container.LineHorizontal(3);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Type, Is.EqualTo(LineType.Horizontal));
+        Assert.That(line?.Thickness, Is.EqualTo(3));
+    }
+    
+    #endregion
+    
+    #region Line Thickness
+    
+    [Test]
+    public void VerticalLineThicknessSupportsUnitConversion()
+    {
+        var container = EmptyContainer.Create();
+        container.LineVertical(2, Unit.Inch);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Thickness, Is.EqualTo(144));
+    }
+    
+    [TestCase(-5f)]
+    [TestCase(-float.Epsilon)]
+    public void LineThicknessCannotBeNegative(float thickness)
+    {
+        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(thickness);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The Line thickness cannot be negative. (Parameter 'thickness')"));
+    }
+    
+    [Test]
+    public void LineThicknessCanBeEqualToZero()
+    {
+        // thickness 0 corresponds to a hairline
+        
+        var container = EmptyContainer.Create();
+        container.LineHorizontal(0);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Thickness, Is.EqualTo(0));
+    }
+    
+    [Test]
+    public void HorizontalLineThicknessSupportsUnitConversion()
+    {
+        var container = EmptyContainer.Create();
+        container.LineHorizontal(3, Unit.Inch);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Thickness, Is.EqualTo(216));
+    }
+    
+    #endregion
+    
+    [Test]
+    public void LineColorIsSetCorrectly()
+    {
+        var container = EmptyContainer.Create();
+        container.LineHorizontal(1).LineColor(Colors.Red.Medium);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.Color, Is.EqualTo(Colors.Red.Medium));
+    }
+    
+    #region Line Dash Pattern
+    
+    [Test]
+    public void LineDashPatternCannotBeNull()
+    {
+        var exception = Assert.Throws<ArgumentNullException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(1)
+                .LineDashPattern(null);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The dash pattern cannot be null. (Parameter 'dashPattern')"));
+    }
+    
+    [Test]
+    public void LineDashPatternCannotBeEmpty()
+    {
+        var exception = Assert.Throws<ArgumentException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(1)
+                .LineDashPattern([]);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The dash pattern cannot be empty. (Parameter 'dashPattern')"));
+    }
+    
+    [Test]
+    public void LineDashPatternMustHaveEvenNumberOfElements()
+    {
+        var exception = Assert.Throws<ArgumentException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(1)
+                .LineDashPattern([ 1, 2, 3 ]);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The dash pattern must contain an even number of elements. (Parameter 'dashPattern')"));
+    }
+    
+    [Test]
+    public void LineDashPatternIsSetCorrectly()
+    {
+        var container = EmptyContainer.Create();
+
+        container
+            .LineVertical(1)
+            .LineDashPattern([1, 2, 3, 4]);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.DashPattern, Is.EquivalentTo([ 1, 2, 3, 4 ]));
+    }
+    
+    [Test]
+    public void LineDashPatternSupportsUnitConversion()
+    {
+        var container = EmptyContainer.Create();
+
+        container
+            .LineVertical(1)
+            .LineDashPattern([1, 2, 3, 4], Unit.Inch);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.DashPattern, Is.EquivalentTo([ 72, 144, 216, 288 ]));
+    }
+    
+    #endregion
+    
+    #region Gradient Colors
+    
+    [Test]
+    public void LineGradientColorsCannotBeBull()
+    {
+        var exception = Assert.Throws<ArgumentNullException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(1)
+                .LineGradient(null);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The gradient colors cannot be null. (Parameter 'colors')"));
+    }
+    
+    [Test]
+    public void LineGradientColorsCannotBeEmpty()
+    {
+        var exception = Assert.Throws<ArgumentException>(() =>
+        {
+            EmptyContainer
+                .Create()
+                .LineVertical(1)
+                .LineGradient([]);
+        });
+        
+        Assert.That(exception.Message, Is.EqualTo("The gradient colors cannot be empty. (Parameter 'colors')"));
+    }
+    
+    [Test]
+    public void LineGradientColorsAreSetCorrectly()
+    {
+        var container = EmptyContainer.Create();
+            
+        container
+            .LineVertical(1)
+            .LineGradient([Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium]);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.GradientColors, Is.EquivalentTo([ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ]));
+    }
+    
+    #endregion
+    
+    #region Companion Hint
+    
+    [Test]
+    public void VerticalLineCompanionHint()
+    {
+        var container = EmptyContainer.Create();
+        container.LineVertical(123.45f);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.GetCompanionHint(), Is.EqualTo("Vertical 123.5"));
+    }
+    
+    [Test]
+    public void HorizontalLineCompanionHint()
+    {
+        var container = EmptyContainer.Create();
+        container.LineHorizontal(234.56f);
+        
+        var line = container.Child as Line;
+        Assert.That(line?.GetCompanionHint(), Is.EqualTo("Horizontal 234.6"));
+    }
+    
+    #endregion
+    
+    [Test]
+    [Repeat(10)]
+    public void LineSupportsStatefulOperations()
+    {
+        var container = EmptyContainer.Create();
+
+        container.LineHorizontal(1);
+        
+        var line = container.Child as Line;
+        
+        Assert.That(line.GetState(), Is.EqualTo(false));
+        line.SetState(true);
+        Assert.That(line.GetState(), Is.EqualTo(true));
+        
+        line.ResetState();
+        Assert.That(line.GetState(), Is.EqualTo(false));
+    }
+}

BIN
Source/QuestPDF.VisualTests/ExpectedOutput/Line/LineShouldRenderOnlyOnce_0.png


BIN
Source/QuestPDF.VisualTests/ExpectedOutput/Line/LineShouldRenderOnlyOnce_1.png


BIN
Source/QuestPDF.VisualTests/ExpectedOutput/Line/LineShouldRerenderWhenCombinedWithRepeat_0.png


BIN
Source/QuestPDF.VisualTests/ExpectedOutput/Line/LineShouldRerenderWhenCombinedWithRepeat_1.png


+ 44 - 0
Source/QuestPDF.VisualTests/LineTests.cs

@@ -111,4 +111,48 @@ public class LineTests
                 .LineGradient([Colors.Red.Medium, Colors.Orange.Medium, Colors.Yellow.Medium]);
                 .LineGradient([Colors.Red.Medium, Colors.Orange.Medium, Colors.Yellow.Medium]);
         });
         });
     }
     }
+    
+    #region IStateful
+    
+    [Test]
+    public void LineShouldRenderOnlyOnce()
+    {
+        VisualTest.PerformWithDefaultPageSettings(container =>
+        {
+            container
+                .Height(400)
+                .Width(400)
+                .Row(row =>
+                {
+                    row.RelativeItem().LineHorizontal(10);
+                    row.RelativeItem().Column(column =>
+                    {
+                        column.Item().Height(300).Background(Colors.Blue.Lighten1);
+                        column.Item().Height(200).Background(Colors.Blue.Lighten3);
+                    });
+                });
+        });
+    }
+    
+    [Test]
+    public void LineShouldRerenderWhenCombinedWithRepeat()
+    {
+        VisualTest.PerformWithDefaultPageSettings(container =>
+        {
+            container
+                .Height(400)
+                .Width(400)
+                .Row(row =>
+                {
+                    row.RelativeItem().Repeat().LineHorizontal(10);
+                    row.RelativeItem().Column(column =>
+                    {
+                        column.Item().Height(300).Background(Colors.Blue.Lighten1);
+                        column.Item().Height(200).Background(Colors.Blue.Lighten3);
+                    });
+                });
+        });
+    }
+    
+    #endregion
 }
 }

+ 1 - 0
Source/QuestPDF/Elements/Line.cs

@@ -30,6 +30,7 @@ namespace QuestPDF.Elements
             if (IsRendered)
             if (IsRendered)
                 return SpacePlan.Empty();
                 return SpacePlan.Empty();
             
             
+            // TODO: this code is defensive, taking into account conditions below, it is not needed
             if (availableSpace.IsNegative())
             if (availableSpace.IsNegative())
                 return SpacePlan.Wrap("The available space is negative.");
                 return SpacePlan.Wrap("The available space is negative.");
 
 

+ 9 - 0
Source/QuestPDF/Skia/SkPaint.cs

@@ -22,6 +22,9 @@ internal sealed class SkPaint : IDisposable
     
     
     public void SetLinearGradient(Position start, Position end, Color[] colors)
     public void SetLinearGradient(Position start, Position end, Color[] colors)
     {
     {
+        if (colors.Length == 0)
+            throw new ArgumentException("At least one color must be provided to create a gradient.", nameof(colors));
+        
         var startPoint = new SkPoint(start.X, start.Y);
         var startPoint = new SkPoint(start.X, start.Y);
         var endPoint = new SkPoint(end.X, end.Y);
         var endPoint = new SkPoint(end.X, end.Y);
         
         
@@ -37,6 +40,12 @@ internal sealed class SkPaint : IDisposable
     
     
     public void SetDashedPathEffect(float[] intervals)
     public void SetDashedPathEffect(float[] intervals)
     {
     {
+        if (intervals.Length == 0)
+            throw new ArgumentException("At least one interval must be provided to create a dashed path effect.", nameof(intervals));
+        
+        if (intervals.Length % 2 != 0)
+            throw new ArgumentException("The intervals array must contain an even number of elements.", nameof(intervals));
+        
         API.paint_set_dashed_path_effect(Instance, intervals.Length, intervals);
         API.paint_set_dashed_path_effect(Instance, intervals.Length, intervals);
     }
     }