From b289310b9f4a440ff58d778091494545972c3c8f Mon Sep 17 00:00:00 2001 From: rstam Date: Tue, 25 Feb 2025 18:42:44 -0800 Subject: [PATCH 1/2] CSHARP-5481: Move OfTypeMethodToAggregationExpressionTranslator to the correct location. --- .../OfTypeMethodToAggregationExpressionTranslator.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/{ => MethodTranslators}/OfTypeMethodToAggregationExpressionTranslator.cs (100%) diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/OfTypeMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs similarity index 100% rename from src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/OfTypeMethodToAggregationExpressionTranslator.cs rename to src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs From a98fe707879bee9219051e0fb59b52399769079f Mon Sep 17 00:00:00 2001 From: rstam Date: Tue, 25 Feb 2025 18:43:53 -0800 Subject: [PATCH 2/2] CSHARP-5481: ScalarDiscriminatorConvention class should implement IScalarDiscriminatorConvention interface. --- .../Serialization/BsonSerializer.cs | 31 + .../ScalarDiscriminatorConvention.cs | 11 +- .../Ast/Optimizers/AstSimplifier.cs | 74 ++- ...MethodToAggregationExpressionTranslator.cs | 80 ++- ...MethodToAggregationExpressionTranslator.cs | 12 +- ...essionToAggregationExpressionTranslator.cs | 2 - .../Serializers/DiscriminatorTests.cs | 22 +- .../Serializers/KnownTypesTests.cs | 5 +- .../LinqIntegrationTest.cs | 2 +- .../Jira/CSharp3140Tests.cs | 44 +- .../Jira/CSharp4100ExpressionTests.cs | 156 ++--- .../Jira/CSharp4100FilterTests.cs | 175 ++--- .../Jira/CSharp4116Tests.cs | 18 +- .../Jira/CSharp4876Tests.cs | 47 +- .../Jira/CSharp5481Tests.cs | 612 ++++++++++++++++++ 15 files changed, 1037 insertions(+), 254 deletions(-) create mode 100644 tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5481Tests.cs diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index b10676062f4..6602e74dec5 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -778,6 +778,37 @@ internal static void EnsureKnownTypesAreRegistered(Type nominalType) } } + // internal static methods + internal static BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) + { + // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock + EnsureKnownTypesAreRegistered(type); + + var discriminators = new List(); + + __configLock.EnterReadLock(); + try + { + foreach (var entry in __discriminators) + { + var discriminator = entry.Key; + var actualTypes = entry.Value; + + var matchingType = actualTypes.SingleOrDefault(t => t == type || t.IsSubclassOf(type)); + if (matchingType != null) + { + discriminators.Add(discriminator); + } + } + } + finally + { + __configLock.ExitReadLock(); + } + + return discriminators.OrderBy(x => x).ToArray(); + } + // private static methods private static void CreateSerializerRegistry() { diff --git a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs index 7adf745fa25..521aff9b1f7 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs @@ -14,14 +14,17 @@ */ using System; +using System.Collections.Concurrent; namespace MongoDB.Bson.Serialization.Conventions { /// /// Represents a discriminator convention where the discriminator is provided by the class map of the actual type. /// - public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention + public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention, IScalarDiscriminatorConvention { + private readonly ConcurrentDictionary _cachedTypeAndSubTypeDiscriminators = new(); + // constructors /// /// Initializes a new instance of the ScalarDiscriminatorConvention class. @@ -52,5 +55,11 @@ public override BsonValue GetDiscriminator(Type nominalType, Type actualType) return null; } } + + /// + public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) + { + return _cachedTypeAndSubTypeDiscriminators.GetOrAdd(type, BsonSerializer.GetDiscriminatorsForTypeAndSubTypes); + } } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs index 40d6171a2f2..206fd8b308c 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs @@ -18,7 +18,9 @@ using MongoDB.Bson; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Filters; +using MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors; +using MongoDB.Driver.Linq.Linq3Implementation.Misc; namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Optimizers { @@ -351,6 +353,33 @@ elemMatchOperation.Filter is AstFieldOperationFilter elemFilter && } } + public override AstNode VisitFilterExpression(AstFilterExpression node) + { + var inputExpression = VisitAndConvert(node.Input); + var condExpression = VisitAndConvert(node.Cond); + var limitExpression = VisitAndConvert(node.Limit); + + if (condExpression is AstConstantExpression condConstantExpression && + condConstantExpression.Value is BsonBoolean condBsonBoolean) + { + if (condBsonBoolean.Value) + { + // { $filter : { input : , as : "x", cond : true } } => + if (limitExpression == null) + { + return inputExpression; + } + } + else + { + // { $filter : { input : , as : "x", cond : false, optional-limit } } => [] + return AstExpression.Constant(new BsonArray()); + } + } + + return node.Update(inputExpression, condExpression, limitExpression); + } + public override AstNode VisitGetFieldExpression(AstGetFieldExpression node) { if (TrySimplifyAsFieldPath(node, out var simplified)) @@ -448,6 +477,26 @@ public override AstNode VisitNotFilterOperation(AstNotFilterOperation node) return base.VisitNotFilterOperation(node); } + public override AstNode VisitPipeline(AstPipeline node) + { + var stages = VisitAndConvert(node.Stages); + + // { $match : { } } => remove redundant stage + if (stages.Any(stage => IsMatchEverythingStage(stage))) + { + stages = stages.Where(stage => !IsMatchEverythingStage(stage)).AsReadOnlyList(); + } + + return node.Update(stages); + + static bool IsMatchEverythingStage(AstStage stage) + { + return + stage is AstMatchStage matchStage && + matchStage.Filter is AstMatchesEverythingFilter; + } + } + public override AstNode VisitSliceExpression(AstSliceExpression node) { node = (AstSliceExpression)base.VisitSliceExpression(node); @@ -498,15 +547,34 @@ arrayConstant.Value is BsonArray bsonArrayConstant && public override AstNode VisitUnaryExpression(AstUnaryExpression node) { + var arg = VisitAndConvert(node.Arg); + // { $first : } => { $arrayElemAt : [, 0] } (or -1 for $last) if (node.Operator == AstUnaryOperator.First || node.Operator == AstUnaryOperator.Last) { - var simplifiedArg = VisitAndConvert(node.Arg); var index = node.Operator == AstUnaryOperator.First ? 0 : -1; - return AstExpression.ArrayElemAt(simplifiedArg, index); + return AstExpression.ArrayElemAt(arg, index); + } + + // { $not : booleanConstant } => !booleanConstant + if (node.Operator is AstUnaryOperator.Not && + arg is AstConstantExpression argConstantExpression && + argConstantExpression.Value is BsonBoolean argBsonBoolean) + { + return AstExpression.Constant(!argBsonBoolean.Value); + } + + // { $not : { $eq : [expr1, expr2] } } => { $ne : [expr1, expr2] } + // { $not : { $ne : [expr1, expr2] } } => { $eq : [expr1, expr2] } + if (node.Operator is AstUnaryOperator.Not && + arg is AstBinaryExpression argBinaryExpression && + argBinaryExpression.Operator is AstBinaryOperator.Eq or AstBinaryOperator.Ne) + { + var oppositeComparisonOperator = argBinaryExpression.Operator == AstBinaryOperator.Eq ? AstBinaryOperator.Ne : AstBinaryOperator.Eq; + return AstExpression.Binary(oppositeComparisonOperator, argBinaryExpression.Arg1, argBinaryExpression.Arg2); } - return base.VisitUnaryExpression(node); + return node.Update(arg); } } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs index bb7b18d3558..5ce6bbe01f1 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs @@ -1,18 +1,19 @@ /* 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. - */ +* +* 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.Linq; using System.Linq.Expressions; using System.Reflection; using MongoDB.Bson.Serialization; @@ -26,7 +27,7 @@ namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggreg { internal static class OfTypeMethodToAggregationExpressionTranslator { - private static readonly MethodInfo[] __ofTypeMethods = + private static MethodInfo[] __ofTypeMethods = { EnumerableMethod.OfType, QueryableMethod.OfType @@ -42,35 +43,46 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); NestedAsQueryableHelper.EnsureQueryableMethodHasNestedAsQueryableSource(expression, sourceTranslation); - var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); - var nominalType = sourceTranslation.Serializer.ValueType; - var actualType = method.GetGenericArguments()[0]; + var sourceAst = sourceTranslation.Ast; + var sourceSerializer = sourceTranslation.Serializer; + if (sourceSerializer is IWrappedValueSerializer wrappedValueSerializer) + { + sourceAst = AstExpression.GetField(sourceAst, wrappedValueSerializer.FieldName); + sourceSerializer = wrappedValueSerializer.ValueSerializer; + } + var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceSerializer); + var nominalType = itemSerializer.ValueType; + var nominalTypeSerializer = itemSerializer; + var actualType = method.GetGenericArguments().Single(); + var actualTypeSerializer = BsonSerializer.LookupSerializer(actualType); + + AstExpression ast; if (nominalType == actualType) { - return sourceTranslation; + ast = sourceAst; } + else + { + var discriminatorConvention = nominalTypeSerializer.GetDiscriminatorConvention(); + var itemVar = AstExpression.Var("item"); + var discriminatorField = AstExpression.GetField(itemVar, discriminatorConvention.ElementName); - var discriminatorConvention = itemSerializer.GetDiscriminatorConvention(); - var discriminatorElementName = discriminatorConvention.ElementName; + var ofTypeExpression = discriminatorConvention switch + { + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + _ => throw new ExpressionNotSupportedException(expression, because: "OfType is not supported with the configured discriminator convention") + }; - var itemVar = AstExpression.Var("this"); - var discriminatorField = AstExpression.GetField(itemVar, discriminatorElementName); - var ofTypePredicate = discriminatorConvention switch - { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), - _ => throw new ExpressionNotSupportedException(expression, because: "is operator is not supported with the configured discriminator convention") - }; + ast = AstExpression.Filter( + input: sourceAst, + cond: ofTypeExpression, + @as: "item"); + } - var ast = AstExpression.Filter( - input: sourceTranslation.Ast, - @as: itemVar.Name, - cond: ofTypePredicate); - var actualTypeSerializer = BsonSerializer.LookupSerializer(actualType); var resultSerializer = NestedAsQueryableSerializer.CreateIEnumerableOrNestedAsQueryableSerializer(expression.Type, actualTypeSerializer); - return new TranslatedExpression(expression, ast, resultSerializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WhereMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WhereMethodToAggregationExpressionTranslator.cs index d702adacdc2..250c8658210 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WhereMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WhereMethodToAggregationExpressionTranslator.cs @@ -41,7 +41,15 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); NestedAsQueryableHelper.EnsureQueryableMethodHasNestedAsQueryableSource(expression, sourceTranslation); - var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); + + var sourceAst = sourceTranslation.Ast; + var sourceSerializer = sourceTranslation.Serializer; + if (sourceSerializer is IWrappedValueSerializer wrappedValueSerializer) + { + sourceAst = AstExpression.GetField(sourceAst, wrappedValueSerializer.FieldName); + sourceSerializer = wrappedValueSerializer.ValueSerializer; + } + var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceSerializer); var predicateLambda = ExpressionHelper.UnquoteLambdaIfQueryableMethod(method, arguments[1]); var predicateParameter = predicateLambda.Parameters[0]; @@ -57,7 +65,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC } var ast = AstExpression.Filter( - sourceTranslation.Ast, + sourceAst, predicateTranslation.Ast, @as: predicateSymbol.Var.Name, limitTranslation?.Ast); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs index cec3551b6f3..defda7b972b 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs @@ -13,9 +13,7 @@ * limitations under the License. */ -using System.Linq; using System.Linq.Expressions; -using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MongoDB.Bson.Serialization.Serializers; diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs index 826b0969da6..78fe458a3aa 100644 --- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs +++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs @@ -40,7 +40,7 @@ private class C : A { } - [BsonDiscriminator("D~", RootClass = true)] + [BsonDiscriminator("D~")] private class D : A { } @@ -212,7 +212,7 @@ public void TestSerializeDAsD() { D d = new D { P = "x" }; var json = d.ToJson(); - var expected = ("{ '_t' : 'D~', 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = d.ToBson(); @@ -329,7 +329,7 @@ public void TestSerializeGAsObject() { G g = new G { P = "x" }; var json = g.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'G~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = g.ToBson(); @@ -342,7 +342,7 @@ public void TestSerializeGAsA() { G g = new G { P = "x" }; var json = g.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'G~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = g.ToBson(); @@ -355,7 +355,7 @@ public void TestSerializeGAsD() { G g = new G { P = "x" }; var json = g.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'G~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = g.ToBson(); @@ -368,7 +368,7 @@ public void TestSerializeGAsG() { G g = new G { P = "x" }; var json = g.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = g.ToBson(); @@ -381,7 +381,7 @@ public void TestSerializeHAsObject() { H h = new H { P = "x" }; var json = h.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~', 'H~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'H~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = h.ToBson(); @@ -394,7 +394,7 @@ public void TestSerializeHAsA() { H h = new H { P = "x" }; var json = h.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~', 'H~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'H~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = h.ToBson(); @@ -407,7 +407,7 @@ public void TestSerializeHAsD() { H h = new H { P = "x" }; var json = h.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~', 'H~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'H~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = h.ToBson(); @@ -420,7 +420,7 @@ public void TestSerializeHAsG() { H h = new H { P = "x" }; var json = h.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~', 'H~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ '_t' : 'H~', 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = h.ToBson(); @@ -433,7 +433,7 @@ public void TestSerializeHAsH() { H h = new H { P = "x" }; var json = h.ToJson(); - var expected = ("{ '_t' : ['D~', 'G~', 'H~'], 'P' : 'x' }").Replace("'", "\""); + var expected = ("{ 'P' : 'x' }").Replace("'", "\""); Assert.Equal(expected, json); var bson = h.ToBson(); diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/KnownTypesTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/KnownTypesTests.cs index 1d0af120b66..618a25892c1 100644 --- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/KnownTypesTests.cs +++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/KnownTypesTests.cs @@ -34,7 +34,6 @@ private class B : A { } - [BsonDiscriminator(RootClass = true)] [BsonKnownTypes(typeof(E))] private class C : A { @@ -77,7 +76,7 @@ public void TestDeserializeEAsA() { var document = new BsonDocument { - { "_t", new BsonArray { "C", "E" } }, + { "_t", "E" }, { "P", "x" } }; @@ -86,7 +85,7 @@ public void TestDeserializeEAsA() Assert.IsType(rehydrated); var json = rehydrated.ToJson(); - var expected = "{ '_t' : ['C', 'E'], 'P' : 'x' }".Replace("'", "\""); + var expected = "{ '_t' : 'E', 'P' : 'x' }".Replace("'", "\""); Assert.Equal(expected, json); Assert.True(bson.SequenceEqual(rehydrated.ToBson())); } diff --git a/tests/MongoDB.Driver.TestHelpers/LinqIntegrationTest.cs b/tests/MongoDB.Driver.TestHelpers/LinqIntegrationTest.cs index cb19e6d5fc5..8663b17230d 100644 --- a/tests/MongoDB.Driver.TestHelpers/LinqIntegrationTest.cs +++ b/tests/MongoDB.Driver.TestHelpers/LinqIntegrationTest.cs @@ -41,7 +41,7 @@ protected void AssertStages(IEnumerable stages, params string[] ex protected void AssertStages(IEnumerable stages, IEnumerable expectedStages) { - stages.Should().Equal(expectedStages.Select(json => BsonDocument.Parse(json))); + stages.Should().Equal(expectedStages.Where(s => s != null).Select(json => BsonDocument.Parse(json))); } protected static List Translate(IMongoCollection collection, IAggregateFluent aggregate) => diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp3140Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp3140Tests.cs index 468bca31027..1ae2625f41f 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp3140Tests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp3140Tests.cs @@ -13,17 +13,24 @@ * limitations under the License. */ +using System.Collections.Generic; using System.Linq; +using MongoDB.Driver.TestHelpers; using Xunit; namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira { - public class CSharp3140Tests : Linq3IntegrationTest + public class CSharp3140Tests : LinqIntegrationTest { + public CSharp3140Tests(ClassFixture fixture) + : base(fixture) + { + } + [Fact] public void AndAlso_with_first_clause_that_evaluates_to_true_should_simplify_to_second_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = new Factory { Id = 1 } }; var queryable = collection.AsQueryable() .Where(x => currentUser.Factory != null && x.FactoryId == currentUser.Factory.Id); @@ -35,7 +42,7 @@ public void AndAlso_with_first_clause_that_evaluates_to_true_should_simplify_to_ [Fact] public void AndAlso_with_first_clause_that_evaluates_to_false_should_simplify_to_false_and_should_not_evaluate_second_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = null }; var queryable = collection.AsQueryable() .Where(x => currentUser.Factory != null && x.FactoryId == currentUser.Factory.Id); @@ -47,7 +54,7 @@ public void AndAlso_with_first_clause_that_evaluates_to_false_should_simplify_to [Fact] public void AndAlso_with_second_clause_that_evaluates_to_true_should_simplify_to_first_cluase() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = new Factory { Id = 1 } }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == currentUser.Factory.Id && currentUser.Factory != null); @@ -59,7 +66,7 @@ public void AndAlso_with_second_clause_that_evaluates_to_true_should_simplify_to [Fact] public void AndAlso_with_second_clause_that_evaluates_to_false_should_simplify_to_false() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = null }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId != 0 && currentUser.Factory != null); @@ -71,7 +78,7 @@ public void AndAlso_with_second_clause_that_evaluates_to_false_should_simplify_t [Fact] public void AndAlso_with_neither_clause_a_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.FactoryId != 0 && x.FactoryId != 1); @@ -82,7 +89,7 @@ public void AndAlso_with_neither_clause_a_constant_should_work() [Fact] public void Conditional_with_test_that_evaluates_to_true_should_simplify_to_if_true_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = null }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == (currentUser.Factory == null ? 0 : currentUser.Factory.Id)); @@ -94,7 +101,7 @@ public void Conditional_with_test_that_evaluates_to_true_should_simplify_to_if_t [Fact] public void Conditional_with_test_that_evaluates_to_false_should_simplify_to_if_true_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = new Factory { Id = 1 } }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == (currentUser.Factory == null ? 0 : currentUser.Factory.Id)); @@ -106,7 +113,7 @@ public void Conditional_with_test_that_evaluates_to_false_should_simplify_to_if_ [Fact] public void Conditional_with_test_that_is_not_a_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == (x.Id == 0 ? 0 : 1)); @@ -117,7 +124,7 @@ public void Conditional_with_test_that_is_not_a_constant_should_work() [Fact] public void OrElse_with_first_clause_that_evaluates_to_false_should_simplify_to_second_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = new Factory { Id = 1 } }; var queryable = collection.AsQueryable() .Where(x => currentUser.Factory == null || x.FactoryId == currentUser.Factory.Id); @@ -129,19 +136,19 @@ public void OrElse_with_first_clause_that_evaluates_to_false_should_simplify_to_ [Fact] public void OrElse_with_first_clause_that_evaluates_to_true_should_simplify_to_true_and_should_not_evaluate_second_clause() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = null }; var queryable = collection.AsQueryable() .Where(x => currentUser.Factory == null || x.FactoryId == currentUser.Factory.Id); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } [Fact] public void OrElse_with_second_clause_that_evaluates_to_false_should_simplify_to_first_cluase() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = new Factory { Id = 1 } }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == currentUser.Factory.Id || currentUser.Factory == null); @@ -153,19 +160,19 @@ public void OrElse_with_second_clause_that_evaluates_to_false_should_simplify_to [Fact] public void OrElse_with_second_clause_that_evaluates_to_true_should_simplify_to_true() { - var collection = GetCollection(); + var collection = Fixture.Collection; var currentUser = new User { Id = 1, Factory = null }; var queryable = collection.AsQueryable() .Where(x => x.FactoryId != 0 || currentUser.Factory == null); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } [Fact] public void OrElse_with_neither_clause_a_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.FactoryId == 0 || x.FactoryId == 1); @@ -189,5 +196,10 @@ public class Factory { public int Id { get; set; } } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => null; + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100ExpressionTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100ExpressionTests.cs index db534655441..49735c157dc 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100ExpressionTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100ExpressionTests.cs @@ -14,6 +14,7 @@ */ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using FluentAssertions; @@ -22,17 +23,22 @@ using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.TestHelpers.XunitExtensions; using MongoDB.Driver.Linq; +using MongoDB.Driver.TestHelpers; using MongoDB.TestHelpers.XunitExtensions; using Xunit; namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira { - public class CSharp4100ExpressionTests : Linq3IntegrationTest + public class CSharp4100ExpressionTests : LinqIntegrationTest { + public CSharp4100ExpressionTests(ClassFixture fixture) : base(fixture) + { + } + [Fact] public void Contains_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains('A') }); @@ -44,7 +50,7 @@ public void Contains_with_string_field_and_char_constant_should_work() [Fact] public void Contains_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains('A') }); @@ -56,7 +62,7 @@ public void Contains_with_string_constant_and_char_constant_should_work() [Fact] public void Contains_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains(x.CS) }); @@ -68,7 +74,7 @@ public void Contains_with_string_field_and_char_field_represented_as_string_shou [Fact] public void Contains_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains(x.CS) }); @@ -83,7 +89,7 @@ public void Contains_with_string_field_and_char_field_not_represented_as_string_ [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -109,7 +115,7 @@ public void Contains_with_string_constant_and_char_field_not_represented_as_stri [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -135,7 +141,7 @@ public void Contains_with_string_constant_and_char_field_not_represented_as_stri [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : [{ $toLower : '$S' }, 'a'] }, 0] }, _id : 0 } }")] public void Contains_with_string_field_and_char_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains('A', comparisonType) }); @@ -151,7 +157,7 @@ public void Contains_with_string_field_and_char_constant_and_comparisonType_shou [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void Contains_with_string_constant_and_char_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains('A', comparisonType) }); @@ -167,7 +173,7 @@ public void Contains_with_string_constant_and_char_constant_and_comparisonType_s [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : [{ $toLower :'$S' }, { $toLower : '$CS' }] }, 0] } , _id : 0 } }")] public void Contains_with_string_field_and_char_field_represented_as_string_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains(x.CS, comparisonType) }); @@ -183,7 +189,7 @@ public void Contains_with_string_field_and_char_field_represented_as_string_and_ [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : ['abc', { $toLower : '$CS' }] }, 0] } , _id : 0 } }")] public void Contains_with_string_constant_and_char_field_represented_as_string_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains(x.CS, comparisonType) }); @@ -203,7 +209,7 @@ public void Contains_with_string_field_and_char_value_not_represented_as_string_ bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -237,7 +243,7 @@ public void Contains_with_string_constant_and_char_value_not_represented_as_stri bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -275,7 +281,7 @@ public void Contains_with_string_field_and_char_value_and_invalid_comparisonType bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -307,7 +313,7 @@ public void Contains_with_string_field_and_char_value_and_invalid_comparisonType [InlineData(StringComparison.OrdinalIgnoreCase)] public void Contains_with_string_constant_and_char_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains('A', comparisonType) }); @@ -320,7 +326,7 @@ public void Contains_with_string_constant_and_char_value_and_invalid_comparisonT [Fact] public void Contains_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains("aBc") }); @@ -332,7 +338,7 @@ public void Contains_with_string_field_and_string_constant_should_work() [Fact] public void Contains_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains("aBc") }); @@ -344,7 +350,7 @@ public void Contains_with_string_constant_and_string_constant_should_work() [Fact] public void Contains_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains(x.T) }); @@ -356,7 +362,7 @@ public void Contains_with_string_field_and_string_field_should_work() [Fact] public void Contains_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains(x.T) }); @@ -371,7 +377,7 @@ public void Contains_with_string_constant_and_string_field_should_work() [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : [{ $toLower : '$S' }, 'abc'] }, 0] }, _id : 0 } }")] public void Contains_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains("aBc", comparisonType) }); @@ -387,7 +393,7 @@ public void Contains_with_string_field_and_string_constant_and_comparisonType_sh [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void Contains_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains("aBc", comparisonType) }); @@ -403,7 +409,7 @@ public void Contains_with_string_constant_and_string_constant_and_comparisonType [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void Contains_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.Contains(x.T, comparisonType) }); @@ -419,7 +425,7 @@ public void Contains_with_string_field_and_string_field_and_comparisonType_shoul [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $gte : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void Contains_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains(x.T, comparisonType) }); @@ -443,7 +449,7 @@ public void Contains_with_string_field_and_string_value_and_invalid_comparisonTy bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -475,7 +481,7 @@ public void Contains_with_string_field_and_string_value_and_invalid_comparisonTy [InlineData(StringComparison.OrdinalIgnoreCase, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void Contains_with_string_constant_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".Contains("aBc", comparisonType) }); @@ -489,7 +495,7 @@ public void Contains_with_string_constant_and_string_value_and_invalid_compariso [Fact] public void EndsWith_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith('A') }); @@ -503,7 +509,7 @@ public void EndsWith_with_string_field_and_char_constant_should_work() [Fact] public void EndsWith_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith('A') }); @@ -517,7 +523,7 @@ public void EndsWith_with_string_constant_and_char_constant_should_work() [Fact] public void EndsWith_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith(x.CS) }); @@ -531,7 +537,7 @@ public void EndsWith_with_string_field_and_char_field_represented_as_string_shou [Fact] public void EndsWith_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith(x.CS) }); @@ -548,7 +554,7 @@ public void EndsWith_with_string_field_and_char_field_not_represented_as_string_ [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -579,7 +585,7 @@ public void EndsWith_with_string_constant_and_char_field_not_represented_as_stri [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -606,7 +612,7 @@ public void EndsWith_with_string_constant_and_char_field_not_represented_as_stri [Fact] public void EndsWith_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith("aBc") }); @@ -618,7 +624,7 @@ public void EndsWith_with_string_field_and_string_constant_should_work() [Fact] public void EndsWith_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith("aBc") }); @@ -630,7 +636,7 @@ public void EndsWith_with_string_constant_and_string_constant_should_work() [Fact] public void EndsWith_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith(x.T) }); @@ -642,7 +648,7 @@ public void EndsWith_with_string_field_and_string_field_should_work() [Fact] public void EndsWith_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith(x.T) }); @@ -656,7 +662,7 @@ public void EndsWith_with_string_constant_and_string_field_should_work() [InlineData(true, "{ $project : { R : { $let : { vars : { string : { $toLower : '$S' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, 3] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', 'abc', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_field_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith("aBc", ignoreCase, CultureInfo.CurrentCulture) }); @@ -670,7 +676,7 @@ public void EndsWith_with_string_field_and_string_constant_and_ignoreCase_and_cu [InlineData(true, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void EndsWith_with_string_constant_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith("aBc", ignoreCase, CultureInfo.CurrentCulture) }); @@ -684,7 +690,7 @@ public void EndsWith_with_string_constant_and_string_constant_and_ignoreCase_and [InlineData(true, "{ $project : { R : { $let : { vars : { string : { $toLower : '$S' }, substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', '$$substring', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_field_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith(x.T, ignoreCase, CultureInfo.CurrentCulture) }); @@ -698,7 +704,7 @@ public void EndsWith_with_string_field_and_string_field_and_ignoreCase_and_cultu [InlineData(true, "{ $project : { R : { $let : { vars : { substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [3, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['abc', '$$substring', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_constant_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith(x.T, ignoreCase, CultureInfo.CurrentCulture) }); @@ -714,7 +720,7 @@ public void EndsWith_with_string_field_and_string_value_and_ignoreCase_and_inval [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var notCurrentCulture = GetACultureThatIsNotTheCurrentCulture(); @@ -743,7 +749,7 @@ public void EndsWith_with_string_field_and_string_value_and_ignoreCase_and_inval [InlineData(true, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void EndsWith_with_string_constant_and_string_value_and_ignoreCase_and_invalid_culture_should_throw(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith("aBc", ignoreCase, CultureInfo.InvariantCulture) }); @@ -757,7 +763,7 @@ public void EndsWith_with_string_constant_and_string_value_and_ignoreCase_and_in [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $let : { vars : { string : { $toLower : '$S' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, 3] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', 'abc', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith("aBc", comparisonType) }); @@ -771,7 +777,7 @@ public void EndsWith_with_string_field_and_string_constant_and_comparisonType_sh [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void EndsWith_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith("aBc", comparisonType) }); @@ -785,7 +791,7 @@ public void EndsWith_with_string_constant_and_string_constant_and_comparisonType [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $let : { vars : { string : { $toLower : '$S' }, substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', '$$substring', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.EndsWith(x.T, comparisonType) }); @@ -799,7 +805,7 @@ public void EndsWith_with_string_field_and_string_field_and_comparisonType_shoul [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $let : { vars : { substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [3, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['abc', '$$substring', '$$start'] }, '$$start'] }] } } } } }, _id : 0 } }")] public void EndsWith_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".EndsWith(x.T, comparisonType) }); @@ -821,7 +827,7 @@ public void EndsWith_with_string_field_and_string_value_and_invalid_comparisonTy bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -857,7 +863,7 @@ public void EndsWith_with_string_constant_and_string_value_and_invalid_compariso bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -884,7 +890,7 @@ public void EndsWith_with_string_constant_and_string_value_and_invalid_compariso [Fact] public void StartsWith_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith('A') }); @@ -898,7 +904,7 @@ public void StartsWith_with_string_field_and_char_constant_should_work() [Fact] public void StartsWith_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith('A') }); @@ -912,7 +918,7 @@ public void StartsWith_with_string_constant_and_char_constant_should_work() [Fact] public void StartsWith_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith(x.CS) }); @@ -926,7 +932,7 @@ public void StartsWith_with_string_field_and_char_field_represented_as_string_sh [Fact] public void StartsWith_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith(x.CS) }); @@ -943,7 +949,7 @@ public void StartsWith_with_string_field_and_char_field_not_represented_as_strin [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -974,7 +980,7 @@ public void StartsWith_with_string_constant_and_char_field_not_represented_as_st [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -1001,7 +1007,7 @@ public void StartsWith_with_string_constant_and_char_field_not_represented_as_st [Fact] public void StartsWith_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith("aBc") }); @@ -1013,7 +1019,7 @@ public void StartsWith_with_string_field_and_string_constant_should_work() [Fact] public void StartsWith_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith("aBc") }); @@ -1025,7 +1031,7 @@ public void StartsWith_with_string_constant_and_string_constant_should_work() [Fact] public void StartsWith_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith(x.T) }); @@ -1037,7 +1043,7 @@ public void StartsWith_with_string_field_and_string_field_should_work() [Fact] public void StartsWith_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith(x.T) }); @@ -1051,7 +1057,7 @@ public void StartsWith_with_string_constant_and_string_field_should_work() [InlineData(true, "{ $project : { R : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, 'abc'] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_field_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith("aBc", ignoreCase, CultureInfo.CurrentCulture) }); @@ -1065,7 +1071,7 @@ public void StartsWith_with_string_field_and_string_constant_and_ignoreCase_and_ [InlineData(true, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void StartsWith_with_string_constant_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith("aBc", ignoreCase, CultureInfo.CurrentCulture) }); @@ -1079,7 +1085,7 @@ public void StartsWith_with_string_constant_and_string_constant_and_ignoreCase_a [InlineData(true, "{ $project : { R : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_field_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith(x.T, ignoreCase, CultureInfo.CurrentCulture) }); @@ -1093,7 +1099,7 @@ public void StartsWith_with_string_field_and_string_field_and_ignoreCase_and_cul [InlineData(true, "{ $project : { R : { $eq : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_constant_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith(x.T, ignoreCase, CultureInfo.CurrentCulture) }); @@ -1109,7 +1115,7 @@ public void StartsWith_with_string_field_and_string_value_and_ignoreCase_and_inv [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var notCurrentCulture = GetACultureThatIsNotTheCurrentCulture(); @@ -1138,7 +1144,7 @@ public void StartsWith_with_string_field_and_string_value_and_ignoreCase_and_inv [InlineData(true, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void StartsWith_with_string_constant_and_string_value_and_ignoreCase_and_invalid_culture_should_throw(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith("aBc", ignoreCase, CultureInfo.InvariantCulture) }); @@ -1152,7 +1158,7 @@ public void StartsWith_with_string_constant_and_string_value_and_ignoreCase_and_ [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, 'abc'] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith("aBc", comparisonType) }); @@ -1166,7 +1172,7 @@ public void StartsWith_with_string_field_and_string_constant_and_comparisonType_ [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { _v : { $literal : { R : true } }, _id : 0 } }")] public void StartsWith_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith("aBc", comparisonType) }); @@ -1180,7 +1186,7 @@ public void StartsWith_with_string_constant_and_string_constant_and_comparisonTy [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = x.S.StartsWith(x.T, comparisonType) }); @@ -1194,7 +1200,7 @@ public void StartsWith_with_string_field_and_string_field_and_comparisonType_sho [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $project : { R : { $eq : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] }, _id : 0 } }")] public void StartsWith_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Select(x => new { R = "ABC".StartsWith(x.T, comparisonType) }); @@ -1215,7 +1221,7 @@ public void StartsWith_with_string_field_and_string_value_and_invalid_comparison [Values(false, true)] bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -1251,7 +1257,7 @@ public void StartsWith_with_string_constant_and_string_value_and_invalid_compari bool enableClientSideProjections) { RequireServer.Check().Supports(Feature.FindProjectionExpressions); - var collection = GetCollection(); + var collection = Fixture.Collection; var translationOptions = new ExpressionTranslationOptions { EnableClientSideProjections = enableClientSideProjections }; var queryable = collection.AsQueryable(translationOptions) @@ -1274,13 +1280,6 @@ public void StartsWith_with_string_constant_and_string_value_and_invalid_compari } } - private IMongoCollection GetCollection() - { - var collection = GetCollection(); - CreateCollection(collection); - return collection; - } - private CultureInfo GetACultureThatIsNotTheCurrentCulture() { var notCurrentCulture = CultureInfo.GetCultureInfo("zu-ZA"); @@ -1298,5 +1297,10 @@ public class Test public string S { get; set; } public string T { get; set; } } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => null; + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100FilterTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100FilterTests.cs index 2e702574c4b..32be4f6e645 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100FilterTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4100FilterTests.cs @@ -14,22 +14,28 @@ */ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using FluentAssertions; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver.Linq; +using MongoDB.Driver.TestHelpers; using Xunit; namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira { - public class CSharp4100FilterTests : Linq3IntegrationTest + public class CSharp4100FilterTests : LinqIntegrationTest { + public CSharp4100FilterTests(ClassFixture fixture) : base(fixture) + { + } + [Fact] public void Contains_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains('A')); @@ -41,19 +47,19 @@ public void Contains_with_string_field_and_char_constant_should_work() [Fact] public void Contains_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains('A')); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } [Fact] public void Contains_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.CS)); @@ -65,7 +71,7 @@ public void Contains_with_string_field_and_char_field_represented_as_string_shou [Fact] public void Contains_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.CS)); @@ -77,7 +83,7 @@ public void Contains_with_string_constant_and_char_field_represented_as_string_s [Fact] public void Contains_with_string_field_and_char_field_not_represented_as_string_should_throw() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.CC)); @@ -90,7 +96,7 @@ public void Contains_with_string_field_and_char_field_not_represented_as_string_ [Fact] public void Contains_with_string_constant_and_char_field_not_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.CC)); @@ -105,7 +111,7 @@ public void Contains_with_string_constant_and_char_field_not_represented_as_stri [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { S : /A/is } }")] public void Contains_with_string_field_and_char_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains('A', comparisonType)); @@ -121,13 +127,13 @@ public void Contains_with_string_field_and_char_constant_and_comparisonType_shou [InlineData(StringComparison.CurrentCultureIgnoreCase)] public void Contains_with_string_constant_and_char_constant_and_comparisonType_should_work(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains('A', comparisonType)); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } #endif @@ -137,7 +143,7 @@ public void Contains_with_string_constant_and_char_constant_and_comparisonType_s [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $gte : [{ $indexOfCP : [{ $toLower :'$S' }, { $toLower : '$CS' }] }, 0] } } }")] public void Contains_with_string_field_and_char_field_represented_as_string_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.CS, comparisonType)); @@ -153,7 +159,7 @@ public void Contains_with_string_field_and_char_field_represented_as_string_and_ [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $gte : [{ $indexOfCP : ['abc', { $toLower : '$CS' }] }, 0] } } }")] public void Contains_with_string_constant_and_char_field_represented_as_string_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.CS, comparisonType)); @@ -169,7 +175,7 @@ public void Contains_with_string_constant_and_char_field_represented_as_string_a [InlineData(StringComparison.CurrentCultureIgnoreCase)] public void Contains_with_string_field_and_char_value_not_represented_as_string_and_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.CC, comparisonType)); @@ -186,7 +192,7 @@ public void Contains_with_string_field_and_char_value_not_represented_as_string_ [InlineData(StringComparison.CurrentCultureIgnoreCase)] public void Contains_with_string_constant_and_char_value_not_represented_as_string_and_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.CC, comparisonType)); @@ -205,7 +211,7 @@ public void Contains_with_string_constant_and_char_value_not_represented_as_stri [InlineData(StringComparison.OrdinalIgnoreCase)] public void Contains_with_string_field_and_char_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains('A', comparisonType)); @@ -224,20 +230,20 @@ public void Contains_with_string_field_and_char_value_and_invalid_comparisonType [InlineData(StringComparison.OrdinalIgnoreCase)] public void Contains_with_string_constant_and_char_value_and_invalid_comparisonType_should_work(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains('A', comparisonType)); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } #endif [Fact] public void Contains_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains("aBc")); @@ -249,7 +255,7 @@ public void Contains_with_string_field_and_string_constant_should_work() [Fact] public void Contains_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains("aBc")); @@ -261,7 +267,7 @@ public void Contains_with_string_constant_and_string_constant_should_work() [Fact] public void Contains_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.T)); @@ -273,7 +279,7 @@ public void Contains_with_string_field_and_string_field_should_work() [Fact] public void Contains_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.T)); @@ -288,7 +294,7 @@ public void Contains_with_string_constant_and_string_field_should_work() [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { S : /aBc/is } }")] public void Contains_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains("aBc", comparisonType)); @@ -301,10 +307,10 @@ public void Contains_with_string_field_and_string_constant_and_comparisonType_sh #if !NETFRAMEWORK [Theory] [InlineData(StringComparison.CurrentCulture, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { } }")] + [InlineData(StringComparison.CurrentCultureIgnoreCase, null)] public void Contains_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains("aBc", comparisonType)); @@ -320,7 +326,7 @@ public void Contains_with_string_constant_and_string_constant_and_comparisonType [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $gte : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] } } }")] public void Contains_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains(x.T, comparisonType)); @@ -336,7 +342,7 @@ public void Contains_with_string_field_and_string_field_and_comparisonType_shoul [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $gte : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] } } }")] public void Contains_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains(x.T, comparisonType)); @@ -354,7 +360,7 @@ public void Contains_with_string_constant_and_string_field_and_comparisonType_sh [InlineData(StringComparison.OrdinalIgnoreCase)] public void Contains_with_string_field_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.Contains("aBc", comparisonType)); @@ -368,12 +374,12 @@ public void Contains_with_string_field_and_string_value_and_invalid_comparisonTy #if !NETFRAMEWORK [Theory] [InlineData(StringComparison.InvariantCulture, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(StringComparison.InvariantCultureIgnoreCase, "{ $match : { } }")] + [InlineData(StringComparison.InvariantCultureIgnoreCase, null)] [InlineData(StringComparison.Ordinal, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(StringComparison.OrdinalIgnoreCase, "{ $match : { } }")] + [InlineData(StringComparison.OrdinalIgnoreCase, null)] public void Contains_with_string_constant_and_string_value_and_invalid_comparisonType_should_(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".Contains("aBc", comparisonType)); @@ -387,7 +393,7 @@ public void Contains_with_string_constant_and_string_value_and_invalid_compariso [Fact] public void EndsWith_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith('A')); @@ -401,7 +407,7 @@ public void EndsWith_with_string_field_and_char_constant_should_work() [Fact] public void EndsWith_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith('A')); @@ -415,7 +421,7 @@ public void EndsWith_with_string_constant_and_char_constant_should_work() [Fact] public void EndsWith_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.CS)); @@ -429,7 +435,7 @@ public void EndsWith_with_string_field_and_char_field_represented_as_string_shou [Fact] public void EndsWith_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.CS)); @@ -443,7 +449,7 @@ public void EndsWith_with_string_constant_and_char_field_represented_as_string_s [Fact] public void EndsWith_with_string_field_and_char_field_not_represented_as_string_should_throw() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.CC)); @@ -458,7 +464,7 @@ public void EndsWith_with_string_field_and_char_field_not_represented_as_string_ [Fact] public void EndsWith_with_string_constant_and_char_field_not_represented_as_string_should_throw() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.CC)); @@ -472,7 +478,7 @@ public void EndsWith_with_string_constant_and_char_field_not_represented_as_stri [Fact] public void EndsWith_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith("aBc")); @@ -484,7 +490,7 @@ public void EndsWith_with_string_field_and_string_constant_should_work() [Fact] public void EndsWith_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith("aBc")); @@ -496,7 +502,7 @@ public void EndsWith_with_string_constant_and_string_constant_should_work() [Fact] public void EndsWith_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.T)); @@ -508,7 +514,7 @@ public void EndsWith_with_string_field_and_string_field_should_work() [Fact] public void EndsWith_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.T)); @@ -522,7 +528,7 @@ public void EndsWith_with_string_constant_and_string_field_should_work() [InlineData(true, "{ $match : { S : /aBc$/is } }")] public void EndsWith_with_string_field_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith("aBc", ignoreCase, CultureInfo.CurrentCulture)); @@ -533,10 +539,10 @@ public void EndsWith_with_string_field_and_string_constant_and_ignoreCase_and_cu [Theory] [InlineData(false, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(true, "{ $match : { } }")] + [InlineData(true, null)] public void EndsWith_with_string_constant_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith("aBc", ignoreCase, CultureInfo.CurrentCulture)); @@ -550,7 +556,7 @@ public void EndsWith_with_string_constant_and_string_constant_and_ignoreCase_and [InlineData(true, "{ $match : { $expr : { $let : { vars : { string : { $toLower : '$S' }, substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', '$$substring', '$$start'] }, '$$start'] }] } } } } } } }")] public void EndsWith_with_string_field_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.T, ignoreCase, CultureInfo.CurrentCulture)); @@ -564,7 +570,7 @@ public void EndsWith_with_string_field_and_string_field_and_ignoreCase_and_cultu [InlineData(true, "{ $match : { $expr : { $let : { vars : { substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [3, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['abc', '$$substring', '$$start'] }, '$$start'] }] } } } } } } }")] public void EndsWith_with_string_constant_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.T, ignoreCase, CultureInfo.CurrentCulture)); @@ -578,7 +584,7 @@ public void EndsWith_with_string_constant_and_string_field_and_ignoreCase_and_cu [InlineData(true)] public void EndsWith_with_string_field_and_string_value_and_ignoreCase_and_invalid_culture_should_throw(bool ignoreCase) { - var collection = GetCollection(); + var collection = Fixture.Collection; var notCurrentCulture = GetACultureThatIsNotTheCurrentCulture(); var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith("aBc", ignoreCase, notCurrentCulture)); @@ -591,10 +597,10 @@ public void EndsWith_with_string_field_and_string_value_and_ignoreCase_and_inval [Theory] [InlineData(false, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(true, "{ $match : { } }")] + [InlineData(true, null)] public void EndsWith_with_string_constant_and_string_value_and_ignoreCase_and_invalid_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith("aBc", ignoreCase, CultureInfo.InvariantCulture)); @@ -608,7 +614,7 @@ public void EndsWith_with_string_constant_and_string_value_and_ignoreCase_and_in [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { S : /aBc$/is } }")] public void EndsWith_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith("aBc", comparisonType)); @@ -619,10 +625,10 @@ public void EndsWith_with_string_field_and_string_constant_and_comparisonType_sh [Theory] [InlineData(StringComparison.CurrentCulture, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { } }")] + [InlineData(StringComparison.CurrentCultureIgnoreCase, null)] public void EndsWith_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith("aBc", comparisonType)); @@ -636,7 +642,7 @@ public void EndsWith_with_string_constant_and_string_constant_and_comparisonType [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $let : { vars : { string : { $toLower : '$S' }, substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [{ $strLenCP : '$$string' }, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['$$string', '$$substring', '$$start'] }, '$$start'] }] } } } } } } }")] public void EndsWith_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.T, comparisonType)); @@ -650,7 +656,7 @@ public void EndsWith_with_string_field_and_string_field_and_comparisonType_shoul [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $let : { vars : { substring : { $toLower : '$T' } }, in : { $let : { vars : { start : { $subtract : [3, { $strLenCP : '$$substring' }] } }, in : { $and : [{ $gte : ['$$start', 0] }, { $eq : [{ $indexOfCP : ['abc', '$$substring', '$$start'] }, '$$start'] }] } } } } } } }")] public void EndsWith_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.T, comparisonType)); @@ -666,7 +672,7 @@ public void EndsWith_with_string_constant_and_string_field_and_comparisonType_sh [InlineData(StringComparison.OrdinalIgnoreCase)] public void EndsWith_with_string_field_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.EndsWith(x.T, comparisonType)); @@ -683,7 +689,7 @@ public void EndsWith_with_string_field_and_string_value_and_invalid_comparisonTy [InlineData(StringComparison.OrdinalIgnoreCase)] public void EndsWith_with_string_constant_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".EndsWith(x.T, comparisonType)); @@ -697,7 +703,7 @@ public void EndsWith_with_string_constant_and_string_value_and_invalid_compariso [Fact] public void StartsWith_with_string_field_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith('A')); @@ -711,13 +717,13 @@ public void StartsWith_with_string_field_and_char_constant_should_work() [Fact] public void StartsWith_with_string_constant_and_char_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith('A')); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $match : { } }"); + AssertStages(stages); } #endif @@ -725,7 +731,7 @@ public void StartsWith_with_string_constant_and_char_constant_should_work() [Fact] public void StartsWith_with_string_field_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.CS)); @@ -739,7 +745,7 @@ public void StartsWith_with_string_field_and_char_field_represented_as_string_sh [Fact] public void StartsWith_with_string_constant_and_char_field_represented_as_string_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.CS)); @@ -753,7 +759,7 @@ public void StartsWith_with_string_constant_and_char_field_represented_as_string [Fact] public void StartsWith_with_string_field_and_char_field_not_represented_as_string_should_throw() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.CC)); @@ -768,7 +774,7 @@ public void StartsWith_with_string_field_and_char_field_not_represented_as_strin [Fact] public void StartsWith_with_string_constant_and_char_field_not_represented_as_string_should_throw() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.CC)); @@ -782,7 +788,7 @@ public void StartsWith_with_string_constant_and_char_field_not_represented_as_st [Fact] public void StartsWith_with_string_field_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith("aBc")); @@ -794,7 +800,7 @@ public void StartsWith_with_string_field_and_string_constant_should_work() [Fact] public void StartsWith_with_string_constant_and_string_constant_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith("aBc")); @@ -806,7 +812,7 @@ public void StartsWith_with_string_constant_and_string_constant_should_work() [Fact] public void StartsWith_with_string_field_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.T)); @@ -818,7 +824,7 @@ public void StartsWith_with_string_field_and_string_field_should_work() [Fact] public void StartsWith_with_string_constant_and_string_field_should_work() { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.T)); @@ -832,7 +838,7 @@ public void StartsWith_with_string_constant_and_string_field_should_work() [InlineData(true, "{ $match : { S : /^aBc/is } }")] public void StartsWith_with_string_field_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith("aBc", ignoreCase, CultureInfo.CurrentCulture)); @@ -843,10 +849,10 @@ public void StartsWith_with_string_field_and_string_constant_and_ignoreCase_and_ [Theory] [InlineData(false, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(true, "{ $match : { } }")] + [InlineData(true, null)] public void StartsWith_with_string_constant_and_string_constant_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith("aBc", ignoreCase, CultureInfo.CurrentCulture)); @@ -860,7 +866,7 @@ public void StartsWith_with_string_constant_and_string_constant_and_ignoreCase_a [InlineData(true, "{ $match : { $expr : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] } } }")] public void StartsWith_with_string_field_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.T, ignoreCase, CultureInfo.CurrentCulture)); @@ -874,7 +880,7 @@ public void StartsWith_with_string_field_and_string_field_and_ignoreCase_and_cul [InlineData(true, "{ $match : { $expr : { $eq : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] } } }")] public void StartsWith_with_string_constant_and_string_field_and_ignoreCase_and_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.T, ignoreCase, CultureInfo.CurrentCulture)); @@ -888,7 +894,7 @@ public void StartsWith_with_string_constant_and_string_field_and_ignoreCase_and_ [InlineData(true)] public void StartsWith_with_string_field_and_string_value_and_ignoreCase_and_invalid_culture_should_throw(bool ignoreCase) { - var collection = GetCollection(); + var collection = Fixture.Collection; var notCurrentCulture = GetACultureThatIsNotTheCurrentCulture(); var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith("aBc", ignoreCase, notCurrentCulture)); @@ -901,10 +907,10 @@ public void StartsWith_with_string_field_and_string_value_and_ignoreCase_and_inv [Theory] [InlineData(false, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(true, "{ $match : { } }")] + [InlineData(true, null)] public void StartsWith_with_string_constant_and_string_value_and_ignoreCase_and_invalid_culture_should_work(bool ignoreCase, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith("aBc", ignoreCase, CultureInfo.InvariantCulture)); @@ -918,7 +924,7 @@ public void StartsWith_with_string_constant_and_string_value_and_ignoreCase_and_ [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { S : /^aBc/is } }")] public void StartsWith_with_string_field_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith("aBc", comparisonType)); @@ -929,10 +935,10 @@ public void StartsWith_with_string_field_and_string_constant_and_comparisonType_ [Theory] [InlineData(StringComparison.CurrentCulture, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { } }")] + [InlineData(StringComparison.CurrentCultureIgnoreCase, null)] public void StartsWith_with_string_constant_and_string_constant_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith("aBc", comparisonType)); @@ -946,7 +952,7 @@ public void StartsWith_with_string_constant_and_string_constant_and_comparisonTy [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $eq : [{ $indexOfCP : [{ $toLower : '$S' }, { $toLower : '$T' }] }, 0] } } }")] public void StartsWith_with_string_field_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.T, comparisonType)); @@ -960,7 +966,7 @@ public void StartsWith_with_string_field_and_string_field_and_comparisonType_sho [InlineData(StringComparison.CurrentCultureIgnoreCase, "{ $match : { $expr : { $eq : [{ $indexOfCP : ['abc', { $toLower : '$T' }] }, 0] } } }")] public void StartsWith_with_string_constant_and_string_field_and_comparisonType_should_work(StringComparison comparisonType, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.T, comparisonType)); @@ -976,7 +982,7 @@ public void StartsWith_with_string_constant_and_string_field_and_comparisonType_ [InlineData(StringComparison.OrdinalIgnoreCase)] public void StartsWith_with_string_field_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => x.S.StartsWith(x.T, comparisonType)); @@ -993,7 +999,7 @@ public void StartsWith_with_string_field_and_string_value_and_invalid_comparison [InlineData(StringComparison.OrdinalIgnoreCase)] public void StartsWith_with_string_constant_and_string_value_and_invalid_comparisonType_should_throw(StringComparison comparisonType) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => "ABC".StartsWith(x.T, comparisonType)); @@ -1020,5 +1026,10 @@ public class Test public string S { get; set; } public string T { get; set; } } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => null; + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4116Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4116Tests.cs index 68751e1622c..4b42a9cd18a 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4116Tests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4116Tests.cs @@ -13,20 +13,27 @@ * limitations under the License. */ +using System.Collections.Generic; using System.Linq; using MongoDB.Bson; +using MongoDB.Driver.TestHelpers; using Xunit; namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira { - public class CSharp4116Tests : Linq3IntegrationTest + public class CSharp4116Tests : LinqIntegrationTest { + public CSharp4116Tests(ClassFixture fixture) + : base(fixture) + { + } + [Theory] [InlineData(false, "{ $match : { _id : { $type : -1 } } }")] - [InlineData(true, "{ $match : { } }")] + [InlineData(true, null)] public void Optimize_match_with_expr(bool value, string expectedStage) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = collection.AsQueryable() .Where(x => value); @@ -34,5 +41,10 @@ public void Optimize_match_with_expr(bool value, string expectedStage) AssertStages(stages, expectedStage); } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => null; + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4876Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4876Tests.cs index c901d80e4ae..4a936177ae9 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4876Tests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp4876Tests.cs @@ -13,51 +13,42 @@ * limitations under the License. */ +using System.Collections.Generic; using System.Linq; using FluentAssertions; using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver.TestHelpers; using MongoDB.TestHelpers.XunitExtensions; using Xunit; namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira { - public class CSharp4876Tests : Linq3IntegrationTest + public class CSharp4876Tests : LinqIntegrationTest { + public CSharp4876Tests(ClassFixture fixture) + : base(fixture) + { + } + [Theory] [ParameterAttributeData] public void OfType_should_work( [Values(false, true)] bool withNestedAsQueryable) { - var collection = GetCollection(); + var collection = Fixture.Collection; var queryable = withNestedAsQueryable ? collection.AsQueryable().Select(x => x.A.AsQueryable().OfType().ToArray()) : collection.AsQueryable().Select(x => x.A.OfType().ToArray()); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $project : { _v : { $filter : { input : '$A', as : 'this', cond : { $cond : { if : { $eq : [{ $type : '$$this._t' }, 'array'] }, then : { $in : ['B2', '$$this._t'] }, else : { $eq : ['$$this._t', 'B2'] } } } } }, _id : 0 } }"); + AssertStages(stages, "{ $project : { _v : { $filter : { input : '$A', as : 'item', cond : { $cond : { if : { $eq : [{ $type : '$$item._t' }, 'array'] }, then : { $in : ['B2', '$$item._t'] }, else : { $eq : ['$$item._t', 'B2'] } } } } }, _id : 0 } }"); var result = queryable.Single(); result.Select(x => x.Id).Should().Equal(2); } - private IMongoCollection GetCollection() - { - var collection = GetCollection("test"); - CreateCollection( - collection, - new C - { - Id = 1, A = - [ - new B1 { Id = 1 }, - new B2 { Id = 2 } - ] - }); - return collection; - } - - private class C + public class C { public int Id { get; set; } public B[] A { get; set; } @@ -76,5 +67,21 @@ public class B1 : B public class B2 : B { } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => + [ + new C + { + Id = 1, + A = + [ + new B1 { Id = 1 }, + new B2 { Id = 2 } + ] + } + ]; + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5481Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5481Tests.cs new file mode 100644 index 00000000000..cfc9b9e5f77 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5481Tests.cs @@ -0,0 +1,612 @@ +/* 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 FluentAssertions; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver.Linq; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.TestHelpers; +using Xunit; + +namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira +{ + public class CSharp5481Tests : LinqIntegrationTest + { + public CSharp5481Tests(ClassFixture fixture) + : base(fixture) + { + } + + [Fact] + public void Documents_should_be_serialized_as_expected() + { + var collection = Fixture.Collection; + + var documents = collection.AsQueryable().As(BsonDocumentSerializer.Instance).ToList(); + + documents.Count.Should().Be(3); + documents[0].Should().Be("{ _id : 1, _t : 'Cat' }"); + documents[1].Should().Be("{ _id : 2, _t : 'Dog' }"); + documents[2].Should().Be("{ _id : 3, _t : 'Snake' }"); + } + + [Fact] + public void OfType_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .OfType(); + + var stages = Translate(collection, queryable); + stages.Count.Should().Be(0); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2, 3); + } + + [Fact] + public void OfType_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .OfType(); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $in : ['Cat', 'Dog', 'Mammal'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void OfType_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .OfType(); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : 'Cat' } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1); + } + + [Fact] + public void OfType_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .OfType(); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $in : ['Reptile', 'Snake'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void OfType_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .OfType(); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : 'Snake' } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Where_is_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => x is Animal); + + var stages = Translate(collection, queryable); + AssertStages(stages); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2, 3); + } + + [Fact] + public void Where_is_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => x is Mammal); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $in : ['Cat', 'Dog', 'Mammal'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Where_is_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => x is Cat); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : 'Cat' } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1); + } + + [Fact] + public void Where_is_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => x is Reptile); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $in : ['Reptile', 'Snake'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Where_is_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => x is Snake); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : 'Snake' } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Where_not_is_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => !(x is Animal)); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _id : { $type : -1 } } }"); + + var results = queryable.ToList(); + results.Count.Should().Be(0); + } + + [Fact] + public void Where_not_is_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => !(x is Mammal)); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $nin : ['Cat', 'Dog', 'Mammal'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Where_not_is_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => !(x is Cat)); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $ne : 'Cat' } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(2, 3); + } + + [Fact] + public void Where_not_is_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => !(x is Reptile)); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $nin : ['Reptile', 'Snake'] } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Where_not_is_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .Where(x => !(x is Snake)); + + var stages = Translate(collection, queryable); + AssertStages(stages, "{ $match : { _t : { $ne : 'Snake' } } }"); + + var results = queryable.ToList(); + results.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Array_OfType_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.OfType().ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : '$_v', _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2, 3); + } + + [Fact] + public void Array_OfType_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.OfType().ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'item', cond : { $in : ['$$item._t', ['Cat', 'Dog', 'Mammal']] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Array_OfType_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.OfType().ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'item', cond : { $eq : ['$$item._t', 'Cat'] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1); + } + + [Fact] + public void Array_OfType_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.OfType().ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'item', cond : { $in : ['$$item._t', ['Reptile', 'Snake']] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Array_OfType_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.OfType().ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'item', cond : { $eq : ['$$item._t', 'Snake'] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Array_Where_is_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => x is Animal).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : '$_v', _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2, 3); + } + + [Fact] + public void Array_Where_is_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => x is Mammal).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v: { $filter : { input : '$_v', as : 'x', cond : { $in : ['$$x._t', ['Cat', 'Dog', 'Mammal']] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Array_Where_is_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => x is Cat).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $eq : ['$$x._t', 'Cat'] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1); + } + + [Fact] + public void Array_Where_is_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => x is Reptile).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $in : ['$$x._t', ['Reptile', 'Snake']] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Array_Where_is_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => x is Snake).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $eq : ['$$x._t', 'Snake'] } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Array_Where_not_is_Animal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => !(x is Animal)).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : [], _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(); + } + + [Fact] + public void Array_Where_not_is_Mammal_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => !(x is Mammal)).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $not : { $in : ['$$x._t', ['Cat', 'Dog', 'Mammal']] } } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(3); + } + + [Fact] + public void Array_Where_not_is_Cat_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => !(x is Cat)).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $ne : ['$$x._t', 'Cat'] } } } , _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(2, 3); + } + + [Fact] + public void Array_Where_not_is_Reptile_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => !(x is Reptile)).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $not : { $in : ['$$x._t', ['Reptile', 'Snake']] } } } }, _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2); + } + + [Fact] + public void Array_Where_not_is_Snake_should_work() + { + var collection = Fixture.Collection; + + var queryable = collection.AsQueryable() + .GroupBy(x => 1, (key, grouping) => grouping.ToArray()) + .Select(x => x.Where(x => !(x is Snake)).ToArray()); + + var stages = Translate(collection, queryable); + AssertStages( + stages, + "{ $group : { _id : 1, _elements : { $push : '$$ROOT' } } }", + "{ $project : { _v : '$_elements', _id : 0 } }", + "{ $project : { _v : { $filter : { input : '$_v', as : 'x', cond : { $ne : ['$$x._t', 'Snake'] } } } , _id : 0 } }"); + + var result = queryable.Single(); + result.Select(x => x.Id).Should().Equal(1, 2); + } + + [BsonKnownTypes(typeof(Mammal))] + [BsonKnownTypes(typeof(Cat))] + [BsonKnownTypes(typeof(Dog))] + [BsonKnownTypes(typeof(Reptile))] + [BsonKnownTypes(typeof(Snake))] + public abstract class Animal + { + public int Id { get; set; } + } + + public abstract class Mammal : Animal + { + } + + public class Cat : Mammal + { + } + + public class Dog : Mammal + { + } + + public class Reptile : Animal + { + } + + public class Snake : Reptile + { + } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData + => + [ + new Cat { Id = 1 }, + new Dog { Id = 2 }, + new Snake { Id = 3 } + ]; + } } +}