Browse Source

Fixed: AspectRatio behaviour does not take into account child measurement. Added tests for AspectRatio, Image and DynamicImage elements. Small TestPlan framework improvements.

MarcinZiabek 4 years ago
parent
commit
c5cb588857

+ 0 - 1
QuestPDF.Examples/QuestPDF.Examples.csproj

@@ -13,7 +13,6 @@
     </ItemGroup>
     </ItemGroup>
 
 
     <ItemGroup>
     <ItemGroup>
-      <ProjectReference Include="..\QuestPDF.InvoiceSample\QuestPDF.InvoiceSample.csproj" />
       <ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
       <ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
     </ItemGroup>
     </ItemGroup>
 
 

+ 14 - 14
QuestPDF.UnitTests/AlignmentTests.cs

@@ -21,10 +21,10 @@ namespace QuestPDF.UnitTests
             TestPlan
             TestPlan
                 .For(x => new Alignment
                 .For(x => new Alignment
                 {
                 {
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(1000, 500))
                 .MeasureElement(new Size(1000, 500))
-                .ExpectChildMeasure("child", expectedInput: new Size(1000, 500), returns: new Wrap())
+                .ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: new Wrap())
                 .CheckMeasureResult(new Wrap());
                 .CheckMeasureResult(new Wrap());
         }
         }
 
 
@@ -37,12 +37,12 @@ namespace QuestPDF.UnitTests
                     Horizontal = HorizontalAlignment.Center,
                     Horizontal = HorizontalAlignment.Center,
                     Vertical = VerticalAlignment.Middle,
                     Vertical = VerticalAlignment.Middle,
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(1000, 500))
                 .DrawElement(new Size(1000, 500))
-                .ExpectChildMeasure("child", expectedInput: new Size(1000, 500), returns: new PartialRender(new Size(400, 200)))
+                .ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: new PartialRender(new Size(400, 200)))
                 .ExpectCanvasTranslate(new Position(300, 150))
                 .ExpectCanvasTranslate(new Position(300, 150))
-                .ExpectChildDraw("child", new Size(400, 200))
+                .ExpectChildDraw(new Size(400, 200))
                 .ExpectCanvasTranslate(new Position(-300, -150))
                 .ExpectCanvasTranslate(new Position(-300, -150))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
@@ -56,12 +56,12 @@ namespace QuestPDF.UnitTests
                     Horizontal = HorizontalAlignment.Left,
                     Horizontal = HorizontalAlignment.Left,
                     Vertical = VerticalAlignment.Middle,
                     Vertical = VerticalAlignment.Middle,
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
+                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
                 .ExpectCanvasTranslate(new Position(0, 125))
                 .ExpectCanvasTranslate(new Position(0, 125))
-                .ExpectChildDraw("child", new Size(100, 50))
+                .ExpectChildDraw(new Size(100, 50))
                 .ExpectCanvasTranslate(new Position(0, -125))
                 .ExpectCanvasTranslate(new Position(0, -125))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
@@ -75,12 +75,12 @@ namespace QuestPDF.UnitTests
                     Horizontal = HorizontalAlignment.Center,
                     Horizontal = HorizontalAlignment.Center,
                     Vertical = VerticalAlignment.Bottom,
                     Vertical = VerticalAlignment.Bottom,
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
+                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
                 .ExpectCanvasTranslate(new Position(150, 250))
                 .ExpectCanvasTranslate(new Position(150, 250))
-                .ExpectChildDraw("child", new Size(100, 50))
+                .ExpectChildDraw(new Size(100, 50))
                 .ExpectCanvasTranslate(new Position(-150, -250))
                 .ExpectCanvasTranslate(new Position(-150, -250))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
@@ -94,12 +94,12 @@ namespace QuestPDF.UnitTests
                     Horizontal = HorizontalAlignment.Right,
                     Horizontal = HorizontalAlignment.Right,
                     Vertical = VerticalAlignment.Top,
                     Vertical = VerticalAlignment.Top,
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
+                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
                 .ExpectCanvasTranslate(new Position(300, 0))
                 .ExpectCanvasTranslate(new Position(300, 0))
-                .ExpectChildDraw("child", new Size(100, 50))
+                .ExpectChildDraw(new Size(100, 50))
                 .ExpectCanvasTranslate(new Position(-300, 0))
                 .ExpectCanvasTranslate(new Position(-300, 0))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }

+ 163 - 0
QuestPDF.UnitTests/AspectRatioTests.cs

@@ -15,5 +15,168 @@ namespace QuestPDF.UnitTests
         
         
         [Test]
         [Test]
         public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
         public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
+        
+        [Test]
+        public void Measure_FitWidth_EnoughSpace_FullRender()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 201))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
+                .CheckMeasureResult(new FullRender(400, 200));
+        }
+        
+        [Test]
+        public void Measure_FitWidth_EnoughSpace_PartialRender()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 201))
+                .ExpectChildMeasure(new Size(400, 200), new PartialRender(100, 50))
+                .CheckMeasureResult(new PartialRender(400, 200));
+        }
+        
+        [Test]
+        public void Measure_FitWidth_EnoughSpace_Wrap()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 201))
+                .ExpectChildMeasure(new Size(400, 200), new Wrap())
+                .CheckMeasureResult(new Wrap());
+        }
+        
+        [Test]
+        public void Measure_FitWidth_EnoughSpace()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitWidth,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 201))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
+                .CheckMeasureResult(new FullRender(400, 200));
+        }
+
+        [Test]
+        public void Measure_FitWidth_NotEnoughSpace()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitWidth,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 199))
+                .CheckMeasureResult(new Wrap());
+        }
+        
+        [Test]
+        public void Measure_FitHeight_EnoughSpace()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitHeight,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(401, 200))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
+                .CheckMeasureResult(new FullRender(400, 200));
+        }
+        
+        [Test]
+        public void Measure_FitHeight_NotEnoughSpace()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitHeight,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(399, 200))
+                .CheckMeasureResult(new Wrap());
+        }
+        
+        [Test]
+        public void Measure_FitArea_ToWidth()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
+                .CheckMeasureResult(new FullRender(400, 200));
+        }
+        
+        [Test]
+        public void Measure_FitArea_ToHeight()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .MeasureElement(new Size(500, 200))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
+                .CheckMeasureResult(new FullRender(400, 200));
+        }
+        
+        [Test]
+        public void DrawChild_PerWidth()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .DrawElement(new Size(500, 200))
+                .ExpectChildDraw(new Size(400, 200))
+                .CheckDrawResult();
+        }
+        
+        [Test]
+        public void DrawChild_PerHeight()
+        {
+            TestPlan
+                .For(x => new AspectRatio
+                {
+                    Child = x.CreateChild(),
+                    Option = AspectRatioOption.FitArea,
+                    Ratio = 2f
+                })
+                .DrawElement(new Size(400, 300))
+                .ExpectChildDraw(new Size(400, 200))
+                .CheckDrawResult();
+        } 
     }
     }
 }
 }

+ 2 - 2
QuestPDF.UnitTests/BackgroundTests.cs

@@ -31,11 +31,11 @@ namespace QuestPDF.UnitTests
                 .For(x => new Background
                 .For(x => new Background
                 {
                 {
                     Color = "#F00",
                     Color = "#F00",
-                    Child = x.CreateChild("a")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), "#F00")
                 .ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), "#F00")
-                .ExpectChildDraw("a", new Size(400, 300))
+                .ExpectChildDraw(new Size(400, 300))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
     }
     }

+ 5 - 5
QuestPDF.UnitTests/BorderTests.cs

@@ -23,10 +23,10 @@ namespace QuestPDF.UnitTests
                     Bottom = 30,
                     Bottom = 30,
                     Left = 40,
                     Left = 40,
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
+                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
                 .CheckMeasureResult( new FullRender(new Size(100, 50)));
                 .CheckMeasureResult( new FullRender(new Size(100, 50)));
         }
         }
         
         
@@ -43,15 +43,15 @@ namespace QuestPDF.UnitTests
                     
                     
                     Color = "#FF0000",
                     Color = "#FF0000",
                     
                     
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
-                .ExpectChildDraw("child", new Size(400, 300))
+                .ExpectChildDraw(new Size(400, 300))
                 .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(430, 10), "#FF0000") // top
                 .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(430, 10), "#FF0000") // top
                 .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(40, 320), "#FF0000") // left
                 .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(40, 320), "#FF0000") // left
                 .ExpectCanvasDrawRectangle(new Position(-20, 285), new Size(430, 30), "#FF0000") // bottom
                 .ExpectCanvasDrawRectangle(new Position(-20, 285), new Size(430, 30), "#FF0000") // bottom
                 .ExpectCanvasDrawRectangle(new Position(390, -5), new Size(20, 320), "#FF0000") // right
                 .ExpectCanvasDrawRectangle(new Position(390, -5), new Size(20, 320), "#FF0000") // right
-                .ExpectChildDraw("child", new Size(400, 300))
+                .ExpectChildDraw(new Size(400, 300))
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
     }
     }

+ 8 - 8
QuestPDF.UnitTests/ConstrainedTests.cs

@@ -34,10 +34,10 @@ namespace QuestPDF.UnitTests
                 .For(x => new Constrained
                 .For(x => new Constrained
                 {
                 {
                     MinHeight = 100,
                     MinHeight = 100,
-                    Child = x.CreateChild("a")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(400, 200))
                 .MeasureElement(new Size(400, 200))
-                .ExpectChildMeasure("a", new Size(400, 200), new FullRender(400, 50))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(400, 50))
                 .CheckMeasureResult(new FullRender(400, 100));
                 .CheckMeasureResult(new FullRender(400, 100));
         }
         }
         
         
@@ -48,10 +48,10 @@ namespace QuestPDF.UnitTests
                 .For(x => new Constrained
                 .For(x => new Constrained
                 {
                 {
                     MinHeight = 100,
                     MinHeight = 100,
-                    Child = x.CreateChild("a")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(400, 200))
                 .MeasureElement(new Size(400, 200))
-                .ExpectChildMeasure("a", new Size(400, 200), new FullRender(400, 150))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(400, 150))
                 .CheckMeasureResult(new FullRender(400, 150));
                 .CheckMeasureResult(new FullRender(400, 150));
         }
         }
         
         
@@ -74,10 +74,10 @@ namespace QuestPDF.UnitTests
                 .For(x => new Constrained
                 .For(x => new Constrained
                 {
                 {
                     MaxHeight = 100,
                     MaxHeight = 100,
-                    Child = x.CreateChild("a")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(400, 200))
                 .MeasureElement(new Size(400, 200))
-                .ExpectChildMeasure("a", new Size(400, 100), new PartialRender(400, 75))
+                .ExpectChildMeasure(new Size(400, 100), new PartialRender(400, 75))
                 .CheckMeasureResult(new PartialRender(400, 75));
                 .CheckMeasureResult(new PartialRender(400, 75));
         }
         }
         
         
@@ -88,10 +88,10 @@ namespace QuestPDF.UnitTests
                 .For(x => new Constrained
                 .For(x => new Constrained
                 {
                 {
                     MaxHeight = 100,
                     MaxHeight = 100,
-                    Child = x.CreateChild("a")
+                    Child = x.CreateChild()
                 })
                 })
                 .MeasureElement(new Size(400, 200))
                 .MeasureElement(new Size(400, 200))
-                .ExpectChildMeasure("a", new Size(400, 100), new Wrap())
+                .ExpectChildMeasure(new Size(400, 100), new Wrap())
                 .CheckMeasureResult(new Wrap());
                 .CheckMeasureResult(new Wrap());
         }
         }
     }
     }

+ 77 - 1
QuestPDF.UnitTests/DynamicImageTests.cs

@@ -1,10 +1,86 @@
-using NUnit.Framework;
+using System;
+using FluentAssertions;
+using NUnit.Framework;
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Elements;
+using QuestPDF.Infrastructure;
+using QuestPDF.UnitTests.TestEngine;
+using SkiaSharp;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {
     [TestFixture]
     [TestFixture]
     public class DynamicImageTests
     public class DynamicImageTests
     {
     {
+        [Test]
+        public void Measure_TakesAvailableSpaceRegardlessOfSize()
+        {
+            TestPlan
+                .For(x => new DynamicImage
+                {
+                    Source = GenerateImage
+                })
+                .MeasureElement(new Size(300, 200))
+                .CheckMeasureResult(new FullRender(300, 200));
+        }
         
         
+        [Test]
+        public void Draw_HandlesNull()
+        {
+            TestPlan
+                .For(x => new DynamicImage
+                {
+                    Source = size => null
+                })
+                .DrawElement(new Size(300, 200))
+                .CheckDrawResult();
+        }
+        
+        [Test]
+        public void Draw_PreservesSize()
+        {
+            TestPlan
+                .For(x => new DynamicImage
+                {
+                    Source = GenerateImage
+                })
+                .DrawElement(new Size(300, 200))
+                .ExpectCanvasDrawImage(Position.Zero, new Size(300, 200))
+                .CheckDrawResult();
+        }
+        
+        [Test]
+        public void Draw_PassesCorrectSizeToSource()
+        {
+            Size passedSize = null;
+
+            TestPlan
+                .For(x => new DynamicImage
+                {
+                    Source = size =>
+                    {
+                        passedSize = size;
+                        return GenerateImage(size);
+                    }
+                })
+                .DrawElement(new Size(400, 300))
+                .ExpectCanvasDrawImage(Position.Zero, new Size(400, 300))
+                .CheckDrawResult();
+            
+            passedSize.Should().Be(new Size(400, 300));
+        }
+        
+        byte[] GenerateImage(Size size)
+        {
+            var image = GenerateImage((int) size.Width, (int) size.Height);
+            return image.Encode(SKEncodedImageFormat.Png, 100).ToArray();
+        }
+        
+        SKImage GenerateImage(int width, int height)
+        {
+            var imageInfo = new SKImageInfo(width, height);
+            using var surface = SKSurface.Create(imageInfo);
+            return surface.Snapshot();
+        }
     }
     }
 }
 }

+ 0 - 10
QuestPDF.UnitTests/EmptyTests.cs

@@ -1,10 +0,0 @@
-using NUnit.Framework;
-
-namespace QuestPDF.UnitTests
-{
-    [TestFixture]
-    public class EmptyTests
-    {
-        
-    }
-}

+ 54 - 9
QuestPDF.UnitTests/ImageTests.cs

@@ -1,7 +1,12 @@
 using Moq;
 using Moq;
 using NUnit.Framework;
 using NUnit.Framework;
+using QuestPDF.Drawing;
+using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
+using QuestPDF.Fluent;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
+using QuestPDF.UnitTests.TestEngine;
+using SkiaSharp;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {
@@ -9,17 +14,57 @@ namespace QuestPDF.UnitTests
     public class ImageTests
     public class ImageTests
     {
     {
         [Test]
         [Test]
-        public void Draw_ShouldHandleNullChild()
+        public void Measure_ShouldHandleNullChild() => new AspectRatio().MeasureWithoutChild();
+        
+        [Test]
+        public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
+        
+        [Test]
+        public void Measure_TakesAvailableSpaceRegardlessOfSize()
+        {
+            TestPlan
+                .For(x => new Image
+                {
+                    InternalImage = GenerateImage(400, 300)
+                })
+                .MeasureElement(new Size(300, 200))
+                .CheckMeasureResult(new FullRender(300, 200));
+        }
+        
+        [Test]
+        public void Draw_TakesAvailableSpaceRegardlessOfSize()
         {
         {
-            Assert.DoesNotThrow(() =>
-            {
-                var image = new Image()
+            TestPlan
+                .For(x => new Image
                 {
                 {
-                    InternalImage = null
-                };
-                
-                image.Draw(It.IsAny<ICanvas>(), Size.Zero);
-            });
+                    InternalImage = GenerateImage(400, 300)
+                })
+                .DrawElement(new Size(300, 200))
+                .ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))
+                .CheckDrawResult();
+        }
+        
+        [Test]
+        public void Fluent_RecognizesImageProportions()
+        {
+            var image = GenerateImage(600, 200).Encode(SKEncodedImageFormat.Png, 100).ToArray();
+            
+            TestPlan
+                .For(x =>
+                {
+                    var container = new Container();
+                    container.Image(image);
+                    return container;
+                })
+                .MeasureElement(new Size(300, 200))
+                .CheckMeasureResult(new FullRender(300, 100));;
+        }
+        
+        SKImage GenerateImage(int width, int height)
+        {
+            var imageInfo = new SKImageInfo(width, height);
+            using var surface = SKSurface.Create(imageInfo);
+            return surface.Snapshot();
         }
         }
     }
     }
 }
 }

+ 54 - 39
QuestPDF.UnitTests/PaddingTests.cs

@@ -17,62 +17,77 @@ namespace QuestPDF.UnitTests
         [Test]
         [Test]
         public void Draw_ShouldHandleNullChild() => new Padding().DrawWithoutChild();
         public void Draw_ShouldHandleNullChild() => new Padding().DrawWithoutChild();
         
         
-        private Padding GetPadding(Element child)
+        private Padding GetPadding(TestPlan plan)
         {
         {
             return new Padding()
             return new Padding()
             {
             {
-                Top = 5,
-                Right = 10,
-                Bottom = 15,
-                Left = 20,
+                Top = 10,
+                Right = 20,
+                Bottom = 30,
+                Left = 40,
                 
                 
-                Child = child
+                Child = plan.CreateChild()
             };
             };
         }
         }
 
 
         [Test]
         [Test]
-        public void Measure_WhenChildReturnsWrap_ReturnsWrap()
+        public void Measure_General_EnoughSpace()
         {
         {
-            var child = new Mock<Element>();
-            
-            child
-                .Setup(x => x.Measure(It.IsAny<Size>()))
-                .Returns(() => new Wrap());
-
-            GetPadding(child.Object)
-                .Measure(Size.Zero)
-                .Should()
-                .BeOfType<Wrap>();
+            TestPlan
+                .For(GetPadding)
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure(new Size(340, 260), new FullRender(140, 60))
+                .CheckMeasureResult(new FullRender(200, 100));
+        } 
+        
+        [Test]
+        public void Measure_NotEnoughWidth()
+        {
+            TestPlan
+                .For(GetPadding)
+                .MeasureElement(new Size(50, 300))
+                .CheckMeasureResult(new Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_WhenChildReturnsFullRender_ReturnsFullRender()
+        public void Measure_NotEnoughHeight()
         {
         {
-            var child = new Mock<Element>();
-            
-            child
-                .Setup(x => x.Measure(It.IsAny<Size>()))
-                .Returns(() => new FullRender(Size.Zero));
-
-            GetPadding(child.Object)
-                .Measure(Size.Zero)
-                .Should()
-                .BeOfType<FullRender>();
+            TestPlan
+                .For(GetPadding)
+                .MeasureElement(new Size(20, 300))
+                .CheckMeasureResult(new Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_WhenChildReturnsPartialRender_ReturnsPartialRender()
+        public void Measure_AcceptsPartialRender()
         {
         {
-            var child = new Mock<Element>();
-            
-            child
-                .Setup(x => x.Measure(It.IsAny<Size>()))
-                .Returns(() => new PartialRender(Size.Zero));
-
-            GetPadding(child.Object)
-                .Measure(Size.Zero)
-                .Should()
-                .BeOfType<PartialRender>();
+            TestPlan
+                .For(GetPadding)
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure(new Size(340, 260), new PartialRender(40, 160))
+                .CheckMeasureResult(new PartialRender(100, 200));
+        }
+        
+        [Test]
+        public void Measure_AcceptsWrap()
+        {
+            TestPlan
+                .For(GetPadding)
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure(new Size(340, 260), new Wrap())
+                .CheckMeasureResult(new Wrap());
+        }
+        
+        [Test]
+        public void Draw_General()
+        {
+            TestPlan
+                .For(GetPadding)
+                .DrawElement(new Size(400, 300))
+                .ExpectCanvasTranslate(new Position(40, 10))
+                .ExpectChildDraw(new Size(340, 260))
+                .ExpectCanvasTranslate(new Position(-40, -10))
+                .CheckDrawResult();
         }
         }
     }
     }
 }
 }

+ 0 - 10
QuestPDF.UnitTests/PlaceholderTests.cs

@@ -1,10 +0,0 @@
-using NUnit.Framework;
-
-namespace QuestPDF.UnitTests
-{
-    [TestFixture]
-    public class PlaceholderTests
-    {
-        
-    }
-}

+ 6 - 6
QuestPDF.UnitTests/ShowOnceTest.cs

@@ -42,7 +42,7 @@ namespace QuestPDF.UnitTests
             TestPlan
             TestPlan
                 .For(x => new ShowOnce()
                 .For(x => new ShowOnce()
                 {
                 {
-                    Child = x.CreateChild("child")
+                    Child = x.CreateChild()
                 })
                 })
                 
                 
                 // Measure the element and return result
                 // Measure the element and return result
@@ -52,21 +52,21 @@ namespace QuestPDF.UnitTests
                 
                 
                 // Draw element partially
                 // Draw element partially
                 .DrawElement(new Size(200, 200))
                 .DrawElement(new Size(200, 200))
-                .ExpectChildMeasure("child", new Size(200, 200), new PartialRender(new Size(200, 200)))
-                .ExpectChildDraw("child", new Size(200, 200))
+                .ExpectChildMeasure(new Size(200, 200), new PartialRender(new Size(200, 200)))
+                .ExpectChildDraw(new Size(200, 200))
                 .CheckDrawResult()
                 .CheckDrawResult()
                 
                 
                 // Element was not fully drawn
                 // Element was not fully drawn
                 // It should be measured again for rendering on next page
                 // It should be measured again for rendering on next page
                 .MeasureElement(new Size(800, 200))
                 .MeasureElement(new Size(800, 200))
-                .ExpectChildMeasure("child", new Size(800, 200), new FullRender(new Size(400, 200)))
+                .ExpectChildMeasure(new Size(800, 200), new FullRender(new Size(400, 200)))
                 .CheckMeasureResult(new FullRender(new Size(400, 200)))
                 .CheckMeasureResult(new FullRender(new Size(400, 200)))
 
 
                 // Draw element on next page
                 // Draw element on next page
                 // Element was fully drawn at this point
                 // Element was fully drawn at this point
                 .DrawElement(new Size(400, 200))
                 .DrawElement(new Size(400, 200))
-                .ExpectChildMeasure("child", new Size(400, 200), new FullRender(new Size(400, 200)))
-                .ExpectChildDraw("child", new Size(400, 200))
+                .ExpectChildMeasure(new Size(400, 200), new FullRender(new Size(400, 200)))
+                .ExpectChildDraw(new Size(400, 200))
                 .CheckDrawResult()
                 .CheckDrawResult()
                 
                 
                 // In the next attempt of measuring element, it should behave like empty parent.
                 // In the next attempt of measuring element, it should behave like empty parent.

+ 14 - 0
QuestPDF.UnitTests/TestEngine/TestPlan.cs

@@ -10,6 +10,8 @@ namespace QuestPDF.UnitTests.TestEngine
 {
 {
     internal class TestPlan
     internal class TestPlan
     {
     {
+        private const string DefaultChildName = "child";
+        
         private Element Element { get; set; }
         private Element Element { get; set; }
         private ICanvas Canvas { get; }
         private ICanvas Canvas { get; }
         
         
@@ -100,6 +102,8 @@ namespace QuestPDF.UnitTests.TestEngine
                 }
                 }
             };
             };
         }
         }
+
+        public Element CreateChild() => CreateChild(DefaultChildName);
         
         
         public Element CreateChild(string id)
         public Element CreateChild(string id)
         {
         {
@@ -153,11 +157,21 @@ namespace QuestPDF.UnitTests.TestEngine
             return this;
             return this;
         }
         }
         
         
+        public TestPlan ExpectChildMeasure(Size expectedInput, ISpacePlan returns)
+        {
+            return ExpectChildMeasure(DefaultChildName, expectedInput, returns);
+        }
+        
         public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
         public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
         {
         {
             return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns));
             return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns));
         }
         }
         
         
+        public TestPlan ExpectChildDraw(Size expectedInput)
+        {
+            return ExpectChildDraw(DefaultChildName, expectedInput);
+        }
+        
         public TestPlan ExpectChildDraw(string child, Size expectedInput)
         public TestPlan ExpectChildDraw(string child, Size expectedInput)
         {
         {
             return AddOperation(new ChildDrawOperationBase(child, expectedInput));
             return AddOperation(new ChildDrawOperationBase(child, expectedInput));

+ 15 - 4
QuestPDF/Elements/AspectRatio.cs

@@ -14,15 +14,26 @@ namespace QuestPDF.Elements
             if(Child == null)
             if(Child == null)
                 return new FullRender(Size.Zero);
                 return new FullRender(Size.Zero);
             
             
-            var size = GetTargetSize(availableSpace);
+            var targetSize = GetTargetSize(availableSpace);
             
             
-            if (size.Height > availableSpace.Height + Size.Epsilon)
+            if (targetSize.Height > availableSpace.Height + Size.Epsilon)
                 return new Wrap();
                 return new Wrap();
             
             
-            if (size.Width > availableSpace.Width + Size.Epsilon)
+            if (targetSize.Width > availableSpace.Width + Size.Epsilon)
+                return new Wrap();
+
+            var childSize = Child.Measure(targetSize);
+
+            if (childSize is Wrap)
                 return new Wrap();
                 return new Wrap();
+
+            if (childSize is PartialRender)
+                return new PartialRender(targetSize);
+
+            if (childSize is FullRender)
+                return new FullRender(targetSize);
             
             
-            return new FullRender(size);
+            throw new NotSupportedException();
         }
         }
 
 
         internal override void Draw(ICanvas canvas, Size availableSpace)
         internal override void Draw(ICanvas canvas, Size availableSpace)

+ 0 - 3
QuestPDF/Elements/DynamicImage.cs

@@ -11,9 +11,6 @@ namespace QuestPDF.Elements
         
         
         internal override ISpacePlan Measure(Size availableSpace)
         internal override ISpacePlan Measure(Size availableSpace)
         {
         {
-            if (availableSpace.Width < 0 || availableSpace.Height < 0)
-                return new Wrap();
-            
             return new FullRender(availableSpace.Width, availableSpace.Height);
             return new FullRender(availableSpace.Width, availableSpace.Height);
         }
         }
 
 

+ 4 - 0
QuestPDF/Elements/Padding.cs

@@ -17,6 +17,10 @@ namespace QuestPDF.Elements
                 return new FullRender(Size.Zero);
                 return new FullRender(Size.Zero);
             
             
             var internalSpace = InternalSpace(availableSpace);
             var internalSpace = InternalSpace(availableSpace);
+
+            if (internalSpace.Width <= 0 || internalSpace.Height <= 0)
+                return new Wrap();
+            
             var measure = Child.Measure(internalSpace) as Size;
             var measure = Child.Measure(internalSpace) as Size;
 
 
             if (measure == null)
             if (measure == null)

+ 0 - 2
QuestPDF/Elements/Placeholder.cs

@@ -14,8 +14,6 @@ namespace QuestPDF.Elements
 
 
         public void Compose(IContainer container)
         public void Compose(IContainer container)
         {
         {
-            // TODO: consider moving this element into fluent API
-            
             container
             container
                 .Background("CCC")
                 .Background("CCC")
                 .AlignMiddle()
                 .AlignMiddle()

+ 0 - 38
QuestPDF/Fluent/ElementExtensions.cs

@@ -48,45 +48,7 @@ namespace QuestPDF.Fluent
         {
         {
             return parent.Element(new Debug());
             return parent.Element(new Debug());
         }
         }
-        
-        public static void Image(this IContainer parent, byte[] data, ImageScaling scaling = ImageScaling.FitWidth)
-        {
-            if (data == null)
-                return;
-            
-            var image = SKImage.FromEncodedData(data);
-            var aspectRatio = image.Width / (float)image.Height;
-            
-            var imageElement = new Image
-            {
-                InternalImage = image
-            };
-
-            if (scaling != ImageScaling.Resize)
-                parent = parent.AspectRatio(aspectRatio, Map(scaling));
-            
-            parent.Element(imageElement);
-
-            static AspectRatioOption Map(ImageScaling scaling)
-            {
-                return scaling switch
-                {
-                    ImageScaling.FitWidth => AspectRatioOption.FitWidth,
-                    ImageScaling.FitHeight => AspectRatioOption.FitHeight,
-                    ImageScaling.FitArea => AspectRatioOption.FitArea,
-                    _ => throw new ArgumentOutOfRangeException()
-                };
-            }
-        }
 
 
-        public static void DynamicImage(this IContainer element, Func<Size, byte[]> imageSource)
-        {
-            element.Element(new DynamicImage
-            {
-                Source = imageSource
-            });
-        }
-        
         public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
         public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
         {
         {
             element.Element(new PageNumber
             element.Element(new PageNumber

+ 48 - 0
QuestPDF/Fluent/ImageExtensions.cs

@@ -0,0 +1,48 @@
+using System;
+using QuestPDF.Elements;
+using QuestPDF.Infrastructure;
+using SkiaSharp;
+
+namespace QuestPDF.Fluent
+{
+    public static class ImageExtensions
+    {
+        public static void Image(this IContainer parent, byte[] data, ImageScaling scaling = ImageScaling.FitWidth)
+        {
+            if (data == null)
+                return;
+            
+            var image = SKImage.FromEncodedData(data);
+            var aspectRatio = image.Width / (float)image.Height;
+            
+            var imageElement = new Image
+            {
+                InternalImage = image
+            };
+
+            if (scaling != ImageScaling.Resize)
+                parent = parent.AspectRatio(aspectRatio, Map(scaling));
+            
+            parent.Element(imageElement);
+
+            static AspectRatioOption Map(ImageScaling scaling)
+            {
+                return scaling switch
+                {
+                    ImageScaling.FitWidth => AspectRatioOption.FitWidth,
+                    ImageScaling.FitHeight => AspectRatioOption.FitHeight,
+                    ImageScaling.FitArea => AspectRatioOption.FitArea,
+                    _ => throw new ArgumentOutOfRangeException()
+                };
+            }
+        }
+
+        public static void DynamicImage(this IContainer element, Func<Size, byte[]> imageSource)
+        {
+            element.Element(new DynamicImage
+            {
+                Source = imageSource
+            });
+        }
+    }
+}