public void TestParseParams()
        {
            var        typeProvider            = Substitute.For <ITypeProvider>();
            var        instanceProvider        = Substitute.For <IInstanceProvider>();
            var        methodCallValueProvider = new DefaultMethodCallValueProvider(typeProvider, instanceProvider);
            MethodInfo method = methodCallValueProvider.GetType().GetMethod("ParseInputParams", BindingFlags.Instance | BindingFlags.NonPublic);

            var result = (string[])method.Invoke(methodCallValueProvider, new[] { string.Empty });

            Assert.AreEqual(0, result.Length);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { (string)null });
            Assert.AreEqual(0, result.Length);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "\"\"" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("\"\"", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { " " });
            Assert.AreEqual(0, result.Length);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "\" \"" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("\" \"", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "4" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("4", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { " p:Name " });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("p:Name", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { " m:Method() " });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m:Method()", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "m:TestClass:Method()" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m:TestClass:Method()", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "m:Namespace.TestClass:Method()" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m:Namespace.TestClass:Method()", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "m::TestClass:Method()" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m::TestClass:Method()", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "m:Method(p:Name)" });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m:Method(p:Name)", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "p:Name, 11, m:TestClass:Method(p:Name), di:Desc, [string]hi, m:Namespace.TestClass:Method( m:Method2() )" });
            Assert.AreEqual(6, result.Length);
            Assert.AreEqual("p:Name", result[0]);
            Assert.AreEqual("11", result[1]);
            Assert.AreEqual("m:TestClass:Method(p:Name)", result[2]);
            Assert.AreEqual("di:Desc", result[3]);
            Assert.AreEqual("[string]hi", result[4]);
            Assert.AreEqual("m:Namespace.TestClass:Method( m:Method2() )", result[5]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { " m:Method(p:Name, di:Desc) " });
            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("m:Method(p:Name, di:Desc)", result[0]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { " m:Method(p:Name, di:Desc) , [Int32] 11,  m:Method2(m:Namespace.TestClass:Method( m:Method2(di:Field, [long]777) , 12, p:Name), [short]11, p:Value) , ," });
            Assert.AreEqual(5, result.Length);
            Assert.AreEqual("m:Method(p:Name, di:Desc)", result[0]);
            Assert.AreEqual("[Int32] 11", result[1]);
            Assert.AreEqual("m:Method2(m:Namespace.TestClass:Method( m:Method2(di:Field, [long]777) , 12, p:Name), [short]11, p:Value)", result[2]);
            Assert.AreEqual(string.Empty, result[3]);
            Assert.AreEqual(string.Empty, result[4]);

            // Escaping
            result = (string[])method.Invoke(methodCallValueProvider, new[] { "Привет,, медвед!,m:Method(10,p:Name)" });
            Assert.AreEqual(2, result.Length);
            Assert.AreEqual("Привет, медвед!", result[0]);
            Assert.AreEqual("m:Method(10,p:Name)", result[1]);

            result = (string[])method.Invoke(methodCallValueProvider, new[] { "(Test1), \"(Test2)\", (), m:Method((Test3), \"(Test4)\", (), (Test5))" });
            Assert.AreEqual(4, result.Length);
            Assert.AreEqual("(Test1)", result[0]);
            Assert.AreEqual("\"(Test2)\"", result[1]);
            Assert.AreEqual("()", result[2]);
            Assert.AreEqual("m:Method((Test3), \"(Test4)\", (), (Test5))", result[3]);
        }
        public void TestParseTemplate()
        {
            var        typeProvider            = Substitute.For <ITypeProvider>();
            var        instanceProvider        = Substitute.For <IInstanceProvider>();
            var        methodCallValueProvider = new DefaultMethodCallValueProvider(typeProvider, instanceProvider);
            MethodInfo method = methodCallValueProvider.GetType().GetMethod("ParseTemplate", BindingFlags.Instance | BindingFlags.NonPublic);

            object       result           = method.Invoke(methodCallValueProvider, new[] { "m()" });
            Type         resultType       = result.GetType();
            PropertyInfo methodNameProp   = resultType.GetProperty("MemberName");
            PropertyInfo typeNameProp     = resultType.GetProperty("TypeName");
            PropertyInfo methodParamsProp = resultType.GetProperty("MethodParams");

            Assert.AreEqual("m", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "T:m()" });
            Assert.AreEqual("m", methodNameProp.GetValue(result));
            Assert.AreEqual("T", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { ":T:m()" });
            Assert.AreEqual("m", methodNameProp.GetValue(result));
            Assert.AreEqual(":T", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "ExcelReportGenerator.Tests.Implementations.Providers:T:m()" });
            Assert.AreEqual("m", methodNameProp.GetValue(result));
            Assert.AreEqual("ExcelReportGenerator.Tests.Implementations.Providers:T", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1()" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "TestClass:Method1()" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { ":TestClass:Method1()" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual(":TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method1()" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("ExcelReportGenerator.Tests.Implementations.Providers:TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual(string.Empty, methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1(,)" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual(",", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1( , )" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual(",", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1(\"\",\" \")" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual("\"\",\" \"", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1(()" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual("(", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1(m:Method2(p:Name))" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual("m:Method2(p:Name)", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "TestClass:Method1(m:Method2(p:Name))" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("m:Method2(p:Name)", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { ":TestClass:Method1(m:Method2(p:Name))" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual(":TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("m:Method2(p:Name)", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method1(m:Method2(p:Name))" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("ExcelReportGenerator.Tests.Implementations.Providers:TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("m:Method2(p:Name)", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1( p:Name, m:Method2(p:Name), di:Field )" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "TestClass:Method1( p:Name, m:Method2(p:Name), di:Field )" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { ":TestClass:Method1( p:Name, m:Method2(p:Name), di:Field )" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual(":TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method1( p:Name, m:Method2(p:Name), di:Field )" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("ExcelReportGenerator.Tests.Implementations.Providers:TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "Method1(p:Name, m:Method2(p:Name,  p:value , m:Method3(\"hi\", 5, p:Desc)), di:Field)" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.IsNull(typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name,  p:value , m:Method3(\"hi\", 5, p:Desc)), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "TestClass:Method1(p:Name, m:Method2(p:Name,  p:value , m:Method3(\"(\", 5, p:Desc)), di:Field)" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name,  p:value , m:Method3(\"(\", 5, p:Desc)), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { ":TestClass:Method1(p:Name, m:Method2(p:Name,  p:value , m:Method3(hi, 5, p:Desc)), di:Field)" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual(":TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name,  p:value , m:Method3(hi, 5, p:Desc)), di:Field", methodParamsProp.GetValue(result));

            result = method.Invoke(methodCallValueProvider, new[] { "ExcelReportGenerator.Tests.Implementations.Providers:TestClass:Method1(p:Name, m:Method2(p:Name,  p:value , m:Method3(hi, 5, p:Desc)), di:Field)" });
            Assert.AreEqual("Method1", methodNameProp.GetValue(result));
            Assert.AreEqual("ExcelReportGenerator.Tests.Implementations.Providers:TestClass", typeNameProp.GetValue(result));
            Assert.AreEqual("p:Name, m:Method2(p:Name,  p:value , m:Method3(hi, 5, p:Desc)), di:Field", methodParamsProp.GetValue(result));

            ExceptionAssert.ThrowsBaseException <InvalidTemplateException>(() => method.Invoke(methodCallValueProvider, new[] { "Method1" }), "Template \"Method1\" is invalid");
            ExceptionAssert.ThrowsBaseException <InvalidTemplateException>(() => method.Invoke(methodCallValueProvider, new[] { "Method1(" }), "Template \"Method1(\" is invalid");
            ExceptionAssert.ThrowsBaseException <InvalidTemplateException>(() => method.Invoke(methodCallValueProvider, new[] { "Method1)" }), "Template \"Method1)\" is invalid");
        }