diff --git a/src/JsonApiDotNetCore/Queries/Internal/Parsing/QueryTokenizer.cs b/src/JsonApiDotNetCore/Queries/Internal/Parsing/QueryTokenizer.cs index 3f49b6c7fe..f050d9f7b0 100644 --- a/src/JsonApiDotNetCore/Queries/Internal/Parsing/QueryTokenizer.cs +++ b/src/JsonApiDotNetCore/Queries/Internal/Parsing/QueryTokenizer.cs @@ -87,7 +87,7 @@ public IEnumerable EnumerateTokens() } else { - if (_textBuffer.Length == 0 && ch == ' ') + if (_textBuffer.Length == 0 && ch == ' ' && !_isInQuotedSection) { throw new QueryParseException("Unexpected whitespace."); } diff --git a/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/FilterParseTests.cs b/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/FilterParseTests.cs index b4319447f1..228ddedbb3 100644 --- a/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/FilterParseTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/FilterParseTests.cs @@ -67,6 +67,7 @@ public void Reader_Is_Enabled(JsonApiQueryStringParameters parametersDisabled, b [InlineData("filter[posts]", "equals(author,'some')", "Attribute 'author' does not exist on resource 'blogPosts'.")] [InlineData("filter[posts]", "lessThan(author,null)", "Attribute 'author' does not exist on resource 'blogPosts'.")] [InlineData("filter", " ", "Unexpected whitespace.")] + [InlineData("filter", "contains(owner.displayName, )", "Unexpected whitespace.")] [InlineData("filter", "some", "Filter function expected.")] [InlineData("filter", "equals", "( expected.")] [InlineData("filter", "equals'", "Unexpected ' outside text.")] @@ -115,6 +116,9 @@ public void Reader_Read_Fails(string parameterName, string parameterValue, strin [InlineData("filter", "equals(title,'Brian O''Quote')", null, "equals(title,'Brian O''Quote')")] [InlineData("filter", "equals(title,'!@#$%^&*()-_=+\"''[]{}<>()/|\\:;.,`~')", null, "equals(title,'!@#$%^&*()-_=+\"''[]{}<>()/|\\:;.,`~')")] [InlineData("filter", "equals(title,'')", null, "equals(title,'')")] + [InlineData("filter", "startsWith(owner.displayName,'GivenName ')", null, "startsWith(owner.displayName,'GivenName ')")] + [InlineData("filter", "endsWith(owner.displayName,' Surname')", null, "endsWith(owner.displayName,' Surname')")] + [InlineData("filter", "contains(owner.displayName,' ')", null, "contains(owner.displayName,' ')")] [InlineData("filter[posts]", "equals(caption,'this, that & more')", "posts", "equals(caption,'this, that & more')")] [InlineData("filter[owner.posts]", "equals(caption,'some')", "owner.posts", "equals(caption,'some')")] [InlineData("filter[posts.comments]", "equals(createdAt,'2000-01-01')", "posts.comments", "equals(createdAt,'2000-01-01')")] diff --git a/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/LegacyFilterParseTests.cs b/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/LegacyFilterParseTests.cs index d16569c941..94e473a7d1 100644 --- a/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/LegacyFilterParseTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/UnitTests/QueryStringParameters/LegacyFilterParseTests.cs @@ -37,7 +37,6 @@ public LegacyFilterParseTests() [InlineData("filter[author]", "some", "Attribute 'author' does not exist on resource 'blogPosts'.")] [InlineData("filter[author.posts]", "some", "Field 'posts' in 'author.posts' must be an attribute or a to-one relationship on resource 'webAccounts'.")] [InlineData("filter[unknown.id]", "some", "Relationship 'unknown' in 'unknown.id' does not exist on resource 'blogPosts'.")] - [InlineData("filter[author]", " ", "Unexpected whitespace.")] [InlineData("filter", "expr:equals(some,'other')", "Field 'some' does not exist on resource 'blogPosts'.")] [InlineData("filter", "expr:equals(author,'Joe')", "Attribute 'author' does not exist on resource 'blogPosts'.")] [InlineData("filter", "expr:has(author)", "Relationship 'author' must be a to-many relationship on resource 'blogPosts'.")] @@ -75,6 +74,7 @@ public void Reader_Read_Fails(string parameterName, string parameterValue, strin [InlineData("filter[caption]", "isnull:", "equals(caption,null)")] [InlineData("filter[caption]", "isnotnull:", "not(equals(caption,null))")] [InlineData("filter[caption]", "unknown:some", "equals(caption,'unknown:some')")] + [InlineData("filter[caption]", " ", "equals(caption,' ')")] [InlineData("filter[author.userName]", "Jack", "equals(author.userName,'Jack')")] [InlineData("filter", "expr:equals(caption,'some')", "equals(caption,'some')")] [InlineData("filter", "expr:equals(author,null)", "equals(author,null)")]