public void Test_Converting_Float()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>($"2147483647 eq FloatValue");

            // Assert
            Assert.Equal("item => (2.1474836E+09 == item.FloatValue)", expression.ToString());
        }
        public void Test_Negate_Constant()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("not true");

            // Assert
            Assert.Equal("item => Not(True)", expression.ToString());
        }
        public void Test_Negate_Expression_With_Parenthesis()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("not(IntegerValue eq 5)");

            // Assert
            Assert.Equal("item => Not((item.IntegerValue == 5))", expression.ToString());
        }
        public void Test_Function_Static_Overload_Double()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("round(DoubleValue) eq 1d");

            // Assert
            Assert.Equal("item => (Round(item.DoubleValue) == 1)", expression.ToString());
        }
        public void Test_Case_Insensitive_Property()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("decimalvalue gt 10");

            // Assert
            Assert.Equal("item => (item.DecimalValue > 10)", expression.ToString());
        }
        public void Test_Function_Single_Parameter()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("tolower(StringValue) eq 'test'");

            // Assert
            Assert.Equal("item => (item.StringValue.ToLower() == \"test\")", expression.ToString());
        }
        public void Test_Function_Overload_Multiple_Parameters()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("substring(StringValue, 5, 4) eq 'Test'");

            // Assert
            Assert.Equal("item => (item.StringValue.Substring(5, 4) == \"Test\")", expression.ToString());
        }
        public void Test_Casting_Operands_Same_Type(string fieldName)
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>($"{fieldName}Value eq {fieldName}Value");

            // Assert
            Assert.Equal($"item => (item.{fieldName}Value == item.{fieldName}Value)", expression.ToString());
        }
        public void Test_Comparison_Operators_Bool(string operatorIn, string operatorOut)
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>($"BoolValue {operatorIn} false");

            // Assert
            Assert.Equal($"item => (item.BoolValue {operatorOut} False)", expression.ToString());
        }
        public void Test_Converting_Byte_To_Decimal()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("DecimalValue gt 10");

            // Assert
            Assert.Equal("item => (item.DecimalValue > 10)", expression.ToString());
        }
        public void Test_Converting_Byte_To_NullableDecimal()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("NullableDecimalValue gt 26");

            // Assert
            Assert.Equal("item => (item.NullableDecimalValue > 26)", expression.ToString());
        }
        public void Test_Converting_Byte()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("IntegerValue eq 255");

            // Assert
            Assert.Equal("item => (item.IntegerValue == 255)", expression.ToString());
        }
        public void Test_Binary_Constant(string boolIn, string boolOut)
        {
            // Act
            var expression = FilterExpressionBuilder.Build <TestType>(boolIn);

            // Assert
            Assert.Equal($"item => {boolOut}", expression.ToString());
        }
        public void Test_Converting_Long()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("2147483647 eq LongValue");

            // Assert
            Assert.Equal("item => (2147483647 == item.LongValue)", expression.ToString());
        }
        public void Test_Unknown_Function()
        {
            // Arrange
            var exception = Assert.Throws <InvalidOperationException>(() => (object)FilterExpressionBuilder.Build <TestType>("Unknown(StringValue)"));

            // Assert
            Assert.Equal("Unmatched function Unknown(String)", exception.Message);
        }
        public void Test_Casting_Operands_CastToInt(string fieldName, string castFieldName, string castType)
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>($"{fieldName}Value eq {castFieldName}Value");

            // Assert
            Assert.Equal($"item => (Convert(item.{fieldName}Value, {castType}) == Convert(item.{castFieldName}Value, {castType}))", expression.ToString());
        }
        public void Test_Function_Property()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("length(StringValue) gt 5");

            // Assert
            Assert.Equal("item => (item.StringValue.Length > 5)", expression.ToString());
        }
        public void Test_Unrecognised_Token()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("IntegerValue eq Unknown"));

            // Assert
            Assert.Equal("Unrecognised token: Unknown @ 16", exception.Message);
        }
        public void Test_Function_Multiple_Parameters()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("indexof(StringValue, 'Test') gt 5");

            // Assert
            Assert.Equal("item => (item.StringValue.IndexOf(\"Test\") > 5)", expression.ToString());
        }
        public void Test_Unexpected_Token()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("IntegerValue eq 5 Unexpected"));

            // Assert
            Assert.Equal("Unexpected token: Unexpected @ 18", exception.Message);
        }
        public void Test_Function_Static_MultipleParameters()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("concat('Some', 'thing') eq 'Something'");

            // Assert
            Assert.Equal("item => (Concat(\"Some\", \"thing\") == \"Something\")", expression.ToString());
        }
        public void Test_Expected_Boolean()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("IntegerValue"));

            // Assert
            Assert.Equal("Expected boolean expression", exception.Message);
        }
        public void Test_Function_Static_Overload_Double_With_Float()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("round(FloatValue) eq 1d");

            // Assert
            Assert.Equal("item => (Round(Convert(item.FloatValue, Double)) == 1)", expression.ToString());
        }
        public void Test_Expected_Close_Parenthesis()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("(IntegerValue gt 5"));

            // Assert
            Assert.Equal("Expected ) but got {No Token} after 5 @ 17", exception.Message);
        }
        public void Test_Comparison_Operators_Int(string operatorIn, string operatorOut)
        {
            // Act
            var expression = FilterExpressionBuilder.Build <TestType>($"IntegerValue {operatorIn} 5");

            // Assert
            Assert.Equal($"item => (item.IntegerValue {operatorOut} 5)", expression.ToString());
        }
        public void Test_Expected_Function_Close_Parenthesis_But_Different()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("Function(StringValue Different"));

            // Assert
            Assert.Equal("Expected ) but got Different @ 21", exception.Message);
        }
        public void Test_Negate_Property()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("not BoolValue");

            // Assert
            Assert.Equal("item => Not(item.BoolValue)", expression.ToString());
        }
        public void Test_Expected_Function_Close_Parenthesis()
        {
            // Arrange
            var exception = Assert.Throws <FilterExpressionException>(() => (object)FilterExpressionBuilder.Build <TestType>("Function(StringValue"));

            // Assert
            Assert.Equal("Expected ) but got {No Token} after StringValue @ 9", exception.Message);
        }
        public void Test_Precidence_Sum_Product()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("1 add 2 sub 4 div 2 mul 3 sub 5 add 10 gt 5");

            // Assert
            Assert.Equal("item => (((((1 + 2) - ((4 / 2) * 3)) - 5) + 10) > 5)", expression.ToString());
        }
        public void Test_Precidence_Sum_Product_With_Parenthesis()
        {
            // Arrange
            var expression = FilterExpressionBuilder.Build <TestType>("1 add (2 sub 4) div 2 mul (3 sub 5) add 10 gt 5");

            // Assert
            Assert.Equal("item => (((1 + (((2 - 4) / 2) * (3 - 5))) + 10) > 5)", expression.ToString());
        }