Пример #1
0
        public void FilterBinderTest()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            this.CombinatorialEngineProvider.RunCombinations(
                LiteralTestCases()
                .Concat(UnaryOperatorTestCases())
                .Concat(BinaryOperatorTestCases())
                .Concat(PropertyAccessTestCases(model))
                .Concat(TopFilterExpressionTestCases(model))
                .Concat(BuiltInStringFunctionCallTestCases(model))
                .Concat(BuiltInDateTimeOffsetFunctionCallTestCases(model))
                .Concat(BuiltInMathFunctionCallTestCases(model)),
                (testCase) =>
            {
                string query    = "/" + testCase.EntitySetName + "?$filter=" + testCase.Filter;
                ODataUri actual = QueryNodeUtils.BindQuery(query, model);

                // construct the expected filter node
                var entitySet = model.FindDeclaredEntitySet(testCase.EntitySetName);
                CollectionResourceNode entityCollectionNode = new EntitySetNode(entitySet);
                var expectedFilter = new FilterClause(
                    testCase.ExpectedFilterCondition,
                    new ResourceRangeVariable(ExpressionConstants.It, entitySet.EntityType().ToTypeReference(false).AsEntity(), entityCollectionNode)
                    );

                QueryNodeUtils.VerifyFilterClausesAreEqual(
                    expectedFilter,
                    actual.Filter,
                    this.Assert);
            });
        }
Пример #2
0
        public void RelationalOperatorTypePromotion()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.StronglyTypedDataServiceProviderFactory);

            BinaryOperatorKind[] relationalOperatorKinds = new BinaryOperatorKind[]
            {
                BinaryOperatorKind.Equal,
                BinaryOperatorKind.NotEqual,
                BinaryOperatorKind.GreaterThan,
                BinaryOperatorKind.GreaterThanOrEqual,
                BinaryOperatorKind.LessThan,
                BinaryOperatorKind.LessThanOrEqual
            };

            var testCases = ComputeRelationalTestCases().Concat(ComputeRelationalErrorTestCases());

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                relationalOperatorKinds,
                (testCase, relationalOperatorKind) =>
            {
                string filter = testCase.Arguments[0] + " " + QueryTestUtils.ToOperatorName(relationalOperatorKind) + " " + testCase.Arguments[1];

                string errorMessage = null;
                if (testCase.ExpectedErrorMessage != null)
                {
                    errorMessage = string.Format(CultureInfo.InvariantCulture, testCase.ExpectedErrorMessage, relationalOperatorKind);
                }

                var actualFilter = this.BindFilter(model, filter, errorMessage);

                if (errorMessage == null)
                {
                    this.Assert.IsNotNull(actualFilter, "Filter must not be null.");

                    BinaryOperatorNode binaryOperatorNode = null;
                    if (actualFilter.Expression.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        binaryOperatorNode = ((ConvertNode)actualFilter.Expression).Source as BinaryOperatorNode;
                    }
                    else
                    {
                        binaryOperatorNode = actualFilter.Expression as BinaryOperatorNode;
                    }
                    this.Assert.IsNotNull(binaryOperatorNode, "Expected a binary operator at the top of the filter.");

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        binaryOperatorNode.Left.TypeReference,
                        this.Assert);

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        binaryOperatorNode.Right.TypeReference,
                        this.Assert);
                }
            });
        }
Пример #3
0
        public void UnsupportedTokenBinderErrorTest()
        {
            IEdmModel model  = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);
            var       binder = new ErrorMetadataBinder(model);
            var       token  = new LiteralToken("d");
            Action    action = () => binder.Bind(token);

            action.ShouldThrow <ODataException>().WithMessage(ODataErrorStrings.MetadataBinder_BoundNodeCannotBeNull(token.Kind));
        }
Пример #4
0
        public void BindExtensionTest()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            MetadataBinder binder = new MetadataBinder(metadata);
            SyntacticTree  syntax = new SyntacticTree(new TestExtensionQueryToken(), null, null, null, null, null, null, null, null, null);

            this.Assert.ExpectedException <ODataException>(
                () => binder.BindQuery(syntax),
                "An unsupported extension query token was found.",
                "BindExtensionTest");
        }
Пример #5
0
        public void NegateTypePromotion()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.StronglyTypedDataServiceProviderFactory);

            this.CombinatorialEngineProvider.RunCombinations(
                ComputeUnaryTestCases(UnaryOperatorKind.Negate).Concat(ComputeUnaryErrorTestCases(UnaryOperatorKind.Negate)),
                (testCase) =>
            {
                string filter = "-" + testCase.Arguments[0] + " le 0";

                string errorMessage = null;
                if (testCase.ExpectedErrorMessage != null)
                {
                    errorMessage = string.Format(CultureInfo.InvariantCulture, testCase.ExpectedErrorMessage, "Negate");
                }

                var actualFilter = this.BindFilter(metadata, filter, errorMessage);

                if (errorMessage == null)
                {
                    this.Assert.IsNotNull(actualFilter, "Filter must not be null.");

                    BinaryOperatorNode binaryOperatorNode = null;
                    if (actualFilter.Expression.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        binaryOperatorNode = ((ConvertNode)actualFilter.Expression).Source as BinaryOperatorNode;
                    }
                    else
                    {
                        binaryOperatorNode = actualFilter.Expression as BinaryOperatorNode;
                    }
                    this.Assert.IsNotNull(binaryOperatorNode, "Expected a binary operator at the top of the filter.");

                    UnaryOperatorNode unaryOperatorNode = null;
                    if (binaryOperatorNode.Left.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        unaryOperatorNode = ((ConvertNode)binaryOperatorNode.Left).Source as UnaryOperatorNode;
                    }
                    else
                    {
                        unaryOperatorNode = binaryOperatorNode.Left as UnaryOperatorNode;
                    }
                    this.Assert.IsNotNull(unaryOperatorNode, "Expected a unary operator as the left argument of the binary operator.");

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        unaryOperatorNode.Operand.TypeReference,
                        this.Assert);
                }
            });
        }
Пример #6
0
        public void InvalidFilterBinderTest()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            this.CombinatorialEngineProvider.RunCombinations(
                InvalidBinaryOperatorTestCases()
                .Concat(InvalidUnaryOperatorTestCases())
                .Concat(InvalidPropertyAccessTestCases()),
                (testCase) =>
            {
                string query = "/Customers?$filter=" + testCase.Filter;
                this.Assert.ExpectedException <ODataException>(
                    () => QueryNodeUtils.BindQuery(query, metadata),
                    testCase.ExpectedExceptionMessage,
                    "Invalid filter binder test.");
            });
        }
Пример #7
0
        public void NotTypePromotion()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.StronglyTypedDataServiceProviderFactory);

            // run over all operator kinds (not, negate)
            // use all combinations with the same argument types (plain and nullable)

            this.CombinatorialEngineProvider.RunCombinations(
                ComputeUnaryTestCases(UnaryOperatorKind.Not).Concat(ComputeUnaryErrorTestCases(UnaryOperatorKind.Not)),
                (testCase) =>
            {
                string filter = "not " + testCase.Arguments[0];

                string errorMessage = null;
                if (testCase.ExpectedErrorMessage != null)
                {
                    errorMessage = string.Format(CultureInfo.InvariantCulture, testCase.ExpectedErrorMessage, "Not");
                }

                var actualFilter = this.BindFilter(metadata, filter, errorMessage);

                if (errorMessage == null)
                {
                    this.Assert.IsNotNull(actualFilter, "Filter must not be null.");

                    UnaryOperatorNode unaryOperatorNode = null;
                    if (actualFilter.Expression.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        unaryOperatorNode = ((ConvertNode)actualFilter.Expression).Source as UnaryOperatorNode;
                    }
                    else
                    {
                        unaryOperatorNode = actualFilter.Expression as UnaryOperatorNode;
                    }
                    this.Assert.IsNotNull(unaryOperatorNode, "Expected a unary operator at the top of the filter.");

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        unaryOperatorNode.Operand.TypeReference,
                        this.Assert);
                }
            });
        }
Пример #8
0
        public void KeyLookupBinderErrorTest()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            var testCases = new[] {
                new {
                    CaseUri         = new Uri("Customers(ID=1,ID=2)", UriKind.Relative),
                    ExpectedMessage = "A key property 'ID' was found twice in a key lookup. Each key property can be specified just once in a key lookup."
                },
                new {
                    CaseUri         = new Uri("Customers(Name='Bob')", UriKind.Relative),
                    ExpectedMessage = "Property 'Name' is not declared on type 'TestNS.Customer' or is not a key property. Only key properties can be used in key lookups."
                },
                new {
                    CaseUri         = new Uri("Customers(UndeclaredProperty='Bob')", UriKind.Relative),
                    ExpectedMessage = "Property 'UndeclaredProperty' is not declared on type 'TestNS.Customer' or is not a key property. Only key properties can be used in key lookups.",
                },
                new {
                    CaseUri         = new Uri("MultiKeys(KeyA='Bob')", UriKind.Relative),
                    ExpectedMessage = "A key lookup on type 'TestNS.MultiKey' didn't specify values for all key properties. All key properties must be specified in a key lookup.",
                },
                new {
                    CaseUri         = new Uri("MultiKeys('Bob')", UriKind.Relative),
                    ExpectedMessage = "An unnamed key value was used in a key lookup on a type 'TestNS.MultiKey' which has more than one key property. Unnamed key value can only be used on a type with one key property.",
                },
                new {
                    CaseUri         = new Uri("Customers(ID='Bob')", UriKind.Relative),
                    ExpectedMessage = "Expression of type 'Edm.String' cannot be converted to type 'Edm.Int32'.",
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases, (testCase) =>
            {
                var parser    = new ODataUriParser(model, testCase.CaseUri);
                Action action = () => parser.ParsePath();
                action.ShouldThrow <ODataException>().WithMessage(testCase.ExpectedMessage);
            });
        }
        public void OrderByBinderTest()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            // TODO: add an error test where the input collection to the order-by is a singleton

            ResourceRangeVariable entityRangeVariable = new ResourceRangeVariable("dummy", model.ResolveTypeReference("TestNS.Customer", false).AsEntity(), model.FindEntityContainer("BinderTestMetadata").FindEntitySet("Customers"));

            OrderByTestCase[] testCases = new OrderByTestCase[]
            {
                new OrderByTestCase()
                {
                    OrderBy = new string[] { "true" },
                    ExpectedOrderByExpressions = new SingleValueNode[]
                    {
                        new ConstantNode(true)
                    }
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Name" },
                    ExpectedOrderByExpressions = new SingleValueNode[]
                    {
                        new SingleValuePropertyAccessNode(
                            new ResourceRangeVariableReferenceNode(entityRangeVariable.Name, entityRangeVariable),
                            model.ResolveProperty("TestNS.Customer.Name")
                            )
                    }
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "3" },
                    ExpectedOrderByExpressions = new SingleValueNode[]
                    {
                        new ConstantNode(3)
                    }
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "null" },
                    ExpectedOrderByExpressions = new SingleValueNode[]
                    {
                        new ConstantNode(null)
                    }
                },


                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Address" },
                    ExpectedExceptionMessage = "The $orderby expression must evaluate to a single value of primitive type."
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Emails" },
                    ExpectedExceptionMessage = "The $orderby expression must evaluate to a single value of primitive type."
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "NonExistant" },
                    ExpectedExceptionMessage = "Could not find a property named 'NonExistant' on type 'TestNS.Customer'."
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Name", "ID" },
                    ExpectedOrderByExpressions = new SingleValueNode[]
                    {
                        new SingleValuePropertyAccessNode(
                            new ResourceRangeVariableReferenceNode(entityRangeVariable.Name, entityRangeVariable),
                            model.ResolveProperty("TestNS.Customer.Name")
                            ),
                        new SingleValuePropertyAccessNode(
                            new ResourceRangeVariableReferenceNode(entityRangeVariable.Name, entityRangeVariable),
                            model.ResolveProperty("TestNS.Customer.ID")
                            ),
                    }
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Name", "Address" },
                    ExpectedExceptionMessage = "The $orderby expression must evaluate to a single value of primitive type."
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Name", "Emails" },
                    ExpectedExceptionMessage = "The $orderby expression must evaluate to a single value of primitive type."
                },

                new OrderByTestCase()
                {
                    OrderBy = new string[] { "Name", "NonExistant" },
                    ExpectedExceptionMessage = "Could not find a property named 'NonExistant' on type 'TestNS.Customer'."
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                new OrderByDirection?[] { null, OrderByDirection.Ascending, OrderByDirection.Descending },
                (testCase, direction) =>
            {
                string orderByDirection = direction == null
                        ? string.Empty
                        : direction == OrderByDirection.Ascending
                            ? " asc"
                            : " desc";

                this.Assert.IsTrue(testCase.OrderBy.Length > 0, "Need at least one order-by expression");

                StringBuilder queryBuilder = new StringBuilder("/Customers?$orderby=");
                for (int i = 0; i < testCase.OrderBy.Length; ++i)
                {
                    if (i > 0)
                    {
                        queryBuilder.Append(", ");
                    }
                    queryBuilder.Append(testCase.OrderBy[i]);
                    queryBuilder.Append(orderByDirection);
                }

                TestExceptionUtils.ExpectedException <ODataException>(
                    this.Assert,
                    () =>
                {
                    ODataUri actual = QueryNodeUtils.BindQuery(queryBuilder.ToString(), model);

                    // construct the expected order-by node
                    OrderByClause orderByNode = null;
                    for (int i = testCase.ExpectedOrderByExpressions.Length - 1; i >= 0; --i)
                    {
                        orderByNode = new OrderByClause(
                            orderByNode,
                            testCase.ExpectedOrderByExpressions[i],
                            direction ?? OrderByDirection.Ascending,
                            new ResourceRangeVariable(ExpressionConstants.It, model.ResolveTypeReference("TestNS.Customer", false).AsEntity(), model.FindEntityContainer("BinderTestMetadata").FindEntitySet("Customers"))
                            );
                    }

                    QueryNodeUtils.VerifyOrderByClauseAreEqual(
                        orderByNode,
                        actual.OrderBy,
                        this.Assert);
                },
                    testCase.ExpectedExceptionMessage,
                    null);
            });
        }
        public void CustomQueryOptionBinderTest()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            var testCases = new[]
            {
                new QueryOptionTestCase
                {
                    Query = "/Customers?$foo=12",
                    ExpectedExceptionMessage = "The system query option '$foo' is not supported."
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?a=b",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("a", "b")
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?a=b&c=d",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("a", "b"),
                        new CustomQueryOptionNode("c", "d")
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?a=b&a=c",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("a", "b"),
                        new CustomQueryOptionNode("a", "c")
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?foo",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode(null, "foo")
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?foo=",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("foo", string.Empty)
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?&",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode(null, string.Empty),
                        new CustomQueryOptionNode(null, string.Empty)
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?a=b&",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("a", "b"),
                        new CustomQueryOptionNode(null, string.Empty)
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?&&",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode(null, string.Empty),
                        new CustomQueryOptionNode(null, string.Empty),
                        new CustomQueryOptionNode(null, string.Empty)
                    }
                },
                new QueryOptionTestCase
                {
                    Query = "/Customers?a=b&&",
                    ExpectedQueryOptions = new CustomQueryOptionNode[]
                    {
                        new CustomQueryOptionNode("a", "b"),
                        new CustomQueryOptionNode(null, string.Empty),
                        new CustomQueryOptionNode(null, string.Empty)
                    }
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                TestExceptionUtils.ExpectedException <ODataException>(
                    this.Assert,
                    () =>
                {
                    SemanticTree actual = QueryNodeUtils.BindQuery(testCase.Query, metadata);
                    QueryNodeUtils.VerifyQueryNodesAreEqual(
                        testCase.ExpectedQueryOptions,
                        actual.CustomQueryOptions,
                        this.Assert);
                },
                    testCase.ExpectedExceptionMessage,
                    null);
            });
        }
Пример #11
0
        public void SkipAndTopBinderTest()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            var testCases = new[]
            {
                new SkipTopTestCase
                {
                    Query = "/Customers?$skip=2",
                    ExpectedSkipClause = 2
                },
                new SkipTopTestCase
                {
                    Query             = "/Customers?$top=2",
                    ExpectedTopClause = 2
                },
                new SkipTopTestCase
                {
                    Query              = "/Customers?$skip=3&$top=2",
                    ExpectedTopClause  = 2,
                    ExpectedSkipClause = 3
                },
                new SkipTopTestCase
                {
                    Query              = "/Customers?$top=2&$skip=3",
                    ExpectedTopClause  = 2,
                    ExpectedSkipClause = 3
                },
                // TODO: enable those?

                /*
                 * new SkipTopTestCase
                 * {
                 *  Query = "/Customers(0)?$top=100",
                 *  ExpectedExceptionMessage = "The $top query option cannot be applied to the query path. Top can only be applied to a collection of entities."
                 * },
                 * new SkipTopTestCase
                 * {
                 *  Query = "/Customers(0)?$skip=100",
                 *  ExpectedExceptionMessage = "The $skip query option cannot be applied to the query path. Skip can only be applied to a collection of entities."
                 * },
                 * new SkipTopTestCase
                 * {
                 *  Query = "/Customers(0)?$skip=100&top=100",
                 *  ExpectedExceptionMessage = "The $skip query option cannot be applied to the query path. Skip can only be applied to a collection of entities."
                 * },
                 * new SkipTopTestCase
                 * {
                 *  Query = "/Customers(0)?top=100&$skip=100",
                 *  ExpectedExceptionMessage = "The $skip query option cannot be applied to the query path. Skip can only be applied to a collection of entities."
                 * },
                 */
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                TestExceptionUtils.ExpectedException <ODataException>(
                    this.Assert,
                    () =>
                {
                    ODataUri actual = QueryNodeUtils.BindQuery(testCase.Query, model);
                    if (testCase.ExpectedSkipClause != null)
                    {
                        Assert.AreEqual(testCase.ExpectedSkipClause, actual.Skip, "Skip amounts are not equal!");
                    }

                    if (testCase.ExpectedTopClause != null)
                    {
                        Assert.AreEqual(testCase.ExpectedTopClause, actual.Top, "Top amounts are not equal!");
                    }
                },
                    testCase.ExpectedExceptionMessage,
                    null);
            });
        }
Пример #12
0
        public void ArithmeticOperatorTypePromotion()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.StronglyTypedDataServiceProviderFactory);

            BinaryOperatorKind[] arithmeticOperatorKinds = new BinaryOperatorKind[]
            {
                BinaryOperatorKind.Add,
                BinaryOperatorKind.Subtract,
                BinaryOperatorKind.Multiply,
                BinaryOperatorKind.Divide,
                BinaryOperatorKind.Modulo,
            };

            var testCases = ComputeArithmeticTestCases().Concat(ComputeArithmeticErrorTestCases());

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                arithmeticOperatorKinds,
                (testCase, arithmeticOperatorKind) =>
            {
                string filter = testCase.Arguments[0] + " " + QueryTestUtils.ToOperatorName(arithmeticOperatorKind) + " " + testCase.Arguments[1] + " le 0";

                string errorMessage = null;
                if (testCase.ExpectedErrorMessage != null)
                {
                    errorMessage = string.Format(CultureInfo.InvariantCulture, testCase.ExpectedErrorMessage, arithmeticOperatorKind);
                }

                var actualFilter = this.BindFilter(metadata, filter, errorMessage);

                if (errorMessage == null)
                {
                    this.Assert.IsNotNull(actualFilter, "Filter must not be null.");

                    BinaryOperatorNode binaryOperatorNode = null;
                    if (actualFilter.Expression.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        binaryOperatorNode = ((ConvertNode)actualFilter.Expression).Source as BinaryOperatorNode;
                    }
                    else
                    {
                        binaryOperatorNode = actualFilter.Expression as BinaryOperatorNode;
                    }
                    this.Assert.IsNotNull(binaryOperatorNode, "Expected a binary operator at the top of the filter.");

                    if (binaryOperatorNode.Left.InternalKind == InternalQueryNodeKind.Convert)
                    {
                        binaryOperatorNode = ((ConvertNode)binaryOperatorNode.Left).Source as BinaryOperatorNode;
                    }
                    else
                    {
                        binaryOperatorNode = binaryOperatorNode.Left as BinaryOperatorNode;
                    }
                    this.Assert.IsNotNull(binaryOperatorNode, "Expected a binary operator as the left argument of the top-level binary operator.");

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        binaryOperatorNode.Left.TypeReference,
                        this.Assert);

                    QueryTestUtils.VerifyTypesAreEqual(
                        testCase.ExpectedResultType,
                        binaryOperatorNode.Right.TypeReference,
                        this.Assert);
                }
            });
        }