Skip to content

Commit 1568da7

Browse files
Adam SchroderGabriel Sadaka
authored andcommitted
Add new option for Erroring when key is missing
1 parent ba066fb commit 1568da7

File tree

7 files changed

+199
-88
lines changed

7 files changed

+199
-88
lines changed

Liquid.NET.Tests/Constants/MissingValueTests.cs

100755100644
Lines changed: 26 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,117 +5,79 @@
55

66
namespace Liquid.NET.Tests.Constants
77
{
8-
98
public class MissingValueTests
109
{
1110
[Theory]
1211
[InlineData("x", "x")]
1312
[InlineData("d.x", "x")]
1413
[InlineData("d[x]", "x")]
15-
[InlineData("a.b.c", "a")]
16-
public void It_Should_Display_An_Error_When_Dereferencing_Missing_Value(String varname, String missingVar)
14+
public void It_Should_Display_An_Error_When_Value_Is_Undefined(String varname, String missingVar)
1715
{
1816
// Arrange
1917

20-
ITemplateContext ctx = new TemplateContext()
18+
ITemplateContext ctx = new TemplateContext()
2119
.ErrorWhenValueMissing();
22-
ctx.DefineLocalVariable("d", new LiquidHash());
23-
20+
ctx.DefineLocalVariable("x", LiquidValue.None);
21+
ctx.DefineLocalVariable("d", new LiquidHash()
22+
{
23+
{
24+
"x", LiquidValue.None
25+
}
26+
});
27+
2428
// Act
2529
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
2630
var result = template.LiquidTemplate.Render(ctx);
2731
//Console.WriteLine(result);
2832

2933
// Assert
3034
Assert.Equal("Result : ERROR: " + missingVar + " is undefined", result.Result);
31-
3235
}
3336

3437
[Theory]
35-
[InlineData("e[1]")]
36-
[InlineData("e.first")]
37-
[InlineData("e.last")]
38-
public void It_Should_Display_An_Error_When_Dereferencing_Empty_Array(String varname)
38+
[InlineData("e[1]", "1")]
39+
[InlineData("e.first", "first")]
40+
[InlineData("e.last", "last")]
41+
public void It_Should_Display_An_Error_When_Array_Value_Is_Undefined(String varname, String missingVar)
3942
{
4043
// Arrange
4144
ITemplateContext ctx = new TemplateContext()
4245
.ErrorWhenValueMissing();
43-
ctx.DefineLocalVariable("e", new LiquidCollection());
46+
ctx.DefineLocalVariable("e", new LiquidCollection(new[] { LiquidValue.None, LiquidValue.None, LiquidValue.None }));
4447

4548
// Act
4649
//var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
4750
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
4851
var result = template.LiquidTemplate.Render(ctx);
4952

5053
// Assert
51-
Assert.Equal("Result : ERROR: cannot dereference empty array", result.Result);
52-
53-
}
54-
55-
56-
57-
[Fact]
58-
public void It_Should_Display_Error_When_Dereferencing_Array_With_Non_Int()
59-
{
60-
// Arrange
61-
ITemplateContext ctx = new TemplateContext()
62-
.ErrorWhenValueMissing();
63-
ctx.DefineLocalVariable("e", new LiquidCollection());
64-
65-
// Act
66-
var template = LiquidTemplate.Create("Result : {{ e.x }}");
67-
var result = template.LiquidTemplate.Render(ctx);
68-
//var result = RenderingHelper.RenderTemplate("Result : {{ e.x }}", ctx);
69-
70-
// Assert
71-
Assert.Contains("invalid index: 'x'", result.Result);
72-
73-
}
74-
75-
[Fact]
76-
public void It_Should_Display_Error_When_Dereferencing_Primitive_With_Index()
77-
{
78-
// Arrange
79-
ITemplateContext ctx = new TemplateContext()
80-
.ErrorWhenValueMissing();
81-
ctx.DefineLocalVariable("e", LiquidString.Create("Hello"));
82-
83-
// Act
84-
var template = LiquidTemplate.Create("Result : {{ e.x }}");
85-
var result = template.LiquidTemplate.Render(ctx);
86-
87-
Assert.True(result.HasRenderingErrors);
88-
var errorMessage = String.Join(",", result.RenderingErrors.Select(x => x.Message));
89-
// Assert
90-
Assert.Contains("invalid string index: 'x'", errorMessage);
91-
54+
Assert.Equal("Result : ERROR: " + missingVar + " is undefined", result.Result);
9255
}
9356

94-
9557
[Theory]
9658
[InlineData("x")]
59+
[InlineData("e.first")]
9760
[InlineData("e[1]")]
98-
[InlineData("e.x")]
9961
[InlineData("d.x")]
10062
[InlineData("d[x]")]
101-
[InlineData("a.b.c")]
102-
public void It_Should_Not_Display_An_Error_When_Dereferencing_Missing_Value(String varname)
63+
public void It_Should_Not_Display_An_Error_When_Values_Are_Missing(String varname)
10364
{
10465
// Arrange
10566
//Console.WriteLine(varname);
106-
TemplateContext ctx = new TemplateContext();
107-
ctx.DefineLocalVariable("e", new LiquidCollection());
108-
ctx.DefineLocalVariable("d", new LiquidHash());
67+
ITemplateContext ctx = new TemplateContext()
68+
.ErrorWhenVariableMissing();
69+
ctx.DefineLocalVariable("e", new LiquidCollection(new[] { LiquidValue.None, LiquidValue.None, LiquidValue.None }));
70+
ctx.DefineLocalVariable("d", new LiquidHash()
71+
{
72+
{ "x", LiquidValue.None }
73+
});
74+
ctx.DefineLocalVariable("x", LiquidValue.None);
10975

11076
// Act
11177
var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
11278

11379
// Assert
11480
Assert.Equal("Result : ", result);
115-
11681
}
117-
118-
119-
12082
}
12183
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System;
2+
using System.Linq;
3+
using Liquid.NET.Constants;
4+
using Xunit;
5+
6+
namespace Liquid.NET.Tests.Constants
7+
{
8+
public class MissingVariableTests
9+
{
10+
[Theory]
11+
[InlineData("x", "x")]
12+
[InlineData("d.x", "x")]
13+
[InlineData("d[x]", "x")]
14+
[InlineData("a.b.c", "a")]
15+
public void It_Should_Display_An_Error_When_Dereferencing_Missing_Variable(String varname, String missingVar)
16+
{
17+
// Arrange
18+
19+
ITemplateContext ctx = new TemplateContext()
20+
.ErrorWhenVariableMissing();
21+
ctx.DefineLocalVariable("d", new LiquidHash());
22+
23+
// Act
24+
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
25+
var result = template.LiquidTemplate.Render(ctx);
26+
Console.WriteLine(result);
27+
28+
// Assert
29+
Assert.Equal("Result : ERROR: " + missingVar + " is undefined", result.Result);
30+
31+
}
32+
33+
[Theory]
34+
[InlineData("e[1]")]
35+
[InlineData("e.first")]
36+
[InlineData("e.last")]
37+
public void It_Should_Display_An_Error_When_Dereferencing_Empty_Array(String varname)
38+
{
39+
// Arrange
40+
ITemplateContext ctx = new TemplateContext()
41+
.ErrorWhenVariableMissing();
42+
ctx.DefineLocalVariable("e", new LiquidCollection());
43+
44+
// Act
45+
//var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
46+
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
47+
var result = template.LiquidTemplate.Render(ctx);
48+
49+
// Assert
50+
Assert.Equal("Result : ERROR: cannot dereference empty array", result.Result);
51+
52+
}
53+
54+
55+
56+
[Fact]
57+
public void It_Should_Display_Error_When_Dereferencing_Array_With_Non_Int()
58+
{
59+
// Arrange
60+
ITemplateContext ctx = new TemplateContext()
61+
.ErrorWhenVariableMissing();
62+
ctx.DefineLocalVariable("e", new LiquidCollection());
63+
64+
// Act
65+
var template = LiquidTemplate.Create("Result : {{ e.x }}");
66+
var result = template.LiquidTemplate.Render(ctx);
67+
//var result = RenderingHelper.RenderTemplate("Result : {{ e.x }}", ctx);
68+
69+
// Assert
70+
Assert.Contains("invalid index: 'x'", result.Result);
71+
72+
}
73+
74+
[Fact]
75+
public void It_Should_Display_Error_When_Dereferencing_Primitive_With_Index()
76+
{
77+
// Arrange
78+
ITemplateContext ctx = new TemplateContext()
79+
.ErrorWhenVariableMissing();
80+
ctx.DefineLocalVariable("e", LiquidString.Create("Hello"));
81+
82+
// Act
83+
var template = LiquidTemplate.Create("Result : {{ e.x }}");
84+
var result = template.LiquidTemplate.Render(ctx);
85+
86+
Assert.True(result.HasRenderingErrors);
87+
var errorMessage = String.Join(",", result.RenderingErrors.Select(x => x.Message));
88+
// Assert
89+
Assert.Contains("invalid string index: 'x'", errorMessage);
90+
91+
}
92+
93+
94+
[Theory]
95+
[InlineData("x")]
96+
[InlineData("e[1]")]
97+
[InlineData("e.x")]
98+
[InlineData("d.x")]
99+
[InlineData("d[x]")]
100+
[InlineData("a.b.c")]
101+
public void It_Should_Not_Display_An_Error_When_Dereferencing_Missing_Variable(String varname)
102+
{
103+
// Arrange
104+
Console.WriteLine(varname);
105+
ITemplateContext ctx = new TemplateContext()
106+
.ErrorWhenValueMissing();
107+
ctx.DefineLocalVariable("e", new LiquidCollection());
108+
ctx.DefineLocalVariable("d", new LiquidHash());
109+
110+
// Act
111+
var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
112+
113+
// Assert
114+
Assert.Equal("Result : ", result);
115+
116+
}
117+
118+
119+
120+
}
121+
}

Liquid.NET/src/Constants/IndexDereferencer.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public LiquidExpressionResult Lookup(
4242

4343
private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidCollection liquidCollection, ILiquidValue indexProperty)
4444
{
45-
bool errorOnEmpty = ctx.Options.ErrorWhenValueMissing && liquidCollection.Count == 0;
45+
bool errorOnEmpty = ctx.Options.ErrorWhenVariableMissing && liquidCollection.Count == 0;
4646

4747

4848

@@ -75,7 +75,7 @@ private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidCollection l
7575

7676
if (!success)
7777
{
78-
if (ctx.Options.ErrorWhenValueMissing)
78+
if (ctx.Options.ErrorWhenVariableMissing)
7979
{
8080
return LiquidExpressionResult.Error("invalid index: '" + propertyNameString + "'");
8181
}
@@ -103,6 +103,11 @@ private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidCollection l
103103
}
104104
var result = liquidCollection.ValueAt(index);
105105

106+
if (!result.HasValue)
107+
{
108+
return LiquidExpressionResult.ErrorOrNone(ctx, propertyNameString);
109+
}
110+
106111
return LiquidExpressionResult.Success(result);
107112
}
108113

@@ -115,15 +120,22 @@ private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidHash liquidH
115120
return LiquidExpressionResult.Success(LiquidNumeric.Create(liquidHash.Keys.Count));
116121
}
117122

118-
var valueAt = liquidHash.ValueAt(indexProperty.Value.ToString());
119-
if (valueAt.HasValue)
123+
var key = indexProperty.Value.ToString();
124+
if (liquidHash.ContainsKey(key))
120125
{
121-
return LiquidExpressionResult.Success(valueAt);
126+
var value = liquidHash[key];
127+
if (value.HasValue)
128+
{
129+
return LiquidExpressionResult.Success(value);
130+
}
131+
else
132+
{
133+
return LiquidExpressionResult.ErrorOrNone(ctx, indexProperty.ToString());
134+
}
122135
}
123136
else
124137
{
125-
return LiquidExpressionResult.ErrorOrNone(ctx, indexProperty.ToString());
126-
138+
return LiquidExpressionResult.MissingOrNone(ctx, indexProperty.ToString());
127139
}
128140
}
129141

@@ -152,7 +164,7 @@ private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidString str,
152164

153165
if (numericIndexProperty == null)
154166
{
155-
return ctx.Options.ErrorWhenValueMissing ?
167+
return ctx.Options.ErrorWhenVariableMissing ?
156168
LiquidExpressionResult.Error("invalid string index: '" + propertyNameString + "'") :
157169
LiquidExpressionResult.Success(new None<ILiquidValue>());
158170
}
@@ -167,7 +179,14 @@ private LiquidExpressionResult DoLookup(ITemplateContext ctx, LiquidString str,
167179
//return LiquidExpressionResult.Error("Empty string: " + propertyNameString);
168180
return LiquidExpressionResult.Success(new None<ILiquidValue>()); // not an error in Ruby liquid.
169181
}
170-
return LiquidExpressionResult.Success(CollectionIndexer.ValueAt(strValues, index));
182+
183+
var result = CollectionIndexer.ValueAt(strValues, index);
184+
if (!result.HasValue)
185+
{
186+
return LiquidExpressionResult.ErrorOrNone(ctx, propertyNameString);
187+
}
188+
189+
return LiquidExpressionResult.Success(result);
171190

172191
}
173192

Liquid.NET/src/Expressions/VariableReference.cs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,9 @@ public VariableReference(String name)
1919
public override LiquidExpressionResult Eval(ITemplateContext templateContext, IEnumerable<Option<ILiquidValue>> childresults)
2020
{
2121
var lookupResult= templateContext.SymbolTableStack.Reference(Name);
22-
return lookupResult.IsSuccess ?
23-
lookupResult :
24-
ErrorOrNone(templateContext, lookupResult);
25-
}
26-
27-
private LiquidExpressionResult ErrorOrNone(ITemplateContext templateContext, LiquidExpressionResult failureResult)
28-
{
29-
if (templateContext.Options.ErrorWhenValueMissing)
30-
{
31-
return failureResult;
32-
}
33-
else
34-
{
35-
return LiquidExpressionResult.Success(new None<ILiquidValue>());
36-
}
22+
return lookupResult.IsSuccess
23+
? (lookupResult.SuccessResult.HasValue ? lookupResult : LiquidExpressionResult.ErrorOrNone(templateContext, Name))
24+
: LiquidExpressionResult.MissingOrNone(templateContext, Name);
3725
}
3826
}
3927
}

Liquid.NET/src/ITemplateContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public interface ITemplateContext
2424
ITemplateContext WithNoForLimit();
2525
ITemplateContext WithASTGenerator(Func<string, Action<LiquidError>, LiquidAST> astGeneratorFunc);
2626

27+
ITemplateContext ErrorWhenValueMissing();
28+
ITemplateContext ErrorWhenVariableMissing();
2729

2830
IFileSystem FileSystem { get; }
2931
IDictionary<String, Object> Registers { get; }

0 commit comments

Comments
 (0)