public void TestCallMethodWithOverloading()
        {
            var typeProvider     = Substitute.For <ITypeProvider>();
            var instanceProvider = Substitute.For <IInstanceProvider>();

            typeProvider.GetType(Arg.Any <string>()).Returns(typeof(TestOverloading));
            var testInstance = new TestOverloading();

            instanceProvider.GetInstance(typeof(TestOverloading)).Returns(testInstance);

            var templateProcessor = Substitute.For <ITemplateProcessor>();

            templateProcessor.LeftTemplateBorder.Returns("{");
            templateProcessor.RightTemplateBorder.Returns("}");
            templateProcessor.MemberLabelSeparator.Returns(":");
            templateProcessor.PropertyMemberLabel.Returns("p");
            templateProcessor.DataItemMemberLabel.Returns("di");
            templateProcessor.MethodCallMemberLabel.Returns("m");
            templateProcessor.GetValue("p:Name").Returns("TestName");
            templateProcessor.GetValue("p:Value").Returns(7);
            templateProcessor.GetValue("p:Value2").Returns((short)77);
            templateProcessor.GetValue("p:Value3").Returns(null);

            var methodCallValueProvider = new DefaultMethodCallValueProvider(typeProvider, instanceProvider);

            Assert.AreEqual("Method1()", methodCallValueProvider.CallMethod("Method1()", templateProcessor, null));

            Assert.AreEqual("Method2(int), a = 15", methodCallValueProvider.CallMethod("Method2([int]15)", templateProcessor, null));
            Assert.AreEqual("Method2(int), a = 15", methodCallValueProvider.CallMethod("Method2([ Int32 ] 15)", templateProcessor, null));
            Assert.AreEqual("Method2(int), a = 7", methodCallValueProvider.CallMethod("Method2(p:Value)", templateProcessor, null));
            Assert.AreEqual("Method2(string), a = str", methodCallValueProvider.CallMethod("Method2([string]str)", templateProcessor, null));
            Assert.AreEqual("Method2(string), a = str", methodCallValueProvider.CallMethod("Method2(\"str\")", templateProcessor, null));
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(15)", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2(15)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2([short] 15)", templateProcessor, null), "More than one method found with suitable number of parameters. In this case the method is chosen by exact match of parameter types. None of methods is suitable. MethodCallTemplate: Method2([short] 15)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(p:Value2)", templateProcessor, null), "More than one method found with suitable number of parameters. In this case the method is chosen by exact match of parameter types. None of methods is suitable. MethodCallTemplate: Method2(p:Value2)");

            Assert.AreEqual("Method2(int, string), a = 15, b = str", methodCallValueProvider.CallMethod("Method2([int]15, \"str\")", templateProcessor, null));
            Assert.AreEqual("Method2(int, string), a = 15, b = str", methodCallValueProvider.CallMethod("Method2([Int32]15, [String]str)", templateProcessor, null));
            Assert.AreEqual("Method2(int, string), a = 15, b = TestName", methodCallValueProvider.CallMethod("Method2([Int32]15, p:Name)", templateProcessor, null));
            Assert.AreEqual("Method2(int, string), a = 7, b = TestName", methodCallValueProvider.CallMethod("Method2(p:Value, p:Name)", templateProcessor, null));
            Assert.AreEqual("Method2(int, string), a = 7, b = p:Name", methodCallValueProvider.CallMethod("Method2(p:Value, \"p:Name\")", templateProcessor, null));
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(15, str)", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2(15, str)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2([int]15, str)", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2([int]15, str)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(15, [string]str)", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2(15, [string]str)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(15, \"str\")", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2(15, \"str\")");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2(p:Value2, p:Name)", templateProcessor, null), "More than one method found with suitable number of parameters. In this case the method is chosen by exact match of parameter types. None of methods is suitable. MethodCallTemplate: Method2(p:Value2, p:Name)");

            Assert.AreEqual("Method2(string, int), a = str, b = 15", methodCallValueProvider.CallMethod("Method2(\"str\", [int]15)", templateProcessor, null));
            Assert.AreEqual("Method2(string, int), a = str, b = 15", methodCallValueProvider.CallMethod("Method2([String]str, [Int32]15)", templateProcessor, null));
            Assert.AreEqual("Method2(string, int), a = TestName, b = 7", methodCallValueProvider.CallMethod("Method2(p:Name, p:Value)", templateProcessor, null));

            Assert.AreEqual("Method2(int, string, long), a = 15, b = str, c = 20", methodCallValueProvider.CallMethod("Method2([int]15, [string]str, [long]20)", templateProcessor, null));
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2([int]15, [string]str, 20)", templateProcessor, null), "More than one method found with suitable number of parameters but some of static parameters does not specify a type explicitly. Specify the type explicitly for all static parameters and try again. MethodCallTemplate: Method2([int]15, [string]str, 20)");
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method2([int]15, [string]str, [short]20)", templateProcessor, null), "More than one method found with suitable number of parameters. In this case the method is chosen by exact match of parameter types. None of methods is suitable. MethodCallTemplate: Method2([int]15, [string]str, [short]20)");

            Assert.AreEqual("Method2(int, string, long, short), a = 15, b = str, c = 20, d = 200", methodCallValueProvider.CallMethod("Method2(15, str, 20, 200)", templateProcessor, null));
            Assert.AreEqual("Method2(int, string, long, short), a = 15, b = str, c = 20, d = 200", methodCallValueProvider.CallMethod("Method2([short]15, str, 20, 200)", templateProcessor, null));
            Assert.AreEqual("Method2(int, string, long, short), a = 7, b = TestName, c = 7, d = 77", methodCallValueProvider.CallMethod("Method2(p:Value, p:Name, p:Value, p:Value2)", templateProcessor, null));
            ExceptionAssert.Throws <ArgumentException>(() => methodCallValueProvider.CallMethod("Method2(p:Value, p:Name, p:Value2, p:Value)", templateProcessor, null));
            ExceptionAssert.Throws <FormatException>(() => methodCallValueProvider.CallMethod("Method2(p:Value, p:Name, str, p:Value)", templateProcessor, null));
            ExceptionAssert.Throws <MethodNotFoundException>(() => methodCallValueProvider.CallMethod("Method2(15, str, 20, 200, str2)", templateProcessor, null), "Could not find public method \"Method2\" in type \"TestOverloading\" and all its parents with suitable number of parameters. MethodCallTemplate: Method2(15, str, 20, 200, str2)");

            Assert.AreEqual("Method3(int, string, sbyte), a = 15, b = str, c = 1", methodCallValueProvider.CallMethod("Method3(15)", templateProcessor, null));
            Assert.AreEqual("Method3(int, string, sbyte), a = 15, b = str2, c = 1", methodCallValueProvider.CallMethod("Method3(15, str2)", templateProcessor, null));
            Assert.AreEqual("Method3(int, string, sbyte), a = 15, b = str2, c = 127", methodCallValueProvider.CallMethod("Method3(15, str2, 127)", templateProcessor, null));
            Assert.AreEqual("Method3(int, string, sbyte), a = 15, b = str2, c = 0", methodCallValueProvider.CallMethod("Method3(15, str2, p:Value3)", templateProcessor, null));
            Assert.AreEqual("Method3(int, string, sbyte), a = 0, b = str2, c = 1", methodCallValueProvider.CallMethod("Method3(p:Value3, str2)", templateProcessor, null));
            ExceptionAssert.Throws <FormatException>(() => methodCallValueProvider.CallMethod("Method3(str, str2, 127)", templateProcessor, null));
            ExceptionAssert.Throws <FormatException>(() => methodCallValueProvider.CallMethod("Method3([int]str, str2, 127)", templateProcessor, null));
            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method3([int33]15)", templateProcessor, null), "Type \"int33\" is not supported");
            ExceptionAssert.Throws <OverflowException>(() => methodCallValueProvider.CallMethod("Method3(15, str2, 200)", templateProcessor, null));
            ExceptionAssert.Throws <InvalidOperationException>(() => methodCallValueProvider.CallMethod("Method3()", templateProcessor, null), "Mismatch parameters count. Input parameters count: 0. Method required parameters count: 1. MethodCallTemplate: Method3()");
            ExceptionAssert.Throws <InvalidOperationException>(() => methodCallValueProvider.CallMethod("Method3(1, 2, 3, 4)", templateProcessor, null), "Mismatch parameters count. Input parameters count: 4. Method parameters count: 3. MethodCallTemplate: Method3(1, 2, 3, 4)");

            ExceptionAssert.Throws <NotSupportedException>(() => methodCallValueProvider.CallMethod("Method4([int]15)", templateProcessor, null), "Methods which have \"params\" argument are not supported. MethodCallTemplate: Method4([int]15)");
            ExceptionAssert.Throws <MethodNotFoundException>(() => methodCallValueProvider.CallMethod("Method5()", templateProcessor, null), "Could not find public method \"Method5\" in type \"TestOverloading\" and all its parents. MethodCallTemplate: Method5()");
        }
        public void TestCallMethod()
        {
            ExceptionAssert.Throws <ArgumentNullException>(() => new DefaultMethodCallValueProvider(null, Substitute.For <IInstanceProvider>()));
            ExceptionAssert.Throws <ArgumentNullException>(() => new DefaultMethodCallValueProvider(Substitute.For <ITypeProvider>(), null));

            var typeProvider     = Substitute.For <ITypeProvider>();
            var instanceProvider = Substitute.For <IInstanceProvider>();

            typeProvider.GetType(Arg.Any <string>()).Returns(typeof(TestClass));
            var testInstance = new TestClass();

            instanceProvider.GetInstance(typeof(TestClass)).Returns(testInstance);

            var templateProcessor = Substitute.For <ITemplateProcessor>();
            var dataItem          = new HierarchicalDataItem();

            templateProcessor.LeftTemplateBorder.Returns("<<");
            templateProcessor.RightTemplateBorder.Returns(">>");
            templateProcessor.MemberLabelSeparator.Returns("**");
            templateProcessor.PropertyMemberLabel.Returns("prop");
            templateProcessor.DataItemMemberLabel.Returns("data");
            templateProcessor.MethodCallMemberLabel.Returns("meth");
            templateProcessor.GetValue("prop**Name").Returns("TestName");
            templateProcessor.GetValue("prop**Value", dataItem).Returns(7);

            var methodCallValueProvider = new DefaultMethodCallValueProvider(typeProvider, instanceProvider);

            ExceptionAssert.Throws <ArgumentException>(() => methodCallValueProvider.CallMethod(null, templateProcessor, new HierarchicalDataItem()));
            ExceptionAssert.Throws <ArgumentException>(() => methodCallValueProvider.CallMethod(string.Empty, templateProcessor, new HierarchicalDataItem()));
            ExceptionAssert.Throws <ArgumentException>(() => methodCallValueProvider.CallMethod(" ", templateProcessor, new HierarchicalDataItem()));

            Assert.AreEqual("Str_1", methodCallValueProvider.CallMethod("Method1()", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("Str_2", methodCallValueProvider.CallMethod("TestClass:Method1()", templateProcessor, null));
            typeProvider.Received(1).GetType("TestClass");
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("Str_3", methodCallValueProvider.CallMethod(" ExcelReportGenerator.Tests.Implementations.Providers : TestClass : Method1() ", templateProcessor, null));
            typeProvider.Received(1).GetType("ExcelReportGenerator.Tests.Implementations.Providers : TestClass");
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("Str_4", methodCallValueProvider.CallMethod(":TestClass:Method1()", templateProcessor, null));
            typeProvider.Received(1).GetType(":TestClass");
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("Str_5", methodCallValueProvider.CallMethod("Method1()", typeof(TestClass), templateProcessor, null));
            typeProvider.DidNotReceiveWithAnyArgs().GetType(Arg.Any <string>());
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual(25, methodCallValueProvider.CallMethod("Method2(prop**Value, 18)", templateProcessor, dataItem));
            typeProvider.Received(1).GetType(null);
            instanceProvider.DidNotReceiveWithAnyArgs().GetInstance(Arg.Any <Type>());
            templateProcessor.Received(1).GetValue("prop**Value", dataItem);

            typeProvider.ClearReceivedCalls();
            templateProcessor.ClearReceivedCalls();
            Assert.AreEqual(25, methodCallValueProvider.CallMethod(" : TestClass : Method2(prop**Value, 18) ", templateProcessor, dataItem));
            typeProvider.Received(1).GetType(": TestClass");
            instanceProvider.DidNotReceiveWithAnyArgs().GetInstance(Arg.Any <Type>());
            templateProcessor.Received(1).GetValue("prop**Value", dataItem);

            typeProvider.ClearReceivedCalls();
            templateProcessor.ClearReceivedCalls();
            Assert.IsNull(methodCallValueProvider.CallMethod("Method3()", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            templateProcessor.GetValue("meth**TestClass:Method5(prop**Desc,  meth**ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method6(str, data**Field) )").Returns(10);
            templateProcessor.GetValue("meth**Method7()").Returns('c');
            templateProcessor.GetValue("meth**:TestClass2:Method1()").Returns(long.MaxValue);

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            object result = methodCallValueProvider.CallMethod(
                "Method4(5, prop**Name, hi,  meth**TestClass:Method5(prop**Desc,  meth**ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method6(str, data**Field) ) , meth**Method7(), meth**:TestClass2:Method1())",
                templateProcessor, null);

            Assert.AreEqual($"5_TestName_hi_10_c_{long.MaxValue}", result);
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.Received(1).GetValue("prop**Name");
            templateProcessor.Received(1).GetValue("meth**TestClass:Method5(prop**Desc,  meth**ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method6(str, data**Field) )");
            templateProcessor.Received(1).GetValue("meth**Method7()");
            templateProcessor.Received(1).GetValue("meth**:TestClass2:Method1()");

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            templateProcessor.ClearReceivedCalls();
            Assert.AreEqual("_ ", methodCallValueProvider.CallMethod("Method5(\"\", \" \")", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("prop**Name_meth**Method6()", methodCallValueProvider.CallMethod("Method5(\"prop**Name\", \"meth**Method6()\")", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("\"prop**Name\"_\"\"", methodCallValueProvider.CallMethod("Method5(\"\"prop**Name\"\", \"\"\"\")", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            ExceptionAssert.Throws <MethodNotFoundException>(() => methodCallValueProvider.CallMethod("TestClass:BadMethod()", templateProcessor, null),
                                                             "Could not find public method \"BadMethod\" in type \"TestClass\" and all its parents. MethodCallTemplate: TestClass:BadMethod()");

            ExceptionAssert.Throws <MethodNotFoundException>(() => methodCallValueProvider.CallMethod("TestClass:BadMethod()", templateProcessor, null),
                                                             "Could not find public method \"BadMethod\" in type \"TestClass\" and all its parents. MethodCallTemplate: TestClass:BadMethod()");

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            templateProcessor.ClearReceivedCalls();
            Assert.AreEqual("Str_Parent", methodCallValueProvider.CallMethod("MethodParent()", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.Received(1).GetInstance(typeof(TestClass));
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());

            typeProvider.ClearReceivedCalls();
            instanceProvider.ClearReceivedCalls();
            Assert.AreEqual("Str_Static_Parent", methodCallValueProvider.CallMethod("MethodStaticParent()", templateProcessor, null));
            typeProvider.Received(1).GetType(null);
            instanceProvider.DidNotReceiveWithAnyArgs().GetInstance(Arg.Any <Type>());
            templateProcessor.DidNotReceiveWithAnyArgs().GetValue(Arg.Any <string>());
        }