Skip to content

Commit

Permalink
fix: solve issues with delayed evaluation for context-related objects (
Browse files Browse the repository at this point in the history
…#244)

* fix: solve issues with delayed evaluation for context-related objects
* refactor: remove resolver classes now fully replaced by Func<>
* test: improve code coverage for methods TryGetValue
  • Loading branch information
Seddryck committed Jan 6, 2024
1 parent f2a9430 commit beb20f1
Show file tree
Hide file tree
Showing 41 changed files with 401 additions and 333 deletions.
129 changes: 96 additions & 33 deletions Expressif.Testing/ContextTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public void VariableAdd_OneVariable_CanBeRetrieved(string name)
Assert.That(context.Variables, Has.Count.EqualTo(1));
Assert.Multiple(() =>
{
Assert.That(context.Variables[name], Is.EqualTo("123"));
Assert.That(context.Variables[name.Replace("@", "")], Is.EqualTo("123"));
Assert.That(context.Variables.Contains(name), Is.True);
Assert.That(context.Variables.Contains(name.Replace("@", "")), Is.True);
});
}

Expand All @@ -47,9 +47,9 @@ public void VariableSet_TwiceTheSameVariable_FinalValue(string name1, string nam
{
var context = new Context();
Assert.That(context.Variables, Has.Count.EqualTo(0));
context.Variables.Set<string>(name1, "123");
context.Variables.Set(name1, "123");
Assert.That(context.Variables, Has.Count.EqualTo(1));
context.Variables.Set<string>(name2, "456");
context.Variables.Set(name2, "456");
Assert.That(context.Variables, Has.Count.EqualTo(1));
Assert.That(context.Variables[name1], Is.EqualTo("456"));
}
Expand All @@ -63,21 +63,50 @@ public void VariableRemove_TwiceTheSameVariable_NoVariableRemaining(string name1
{
var context = new Context();
Assert.That(context.Variables, Has.Count.EqualTo(0));
context.Variables.Set<string>(name1, "123");
context.Variables.Set(name1, "123");
Assert.That(context.Variables, Has.Count.EqualTo(1));
context.Variables.Remove(name2);
Assert.That(context.Variables, Has.Count.EqualTo(0));
}

[Test]
[TestCase("foo", true)]
[TestCase("@foo", true)]
[TestCase("@bar", false)]
[TestCase("bar", false)]
public void VariableContains_FooExisting_CorrectResult(string name, bool expected)
{
var context = new Context(new() { { "foo", "123" } });
Assert.That(context.Variables.Contains(name), Is.EqualTo(expected));
}

[Test]
[TestCase("foo", true)]
[TestCase("@foo", true)]
[TestCase("@bar", false)]
[TestCase("bar", false)]
public void VariableTryGetValue_FooExisting_CorrectResult(string name, bool expected)
{
var context = new Context(new() { { "foo", "123" } });
Assert.Multiple(() =>
{
Assert.That(context.Variables.TryGetValue(name, out var result), Is.EqualTo(expected));
if (expected)
Assert.That(result, Is.EqualTo("123"));
else
Assert.That(result, Is.Null);
});
}

[Test]
public void CurrentObjectName_DictionaryWithExistingKey_KeyReturned()
{
var context = new Context();
context.CurrentObject.Set(new Dictionary<string, object>{ { "foo", 123 }, { "bar", 456 } });
context.CurrentObject.Set(new Dictionary<string, object> { { "foo", 123 }, { "bar", 456 } });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.True);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.True);
});
Assert.Multiple(() =>
{
Expand All @@ -93,8 +122,8 @@ public void CurrentObjectName_ObjectWithExistingProperty_ValueReturned()
context.CurrentObject.Set(new { foo = 123, bar = 456 });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.True);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.True);
});
Assert.Multiple(() =>
{
Expand All @@ -116,8 +145,8 @@ public void CurrentObjectName_DataRowWithExistingColumn_ValueReturned()
context.CurrentObject.Set(row);
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.True);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.True);
});
Assert.Multiple(() =>
{
Expand All @@ -133,8 +162,8 @@ public void CurrentObjectName_DictionaryWithUnavailableKey_ThrowsException()
context.CurrentObject.Set(new Dictionary<string, object> { { "foo", 123 } });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.False);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.False);
});
Assert.Multiple(() =>
{
Expand All @@ -150,8 +179,8 @@ public void CurrentObjectName_ObjectWithUnavailableProperty_ThrowsException()
context.CurrentObject.Set(new { foo = 123 });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.False);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.False);
});
Assert.Multiple(() =>
{
Expand All @@ -172,8 +201,8 @@ public void CurrentObjectName_DataRowWithUnavailableColumn_ThrowsException()
context.CurrentObject.Set(row);
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists("foo"), Is.True);
Assert.That(context.CurrentObject.Exists("bar"), Is.False);
Assert.That(context.CurrentObject.Contains("foo"), Is.True);
Assert.That(context.CurrentObject.Contains("bar"), Is.False);
});
Assert.Multiple(() =>
{
Expand All @@ -186,23 +215,40 @@ public void CurrentObjectName_DataRowWithUnavailableColumn_ThrowsException()
public void CurrentObjectName_List_ThrowsException()
{
var context = new Context();
context.CurrentObject.Set(new List<int>{ 123 });
context.CurrentObject.Set(new List<int> { 123 });
Assert.Multiple(() =>
{
Assert.That(() => context.CurrentObject.Exists("myVar"), Throws.TypeOf<NotNameableContextObjectException>());
Assert.That(() => context.CurrentObject.Contains("myVar"), Throws.TypeOf<NotNameableContextObjectException>());
Assert.That(() => context.CurrentObject["myVar"], Throws.TypeOf<NotNameableContextObjectException>());
});
}

[Test]
[TestCase("foo", true)]
[TestCase("bar", false)]
public void CurrentObjectNameTryGetValue_NameExisting_CorrectResult(string name, bool expected)
{
var context = new Context();
context.CurrentObject.Set(new Dictionary<string, object> { { "foo", 123 } });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.TryGetValue(name, out var result), Is.EqualTo(expected));
if (expected)
Assert.That(result, Is.EqualTo(123));
else
Assert.That(result, Is.Null);
});
}

[Test]
public void CurrentObjectIndex_ListWithExistingIndex_ValueReturned()
{
var context = new Context();
context.CurrentObject.Set(new List<int>() { 123 , 456 });
context.CurrentObject.Set(new List<int>() { 123, 456 });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists(0), Is.True);
Assert.That(context.CurrentObject.Exists(1), Is.True);
Assert.That(context.CurrentObject.Contains(0), Is.True);
Assert.That(context.CurrentObject.Contains(1), Is.True);
});
Assert.Multiple(() =>
{
Expand All @@ -224,8 +270,8 @@ public void CurrentObjectIndex_DataRowWithExistingColumn_ValueReturned()
context.CurrentObject.Set(row);
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists(0), Is.True);
Assert.That(context.CurrentObject.Exists(1), Is.True);
Assert.That(context.CurrentObject.Contains(0), Is.True);
Assert.That(context.CurrentObject.Contains(1), Is.True);
});
Assert.Multiple(() =>
{
Expand All @@ -241,8 +287,8 @@ public void CurrentObjectIndex_ListWithUnavailableIndex_ThrowsException()
context.CurrentObject.Set(new List<int>() { 123 });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists(0), Is.True);
Assert.That(context.CurrentObject.Exists(1), Is.False);
Assert.That(context.CurrentObject.Contains(0), Is.True);
Assert.That(context.CurrentObject.Contains(1), Is.False);
});
Assert.Multiple(() =>
{
Expand All @@ -263,8 +309,8 @@ public void CurrentObjectIndex_DataRowWithUnavailableColumn_ThrowsException()
context.CurrentObject.Set(row);
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.Exists(0), Is.True);
Assert.That(context.CurrentObject.Exists(1), Is.False);
Assert.That(context.CurrentObject.Contains(0), Is.True);
Assert.That(context.CurrentObject.Contains(1), Is.False);
});
Assert.Multiple(() =>
{
Expand All @@ -277,10 +323,10 @@ public void CurrentObjectIndex_DataRowWithUnavailableColumn_ThrowsException()
public void CurrentObjectIndex_Object_ThrowsException()
{
var context = new Context();
context.CurrentObject.Set(new { foo=123 });
context.CurrentObject.Set(new { foo = 123 });
Assert.Multiple(() =>
{
Assert.That(() => context.CurrentObject.Exists(0), Throws.TypeOf<NotIndexableContextObjectException>());
Assert.That(() => context.CurrentObject.Contains(0), Throws.TypeOf<NotIndexableContextObjectException>());
Assert.That(() => context.CurrentObject[0], Throws.TypeOf<NotIndexableContextObjectException>());
});
}
Expand All @@ -292,8 +338,25 @@ public void CurrentObjectIndex_Dictionary_ThrowsException()
context.CurrentObject.Set(new Dictionary<string, object> { { "foo", 123 }, { "bar", 456 } });
Assert.Multiple(() =>
{
Assert.That(() => context.CurrentObject.Exists(0), Throws.TypeOf<NotIndexableContextObjectException>());
Assert.That(() => context.CurrentObject.Contains(0), Throws.TypeOf<NotIndexableContextObjectException>());
Assert.That(() => context.CurrentObject[0], Throws.TypeOf<NotIndexableContextObjectException>());
});
}
}

[Test]
[TestCase(0, true)]
[TestCase(100, false)]
public void CurrentObjectIndexTryGetValue_IndexExisting_CorrectResult(int index, bool expected)
{
var context = new Context();
context.CurrentObject.Set(new List<int>() { 123, 456 });
Assert.Multiple(() =>
{
Assert.That(context.CurrentObject.TryGetValue(index, out var result), Is.EqualTo(expected));
if (expected)
Assert.That(result, Is.EqualTo(123));
else
Assert.That(result, Is.Null);
});
}
}
15 changes: 9 additions & 6 deletions Expressif.Testing/ExpressionBuilderTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Expressif.Functions.Text;
using Expressif.Parsers;
using Expressif.Serializers;
using Expressif.Values.Resolvers;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -65,14 +64,18 @@ public void Chain_Multiple_CorrectlyEvaluate()
public void Chain_MultipleWithContext_CorrectlyEvaluate()
{
var context = new Context();
context.Variables.Add<int>("myVar", 15);
context.CurrentObject.Set(new List<char>() { '-', '*', ' ' });

var builder = new ExpressionBuilder()
var builder = new ExpressionBuilder(context)
.Chain<Lower>()
.Chain<PadRight>(context.Variables["myVar"]!, context.CurrentObject[1]!);
.Chain<PadRight>(ctx => ctx.Variables["myVar"], ctx => ctx.CurrentObject[1]);
var expression = builder.Build();

context.Variables.Add<int>("myVar", 15);
context.CurrentObject.Set(new List<char>() { '-', '*', ' ' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikola tesla***"));

context.Variables.Set("myVar", 16);
context.CurrentObject.Set(new List<char>() { '*', '+' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikola tesla++++"));
}

[Test]
Expand Down
40 changes: 39 additions & 1 deletion Expressif.Testing/ExpressionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ public void Evaluate_VariableAsParameter_Valid()
Assert.That(result, Is.EqualTo("niola tesla"));
}

[Test]
public void Evaluate_VariableAsParameterDoublePass_Valid()
{
var context = new Context();
var expression = new Expression("lower | remove-chars(@myChar)", context);

context.Variables.Add<char>("myChar", 'k');
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("niola tesla"));
context.Variables.Set("myChar", 'a');
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikol tesl"));
}

[Test]
public void Evaluate_ObjectPropertyAsParameter_Valid()
{
Expand All @@ -58,6 +70,19 @@ public void Evaluate_ObjectPropertyAsParameter_Valid()
Assert.That(result, Is.EqualTo("nikola esla"));
}

[Test]
public void Evaluate_ObjectPropertyAsParameterDoublePass_Valid()
{
var context = new Context();
var expression = new Expression("lower | remove-chars([CharToBeRemoved])", context);

context.CurrentObject.Set(new { CharToBeRemoved = 't' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikola esla"));

context.CurrentObject.Set(new { CharToBeRemoved = 'k' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("niola tesla"));
}

[Test]
public void Evaluate_ObjectIndexAsParameter_Valid()
{
Expand All @@ -69,6 +94,19 @@ public void Evaluate_ObjectIndexAsParameter_Valid()
Assert.That(result, Is.EqualTo("nikola tela"));
}

[Test]
public void Evaluate_ObjectIndexAsParameterDoublePass_Valid()
{
var context = new Context();
var expression = new Expression("lower | remove-chars(#1)", context);

context.CurrentObject.Set(new List<char>() { 'e', 's' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikola tela"));

context.CurrentObject.Set(new List<char>() { 'e', 'o' });
Assert.That(expression.Evaluate("Nikola Tesla"), Is.EqualTo("nikla tesla"));
}

[Test]
public void Evaluate_AliasesPrefix_Valid()
{
Expand Down Expand Up @@ -104,7 +142,7 @@ public void Evaluate_FunctionAsParameter_Valid()
{
var context = new Context();
context.Variables.Add<int>("myVar", 6);
context.CurrentObject.Set(new List<int>() { 15, 8, 3 });
context.CurrentObject.Set(new List<decimal>() { 15, 8, 3 });

var expression = new Expression("lower | skip-last-chars( {@myVar | subtract(#2) })", context);
var result = expression.Evaluate("Nikola Tesla");
Expand Down
12 changes: 6 additions & 6 deletions Expressif.Testing/Functions/ExpressionFactoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,20 @@ public void Instantiate_RoundObjectPropertyParameter_Valid()
public void Instantiate_RoundObjectIndexParameter_Valid()
{
var context = new Context();
context.CurrentObject.Set(new List<int> { 0, 4 });
var function = new ExpressionFactory().Instantiate(typeof(Round), new[] { new ObjectIndexParameter(1) }, context);
context.CurrentObject.Set(new List<int> { 0, 4 });
Assert.That(function, Is.Not.Null);
Assert.That(function, Is.TypeOf<Round>());
Assert.That((function as Round)!.Digits.Invoke(), Is.EqualTo(4));
Assert.That(((Round)function).Digits.Invoke(), Is.EqualTo(4));
}

[Test]
public void Instantiate_RoundExpressionParameter_Valid()
{
var context = new Context();
context.Variables.Add<int>("myVar", 4);
var subFunction = new InputExpressionParameter(new InputExpression(new VariableParameter("myVar"), new[] { new Function("numeric-to-increment", Array.Empty<IParameter>()) }));
var subFunction = new InputExpressionParameter(new InputExpression(new VariableParameter("myVar"), new[] { new Function("numeric-to-increment", []) }));
var function = new ExpressionFactory().Instantiate(typeof(Round), new[] { subFunction }, context);
context.Variables.Add<int>("myVar", 4);
Assert.That(function, Is.Not.Null);
Assert.That(function, Is.TypeOf<Round>());
Assert.That((function as Round)!.Digits.Invoke(), Is.EqualTo(5));
Expand All @@ -98,12 +98,12 @@ public void Instantiate_RoundExpressionParameter_Valid()
public void Instantiate_RoundMultipleExpressionParameter_Valid()
{
var context = new Context();
context.Variables.Add<int>("myVar1", 4);
context.Variables.Add<int>("myVar2", 5);
var subFunction1 = new InputExpressionParameter(new InputExpression(new VariableParameter("myVar1"), new[] { new Function("numeric-to-decrement", Array.Empty<IParameter>()) }));
var subFunction2 = new InputExpressionParameter(new InputExpression(new VariableParameter("myVar2"), new[] { new Function("numeric-to-increment", Array.Empty<IParameter>()) }));
var subFunction3 = new InputExpressionParameter(new InputExpression(new VariableParameter("myVar1"), new[] { new Function("numeric-to-add", [subFunction1]), new Function("numeric-to-multiply", [subFunction2]) }));
var function = new ExpressionFactory().Instantiate(typeof(Round), new[] { subFunction3 }, context);
context.Variables.Add<int>("myVar1", 4);
context.Variables.Add<int>("myVar2", 5);
Assert.That(function, Is.Not.Null);
Assert.That(function, Is.TypeOf<Round>());
Assert.That((function as Round)!.Digits.Invoke(), Is.EqualTo(42)); // (4+3)*6
Expand Down

0 comments on commit beb20f1

Please sign in to comment.