Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ void DeduceMethodCallSerializers()
case "ToHashedIndexKey": DeduceToHashedIndexKeySerializers(); break;
case "ToList": DeduceToListSerializers(); break;
case "ToString": DeduceToStringSerializers(); break;
case "Trim": DeduceTrimSerializers(); break;
case "Trim":
case "TrimStart":
case "TrimEnd":
DeduceTrimSerializers();
break;
case "Truncate": DeduceTruncateSerializers(); break;
case "Union": DeduceUnionSerializers(); break;
case "Week": DeduceWeekSerializers(); break;
Expand Down
155 changes: 155 additions & 0 deletions tests/MongoDB.Driver.Tests/Linq/Integration/StringTrimTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System.Collections.Generic;
using System.Linq;
using MongoDB.Driver.TestHelpers;
using FluentAssertions;
using Xunit;

namespace MongoDB.Driver.Tests.Linq.Integration;

public class StringTrimTests : LinqIntegrationTest<StringTrimTests.ClassFixture>
{
public StringTrimTests(ClassFixture fixture)
: base(fixture)
{
}

[Fact]
public void Select_with_Trim_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.Trim());

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $trim : { input : "$Str" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal("abcd", "abcd", "abcd", "abcd");
}

[Fact]
public void Select_with_Trim_with_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.Trim(new[] { ' ', 'a' }));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $trim : { input : "$Str", chars : " a" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal("bcd", "bcd", "bcd", "bcd");
}

[Fact]
public void Select_with_Trim_with_empty_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.Trim(new char[0]));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $trim : { input : "$Str" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal("abcd", "abcd", "abcd", "abcd");
}

[Fact]
public void Select_with_TrimStart_with_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.TrimStart(new[] { ' ', 'a' }));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $ltrim : { input : "$Str", chars : " a" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal("bcd ", "bcd ", "bcd", "bcd");
}

[Fact]
public void Select_with_TrimStart_with_empty_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.TrimStart(new char[0]));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $ltrim : { input : "$Str" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal("abcd ", "abcd ", "abcd", "abcd");
}

[Fact]
public void Select_with_TrimEnd_with_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.TrimEnd(new[] { ' ', 'd' }));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $rtrim : { input : "$Str", chars : " d" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal(" abc", "abc", " abc", "abc");
}

[Fact]
public void Select_with_TrimEnd_with_empty_chars_should_work()
{
var collection = Fixture.Collection;

var queryable = collection.AsQueryable()
.Select(x => x.Str.TrimEnd(new char[0]));

var stages = Translate(collection, queryable);
AssertStages(stages, """{ $project : { _v : { $rtrim : { input : "$Str" } }, _id : 0 } }""");

var results = queryable.ToList();
results.Should().Equal(" abcd", "abcd", " abcd", "abcd");
}

// Add coverage for parameterless and single char overloads of Trim, TrimStart, and TrimEnd, see https://jira.mongodb.org/browse/CSHARP-5979
// e.g. Trim(' '), TrimStart(), TrimStart(' '), TrimEnd(), TrimEnd(' ')

public class C
{
public int Id { get; set; }
public string Str { get; set; }
}

public sealed class ClassFixture : MongoCollectionFixture<C>
{
protected override IEnumerable<C> InitialData =>
[
new C { Id = 1, Str = " abcd "},
new C { Id = 2, Str = "abcd "},
new C { Id = 3, Str = " abcd"},
new C { Id = 4, Str = "abcd"},
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public void SerializerFinder_should_resolve_string_methods(LambdaExpression expr
[TestHelpers.MakeLambda((MyModel model) => model.Name.ToUpperInvariant()), typeof(StringSerializer)],
[TestHelpers.MakeLambda((MyModel model) => model.Name.Trim()), typeof(StringSerializer)],
[TestHelpers.MakeLambda((MyModel model) => model.Name.Trim(new char[] { ' ' })), typeof(StringSerializer)],
[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimStart(new char[] { ' ' })), typeof(StringSerializer)],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add parameter-less methods as non-supported, probably together with the link to Jira ticket where we will implement them. Example of negative tests could be find here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the team usually link the Jira ticket? In Server it would have been something like // TODO CSHARP-5979 Make these tests supported, but the closest example I found was:

// https://jira.mongodb.org/browse/CSHARP-2678
if (IsRetryableWriteExceptionAndDeploymentDoesNotSupportRetryableWrites(exception))
{ 
    ....
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, iirc they had a PR-level check for any remaining TODO SERVER-XXXX tickets matching the ticket name. Not sure if the team has something like this already, or if might be worth trying

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually I put comment something like:

Not supported yet, see https://jira.mongodb.org/browse/CSHARP-2678

[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimEnd(new char[] { ' ' })), typeof(StringSerializer)],
];

[Theory]
Expand All @@ -153,6 +155,12 @@ public void SerializerFinder_should_set_unknowable_serializer_for_unsupported_st
// StringComparison and CultureInfo overloads are not in ReplaceOverloads
[TestHelpers.MakeLambda((MyModel model) => model.Name.Replace("old", "new", StringComparison.Ordinal))],
[TestHelpers.MakeLambda((MyModel model) => model.Name.Replace("old", "new", false, CultureInfo.InvariantCulture))],
// Not supported yet, see https://jira.mongodb.org/browse/CSHARP-5979
[TestHelpers.MakeLambda((MyModel model) => model.Name.Trim(' '))],
[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimStart(' '))],
[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimEnd())],
[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimStart())],
[TestHelpers.MakeLambda((MyModel model) => model.Name.TrimEnd())],
#endif
];

Expand Down