Skip to content

Commit e914091

Browse files
author
Adam Schroder
committed
Add new option for Erroring when key is missing
1 parent f1c53d0 commit e914091

File tree

8 files changed

+199
-83
lines changed

8 files changed

+199
-83
lines changed

Liquid.NET.Tests/Constants/MissingValueTests.cs

Lines changed: 24 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ public class MissingValueTests
1212
[TestCase("x", "x")]
1313
[TestCase("d.x", "x")]
1414
[TestCase("d[x]", "x")]
15-
[TestCase("a.b.c", "a")]
16-
public void It_Should_Display_An_Error_When_Dereferencing_Missing_Value(String varname, String missingVar)
15+
public void It_Should_Display_An_Error_When_Value_Is_Undefined(String varname, String missingVar)
1716
{
1817
// Arrange
1918

2019
ITemplateContext ctx = new TemplateContext()
2120
.ErrorWhenValueMissing();
22-
ctx.DefineLocalVariable("d", new LiquidHash());
21+
ctx.DefineLocalVariable("x", LiquidValue.None);
22+
ctx.DefineLocalVariable("d", new LiquidHash()
23+
{
24+
{
25+
"x", LiquidValue.None
26+
}
27+
});
2328

2429
// Act
2530
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
@@ -32,90 +37,50 @@ public void It_Should_Display_An_Error_When_Dereferencing_Missing_Value(String v
3237
}
3338

3439
[Test]
35-
[TestCase("e[1]")]
36-
[TestCase("e.first")]
37-
[TestCase("e.last")]
38-
public void It_Should_Display_An_Error_When_Dereferencing_Empty_Array(String varname)
40+
[TestCase("e[1]", "1")]
41+
[TestCase("e.first", "first")]
42+
[TestCase("e.last", "last")]
43+
public void It_Should_Display_An_Error_When_Array_Value_Is_Undefined(String varname, String missingVar)
3944
{
4045
// Arrange
4146
ITemplateContext ctx = new TemplateContext()
4247
.ErrorWhenValueMissing();
43-
ctx.DefineLocalVariable("e", new LiquidCollection());
48+
ctx.DefineLocalVariable("e", new LiquidCollection(new[] {LiquidValue.None, LiquidValue.None, LiquidValue.None}));
4449

4550
// Act
4651
//var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
4752
var template = LiquidTemplate.Create("Result : {{ " + varname + " }}");
4853
var result = template.LiquidTemplate.Render(ctx);
4954

5055
// Assert
51-
Assert.That(result.Result, Is.EqualTo("Result : ERROR: cannot dereference empty array"));
52-
53-
}
54-
55-
56-
57-
[Test]
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.That(result.Result, Is.StringContaining("invalid index: 'x'"));
72-
73-
}
74-
75-
[Test]
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.That(result.HasRenderingErrors, Is.True);
88-
var errorMessage = String.Join(",", result.RenderingErrors.Select(x => x.Message));
89-
// Assert
90-
Assert.That(errorMessage, Is.StringContaining("invalid string index: 'x'"));
56+
Assert.That(result.Result, Is.EqualTo("Result : ERROR: " + missingVar + " is undefined"));
9157

9258
}
9359

94-
9560
[Test]
9661
[TestCase("x")]
62+
[TestCase("e.first")]
9763
[TestCase("e[1]")]
98-
[TestCase("e.x")]
9964
[TestCase("d.x")]
10065
[TestCase("d[x]")]
101-
[TestCase("a.b.c")]
102-
public void It_Should_Not_Display_An_Error_When_Dereferencing_Missing_Value(String varname)
66+
public void It_Should_Not_Display_An_Error_When_Values_Are_Missing(String varname)
10367
{
10468
// Arrange
10569
Console.WriteLine(varname);
106-
TemplateContext ctx = new TemplateContext();
107-
ctx.DefineLocalVariable("e", new LiquidCollection());
108-
ctx.DefineLocalVariable("d", new LiquidHash());
70+
ITemplateContext ctx = new TemplateContext()
71+
.ErrorWhenVariableMissing();
72+
ctx.DefineLocalVariable("e", new LiquidCollection(new[] { LiquidValue.None, LiquidValue.None, LiquidValue.None }));
73+
ctx.DefineLocalVariable("d", new LiquidHash()
74+
{
75+
{ "x", LiquidValue.None }
76+
});
77+
ctx.DefineLocalVariable("x", LiquidValue.None);
10978

11079
// Act
11180
var result = RenderingHelper.RenderTemplate("Result : {{ " + varname + " }}", ctx);
11281

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

Liquid.NET.Tests/Liquid.NET.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<Compile Include="Constants\LiquidRangeTests.cs" />
6666
<Compile Include="Constants\IndexDereferencerTests.cs" />
6767
<Compile Include="Constants\MissingValueTests.cs" />
68+
<Compile Include="Constants\MissingVariableTests.cs" />
6869
<Compile Include="Constants\LiquidNumericTests.cs" />
6970
<Compile Include="Constants\LiquidStringTests.cs" />
7071
<Compile Include="Constants\ValueCasterTests.cs" />

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; }

Liquid.NET/src/TemplateContext.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,19 @@ public ITemplateContext ErrorWhenValueMissing()
263263
_options.ErrorWhenValueMissing = true;
264264
return this;
265265
}
266+
267+
public ITemplateContext ErrorWhenVariableMissing()
268+
{
269+
_options.ErrorWhenVariableMissing = true;
270+
return this;
271+
}
266272
}
267273

268274
public class LiquidOptions
269275
{
270276
public bool NoForLimit { get; internal set; }
271277
public bool ErrorWhenValueMissing { get; set; }
278+
public bool ErrorWhenVariableMissing { get; set; }
272279
}
273280

274281
}

0 commit comments

Comments
 (0)