Click here to Skip to main content
15,885,216 members
Articles / Web Development / HTML

Dynamic Expresso

Rate me:
Please Sign up or sign in to vote.
4.91/5 (44 votes)
18 Jan 2015MIT11 min read 80.3K   935   72  
Generate LambdaExpression or function delegate on the fly without compilation.
using System;
using System.Linq;
using NUnit.Framework;

namespace DynamicExpresso.UnitTest
{
	[TestFixture]
	public class MemberInvocationTest
	{
		[Test]
		public void Method_Property_Field_basic_test()
		{
			var x = new MyTestService();

			var target = new Interpreter().SetVariable("x", x);

			Assert.AreEqual(x.HelloWorld(), target.Eval("x.HelloWorld()"));
			Assert.AreEqual(x.AProperty, target.Eval("x.AProperty"));
			Assert.AreEqual(x.AField, target.Eval("x.AField"));
		}

		[Test]
		public void Indexer()
		{
			var target = new Interpreter();

			var x = "ciao";
			target.SetVariable("x", x);
			var y = new MyTestService();
			target.SetVariable("y", y);

			Assert.AreEqual(x[2], target.Eval("x[2]"));
			Assert.AreEqual(y[2], target.Eval("y[2]"));
			Assert.AreEqual(y[2].ToString(), target.Eval("y[2].ToString()"));
		}

		[Test]
		public void String_format()
		{
			var target = new Interpreter();

			Assert.AreEqual(string.Format("ciao {0}, today is {1}", "mondo", DateTime.Today),
											target.Eval("string.Format(\"ciao {0}, today is {1}\", \"mondo\", DateTime.Today.ToString())"));
		}

		[Test]
		public void String_format_with_type_conversion()
		{
			var target = new Interpreter();

			Assert.AreEqual(string.Format("ciao {0}, today is {1}", "mondo", DateTime.Today),
											target.Eval("string.Format(\"ciao {0}, today is {1}\", \"mondo\", DateTime.Today)"));
		}

		[Test]
		public void String_format_with_empty_string()
		{
			var target = new Interpreter();

			Assert.AreEqual(string.Format("ciao {0}", ""),
											target.Eval("string.Format(\"ciao {0}\", \"\")"));
		}

		[Test]
		public void String_format_With_Object_Params()
		{
			var target = new Interpreter();

			Assert.AreEqual(string.Format("ciao mondo, today is {0}", DateTime.Today),
											target.Eval("string.Format(\"ciao {0}, today is {1}\", \"mondo\", DateTime.Today)"));
		}

		[Test]
		public void Methods_Fields_And_Properties_By_Default_Are_Case_Sensitive()
		{
			var target = new Interpreter();

			var x = new MyTestService();
			var parameters = new[] {
                            new Parameter("x", x.GetType(), x)
                            };

			Assert.AreEqual(x.HelloWorld(), target.Eval("x.HelloWorld()", parameters));
			Assert.AreEqual(x.HELLOWORLD(), target.Eval("x.HELLOWORLD()", parameters));
			Assert.AreEqual(x.AProperty, target.Eval("x.AProperty", parameters));
			Assert.AreEqual(x.APROPERTY, target.Eval("x.APROPERTY", parameters));
			Assert.AreEqual(x.AField, target.Eval("x.AField", parameters));
			Assert.AreEqual(x.AFIELD, target.Eval("x.AFIELD", parameters));
		}

		[Test]
		public void Methods_Fields_And_Properties_Can_Be_Case_Insensitive()
		{
			var target = new Interpreter(InterpreterOptions.DefaultCaseInsensitive);

			var x = new MyTestServiceCaseInsensitive();
			var parameters = new[] {
                            new Parameter("x", x.GetType(), x)
                            };

			Assert.AreEqual(x.AMethod(), target.Eval("x.AMethod()", parameters));
			Assert.AreEqual(x.AMethod(), target.Eval("x.AMETHOD()", parameters));
			Assert.AreEqual(x.AProperty, target.Eval("x.AProperty", parameters));
			Assert.AreEqual(x.AProperty, target.Eval("x.APROPERTY", parameters));
			Assert.AreEqual(x.AField, target.Eval("x.AField", parameters));
			Assert.AreEqual(x.AField, target.Eval("x.AFIELD", parameters));
		}

		[Test]
		public void Void_Method()
		{
			var service = new MyTestService();
			var target = new Interpreter()
											.SetVariable("service", service);

			Assert.AreEqual(0, service.VoidMethodCalls);
			target.Eval("service.VoidMethod()");
			Assert.AreEqual(1, service.VoidMethodCalls);

			Assert.AreEqual(typeof(void), target.Parse("service.VoidMethod()").ReturnType);
		}

		[Test]
		public void ToString_Method_on_a_custom_type()
		{
			var service = new MyTestService();
			var target = new Interpreter()
											.SetVariable("service", service);

			Assert.AreEqual("DynamicExpresso.UnitTest.MemberInvocationTest+MyTestService", target.Eval("service.ToString()"));
		}

		[Test]
		public void ToString_Method_on_a_custom_interface_type()
		{
			MyTestInterface service = new MyTestInterfaceImp();
			var target = new Interpreter()
											.SetVariable("service", service, typeof(MyTestInterface));

			Assert.AreEqual("DynamicExpresso.UnitTest.MemberInvocationTest+MyTestInterfaceImp", target.Eval("service.ToString()"));
		}

		[Test]
		public void ToString_Method_on_a_primitive_type()
		{
			var target = new Interpreter();
			Assert.AreEqual("3", target.Eval("(3).ToString()"));
		}

		[Test]
		public void GetType_Method_on_a_custom_type()
		{
			var service = new MyTestService();
			var target = new Interpreter()
											.SetVariable("service", service);

			Assert.AreEqual(typeof(MyTestService), target.Eval("service.GetType()"));
		}

		[Test]
		public void GetType_Method_on_a_custom_interface_type()
		{
			MyTestInterface service = new MyTestInterfaceImp();
			var target = new Interpreter()
											.SetVariable("service", service, typeof(MyTestInterface));

			Assert.AreEqual(typeof(MyTestInterfaceImp), target.Eval("service.GetType()"));
		}

		[Test]
		public void GetType_Method_on_a_primitive_type()
		{
			var target = new Interpreter();
			Assert.AreEqual((3).GetType(), target.Eval("(3).GetType()"));
		}

		[Test]
		public void Method_with_nullable_param()
		{
			var target = new Interpreter();

			var x = new MyTestService();
			var y = "davide";
			var z = 5;
			int? w = null;
			var parameters = new[] {
                            new Parameter("x", x.GetType(), x),
                            new Parameter("y", y.GetType(), y),
                            new Parameter("z", z.GetType(), z),
                            new Parameter("w", typeof(int?), w)
                            };

			Assert.AreEqual(x.MethodWithNullableParam(y, z), target.Eval("x.MethodWithNullableParam(y, z)", parameters));
			Assert.AreEqual(x.MethodWithNullableParam(y, w), target.Eval("x.MethodWithNullableParam(y, w)", parameters));
			Assert.AreEqual(x.MethodWithNullableParam(y, 30), target.Eval("x.MethodWithNullableParam(y, 30)", parameters));
			Assert.AreEqual(x.MethodWithNullableParam(y, null), target.Eval("x.MethodWithNullableParam(y, null)", parameters));
		}

		[Test]
		public void Method_with_generic_param()
		{
			var target = new Interpreter();

			var x = new MyTestService();
			var y = "davide";
			double z = 5;
			int? w = null;
			var parameters = new[] {
                            new Parameter("x", x.GetType(), x),
                            new Parameter("y", y.GetType(), y),
                            new Parameter("z", z.GetType(), z),
                            new Parameter("w", typeof(int?), w)
                            };

			Assert.AreEqual(x.MethodWithGenericParam(x), target.Eval("x.MethodWithGenericParam(x)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(y), target.Eval("x.MethodWithGenericParam(y)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(z), target.Eval("x.MethodWithGenericParam(z)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(w), target.Eval("x.MethodWithGenericParam(w)", parameters));

			Assert.AreEqual(x.MethodWithGenericParam(y, x), target.Eval("x.MethodWithGenericParam(y, x)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(y, y), target.Eval("x.MethodWithGenericParam(y, y)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(y, z), target.Eval("x.MethodWithGenericParam(y, z)", parameters));
			Assert.AreEqual(x.MethodWithGenericParam(y, w), target.Eval("x.MethodWithGenericParam(y, w)", parameters));
		}

		[Test]
		public void Method_with_params_array()
		{
			var target = new Interpreter();

			var x = new MyTestService();

			target.SetVariable("x", x);

			Assert.AreEqual(0, x.MethodWithParamsArrayCalls);

			Assert.AreEqual(x.MethodWithParamsArray(DateTime.Now, 2, 1, 34), target.Eval("x.MethodWithParamsArray(DateTime.Now, 2, 1, 34)"));
			Assert.AreEqual(2, x.MethodWithParamsArrayCalls);

			var myParamArray = new int[] { 2, 1, 34 };
			target.SetVariable("myParamArray", myParamArray);

			Assert.AreEqual(x.MethodWithParamsArray(DateTime.Now, myParamArray), target.Eval("x.MethodWithParamsArray(DateTime.Now, myParamArray)"));
			Assert.AreEqual(4, x.MethodWithParamsArrayCalls);
		}

		[Test]
		public void ParamsArray_methods_are_not_called_when_there_is_an_exact_method_match()
		{
			var target = new Interpreter();

			var x = new MyTestService();

			target.SetVariable("x", x);

			target.Eval("x.AmbiguousMethod(DateTime.Now, 2, 3)");
			Assert.AreEqual(1, x.AmbiguousMethod_NormalCalls);
			Assert.AreEqual(0, x.AmbiguousMethod_ParamsArrayCalls);

			target.Eval("x.AmbiguousMethod(DateTime.Now, 2, 3, 4)");
			Assert.AreEqual(1, x.AmbiguousMethod_NormalCalls);
			Assert.AreEqual(1, x.AmbiguousMethod_ParamsArrayCalls);
		}

		interface MyTestInterface
		{
		}
		class MyTestInterfaceImp : MyTestInterface
		{

		}

		class MyTestService
		{
			public DateTime AField = DateTime.Now;
			public DateTime AFIELD = DateTime.UtcNow;

			public int AProperty
			{
				get { return 769; }
			}

			public int APROPERTY
			{
				get { return 887; }
			}

			public string HelloWorld()
			{
				return "Ciao mondo";
			}

			public string HELLOWORLD()
			{
				return "HELLO";
			}

			public int VoidMethodCalls { get; set; }
			public void VoidMethod()
			{
				System.Diagnostics.Debug.WriteLine("VoidMethod called");
				VoidMethodCalls++;
			}

			public string MethodWithNullableParam(string param1, int? param2)
			{
				return string.Format("{0} {1}", param1, param2);
			}

			public string MethodWithGenericParam<T>(T p)
			{
				return string.Format("{0}", p);
			}

			public string MethodWithGenericParam<T>(string a, T p)
			{
				return string.Format("{0} {1}", a, p);
			}

			public DateTime this[int i]
			{
				get { return DateTime.Today.AddDays(i); }
			}

			public int MethodWithParamsArrayCalls { get; set; }
			public int MethodWithParamsArray(DateTime fixedParam, params int[] paramsArray)
			{
				MethodWithParamsArrayCalls++;

				return paramsArray.Sum();
			}

			public int AmbiguousMethod_ParamsArrayCalls { get; set; }
			public void AmbiguousMethod(DateTime fixedParam, params int[] paramsArray)
			{
				AmbiguousMethod_ParamsArrayCalls++;
			}
			public int AmbiguousMethod_NormalCalls { get; set; }
			public void AmbiguousMethod(DateTime fixedParam, int p1, int p2)
			{
				AmbiguousMethod_NormalCalls++;
			}
		}

		class MyTestServiceCaseInsensitive
		{
			public DateTime AField = DateTime.Now;

			public int AProperty
			{
				get { return 769; }
			}

			public string AMethod()
			{
				return "Ciao mondo";
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions