diff --git a/Liquid.NET.Tests/Examples/ExampleTests.cs b/Liquid.NET.Tests/Examples/ExampleTests.cs index bae8812..907cde9 100755 --- a/Liquid.NET.Tests/Examples/ExampleTests.cs +++ b/Liquid.NET.Tests/Examples/ExampleTests.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Runtime.Remoting; using Liquid.NET.Constants; +using Liquid.NET.Filters; using Liquid.NET.Utils; using NUnit.Framework; @@ -141,5 +144,116 @@ public class MyPoco } + + public class MyUpCaseFilter : FilterExpression + { + public override LiquidExpressionResult ApplyTo(ITemplateContext ctx, LiquidString liquidExpression) + { + return LiquidExpressionResult.Success(liquidExpression.ToString().ToUpper()); + } + } + + [Test] + public void It_Should_Render_In_Upper_Case() + { + // Arrange + var ctx = new TemplateContext() + .WithFilter("myupcase"); + var parsingResult = LiquidTemplate.Create("Result : {{ \"test\" | myupcase }}"); + + // Act + var renderingResult = parsingResult.LiquidTemplate.Render(ctx); + + // Assert + Assert.That(renderingResult.Result, Is.EqualTo("Result : TEST")); + } + + [Test] + public void Test_Introductory_Example() + { + // create a template context that knows about the standard filters, + // and define a string variable "myvariable" + ITemplateContext ctx = new TemplateContext() + .WithAllFilters() + .DefineLocalVariable("myvariable", LiquidString.Create("Hello World")); + + // parse the template and check for errors + var parsingResult = LiquidTemplate.Create("
{{myvariable}}
"); + + if (parsingResult.HasParsingErrors) + { + HandleErrors(parsingResult.ParsingErrors); + return; + } + + // merge the variables from the context into the template and check for errors + var renderingResult = parsingResult.LiquidTemplate.Render(ctx); + if (renderingResult.HasParsingErrors) + { + HandleErrors(renderingResult.ParsingErrors); + return; + } + if (renderingResult.HasRenderingErrors) + { + HandleErrors(renderingResult.RenderingErrors); + return; + } + + Assert.That(renderingResult.Result, Is.EqualTo("
Hello World
")); + + } + + [Test] + public void Test_Introductory_Example_With_Syntactic_Sugar() + { + // create a place to accumulate parsing and rendering errors. + var errors = new List(); + + // Note that you will still get a best-guess LiquidTemplate, even if you encounter errors. + var liquidTemplate = LiquidTemplate.Create("
{{myvariable}}
") + .OnParsingError(errors.Add) + .LiquidTemplate; + + // [add code here to handle the parsing errors, return] + Assert.That(errors.Any(), Is.False); + + var ctx = new TemplateContext() + .WithAllFilters() + .DefineLocalVariable("myvariable", LiquidString.Create("Hello World")); + + + // The final String output will still be available in .Result, + // even when parsing or rendering errors are encountered. + var result = liquidTemplate.Render(ctx) + .OnAnyError(errors.Add) // also available: .OnParsingError, .OnRenderingError + .Result; + + // [add code here to handle the parsing and rendering errors] + Assert.That(errors.Any(), Is.False); + + Console.WriteLine(result); + Assert.That(result, Is.EqualTo("
Hello World
")); + + } + +// [Test] +// public void It_Should_Throw_An_Error() +// { +// LiquidHash hash = new LiquidHash(); +// ITemplateContext ctx = new TemplateContext() +// .ErrorWhenValueMissing() +// .DefineLocalVariable("myvariable", hash); +// +// var parsingResult = LiquidTemplate.Create("
{{myvariable.ss}}
"); +// var renderingResult = parsingResult.LiquidTemplate.Render(ctx); +// +// Console.WriteLine("ERROR: " + String.Join("; ", renderingResult.RenderingErrors.Select(x => x.Message))); +// Console.WriteLine(renderingResult.Result, "
ui
"); +// } + + private void HandleErrors(IList errors) + { + // ... + } } } diff --git a/Liquid.NET.Tests/Filters/LookupFilterTests.cs b/Liquid.NET.Tests/Filters/LookupFilterTests.cs deleted file mode 100755 index c3a7183..0000000 --- a/Liquid.NET.Tests/Filters/LookupFilterTests.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using System.Collections.Generic; - -using Liquid.NET.Constants; -using Liquid.NET.Tests.Filters.Array; - -using NUnit.Framework; - -namespace Liquid.NET.Tests.Filters -{ - [TestFixture] - [Ignore("TO DELETE when replaced with IndexDereferencer")] - public class LookupFilterTests - { - private static String LOOKUP = "lookup"; - - [Test] - [TestCase("3", "false")] - [TestCase("4", "")] - [TestCase("30", "")] - [TestCase("-1", "false")] - [TestCase("-2", "456.0")] - [TestCase("-4", "a string")] - [TestCase("-5", "")] - [TestCase("4", "")] - [TestCase("-30", "")] - public void It_Should_Look_Up_ArrayValues(String index, String expected) - { - // Arrange - TemplateContext ctx = new TemplateContext(); - var liquidCollection = DataFixtures.CreateArrayValue(); - ctx.DefineLocalVariable("myarray", liquidCollection); - String tmpl = "{{ myarray | " + LOOKUP + ": "+index+" }}"; - - // Act - var result = RenderingHelper.RenderTemplate(tmpl, ctx); - - // Assert - //var expected = ValueCaster.RenderAsString(liquidCollection.ArrValue[3]); - Assert.That(result, Is.EqualTo(expected)); - } - - [Test] - [TestCase("mydict.field1", "Property 1")] - [TestCase("mydict | lookup: \"field1\"", "Property 1")] - [TestCase("mydict[\"field1\"]", "Property 1")] - [TestCase("mydict[\"qwefqwefwef\"]", "")] - public void It_Should_Look_Up_DictionaryValues(String liquid, String expected) - { - // Arrange - TemplateContext ctx = new TemplateContext(); - var dictValue = DataFixtures.CreateDictionary(1, "Property 1", "prop2"); - ctx.DefineLocalVariable("mydict", dictValue); - String tmpl = "{{ "+liquid+" }}"; - - // Act - var result = RenderingHelper.RenderTemplate(tmpl, ctx); - - // Assert - Assert.That(result, Is.EqualTo(expected)); - } - - [Test] - [TestCase("{% assign str = \"A String\" %}{{str[0]}}", "A")] - [TestCase("{% assign str = \"A String\" %}{{str[-1]}}", "g")] - [TestCase("{% assign str = \"A String\" %}{{str[-20]}}", "")] - [TestCase("{% assign str = \"\" %}{{str[0]}}", "")] - public void It_Should_Look_Up_StringValues(String input, String expected) - { - - // Act - var result = RenderingHelper.RenderTemplate(input); - - // Assert - Assert.That(result, Is.EqualTo(expected)); - } - - - [Test] - // see: https://github.com/Shopify/liquid/issues/543 - [TestCase("first", "a string")] - [TestCase("last", "false")] - [TestCase("size", "4")] - public void It_Should_Dereference_Properties_Of_Array(String property, String expected) - { - // Arrange - TemplateContext ctx = new TemplateContext(); - var liquidCollection = DataFixtures.CreateArrayValue(); - ctx.DefineLocalVariable("myarray", liquidCollection); - String tmpl = "{{ myarray."+property+" }}"; - - // Act - var result = RenderingHelper.RenderTemplate(tmpl, ctx); - - // Assert - Assert.That(result, Is.EqualTo(expected)); - } - - [Test] - [TestCase("size")] - public void It_Should_Dereference_Properties_Of_Dictionary(String property) - { - // Arrange - TemplateContext ctx = new TemplateContext(); - var dictValue = DataFixtures.CreateDictionary(1, "Property 1", "prop2"); - ctx.DefineLocalVariable("mydict", dictValue); - String tmpl = "{{ mydict." + property + " }}"; - - // Act - var result = RenderingHelper.RenderTemplate(tmpl, ctx); - - // Assert - Assert.That(result, Is.EqualTo(dictValue.DictValue.Count.ToString())); - } - - public ArrayValue CreateArrayOfDicts() - { - // Arrange - IList objlist = new List - { - DataFixtures.CreateDictionary(1, "Value 1 A", "Value 1 B"), - DataFixtures.CreateDictionary(2, "Value 2 A", "Value 2 B"), - DataFixtures.CreateDictionary(3, "Value 3 A", "Value 3 B"), - DataFixtures.CreateDictionary(4, "Value 4 A", "Value 4 B"), - }; - return new ArrayValue(objlist); - - } - } -} diff --git a/Liquid.NET.Tests/Liquid.NET.Tests.csproj b/Liquid.NET.Tests/Liquid.NET.Tests.csproj index 537e812..325589a 100755 --- a/Liquid.NET.Tests/Liquid.NET.Tests.csproj +++ b/Liquid.NET.Tests/Liquid.NET.Tests.csproj @@ -144,6 +144,8 @@ + + diff --git a/Liquid.NET.Tests/LiquidParsingResultTests.cs b/Liquid.NET.Tests/LiquidParsingResultTests.cs new file mode 100755 index 0000000..450a050 --- /dev/null +++ b/Liquid.NET.Tests/LiquidParsingResultTests.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; + +namespace Liquid.NET.Tests +{ + [TestFixture] + public class LiquidParsingResultTests + { + [Test] + public void It_Should_Call_An_Error_Function() + { + // Arrange + IList errors = new List{ new LiquidError { Message = "Hello" } }; + var parsingResult = LiquidParsingResult.Create(new LiquidTemplate(new LiquidAST()), errors); + + // Act + IList heardErrors = new List(); + parsingResult.OnParsingError(heardErrors.Add); + + // Assert + Assert.That(heardErrors.Any()); + + } + + + } +} diff --git a/Liquid.NET.Tests/LiquidRenderingResultTests.cs b/Liquid.NET.Tests/LiquidRenderingResultTests.cs new file mode 100755 index 0000000..98e4999 --- /dev/null +++ b/Liquid.NET.Tests/LiquidRenderingResultTests.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using NUnit.Framework; + +namespace Liquid.NET.Tests +{ + [TestFixture] + public class LiquidRenderingResultTests + { + + [Test] + public void It_Should_Call_An_Error_Function() + { + // Arrange + IList renderingErrors = new List { new LiquidError { Message = "Rendering" } }; + IList parsingErrors = new List { new LiquidError { Message = "Parsing" } }; + var parsingResult = LiquidRenderingResult.Create("result", renderingErrors, parsingErrors); + + // Act + IList heardParsingErrors = new List(); + IList heardRenderingErrors = new List(); + IList heardAllErrors = new List(); + parsingResult.OnParsingError(heardParsingErrors.Add); + parsingResult.OnRenderingError(heardRenderingErrors.Add); + parsingResult.OnAnyError(heardAllErrors.Add); + + // Assert + Assert.That(heardParsingErrors.Count, Is.EqualTo(1)); + Assert.That(heardRenderingErrors.Count, Is.EqualTo(1)); + Assert.That(heardAllErrors.Count, Is.EqualTo(2)); + + } + + } +} diff --git a/Liquid.NET/src/LiquidParsingResult.cs b/Liquid.NET/src/LiquidParsingResult.cs index 622a62a..51dc880 100755 --- a/Liquid.NET/src/LiquidParsingResult.cs +++ b/Liquid.NET/src/LiquidParsingResult.cs @@ -1,10 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace Liquid.NET { public class LiquidParsingResult { + public static LiquidParsingResult Create(LiquidTemplate liquidTemplate, IList parsingErrors) { return new LiquidParsingResult @@ -29,6 +31,24 @@ private LiquidParsingResult() public IList ParsingErrors { get; private set; } + /// + /// This function will be called once for each error encountered + /// during parsing + /// + /// + /// + public LiquidParsingResult OnParsingError(Action onErrorFn) + { + if (onErrorFn != null) + { + foreach (var err in ParsingErrors) + { + onErrorFn(err); + } + } + return this; + } + } } diff --git a/Liquid.NET/src/LiquidRenderingResult.cs b/Liquid.NET/src/LiquidRenderingResult.cs index b74b8f5..dc26bf6 100755 --- a/Liquid.NET/src/LiquidRenderingResult.cs +++ b/Liquid.NET/src/LiquidRenderingResult.cs @@ -8,6 +8,12 @@ namespace Liquid.NET { public class LiquidRenderingResult { + private Action _onParsingError; + private Action _onRenderingError; + private Action _onAnyError = err => { }; + + private Action AnyError { get { return _onAnyError;} } + public static LiquidRenderingResult Create( String result, IList renderingErrors, @@ -26,7 +32,8 @@ IList parsingErrors private LiquidRenderingResult() { - + _onParsingError = AnyError; + _onRenderingError = AnyError; } public String Result { get; private set; } @@ -45,5 +52,35 @@ public bool HasRenderingErrors get { return RenderingErrors.Any(); } } + public LiquidRenderingResult OnParsingError(Action onErrorFn) + { + EvalWithErrors(onErrorFn, ParsingErrors); + return this; + } + + public LiquidRenderingResult OnRenderingError(Action onErrorFn) + { + EvalWithErrors(onErrorFn, RenderingErrors); + return this; + } + + public LiquidRenderingResult OnAnyError(Action onErrorFn) + { + EvalWithErrors(onErrorFn, RenderingErrors); + EvalWithErrors(onErrorFn, ParsingErrors); + return this; + } + + private void EvalWithErrors(Action onErrorFn, IList parsingErrors) + { + if (onErrorFn != null) + { + foreach (var err in parsingErrors) + { + onErrorFn(err); + } + } + + } } } diff --git a/Liquid.Ruby/tests.liquid b/Liquid.Ruby/tests.liquid index 3b2baa8..ef84f6e 100755 --- a/Liquid.Ruby/tests.liquid +++ b/Liquid.Ruby/tests.liquid @@ -39,48 +39,36 @@ namespace Liquid.NET.Tests.Ruby var template = LiquidTemplate.Create(input); // Act - String result = template.LiquidTemplate.Render(ctx); - + var result = template.LiquidTemplate.Render(ctx); + Assert.That(result.HasParsingErrors, Is.False); + //Assert.That(result.HasRenderingErrors, Is.False); + // Assert - Assert.That(result.Trim(), Is.EqualTo(expected)); + Assert.That(result.Result.Trim(), Is.EqualTo(expected)); } {% if exceptions != empty %}[Test]{% for test in exceptions %} [TestCase(@"{{test.input}}", @"{{test.assigns}}", @"{{test.expected | remove: 'EXCEPTION: '}}")]{% endfor %} public void It_Should_Capture_An_Error(String input, String assigns, String expectedMessage) - { - // Arrange - ITemplateContext ctx = new TemplateContext() - .WithAllFilters() - .WithFileSystem(new TestFileSystem()); - - foreach (var tuple in DictionaryFactory.CreateStringMapFromJson(assigns)) - { - ctx.DefineLocalVariable(tuple.Item1, tuple.Item2); - } - - var template = LiquidTemplate.Create(input); - IList errors = new List(); - //try - //{ - - String result = template.LiquidTemplate.Render(ctx, onRenderingError: errors.Add); - Assert.That(errors.Count, Is.EqualTo(1)); - Assert.That(errors[0].ToString(), Is.StringContaining(expectedMessage)); - - // TODO: Clean this up: - //} - //catch (LiquidParserException ex) - //{ - // Assert - // Assert.That(ex.LiquidErrors[0].ToString(), Is.StringContaining(expectedMessage)); - //} - //catch (LiquidRendererException ex) - //{ - // Assert - // Assert.That(ex.LiquidErrors[0].ToString(), Is.StringContaining(expectedMessage)); - // Assert.That(errors.ToString(), Is.StringContaining(expectedMessage)); - //} + { + // Arrange + ITemplateContext ctx = new TemplateContext() + .WithAllFilters() + .WithFileSystem(new TestFileSystem()); + + foreach (var tuple in DictionaryFactory.CreateStringMapFromJson(assigns)) + { + ctx.DefineLocalVariable(tuple.Item1, tuple.Item2); + } + + var template = LiquidTemplate.Create(input); + IList renderingerrors = new List(); + IList parsingerrors = new List(); + + String result = template.LiquidTemplate.Render(ctx, onRenderingError: renderingerrors.Add, onParsingError: parsingerrors.Add); + Assert.That(parsingerrors.Count, Is.EqualTo(1)); + Assert.That(parsingerrors[0].ToString(), Is.StringContaining(expectedMessage)); + } {% endif %} }