diff --git a/Fluid.Benchmarks/BaseBenchmarks.cs b/Fluid.Benchmarks/BaseBenchmarks.cs index 0ee74f07..94138119 100644 --- a/Fluid.Benchmarks/BaseBenchmarks.cs +++ b/Fluid.Benchmarks/BaseBenchmarks.cs @@ -1,13 +1,14 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; namespace Fluid.Benchmarks { public abstract class BaseBenchmarks { - protected List Products = new List(ProductCount); + protected List Products = new(ProductCount); - protected const int ProductCount = 500; + protected const int ProductCount = 100; protected const string Lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"; @@ -47,11 +48,23 @@ public BaseBenchmarks() } } + public void CheckBenchmark() + { + var result = ParseAndRender(); + if (string.IsNullOrEmpty(result) || + !result.Contains("

Name0

") || + !result.Contains($"

Name{ProductCount - 1}

") || + !result.Contains($"Lorem ipsum ...") || + !result.Contains($"Only 0") || + !result.Contains($"Only {ProductCount - 1}")) + { + throw new InvalidOperationException($"Template rendering failed: \n {result}"); + } + } + public abstract object Parse(); public abstract object ParseBig(); - public abstract string Render(); - public abstract string ParseAndRender(); } diff --git a/Fluid.Benchmarks/ComparisonBenchmarks.cs b/Fluid.Benchmarks/ComparisonBenchmarks.cs index bfbfea7e..44abff91 100644 --- a/Fluid.Benchmarks/ComparisonBenchmarks.cs +++ b/Fluid.Benchmarks/ComparisonBenchmarks.cs @@ -66,19 +66,22 @@ public string DotLiquid_Render() return _dotLiquidBenchmarks.Render(); } - [Benchmark, BenchmarkCategory("Parse")] + // Ignored since Liquid.NET is much slower and not in active development + [BenchmarkCategory("Parse")] public object LiquidNet_Parse() { return _liquidNetBenchmarks.Parse(); } - [Benchmark, BenchmarkCategory("ParseBig")] + // Ignored since Liquid.NET is much slower and not in active development + [BenchmarkCategory("ParseBig")] public object LiquidNet_ParseBig() { return _liquidNetBenchmarks.ParseBig(); } - [Benchmark, BenchmarkCategory("Render")] + // Ignored since Liquid.NET is much slower and not in active development + [BenchmarkCategory("Render")] public string LiquidNet_Render() { return _liquidNetBenchmarks.Render(); diff --git a/Fluid.Benchmarks/CompiledFluidBenchmarks.cs b/Fluid.Benchmarks/CompiledFluidBenchmarks.cs index 518e5df2..9dd4ba20 100644 --- a/Fluid.Benchmarks/CompiledFluidBenchmarks.cs +++ b/Fluid.Benchmarks/CompiledFluidBenchmarks.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; namespace Fluid.Benchmarks { @@ -14,6 +14,8 @@ public CompiledFluidBenchmarks() _options.MemberAccessStrategy.Register(); _options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase; _parser.TryParse(ProductTemplate, out _fluidTemplate, out var _); + + CheckBenchmark(); } [Benchmark] diff --git a/Fluid.Benchmarks/DotLiquidBenchmarks.cs b/Fluid.Benchmarks/DotLiquidBenchmarks.cs index 0a5b5da0..20b54792 100644 --- a/Fluid.Benchmarks/DotLiquidBenchmarks.cs +++ b/Fluid.Benchmarks/DotLiquidBenchmarks.cs @@ -1,4 +1,4 @@ -using DotLiquid; +using DotLiquid; using System.Linq; namespace Fluid.Benchmarks @@ -11,6 +11,8 @@ public DotLiquidBenchmarks() { _dotLiquidTemplate = Template.Parse(ProductTemplate); _dotLiquidTemplate.MakeThreadSafe(); + + CheckBenchmark(); } private Hash MakeProducts() diff --git a/Fluid.Benchmarks/FluidBenchmarks.cs b/Fluid.Benchmarks/FluidBenchmarks.cs index c14c3103..58b7bfa7 100644 --- a/Fluid.Benchmarks/FluidBenchmarks.cs +++ b/Fluid.Benchmarks/FluidBenchmarks.cs @@ -12,9 +12,11 @@ public class FluidBenchmarks : BaseBenchmarks public FluidBenchmarks() { - _options.MemberAccessStrategy.Register(); _options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase; + _options.MemberAccessStrategy.Register(); _parser.TryParse(ProductTemplate, out _fluidTemplate, out var _); + + CheckBenchmark(); } [Benchmark] diff --git a/Fluid.Benchmarks/HandlebarsBenchmarks.cs b/Fluid.Benchmarks/HandlebarsBenchmarks.cs index 15074ca7..fa33ecb2 100644 --- a/Fluid.Benchmarks/HandlebarsBenchmarks.cs +++ b/Fluid.Benchmarks/HandlebarsBenchmarks.cs @@ -1,4 +1,4 @@ -using HandlebarsDotNet; +using HandlebarsDotNet; using System; namespace Fluid.Benchmarks @@ -9,7 +9,28 @@ public class HandlebarsBenchmarks : BaseBenchmarks public HandlebarsBenchmarks() { - _handlebarsTemplate = Handlebars.Compile(ProductTemplateMustache); + _handlebarsTemplate = CompileTemplate(ProductTemplateMustache); + CheckBenchmark(); + } + + private HandlebarsTemplate CompileTemplate(string template) + { + var handlebars = Handlebars.Create(); + + using (handlebars.Configure()) + { + handlebars.RegisterHelper("truncate", (output, options, context, arguments) => + { + const string ellipsisStr = "..."; + var inputStr = options.Template(); + var length = Convert.ToInt32(arguments.Length > 0 ? arguments[0] : 50); + var l = Math.Max(0, length - ellipsisStr.Length); + var concat = string.Concat(inputStr.AsSpan().Slice(0, l), ellipsisStr); + output.WriteSafeString(concat); + }); + + return handlebars.Compile(ProductTemplateMustache); + } } public override object Parse() @@ -32,7 +53,7 @@ public override string Render() public override string ParseAndRender() { - var template = Handlebars.Compile(ProductTemplateMustache); + var template = CompileTemplate(ProductTemplateMustache); return template(new { products = Products }); } } diff --git a/Fluid.Benchmarks/LiquidNetBenchmarks.cs b/Fluid.Benchmarks/LiquidNetBenchmarks.cs index 09dbed5b..9e9321e5 100644 --- a/Fluid.Benchmarks/LiquidNetBenchmarks.cs +++ b/Fluid.Benchmarks/LiquidNetBenchmarks.cs @@ -1,4 +1,4 @@ -using Liquid.NET; +using Liquid.NET; using Liquid.NET.Utils; namespace Fluid.Benchmarks @@ -10,6 +10,7 @@ public class LiquidNetBenchmarks : BaseBenchmarks public LiquidNetBenchmarks() { _liquidNetTemplate = LiquidTemplate.Create(ProductTemplate); + CheckBenchmark(); } public override object Parse() @@ -25,6 +26,7 @@ public override object ParseBig() public override string Render() { var context = new Liquid.NET.TemplateContext(); + context.WithAllFilters(); context.DefineLocalVariable("products", Products.ToLiquid()); return _liquidNetTemplate.LiquidTemplate.Render(context).Result; } @@ -33,6 +35,7 @@ public override string ParseAndRender() { var template = LiquidTemplate.Create(ProductTemplate); var context = new Liquid.NET.TemplateContext(); + context.WithAllFilters(); context.DefineLocalVariable("products", Products.ToLiquid()); return template.LiquidTemplate.Render(context).Result; } diff --git a/Fluid.Benchmarks/Program.cs b/Fluid.Benchmarks/Program.cs index e8c0405b..df751453 100644 --- a/Fluid.Benchmarks/Program.cs +++ b/Fluid.Benchmarks/Program.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Running; +using BenchmarkDotNet.Running; namespace Fluid.Benchmarks { diff --git a/Fluid.Benchmarks/ScribanBenchmarks.cs b/Fluid.Benchmarks/ScribanBenchmarks.cs index eba21379..0287b2e9 100644 --- a/Fluid.Benchmarks/ScribanBenchmarks.cs +++ b/Fluid.Benchmarks/ScribanBenchmarks.cs @@ -1,4 +1,4 @@ -using Scriban; +using Scriban; using Scriban.Runtime; namespace Fluid.Benchmarks @@ -10,6 +10,8 @@ public class ScribanBenchmarks : BaseBenchmarks public ScribanBenchmarks() { _scribanTemplate = Template.ParseLiquid(ProductTemplate); + + CheckBenchmark(); } public override object Parse() diff --git a/Fluid.Benchmarks/product.mustache b/Fluid.Benchmarks/product.mustache index 6e8dbaf4..f2195917 100644 --- a/Fluid.Benchmarks/product.mustache +++ b/Fluid.Benchmarks/product.mustache @@ -1,9 +1,9 @@ -
    +
      {{#products}}
    • {{ name }}

      Only {{ price }} - {{#truncate}}{{description}}{{/truncate}} + {{#truncate 15}}{{description}}{{/truncate}}
    • {{/products}}