internal static string ToDebugString(this SyntacticTree queryDescriptor) { if (queryDescriptor == null) { return("(null)"); } string result = queryDescriptor.Path.ToDebugString(); var queryOptions = new List <KeyValuePair <string, string> >(); if (queryDescriptor.Filter != null) { queryOptions.Add(new KeyValuePair <string, string>("$filter", queryDescriptor.Filter.ToDebugString())); } if (queryDescriptor.OrderByTokens != null) { queryOptions.Add(new KeyValuePair <string, string>("$orderby", string.Join(",", queryDescriptor.OrderByTokens.Select(ob => ob.ToDebugString()).ToArray()))); } if (queryDescriptor.Select != null) { queryOptions.Add(new KeyValuePair <string, string>("$select", queryDescriptor.Select.ToDebugString())); } if (queryOptions.Count > 0) { result += "?" + string.Join("&", queryOptions.Select(qo => qo.Key + "=" + qo.Value).ToArray()); } return(result); }
public void FormatExpressionTest() { string[] values = new string[] { "json", "xml", "foo", "bar" }; var testCases = values.Select(value => new { Value = value, }); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", format: testCase.Value); SyntacticTree expected = new SyntacticTree( null, new[] { "Root" }, null, null, null, null, null, null, null, testCase.Value, null); QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert); }); }
/// <summary> /// Binds a <see cref="SyntacticTree"/>. /// </summary> /// <param name="syntax">The query descriptor token to bind.</param> /// <returns>The bound query descriptor.</returns> public ODataUri BindTree(SyntacticTree syntax) { ExceptionUtils.CheckArgumentNotNull(syntax, "syntax"); ExceptionUtils.CheckArgumentNotNull(syntax.Path, "syntax.Path"); // Make a copy of query options since we may consume some of them as we bind the query bindingState.QueryOptions = new List <CustomQueryOptionToken>(syntax.QueryOptions); ParameterAliasValueAccessor parameterAliasValueAccessor = new ParameterAliasValueAccessor(syntax.ParameterAliases); ODataPath path = null; FilterClause filter = null; OrderByClause orderBy = null; long? skip = null; long? top = null; SelectExpandClause selectExpand = null; bool? count = null; // set parameterAliasValueAccessor for uri path, $filter, $orderby this.bindingState.Configuration.ParameterAliasValueAccessor = parameterAliasValueAccessor; // First bind the path path = ODataPathFactory.BindPath(syntax.Path, this.bindingState.Configuration); // If the path leads to a collection, then create a range variable that represents iterating over the collection var rangeVariable = NodeFactory.CreateImplicitRangeVariable(path); if (rangeVariable != null) { this.bindingState.RangeVariables.Push(rangeVariable); } if (syntax.Filter != null || syntax.OrderByTokens.Any()) { this.bindingState.ImplicitRangeVariable = this.bindingState.RangeVariables.Peek(); } // Apply filter first, then order-by, skip, top, select and expand filter = BindFilter(syntax, rangeVariable); orderBy = BindOrderBy(syntax, rangeVariable, path); skip = BindSkip(syntax, rangeVariable, path); top = BindTop(syntax, rangeVariable, path); selectExpand = BindSelectExpand(syntax, path, this.bindingState.Configuration); count = BindQueryCount(syntax, path); // Add the remaining query options to the query descriptor. List <QueryNode> boundQueryOptions = MetadataBinder.ProcessQueryOptions(this.bindingState, this.bindMethod); Debug.Assert(bindingState.QueryOptions == null, "this.queryOptions == null"); bindingState.RangeVariables.Pop(); bindingState.ImplicitRangeVariable = null; return(new ODataUri(parameterAliasValueAccessor, path, boundQueryOptions, selectExpand, filter, orderBy, skip, top, count)); }
public void CountExpressionTest() { object[] values = new object[] { null, 0, 1, 2, 5, 11111, -2, 12.3, "Foo", -12.4m, 'c', (long)int.MaxValue + 1, (long)int.MinValue - 1, 2.3f, "(1)", "2 + 3", "int.MaxValue", "false", "true", "False", "True", "FaLSE", "trUE" }; string errorMessageTemplate = "Invalid value '{0}' for $count query option found. Valid values are '{1}'."; HashSet <string> correctValues = new HashSet <string>(StringComparer.OrdinalIgnoreCase) { "true", "false" }; string correctValuesStr = string.Join(", ", correctValues.ToArray()); var testCases = values.Select(value => new { Value = value == null ? null : value.ToString(), ExpectedErrorMessage = value == null || correctValues.Contains(value.ToString()) ? null : string.Format(CultureInfo.InvariantCulture, errorMessageTemplate, value, correctValuesStr).Replace('+', ' ') // URI all + will be replace by space }); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { this.Assert.ExpectedException <ODataException>( () => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", count: testCase.Value); bool?countQuery = null; if (testCase.Value != null) { bool countValue; bool.TryParse(testCase.Value, out countValue); countQuery = countValue; } SyntacticTree expected = new SyntacticTree( null, new[] { "Root" }, null, null, null, null, null, null, countQuery, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert); }, testCase.ExpectedErrorMessage, null); }); }
public void ParseThenBind() { var serviceBaseUri = new Uri("http://server/service/"); var queryUri = new Uri(serviceBaseUri, "Customers(1)"); var syntacticTree = SyntacticTree.ParseUri(queryUri, serviceBaseUri); var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); MetadataBinder binder = new MetadataBinder(model); var semanticTree = binder.BindQuery(syntacticTree); }
/// <summary> /// Parses the specified query into a query descriptor. /// </summary> /// <param name="query">The query.</param> /// <returns>The parsed query.</returns> internal static SyntacticTree ParseQuery(string query) { Uri baseUri = new Uri("http://odata.org/test/"); if (query.StartsWith("/")) { query = query.Substring(1); } return(SyntacticTree.ParseUri(new Uri(baseUri, query), baseUri)); }
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"); }
/// <summary> /// Bind a skip option /// </summary> /// <param name="syntax">a syntax tree containing the skip option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection</param> /// <param name="path">the top level path.</param> /// <returns>a nullable long representing this skip option</returns> public static long?BindSkip(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path) { if (syntax.Skip != null) { if (rangeVariable == null || !path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$skip")); } return(MetadataBinder.ProcessSkip(syntax.Skip)); } return(null); }
/// <summary> /// Bind a count option /// </summary> /// <param name="syntax">The count option to bind.</param> /// <param name="path">the top level path</param> /// <returns>a count representing this count option</returns> public static bool?BindQueryCount(SyntacticTree syntax, ODataPath path) { if (syntax.QueryCount != null) { if (!path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$count")); } return(syntax.QueryCount); } return(null); }
/// <summary> /// Bind an orderby option /// </summary> /// <param name="syntax">a syntac tree containing the orderby option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection</param> /// <param name="path">the top level path</param> /// <returns>an OrderByClause representing this orderby option</returns> public OrderByClause BindOrderBy(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path) { if (syntax.OrderByTokens != null && syntax.OrderByTokens.Any()) { if (rangeVariable == null || !path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$orderby")); } OrderByBinder orderByBinder = new OrderByBinder(this.bindMethod); return(orderByBinder.BindOrderBy(this.bindingState, syntax.OrderByTokens)); } return(null); }
/// <summary> /// Bind a filter option /// </summary> /// <param name="syntax">a syntactic tree containing the filter option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection.</param> /// <returns>A filter clause representing this filter option</returns> public FilterClause BindFilter(SyntacticTree syntax, RangeVariable rangeVariable) { if (syntax.Filter != null) { if (rangeVariable == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$filter")); } FilterBinder filterBinder = new FilterBinder(this.bindMethod, this.bindingState); return(filterBinder.BindFilter(syntax.Filter)); } return(null); }
/// <summary> /// Bind a select and expand option. /// </summary> /// <param name="syntax">A syntax tree containing the select and expand options to bind</param> /// <param name="path">the top level path</param> /// <param name="configuration">The configuration to use for binding.</param> /// <returns>a select expand clause bound to metadata</returns> public static SelectExpandClause BindSelectExpand(SyntacticTree syntax, ODataPath path, ODataUriParserConfiguration configuration) { if (syntax.Select != null || syntax.Expand != null) { if (!path.EdmType().IsEntityCollection() && !path.EdmType().IsEntity()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$select or $expand")); } SelectExpandSemanticBinder semanticBinder = new SelectExpandSemanticBinder(); return(semanticBinder.Bind((IEdmEntityType)((IEdmCollectionTypeReference)path.EdmType()).ElementType().Definition, path.NavigationSource(), syntax.Expand, syntax.Select, configuration)); } return(null); }
/// <summary> /// Verifies that two queries are equal. /// </summary> /// <param name="expected">The expected query.</param> /// <param name="actual">The actual query.</param> /// <param name="assert">Assertion handler to use.</param> internal static void VerifySyntaxTreesAreEqual(SyntacticTree expected, SyntacticTree actual, AssertionHandler assert) { try { if (!VerifyNullnessMatches(expected, actual, assert, "query")) { return; } VerifySyntaxTreesAreEqualImpl(expected, actual, assert); } catch (Exception) { assert.Warn("Expected query: " + expected.ToDebugString()); assert.Warn("Actual query: " + actual.ToDebugString()); throw; } }
public void ExpandExpressionTest() { IEnumerable <ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases() .Concat(ExpressionTestCase.BinaryOperatorTestCases()) .Concat(ExpressionTestCase.UnaryOperatorTestCases()) .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames)) .Concat(ExpressionTestCase.ParenthesisTestCases()) .Concat(ExpressionTestCase.FunctionCallTestCases()); var testCases = expressionTestCases.Select(tc => new ExpandTestCase() { Expand = tc.Expression, ExpectedExpandToken = new ExpandToken(new QueryToken[] { tc.ExpectedToken }) }); // All expressions testCases.Concat(new ExpandTestCase[] { new ExpandTestCase() { Expand = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()), ExpectedExpandToken = new ExpandToken(expressionTestCases.Select(tc => tc.ExpectedToken)) } }); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", expand: testCase.Expand); SyntacticTree expected = new SyntacticTree( new SegmentToken("Root", null, null), null, null, null, testCase.ExpectedExpandToken, null, null, null, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual( expected, actual, this.Assert); }); }
public static string GetOperationName(Uri requestUri, Uri baseAddress) { try { // remove the query part as they are irrelevant here and we dont want to fail parsing them. Uri requestUriWithoutQuerypart = new Uri(requestUri.GetLeftPart(UriPartial.Path)); SyntacticTree syntacticTree = SyntacticTree.ParseUri(requestUriWithoutQuerypart, baseAddress); SegmentQueryToken lastSegment = syntacticTree.Path as SegmentQueryToken; if (lastSegment != null && !String.IsNullOrEmpty(lastSegment.Name)) { return(lastSegment.Name); } } catch (Exception) { } return(null); }
private static void VerifySyntaxTreesAreEqualImpl(SyntacticTree expected, SyntacticTree actual, AssertionHandler assert) { VerifyStringsAreEqual(expected.Path, actual.Path, assert); VerifyQueryTokensAreEqual(expected.Filter, actual.Filter, assert); if (expected.OrderByTokens != null && actual.OrderByTokens != null) { VerifyQueryTokensAreEqual(expected.OrderByTokens.Cast <QueryToken>(), actual.OrderByTokens.Cast <QueryToken>(), assert); } else if ((expected.OrderByTokens != null && actual.OrderByTokens == null) || (expected.OrderByTokens == null && actual.OrderByTokens != null)) { assert.Fail("Query tokens are different"); } assert.AreEqual(expected.Skip, actual.Skip, "Skip values are different."); VerificationUtils.VerifyEnumerationsAreEqual( expected.QueryOptions, actual.QueryOptions, VerifyCustomQueryOptionQueryTokensAreEqual, (item) => item.ToDebugString(), assert); }
public void UriCheckTests() { this.Assert.ExpectedException <ODataException>( () => SyntacticTree.ParseUri(new Uri("http://www.odata.org/base1/foo"), new Uri("http://www.odata.org/base2/")), "The URI 'http://www.odata.org/base1/foo' is not valid because it is not based on 'http://www.odata.org/base2/'.", "The operation should fail if the request URI is not relative to the specified base."); // Starting with .Net 4.5, Uri.UnescapeDataString does not throw an exception on invalid sequence. It just does not unescape something // that it does not understand. Hence disabling these tests. //this.Assert.ExpectedException<ODataException>( // () => SyntacticTree.ParseUri(new Uri("http://www.odata.org/base1/foo%ZZ%%/", true), new Uri("http://www.odata.org/base1/")), // "Bad Request: there was an error in the query syntax.", // "Wrong escape sequence should cause ODataException."); // Test the what will be a default max depth which should be 800 string longUri = "http://www.odata.org/"; for (int i = 0; i < 801; i++) { longUri += "seg/"; } this.Assert.ExpectedException <ODataException>( () => SyntacticTree.ParseUri(new Uri(longUri), new Uri("http://www.odata.org/")), "Too many segments in URI.", "Recursion limit should reject long URI."); // Test the explicit max depth // Test short max depth longUri = "http://www.odata.org/"; for (int i = 0; i < 11; i++) { longUri += "seg/"; } this.Assert.ExpectedException <ODataException>( () => SyntacticTree.ParseUri(new Uri(longUri), new Uri("http://www.odata.org/"), 10), "Too many segments in URI.", "Recursion limit should reject long URI."); }
public void SelectExpressionTest() { IEnumerable<SelectExpressionTestCase> expressionTestCases = SelectExpressionTestCase.SelectPropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames); var testCases = expressionTestCases.Select(tc => new SelectTestCase() { Select = tc.Expression, ExpectedSelectToken = new SelectToken(new PathSegmentToken[] { tc.ExpectedToken }) }); // All expressions testCases.Concat(new SelectTestCase[] { new SelectTestCase() { Select = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()), ExpectedSelectToken = new SelectToken(expressionTestCases.Select(tc => tc.ExpectedToken)) }}); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", select: testCase.Select); SyntacticTree expected = new SyntacticTree( new StartPathToken("Root", null, null), null, null, testCase.ExpectedSelectToken, null, null, null, null, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual( expected, actual, this.Assert); }); }
public void SelectExpressionTest() { IEnumerable <SelectExpressionTestCase> expressionTestCases = SelectExpressionTestCase.SelectPropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames); var testCases = expressionTestCases.Select(tc => new SelectTestCase() { Select = tc.Expression, ExpectedSelectToken = new SelectToken(new PathSegmentToken[] { tc.ExpectedToken }) }); // All expressions testCases.Concat(new SelectTestCase[] { new SelectTestCase() { Select = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()), ExpectedSelectToken = new SelectToken(expressionTestCases.Select(tc => tc.ExpectedToken)) } }); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", select: testCase.Select); SyntacticTree expected = new SyntacticTree( new StartPathToken("Root", null, null), null, null, testCase.ExpectedSelectToken, null, null, null, null, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual( expected, actual, this.Assert); }); }
void RunTest(bool includeSpaceAroundSymbols) { var testCases = new[] { new { QueryOptions = (List <KeyValuePair <string, string> >)null, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$filter", "3 eq 2") }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("CustomValue", "null") }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("null", "CustomValue") }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$custom", "2") }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$a", "1"), new KeyValuePair <string, string>("$b", "2"), }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("a", "1"), new KeyValuePair <string, string>("$filter", "3 eq 2"), new KeyValuePair <string, string>("b", "2"), }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$a", "1"), new KeyValuePair <string, string>("$filter", "3 eq 2"), new KeyValuePair <string, string>("$b", "2"), }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("a", "1"), new KeyValuePair <string, string>("b", "2"), new KeyValuePair <string, string>("a", "2"), new KeyValuePair <string, string>("b", "4"), }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$filter", "3 eq 2"), new KeyValuePair <string, string>("$filter", "2 eq 3"), new KeyValuePair <string, string>("$b", "2"), }, ExpectedErrorMessage = "Query option '$filter' was specified more than once, but it must be specified at most once.", }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$select", "Name") }, ExpectedErrorMessage = (string)null, }, new { QueryOptions = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("$expand", "Products") }, ExpectedErrorMessage = (string)null, }, }; this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { this.Assert.ExpectedException <ODataException>( () => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", testCase.QueryOptions, includeSpaceAroundSymbols); List <CustomQueryOptionToken> options = QueryTokenUtils.NormalizeAndRemoveBuiltInQueryOptions(testCase.QueryOptions); options = options != null && options.Count == 0 ? null : options; SyntacticTree expected = new SyntacticTree( null, new[] { "Feed" }, actual.Filter, actual.OrderByTokens, null, null, actual.Skip, null, null, null, options); QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert); }, testCase.ExpectedErrorMessage, null); }); }
private bool TryReadSearchFilter(HttpRequestBase request, out SearchFilter searchFilter) { var odataQuery = SyntacticTree.ParseUri(new Uri(SiteRoot + request.RawUrl), new Uri(SiteRoot)); var keywordPath = odataQuery.Path as KeywordSegmentQueryToken; searchFilter = new SearchFilter { // HACK: The way the default paging works is WCF attempts to read up to the MaxPageSize elements. If it finds as many, it'll assume there // are more elements to be paged and generate a continuation link. Consequently we'll always ask to pull MaxPageSize elements so WCF generates the // link for us and then allow it to do a Take on the results. The alternative to do is roll our IDataServicePagingProvider, but we run into // issues since we need to manage state over concurrent requests. This seems like an easier solution. Take = MaxPageSize, Skip = odataQuery.Skip ?? 0, CountOnly = keywordPath != null && keywordPath.Keyword == KeywordKind.Count, SortDirection = SortDirection.Ascending }; var filterProperty = odataQuery.Filter as PropertyAccessQueryToken; if (filterProperty == null || !(filterProperty.Name.Equals("IsLatestVersion", StringComparison.Ordinal) || filterProperty.Name.Equals("IsAbsoluteLatestVersion", StringComparison.Ordinal))) { // We'll only use the index if we the query searches for latest \ latest-stable packages return(false); } var orderBy = odataQuery.OrderByTokens.FirstOrDefault(); if (orderBy == null || orderBy.Expression == null) { searchFilter.SortProperty = SortProperty.Relevance; } else if (orderBy.Expression.Kind == QueryTokenKind.PropertyAccess) { var propertyAccess = (PropertyAccessQueryToken)orderBy.Expression; if (propertyAccess.Name.Equals("DownloadCount", StringComparison.Ordinal)) { searchFilter.SortProperty = SortProperty.DownloadCount; } else if (propertyAccess.Name.Equals("Published", StringComparison.Ordinal)) { searchFilter.SortProperty = SortProperty.Recent; } else if (propertyAccess.Name.Equals("Id", StringComparison.Ordinal)) { searchFilter.SortProperty = SortProperty.DisplayName; } else { Debug.WriteLine("Order by clause {0} is unsupported", propertyAccess.Name); return(false); } } else if (orderBy.Expression.Kind == QueryTokenKind.FunctionCall) { var functionCall = (FunctionCallQueryToken)orderBy.Expression; if (functionCall.Name.Equals("concat", StringComparison.OrdinalIgnoreCase)) { // We'll assume this is concat(Title, Id) searchFilter.SortProperty = SortProperty.DisplayName; searchFilter.SortDirection = orderBy.Direction == OrderByDirection.Descending ? SortDirection.Descending : SortDirection.Ascending; } else { Debug.WriteLine("Order by clause {0} is unsupported", functionCall.Name); return(false); } } else { Debug.WriteLine("Order by clause {0} is unsupported", orderBy.Expression.Kind); return(false); } return(true); }
public void OrderByExpressionTest() { IEnumerable <ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases() .Concat(ExpressionTestCase.BinaryOperatorTestCases()) .Concat(ExpressionTestCase.UnaryOperatorTestCases()) .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames)) .Concat(ExpressionTestCase.ParenthesisTestCases()) .Concat(ExpressionTestCase.FunctionCallTestCases()); // Use filter expressions first without anything var filterWithNoDirection = expressionTestCases.Select(tc => new OrderByTestCase() { OrderBy = tc.Expression, ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Ascending) } }); // Use filter expressions with asc var filterWithAscending = expressionTestCases.Select(tc => new OrderByTestCase() { OrderBy = tc.Expression + " asc", ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Ascending) } }); // Use filter expressions with desc var filterWithDescending = expressionTestCases.Select(tc => new OrderByTestCase() { OrderBy = tc.Expression + " desc", ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Descending) } }); // And now some order by specific cases with multiple orderbys var orderByTestCases = ExpressionTestCase.VariousExpressions().ToList().Variations(3).Select(tc => new OrderByTestCase { OrderBy = string.Join(",", tc.Select((t, index) => t.Expression + ((index % 3 == 0) ? "" : ((index % 3 == 1) ? " asc" : " desc"))).ToArray()), ExpectedOrderByTokens = tc.Select((t, index) => new OrderByToken( t.ExpectedToken, (index % 3 == 2) ? OrderByDirection.Descending : OrderByDirection.Ascending)).ToArray() }); CombinatorialEngineProvider.RunCombinations( filterWithNoDirection .Concat(filterWithAscending) .Concat(filterWithDescending) .Concat(orderByTestCases), (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", orderby: testCase.OrderBy); SyntacticTree expected = new SyntacticTree( null, new[] { "Root" }, null, testCase.ExpectedOrderByTokens, null, null, null, null, null, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual( expected, actual, this.Assert); }); }
public void CanBuildSyntacticTree() { var serviceBaseUri = new Uri("http://server/service/"); var queryUri = new Uri(serviceBaseUri, "Customers(1)"); var syntacticTree = SyntacticTree.ParseUri(queryUri, serviceBaseUri); }
public void ExpandExpressionTest() { IEnumerable<ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases() .Concat(ExpressionTestCase.BinaryOperatorTestCases()) .Concat(ExpressionTestCase.UnaryOperatorTestCases()) .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames)) .Concat(ExpressionTestCase.ParenthesisTestCases()) .Concat(ExpressionTestCase.FunctionCallTestCases()); var testCases = expressionTestCases.Select(tc => new ExpandTestCase() { Expand = tc.Expression, ExpectedExpandToken = new ExpandToken(new QueryToken[] { tc.ExpectedToken }) }); // All expressions testCases.Concat(new ExpandTestCase[] { new ExpandTestCase() { Expand = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()), ExpectedExpandToken = new ExpandToken(expressionTestCases.Select(tc => tc.ExpectedToken)) }}); this.CombinatorialEngineProvider.RunCombinations( testCases, (testCase) => { SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", expand: testCase.Expand); SyntacticTree expected = new SyntacticTree( new SegmentToken("Root", null, null), null, null, null, testCase.ExpectedExpandToken, null, null, null, null, null); QueryTokenUtils.VerifySyntaxTreesAreEqual( expected, actual, this.Assert); }); }