diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs
index 15d4858c3e7..5c027786d87 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs
@@ -678,6 +678,28 @@ public static void Serialize(
serializer.Serialize(context, args, value);
}
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The serializer.
+ /// The type.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
+ {
+ return __serializerRegistry.TryRegisterSerializer(type, serializer);
+ }
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ public static bool TryRegisterSerializer(IBsonSerializer serializer)
+ {
+ return TryRegisterSerializer(typeof(T), serializer);
+ }
+
// internal static methods
internal static void EnsureKnownTypesAreRegistered(Type nominalType)
{
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
index 4ff54ec6134..429386f6019 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
@@ -93,17 +93,7 @@ public void RegisterSerializer(Type type, IBsonSerializer serializer)
{
throw new ArgumentNullException("serializer");
}
- var typeInfo = type.GetTypeInfo();
- if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type))
- {
- var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
- throw new BsonSerializationException(message);
- }
- if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
- {
- var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
- throw new ArgumentException(message, "type");
- }
+ EnsureRegisteringASerializerForThisTypeIsAllowed(type);
if (!_cache.TryAdd(type, serializer))
{
@@ -127,6 +117,40 @@ public void RegisterSerializationProvider(IBsonSerializationProvider serializati
_serializationProviders.Push(serializationProvider);
}
+ ///
+ /// Tries to register the serializer.
+ ///
+ /// The type.
+ /// The serializer.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ public bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+ if (serializer == null)
+ {
+ throw new ArgumentNullException(nameof(serializer));
+ }
+ EnsureRegisteringASerializerForThisTypeIsAllowed(type);
+
+ if (_cache.TryAdd(type, serializer))
+ {
+ return true;
+ }
+ else
+ {
+ var existingSerializer = _cache[type];
+ if (!existingSerializer.Equals(serializer))
+ {
+ var message = $"There is already a different serializer registered for type {BsonUtils.GetFriendlyTypeName(type)}.";
+ throw new BsonSerializationException(message);
+ }
+ return false;
+ }
+ }
+
// private methods
private IBsonSerializer CreateSerializer(Type type)
{
@@ -153,5 +177,20 @@ private IBsonSerializer CreateSerializer(Type type)
var message = string.Format("No serializer found for type {0}.", type.FullName);
throw new BsonSerializationException(message);
}
+
+ private void EnsureRegisteringASerializerForThisTypeIsAllowed(Type type)
+ {
+ var typeInfo = type.GetTypeInfo();
+ if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type))
+ {
+ var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
+ throw new BsonSerializationException(message);
+ }
+ if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
+ {
+ var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
+ throw new ArgumentException(message, "type");
+ }
+ }
}
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
index c38430fdb2e..52265b9fd15 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
@@ -651,13 +651,23 @@ private void SerializeDiscriminator(BsonSerializationContext context, Type nomin
private void SerializeMember(BsonSerializationContext context, object obj, BsonMemberMap memberMap)
{
- if (memberMap != _classMap.ExtraElementsMemberMap)
+ try
{
- SerializeNormalMember(context, obj, memberMap);
+ if (memberMap != _classMap.ExtraElementsMemberMap)
+ {
+ SerializeNormalMember(context, obj, memberMap);
+ }
+ else
+ {
+ SerializeExtraElements(context, obj, memberMap);
+ }
}
- else
+ catch (Exception ex)
{
- SerializeExtraElements(context, obj, memberMap);
+ var message = string.Format(
+ "An error occurred while serializing the {0} {1} of class {2}: {3}", // terminating period provided by nested message
+ memberMap.MemberName, (memberMap.MemberInfo is FieldInfo) ? "field" : "property", memberMap.ClassMap.ClassType.FullName, ex.Message);
+ throw new BsonSerializationException(message, ex);
}
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
index 73b45873c5c..9b04916444a 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
@@ -16,7 +16,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq.Expressions;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Options;
@@ -59,7 +58,7 @@ public DictionarySerializerBase()
///
/// The dictionary representation.
public DictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation)
- : this(dictionaryRepresentation, new ObjectSerializer(), new ObjectSerializer())
+ : this(dictionaryRepresentation, BsonSerializer.LookupSerializer(), BsonSerializer.LookupSerializer())
{
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
index 760b03197ff..f59caa60836 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
@@ -81,7 +81,7 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo
_interfaceType = typeof(TInterface);
_discriminatorConvention = discriminatorConvention;
- _objectSerializer = new ObjectSerializer(_discriminatorConvention);
+ _objectSerializer = ((ObjectSerializer)BsonSerializer.LookupSerializer()).WithDiscriminatorConvention(_discriminatorConvention);
_interfaceSerializer = interfaceSerializer;
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs
index 1415d0160fe..cdfce696933 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs
@@ -14,8 +14,11 @@
*/
using System;
+using System.Collections.Generic;
+using System.Linq;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Conventions;
+using MongoDB.Shared;
namespace MongoDB.Bson.Serialization.Serializers
{
@@ -24,10 +27,36 @@ namespace MongoDB.Bson.Serialization.Serializers
///
public class ObjectSerializer : ClassSerializerBase
{
+ #region static
// private static fields
+ private static readonly Func __allAllowedTypes = t => true;
private static readonly ObjectSerializer __instance = new ObjectSerializer();
+ private static readonly Func __noAllowedTypes = t => false;
+
+ // public static properties
+ ///
+ /// An allowed types function that returns true for all types.
+ ///
+ public static Func AllAllowedTypes => __allAllowedTypes;
+
+ ///
+ /// An allowed types function that returns true for framework types known to be safe.
+ ///
+ public static Func DefaultAllowedTypes => DefaultFrameworkAllowedTypes.AllowedTypes;
+
+ ///
+ /// Gets the standard instance.
+ ///
+ public static ObjectSerializer Instance => __instance;
+
+ ///
+ /// An allowed types function that returns false for all types.
+ ///
+ public static Func NoAllowedTypes => __noAllowedTypes;
+ #endregion
// private fields
+ private readonly Func _allowedTypes;
private readonly IDiscriminatorConvention _discriminatorConvention;
private readonly GuidRepresentation _guidRepresentation;
private readonly GuidSerializer _guidSerializer;
@@ -57,27 +86,50 @@ public ObjectSerializer(IDiscriminatorConvention discriminatorConvention)
/// The discriminator convention.
/// The Guid representation.
public ObjectSerializer(IDiscriminatorConvention discriminatorConvention, GuidRepresentation guidRepresentation)
+ : this(discriminatorConvention, guidRepresentation, DefaultFrameworkAllowedTypes.AllowedTypes)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A delegate that determines what types are allowed.
+ public ObjectSerializer(Func allowedTypes)
+ : this(BsonSerializer.LookupDiscriminatorConvention(typeof(object)), allowedTypes)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The discriminator convention.
+ /// A delegate that determines what types are allowed.
+ public ObjectSerializer(IDiscriminatorConvention discriminatorConvention, Func allowedTypes)
+ : this(discriminatorConvention, GuidRepresentation.Unspecified, allowedTypes)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The discriminator convention.
+ /// The Guid representation.
+ /// A delegate that determines what types are allowed.
+ public ObjectSerializer(IDiscriminatorConvention discriminatorConvention, GuidRepresentation guidRepresentation, Func allowedTypes)
{
if (discriminatorConvention == null)
{
throw new ArgumentNullException("discriminatorConvention");
}
+ if (allowedTypes == null)
+ {
+ throw new ArgumentNullException(nameof(allowedTypes));
+ }
_discriminatorConvention = discriminatorConvention;
_guidRepresentation = guidRepresentation;
_guidSerializer = new GuidSerializer(_guidRepresentation);
- }
-
- // public static properties
- ///
- /// Gets the standard instance.
- ///
- ///
- /// The standard instance.
- ///
- public static ObjectSerializer Instance
- {
- get { return __instance; }
+ _allowedTypes = allowedTypes;
}
// public methods
@@ -165,6 +217,21 @@ public override object Deserialize(BsonDeserializationContext context, BsonDeser
}
}
+ ///
+ public override bool Equals(object obj) =>
+ obj is ObjectSerializer other &&
+ GetType() == other.GetType() &&
+ _allowedTypes.Equals(other._allowedTypes) &&
+ _discriminatorConvention.Equals(other._discriminatorConvention) &&
+ _guidRepresentation == other._guidRepresentation;
+
+ ///
+ public override int GetHashCode() =>
+ new Hasher()
+ .Hash(_discriminatorConvention)
+ .Hash(_guidRepresentation)
+ .GetHashCode();
+
///
/// Serializes a value.
///
@@ -264,12 +331,27 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
}
}
+ ///
+ /// Returns a new ObjectSerializer configured the same but with the specified discriminator convention.
+ ///
+ /// The discriminator convention.
+ /// An ObjectSerializer with the specified discriminator convention.
+ public ObjectSerializer WithDiscriminatorConvention(IDiscriminatorConvention discriminatorConvention)
+ {
+ return new ObjectSerializer(discriminatorConvention, _guidRepresentation, _allowedTypes);
+ }
+
// private methods
private object DeserializeDiscriminatedValue(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var actualType = _discriminatorConvention.GetActualType(bsonReader, typeof(object));
+ if (!_allowedTypes(actualType))
+ {
+ throw new BsonSerializationException($"Type {actualType.FullName} is not configured as an allowed type for this instance of ObjectSerializer.");
+ }
+
if (actualType == typeof(object))
{
var type = bsonReader.GetCurrentBsonType();
@@ -333,6 +415,11 @@ private object DeserializeDiscriminatedValue(BsonDeserializationContext context,
private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)
{
+ if (!_allowedTypes(actualType))
+ {
+ throw new BsonSerializationException($"Type {actualType.FullName} is not configured as an allowed type for this instance of ObjectSerializer.");
+ }
+
var serializer = BsonSerializer.LookupSerializer(actualType);
var polymorphicSerializer = serializer as IBsonPolymorphicSerializer;
@@ -361,5 +448,101 @@ private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonS
}
}
}
+
+ // nested types
+ private static class DefaultFrameworkAllowedTypes
+ {
+ private readonly static HashSet __allowedTypes = new HashSet
+ {
+ typeof(System.Boolean),
+ typeof(System.Byte),
+ typeof(System.Char),
+ typeof(System.Collections.ArrayList),
+ typeof(System.Collections.BitArray),
+ typeof(System.Collections.Hashtable),
+ typeof(System.Collections.Queue),
+ typeof(System.Collections.SortedList),
+ typeof(System.Collections.Specialized.ListDictionary),
+ typeof(System.Collections.Specialized.OrderedDictionary),
+ typeof(System.Collections.Stack),
+ typeof(System.DateTime),
+ typeof(System.DateTimeOffset),
+ typeof(System.Decimal),
+ typeof(System.Double),
+ typeof(System.Dynamic.ExpandoObject),
+ typeof(System.Guid),
+ typeof(System.Int16),
+ typeof(System.Int32),
+ typeof(System.Int64),
+ typeof(System.Net.DnsEndPoint),
+ typeof(System.Net.EndPoint),
+ typeof(System.Net.IPAddress),
+ typeof(System.Net.IPEndPoint),
+ typeof(System.Net.IPHostEntry),
+ typeof(System.Object),
+ typeof(System.SByte),
+ typeof(System.Single),
+ typeof(System.String),
+ typeof(System.Text.RegularExpressions.Regex),
+ typeof(System.TimeSpan),
+ typeof(System.UInt16),
+ typeof(System.UInt32),
+ typeof(System.UInt64),
+ typeof(System.Uri),
+ typeof(System.Version)
+ };
+
+ private readonly static HashSet __allowedGenericTypes = new HashSet
+ {
+ typeof(System.Collections.Generic.Dictionary<,>),
+ typeof(System.Collections.Generic.HashSet<>),
+ typeof(System.Collections.Generic.KeyValuePair<,>),
+ typeof(System.Collections.Generic.LinkedList<>),
+ typeof(System.Collections.Generic.List<>),
+ typeof(System.Collections.Generic.Queue<>),
+ typeof(System.Collections.Generic.SortedDictionary<,>),
+ typeof(System.Collections.Generic.SortedList<,>),
+ typeof(System.Collections.Generic.SortedSet<>),
+ typeof(System.Collections.Generic.Stack<>),
+ typeof(System.Collections.ObjectModel.Collection<>),
+ typeof(System.Collections.ObjectModel.KeyedCollection<,>),
+ typeof(System.Collections.ObjectModel.ObservableCollection<>),
+ typeof(System.Collections.ObjectModel.ReadOnlyCollection<>),
+ typeof(System.Collections.ObjectModel.ReadOnlyDictionary<,>),
+ typeof(System.Collections.ObjectModel.ReadOnlyObservableCollection<>),
+ typeof(System.Nullable<>),
+ typeof(System.Tuple<>),
+ typeof(System.Tuple<,>),
+ typeof(System.Tuple<,,>),
+ typeof(System.Tuple<,,,>),
+ typeof(System.Tuple<,,,,>),
+ typeof(System.Tuple<,,,,,>),
+ typeof(System.Tuple<,,,,,,>),
+ typeof(System.Tuple<,,,,,,,>),
+ typeof(System.ValueTuple<,,,,,,,>),
+ typeof(System.ValueTuple<>),
+ typeof(System.ValueTuple<,>),
+ typeof(System.ValueTuple<,,>),
+ typeof(System.ValueTuple<,,,>),
+ typeof(System.ValueTuple<,,,,>),
+ typeof(System.ValueTuple<,,,,,>),
+ typeof(System.ValueTuple<,,,,,,>),
+ typeof(System.ValueTuple<,,,,,,,>)
+ };
+
+ public static bool AllowedTypes(Type type)
+ {
+ return type.IsConstructedGenericType ? IsAllowedGenericType(type) : IsAllowedType(type);
+
+ static bool IsAllowedType(Type type) =>
+ __allowedTypes.Contains(type) ||
+ type.IsArray && AllowedTypes(type.GetElementType()) ||
+ type.IsEnum;
+
+ static bool IsAllowedGenericType(Type type) =>
+ __allowedGenericTypes.Contains(type.GetGenericTypeDefinition()) &&
+ type.GetGenericArguments().All(AllowedTypes);
+ }
+ }
}
}
diff --git a/tests/MongoDB.Bson.TestHelpers/RegisterObjectSerializerFixture.cs b/tests/MongoDB.Bson.TestHelpers/RegisterObjectSerializerFixture.cs
new file mode 100644
index 00000000000..0f0ac43d303
--- /dev/null
+++ b/tests/MongoDB.Bson.TestHelpers/RegisterObjectSerializerFixture.cs
@@ -0,0 +1,55 @@
+/* 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;
+using System.Collections.Concurrent;
+using System.Reflection;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Bson.TestHelpers
+{
+ public sealed class RegisterObjectSerializerFixture
+ {
+ public const string CollectionName = "RegisterObjectSerializer";
+
+ public RegisterObjectSerializerFixture()
+ {
+ // note: because xUnit has no way of letting us run some initialization code before any tests are run
+ // and because xUnit runs tests in random order it's very likely some other test has had the side effect
+ // of already registering a standard ObjectSerializer, so we have to use reflection below to replace
+ // any existing ObjectSerializer with one configured with AllowedTypes for testing
+
+ var testObjectSerializer = new ObjectSerializer(TestAllowedTypes);
+ RegisterOrReplaceExistingSerializer(testObjectSerializer);
+ }
+
+ public static bool TestAllowedTypes(Type type)
+ {
+ return
+ ObjectSerializer.DefaultAllowedTypes(type) ||
+ type.FullName.StartsWith("MongoDB");
+ }
+
+ private static void RegisterOrReplaceExistingSerializer(IBsonSerializer serializer)
+ {
+ // we have to use reflection because the serialization API specifically prohibits this operation
+ var serializerRegistry = BsonSerializer.SerializerRegistry;
+ var cacheInfo = typeof(BsonSerializerRegistry).GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance);
+ var cache = (ConcurrentDictionary)cacheInfo.GetValue(serializerRegistry);
+ cache.AddOrUpdate(typeof(object), serializer, (objectType, existingObjectSerializer) => serializer); // might replace existing serializer!
+ }
+ }
+}
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp1559Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp1559Tests.cs
index f42fc63eff0..7e9526b8fe7 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp1559Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp1559Tests.cs
@@ -24,6 +24,7 @@
namespace MongoDB.Bson.Tests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp1559Tests
{
[Theory]
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp263Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp263Tests.cs
index bfad065dc53..a871463e4d5 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp263Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp263Tests.cs
@@ -13,12 +13,13 @@
* limitations under the License.
*/
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp263Tests
{
public class C
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp301Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp301Tests.cs
index 6c1645f0e6a..23a12e00faa 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp301Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp301Tests.cs
@@ -15,12 +15,13 @@
using System.Collections;
using System.Collections.Generic;
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp301Tests
{
public class C
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp313Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp313Tests.cs
index 23b0da39f9d..a7c5ee9e4cf 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp313Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp313Tests.cs
@@ -14,12 +14,13 @@
*/
using System;
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp313Tests
{
private static object[] __scalarValues = new object[]
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp4475Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp4475Tests.cs
new file mode 100644
index 00000000000..980893e1149
--- /dev/null
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp4475Tests.cs
@@ -0,0 +1,95 @@
+/* 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;
+using FluentAssertions;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using Xunit;
+
+namespace MongoDB.Bson.Tests.Jira
+{
+ public class CSharp4475Tests
+ {
+ static CSharp4475Tests()
+ {
+ var objectSerializerWithAllowedTypes = new ObjectSerializer(t => t == typeof(Allowed));
+
+ BsonClassMap.RegisterClassMap(classMap =>
+ {
+ classMap.AutoMap();
+ classMap.MapProperty(x => x.Object).SetSerializer(objectSerializerWithAllowedTypes);
+ });
+ }
+
+ [Fact]
+ public void Deserialize_should_return_expected_result_when_deserializing_an_allowed_type()
+ {
+ var json = "{ Object : { _t : 'MongoDB.Bson.Tests.Jira.CSharp4475Tests+Allowed, MongoDB.Bson.Tests', X : 1 } }";
+
+ var result = BsonSerializer.Deserialize(json);
+
+ var allowed = result.Object.Should().BeOfType().Subject;
+ allowed.X.Should().Be(1);
+ }
+
+ [Fact]
+ public void Deserialize_should_throw_when_deserializing_a_not_allowed_type()
+ {
+ var json = "{ Object : { _t : 'MongoDB.Bson.Tests.Jira.CSharp4475Tests+NotAllowed, MongoDB.Bson.Tests', X : 1 } }";
+
+ var exception = Record.Exception(() => BsonSerializer.Deserialize(json));
+
+ exception.Should().BeOfType();
+ exception.Message.Should().Be("An error occurred while deserializing the Object property of class MongoDB.Bson.Tests.Jira.CSharp4475Tests+C: Type MongoDB.Bson.Tests.Jira.CSharp4475Tests+NotAllowed is not configured as an allowed type for this instance of ObjectSerializer.");
+ }
+
+ [Fact]
+ public void Serialize_should_have_expected_result_when_serializing_an_allowed_type()
+ {
+ var c = new C { Object = new Allowed { X = 1 } };
+
+ var result = c.ToJson();
+
+ result.Should().Be("{ \"Object\" : { \"_t\" : \"Allowed\", \"X\" : 1 } }");
+ }
+
+ [Fact]
+ public void Serialize_should_throw_when_serializing_a_not_allowed_type()
+ {
+ var c = new C { Object = new NotAllowed { X = 1 } };
+
+ var exception = Record.Exception(() => c.ToJson());
+
+ exception.Should().BeOfType();
+ exception.Message.Should().Be("An error occurred while serializing the Object property of class MongoDB.Bson.Tests.Jira.CSharp4475Tests+C: Type MongoDB.Bson.Tests.Jira.CSharp4475Tests+NotAllowed is not configured as an allowed type for this instance of ObjectSerializer.");
+ }
+
+ public class C
+ {
+ public object Object { get; set; }
+ }
+
+ public class Allowed
+ {
+ public int X { get; set; }
+ }
+
+ public class NotAllowed
+ {
+ public int X { get; set; }
+ }
+ }
+}
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp515Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp515Tests.cs
index 4fda6e577f5..54920f37ef1 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp515Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp515Tests.cs
@@ -16,12 +16,13 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira.CSharp515
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp515Tests
{
public class C
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp564Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp564Tests.cs
index b385151e1d9..8c670ad3502 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp564Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp564Tests.cs
@@ -13,12 +13,13 @@
* limitations under the License.
*/
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira.CSharp564
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp564Tests
{
interface IWhatever { }
diff --git a/tests/MongoDB.Bson.Tests/Jira/CSharp783Tests.cs b/tests/MongoDB.Bson.Tests/Jira/CSharp783Tests.cs
index 82d983a7589..8408afab25f 100644
--- a/tests/MongoDB.Bson.Tests/Jira/CSharp783Tests.cs
+++ b/tests/MongoDB.Bson.Tests/Jira/CSharp783Tests.cs
@@ -19,11 +19,13 @@
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Jira.CSharp783
{
#if WINDOWS
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp783DiscriminatedInterfaceTests
{
// nested types
@@ -144,6 +146,7 @@ public void TestSortedSetTwoInts(int x, int y)
}
#endif
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp783ImpliedHashSetImplementationTests
{
// nested types
@@ -262,6 +265,7 @@ public void TestSortedSetTwoInts(int x, int y)
}
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp783ImpliedSortedSetImplementationTests
{
// nested types
diff --git a/tests/MongoDB.Bson.Tests/RegisterObjectSerializerCollection.cs b/tests/MongoDB.Bson.Tests/RegisterObjectSerializerCollection.cs
new file mode 100644
index 00000000000..5ea624b4564
--- /dev/null
+++ b/tests/MongoDB.Bson.Tests/RegisterObjectSerializerCollection.cs
@@ -0,0 +1,25 @@
+/* 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 MongoDB.Bson.TestHelpers;
+using Xunit;
+
+namespace MongoDB.Bson.Tests
+{
+ [CollectionDefinition(RegisterObjectSerializerFixture.CollectionName)]
+ public sealed class RegisterObjectSerializerCollection : ICollectionFixture
+ {
+ }
+}
diff --git a/tests/MongoDB.Bson.Tests/Serialization/BsonSerializerRegistryTests.cs b/tests/MongoDB.Bson.Tests/Serialization/BsonSerializerRegistryTests.cs
new file mode 100644
index 00000000000..6989565923c
--- /dev/null
+++ b/tests/MongoDB.Bson.Tests/Serialization/BsonSerializerRegistryTests.cs
@@ -0,0 +1,193 @@
+/* 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;
+using System.Collections.Generic;
+using FluentAssertions;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using Moq;
+using Xunit;
+
+namespace MongoDB.Bson.Tests.Serialization
+{
+ public class BsonSerializerRegistryTests
+ {
+ [Fact]
+ public void RegisterSerializer_should_work()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = new ObjectSerializer();
+
+ subject.RegisterSerializer(typeof(object), serializer);
+
+ subject.GetSerializer(typeof(object)).Should().BeSameAs(serializer);
+ }
+
+ [Fact]
+ public void RegisterSerializer_should_throw_when_type_is_null()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = new ObjectSerializer();
+
+ var exception = Record.Exception(() => subject.RegisterSerializer(type: null, serializer));
+
+ var argumentNullException = exception.Should().BeOfType().Subject;
+ argumentNullException.ParamName.Should().Be("type");
+ }
+
+ [Fact]
+ public void RegisterSerializer_should_throw_when_type_is_BsonValue()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = BsonValueSerializer.Instance;
+
+ var exception = Record.Exception(() => subject.RegisterSerializer(typeof(BsonValue), serializer));
+
+ exception.Should().BeOfType();
+ exception.Message.Should().Contain("A serializer cannot be registered for type BsonValue because it is a subclass of BsonValue");
+ }
+
+ [Fact]
+ public void RegisterSerializer_should_throw_when_type_is_not_closed_generic_type()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = Mock.Of>();
+
+ var exception = Record.Exception(() => subject.RegisterSerializer(typeof(List<>), serializer));
+
+ var argumentException = exception.Should().BeOfType().Subject;
+ argumentException.ParamName.Should().Be("type");
+ argumentException.Message.Should().Contain("Generic type List has unassigned type parameters");
+ }
+
+ [Fact]
+ public void RegisterSerializer_should_throw_when_serializer_is_null()
+ {
+ var subject = new BsonSerializerRegistry();
+
+ var exception = Record.Exception(() => subject.RegisterSerializer(typeof(object), serializer: null));
+
+ var argumentNullException = exception.Should().BeOfType().Subject;
+ argumentNullException.ParamName.Should().Be("serializer");
+ }
+
+ [Fact]
+ public void RegisterSerializer_should_throw_when_serializer_is_already_registered()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = new ObjectSerializer();
+
+ subject.RegisterSerializer(typeof(object), serializer);
+ var exception = Record.Exception(() => subject.RegisterSerializer(typeof(object), serializer));
+
+ exception.Should().BeOfType();
+ exception.Message.Should().Contain("There is already a serializer registered for type Object");
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_return_true_when_serializer_is_not_already_registered()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = new ObjectSerializer();
+
+ var result = subject.TryRegisterSerializer(typeof(object), serializer);
+
+ result.Should().BeTrue();
+ subject.GetSerializer(typeof(object)).Should().BeSameAs(serializer);
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_return_false_when_equivalent_serializer_is_already_registered()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer1 = new ObjectSerializer(ObjectSerializer.DefaultAllowedTypes);
+ var serializer2 = new ObjectSerializer(ObjectSerializer.DefaultAllowedTypes);
+
+ var result1 = subject.TryRegisterSerializer(typeof(object), serializer1);
+ var result2 = subject.TryRegisterSerializer(typeof(object), serializer2);
+
+ result1.Should().BeTrue();
+ result2.Should().BeFalse();
+ subject.GetSerializer(typeof(object)).Should().BeSameAs(serializer1);
+ subject.GetSerializer(typeof(object)).Should().NotBeSameAs(serializer2);
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_throw_when_type_is_null()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = new ObjectSerializer();
+
+ var exception = Record.Exception(() => subject.TryRegisterSerializer(type: null, serializer));
+
+ var argumentNullException = exception.Should().BeOfType().Subject;
+ argumentNullException.ParamName.Should().Be("type");
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_throw_when_type_is_BsonValue()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = BsonValueSerializer.Instance;
+
+ var exception = Record.Exception(() => subject.TryRegisterSerializer(typeof(BsonValue), serializer));
+
+ exception.Should().BeOfType();
+ exception.Message.Should().Contain("A serializer cannot be registered for type BsonValue because it is a subclass of BsonValue");
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_throw_when_type_is_not_closed_generic_type()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer = Mock.Of>();
+
+ var exception = Record.Exception(() => subject.TryRegisterSerializer(typeof(List<>), serializer));
+
+ var argumentException = exception.Should().BeOfType().Subject;
+ argumentException.ParamName.Should().Be("type");
+ argumentException.Message.Should().Contain("Generic type List has unassigned type parameters");
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_throw_when_serializer_is_null()
+ {
+ var subject = new BsonSerializerRegistry();
+
+ var exception = Record.Exception(() => subject.TryRegisterSerializer(typeof(object), serializer: null));
+
+ var argumentNullException = exception.Should().BeOfType().Subject;
+ argumentNullException.ParamName.Should().Be("serializer");
+ }
+
+ [Fact]
+ public void TryRegisterSerializer_should_throw_when_different_serializer_is_already_registered()
+ {
+ var subject = new BsonSerializerRegistry();
+ var serializer1 = new ObjectSerializer(ObjectSerializer.DefaultAllowedTypes);
+ var serializer2 = new ObjectSerializer(ObjectSerializer.AllAllowedTypes);
+
+ var result1 = subject.TryRegisterSerializer(typeof(object), serializer1);
+ var exception = Record.Exception(() => subject.TryRegisterSerializer(typeof(object), serializer2));
+
+ result1.Should().BeTrue();
+ subject.GetSerializer(typeof(object)).Should().BeSameAs(serializer1);
+ subject.GetSerializer(typeof(object)).Should().NotBeSameAs(serializer2);
+ exception.Should().BeOfType();
+ exception.Message.Should().Contain("There is already a different serializer registered for type Object");
+ }
+ }
+}
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerGenericTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerGenericTests.cs
index ff17df7b79f..6d6a33a06ad 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerGenericTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerGenericTests.cs
@@ -32,6 +32,7 @@ public class C
public string P { get; set; }
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class EnumerableSerializerTests
{
public class T
@@ -277,6 +278,7 @@ public void TestMixedPrimitiveTypes(
}
#if WINDOWS
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class EnumerableSerializerNominalTypeObjectTests
{
public class T
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerTests.cs
index ab5a2a99954..2f97d67c933 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/CollectionSerializerTests.cs
@@ -32,6 +32,7 @@ public class C
public string P { get; set; }
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CollectionSerializerTests
{
public class T
@@ -274,6 +275,7 @@ public void TestMixedPrimitiveTypes(
}
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CollectionSerializerNominalTypeObjectTests
{
public class T
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionaryGenericSerializerTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionaryGenericSerializerTests.cs
index e7646e5a181..42f64421431 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionaryGenericSerializerTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionaryGenericSerializerTests.cs
@@ -22,6 +22,8 @@
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
+using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Bson.TestHelpers;
using MongoDB.TestHelpers.XunitExtensions;
using Xunit;
@@ -34,8 +36,35 @@ public class C
public string P { get; set; }
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class DictionaryGenericSerializerTests
{
+ static DictionaryGenericSerializerTests()
+ {
+ _ = new RegisterObjectSerializerFixture(); // ensure correct ObjectSerializer is registered
+
+ var objectSerializer = BsonSerializer.LookupSerializer();
+ var dictionaryRepresentation = DictionaryRepresentation.Document;
+ var keySerializer = objectSerializer;
+ var valueSerializer = objectSerializer;
+ var dictionarySerializer = new DictionaryInterfaceImplementerSerializer, object, object>(dictionaryRepresentation, keySerializer, valueSerializer);
+ var idictionarySerializer = new ImpliedImplementationInterfaceSerializer, Dictionary>(dictionarySerializer);
+ var readOnlyDictionarySerializer = new ReadOnlyDictionaryInterfaceImplementerSerializer, object, object>(dictionaryRepresentation, keySerializer, valueSerializer);
+ var ireadOnlyDictionarySerializer = new ImpliedImplementationInterfaceSerializer, ReadOnlyDictionary>(readOnlyDictionarySerializer);
+ var sortedDictionarySerializer = new DictionaryInterfaceImplementerSerializer, object, object>(dictionaryRepresentation, keySerializer, valueSerializer);
+ var sortedListSerializer = new DictionaryInterfaceImplementerSerializer, object, object>(dictionaryRepresentation, keySerializer, valueSerializer);
+
+ BsonClassMap.RegisterClassMap(cm =>
+ {
+ cm.MapProperty(t => t.D).SetSerializer(dictionarySerializer);
+ cm.MapProperty(t => t.ID).SetSerializer(idictionarySerializer);
+ cm.MapProperty(t => t.IROD).SetSerializer(ireadOnlyDictionarySerializer);
+ cm.MapProperty(t => t.ROD).SetSerializer(readOnlyDictionarySerializer);
+ cm.MapProperty(t => t.SD).SetSerializer(sortedDictionarySerializer);
+ cm.MapProperty(t => t.SL).SetSerializer(sortedListSerializer);
+ });
+ }
+
public class T
{
public Dictionary D { get; set; }
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionarySerializerTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionarySerializerTests.cs
index 5f8a493abc4..e8ba363c16d 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionarySerializerTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DictionarySerializerTests.cs
@@ -23,6 +23,8 @@
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
+using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Bson.TestHelpers;
using MongoDB.TestHelpers.XunitExtensions;
using Xunit;
@@ -51,8 +53,33 @@ public override int GetHashCode()
}
}
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class DictionarySerializerTests
{
+ static DictionarySerializerTests()
+ {
+ _ = new RegisterObjectSerializerFixture(); // ensure correct ObjectSerializer is registered
+
+ var objectSerializer = BsonSerializer.LookupSerializer();
+ var dictionaryRepresentation = DictionaryRepresentation.Document;
+ var keySerializer = objectSerializer;
+ var valueSerializer = objectSerializer;
+ var hashTableSerializer = new DictionaryInterfaceImplementerSerializer(dictionaryRepresentation, keySerializer, valueSerializer);
+ var iDictionarySerializer = new ImpliedImplementationInterfaceSerializer(hashTableSerializer);
+ var listDictionarySerializer = new DictionaryInterfaceImplementerSerializer(dictionaryRepresentation, keySerializer, valueSerializer);
+ var orderedDictionarySerializer = new DictionaryInterfaceImplementerSerializer(dictionaryRepresentation, keySerializer, valueSerializer);
+ var sortedListDictionarySerializer = new DictionaryInterfaceImplementerSerializer(dictionaryRepresentation, keySerializer, valueSerializer);
+
+ BsonClassMap.RegisterClassMap(cm =>
+ {
+ cm.MapProperty(t => t.HT).SetSerializer(hashTableSerializer);
+ cm.MapProperty(t => t.ID).SetSerializer(iDictionarySerializer);
+ cm.MapProperty(t => t.LD).SetSerializer(listDictionarySerializer);
+ cm.MapProperty(t => t.OD).SetSerializer(orderedDictionarySerializer);
+ cm.MapProperty(t => t.SL).SetSerializer(sortedListDictionarySerializer);
+ });
+ }
+
public class T
{
public Hashtable HT { get; set; }
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs
index 900cdd69277..826b0969da6 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs
@@ -14,13 +14,14 @@
*/
using System.Linq;
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Serialization
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class DiscriminatorTests
{
[BsonDiscriminator("A~")] // make discriminators unique with respect to object
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/ExpandoObjectSerializerTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/ExpandoObjectSerializerTests.cs
index 69248b92b3e..4d489ed4c08 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/ExpandoObjectSerializerTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/ExpandoObjectSerializerTests.cs
@@ -16,16 +16,13 @@
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
-using System.IO;
-using System.Text;
-using MongoDB.Bson;
-using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
-using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Serialization
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class ExpandoSerializerTests
{
[Fact]
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/ObjectSerializerTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/ObjectSerializerTests.cs
index a7da6c543fd..75eedcca133 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/ObjectSerializerTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/ObjectSerializerTests.cs
@@ -31,6 +31,7 @@
namespace MongoDB.Bson.Tests.Serialization
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class ObjectSerializerTests
{
public class C
@@ -294,7 +295,7 @@ public void constructor_with_discriminator_convention_should_initialize_instance
[Fact]
public void constructor_with_discriminator_convention_should_throw_when_discriminator_convention_is_null()
{
- var exception = Record.Exception(() => new ObjectSerializer(null));
+ var exception = Record.Exception(() => new ObjectSerializer(discriminatorConvention: null));
var e = exception.Should().BeOfType().Subject;
e.ParamName.Should().Be("discriminatorConvention");
@@ -365,6 +366,56 @@ public void Deserialize_binary_data_should_return_expected_result_when_guid_repr
#pragma warning restore 618
}
+ [Fact]
+ public void Equals_should_return_true_when_instances_are_equal()
+ {
+ var discriminatorConvention = new ScalarDiscriminatorConvention("_t");
+ var subject1 = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Standard, ObjectSerializer.DefaultAllowedTypes);
+ var subject2 = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Standard, ObjectSerializer.DefaultAllowedTypes);
+
+ var result = subject1.Equals(subject2);
+ var hashCode1 = subject1.GetHashCode();
+ var hashCode2 = subject2.GetHashCode();
+
+ result.Should().BeTrue();
+ hashCode2.Should().Be(hashCode1); // required by the contract of Equals
+ }
+
+ [Theory]
+ [ParameterAttributeData]
+ public void Equals_should_return_false_when_instances_are_not_equal(
+ [Values("allowedTypes", "discriminatorConvention", "guidRepresentation")]
+ string notEqualFieldName)
+ {
+ IDiscriminatorConvention discriminatorConvention = new ScalarDiscriminatorConvention("_t");
+ var guidRepresentation = GuidRepresentation.Standard;
+ var allowedTypes = ObjectSerializer.DefaultAllowedTypes;
+ var subject1 = new ObjectSerializer(discriminatorConvention, guidRepresentation, allowedTypes);
+
+ switch (notEqualFieldName)
+ {
+ case "allowedTypes": allowedTypes = ObjectSerializer.NoAllowedTypes; break;
+ case "discriminatorConvention": discriminatorConvention = new HierarchicalDiscriminatorConvention("_t"); break;
+ case "guidRepresentation": guidRepresentation = GuidRepresentation.CSharpLegacy; break;
+ default: throw new ArgumentException($"Invalid notEqualFieldName: {notEqualFieldName}.", nameof(notEqualFieldName));
+ }
+ var subject2 = new ObjectSerializer(discriminatorConvention, guidRepresentation, allowedTypes);
+
+ var result = subject1.Equals(subject2);
+ var hashCode1 = subject1.GetHashCode();
+ var hashCode2 = subject2.GetHashCode();
+
+ result.Should().BeFalse();
+ if (notEqualFieldName == "allowedTypes")
+ {
+ hashCode2.Should().Be(hashCode1); // because allowedTypes is not part of the hash code computation
+ }
+ else
+ {
+ hashCode2.Should().NotBe(hashCode1); // not strictly required but desirable
+ }
+ }
+
[Theory]
[ParameterAttributeData]
[ResetGuidModeAfterTest]
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Serializers/SerializeInterfaceTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Serializers/SerializeInterfaceTests.cs
index 3d297c0b9a5..5d6123fbbec 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Serializers/SerializeInterfaceTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Serializers/SerializeInterfaceTests.cs
@@ -14,12 +14,13 @@
*/
using System.Linq;
-using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Bson.Tests.Serialization
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class SerializeInterfaceTests
{
private interface IX
diff --git a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp140Tests.cs b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp140Tests.cs
index 44f003d6e6e..a1b983f07a3 100644
--- a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp140Tests.cs
+++ b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp140Tests.cs
@@ -14,12 +14,14 @@
*/
using MongoDB.Bson;
+using MongoDB.Bson.TestHelpers;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Wrappers;
using Xunit;
namespace MongoDB.Driver.Tests.Jira.CSharp140
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp140Tests
{
private class C
diff --git a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp247Tests.cs b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp247Tests.cs
index db2fbbe018c..7a7b482f7a4 100644
--- a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp247Tests.cs
+++ b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp247Tests.cs
@@ -14,11 +14,12 @@
*/
using MongoDB.Bson;
-using MongoDB.Driver;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Driver.Tests.Jira.CSharp247
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp247Tests
{
public interface I
diff --git a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp958Tests.cs b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp958Tests.cs
index 5e53d73a7df..a02e1f5d77b 100644
--- a/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp958Tests.cs
+++ b/tests/MongoDB.Driver.Legacy.Tests/Jira/CSharp958Tests.cs
@@ -13,14 +13,13 @@
* limitations under the License.
*/
-using System;
-using System.Linq;
using MongoDB.Bson;
-using MongoDB.Driver;
+using MongoDB.Bson.TestHelpers;
using Xunit;
namespace MongoDB.Driver.Tests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp958Tests
{
private interface IPerson { }
diff --git a/tests/MongoDB.Driver.Legacy.Tests/RegisterObjectSerializerCollection.cs b/tests/MongoDB.Driver.Legacy.Tests/RegisterObjectSerializerCollection.cs
new file mode 100644
index 00000000000..bd4fcb327db
--- /dev/null
+++ b/tests/MongoDB.Driver.Legacy.Tests/RegisterObjectSerializerCollection.cs
@@ -0,0 +1,25 @@
+/* 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 MongoDB.Bson.TestHelpers;
+using Xunit;
+
+namespace MongoDB.Driver.Legacy.Tests
+{
+ [CollectionDefinition(RegisterObjectSerializerFixture.CollectionName)]
+ public sealed class RegisterObjectSerializerCollection : ICollectionFixture
+ {
+ }
+}
diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/Jira/CSharp2113Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/Jira/CSharp2113Tests.cs
index 957b371d13b..fbd12010793 100644
--- a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/Jira/CSharp2113Tests.cs
+++ b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/Jira/CSharp2113Tests.cs
@@ -15,11 +15,13 @@
using System.Linq;
using FluentAssertions;
+using MongoDB.Bson.TestHelpers;
using MongoDB.Driver.Linq;
using Xunit;
namespace MongoDB.Driver.Tests.Linq.Linq3ImplementationTests.Jira
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class CSharp2113Tests : Linq3IntegrationTest
{
[Fact]
diff --git a/tests/MongoDB.Driver.Tests/RegisterObjectSerializerCollection.cs b/tests/MongoDB.Driver.Tests/RegisterObjectSerializerCollection.cs
new file mode 100644
index 00000000000..69d2852f291
--- /dev/null
+++ b/tests/MongoDB.Driver.Tests/RegisterObjectSerializerCollection.cs
@@ -0,0 +1,25 @@
+/* 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 MongoDB.Bson.TestHelpers;
+using Xunit;
+
+namespace MongoDB.Driver.Tests
+{
+ [CollectionDefinition(RegisterObjectSerializerFixture.CollectionName)]
+ public sealed class RegisterObjectSerializerCollection : ICollectionFixture
+ {
+ }
+}
diff --git a/tests/MongoDB.Driver.Tests/UpdateDefinitionBuilderTests.cs b/tests/MongoDB.Driver.Tests/UpdateDefinitionBuilderTests.cs
index d142e8ca17d..24d9773465d 100644
--- a/tests/MongoDB.Driver.Tests/UpdateDefinitionBuilderTests.cs
+++ b/tests/MongoDB.Driver.Tests/UpdateDefinitionBuilderTests.cs
@@ -16,17 +16,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using FluentAssertions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
-using MongoDB.TestHelpers.XunitExtensions;
+using MongoDB.Bson.TestHelpers;
using MongoDB.Driver.Linq;
+using MongoDB.TestHelpers.XunitExtensions;
using Xunit;
namespace MongoDB.Driver.Tests
{
+ [Collection(RegisterObjectSerializerFixture.CollectionName)]
public class UpdateDefinitionBuilderTests
{
[Fact]