From 3d78530e74a92ba2d918112fa4880a97358aed0b Mon Sep 17 00:00:00 2001 From: Lukas Vosyka Date: Mon, 24 Nov 2025 23:55:08 +0100 Subject: [PATCH 1/2] #CSHARP-5792: Fix Decimal.MaxValue and Decimal.MinValue serialization behavior in RepresentationConverter, add decimal test cases to RepresentationConverterTests --- src/MongoDB.Bson/ObjectModel/Decimal128.cs | 16 ++++++++++++++-- .../Options/RepresentationConverter.cs | 10 ++++++---- .../Options/RepresentationConverterTests.cs | 10 ++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/MongoDB.Bson/ObjectModel/Decimal128.cs b/src/MongoDB.Bson/ObjectModel/Decimal128.cs index 0853fdf99e1..49293ddbefd 100644 --- a/src/MongoDB.Bson/ObjectModel/Decimal128.cs +++ b/src/MongoDB.Bson/ObjectModel/Decimal128.cs @@ -42,17 +42,29 @@ public struct Decimal128 : IConvertible, IComparable, IEquatable - /// Gets the maximum value. + /// Gets the maximum Decimal128 value. /// public static Decimal128 MaxValue => __maxValue; /// - /// Gets the minimum value. + /// Gets the minimum Decimal128 value. /// public static Decimal128 MinValue => __minValue; + /// + /// Gets the maximum System.Decimal value. + /// + public static Decimal128 MaxDecimalValue => + __maxDecimalValue; + + /// + /// Gets the minimum System.Decimal value. + /// + public static Decimal128 MinDecimalValue => + __minDecimalValue; + /// /// Represents negative infinity. /// diff --git a/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs b/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs index ed5f6965a9f..acbb4ebb82c 100644 --- a/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs +++ b/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs @@ -78,11 +78,13 @@ obj is RepresentationConverter other && /// A Decimal. public decimal ToDecimal(Decimal128 value) { - if (value == Decimal128.MaxValue) + // comparison against Decimal128.MaxValue remains valid for backwards compat. + if (value == Decimal128.MaxValue || value == Decimal128.MaxDecimalValue) { return decimal.MaxValue; } - else if (value == Decimal128.MinValue) + // comparison against Decimal128.MinValue remains valid for backwards compat. + else if (value == Decimal128.MinValue || value == Decimal128.MinDecimalValue) { return decimal.MinValue; } @@ -166,11 +168,11 @@ public Decimal128 ToDecimal128(decimal value) { if (value == decimal.MaxValue) { - return Decimal128.MaxValue; + return Decimal128.MaxDecimalValue; } else if (value == decimal.MinValue) { - return Decimal128.MinValue; + return Decimal128.MinDecimalValue; } // conversion from decimal to Decimal128 is lossless so need to check for overflow or truncation diff --git a/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs index 0bed83d83e3..f8260437673 100644 --- a/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs +++ b/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs @@ -119,6 +119,16 @@ public void TestConversions() Assert.Equal((long)(ulong)int.MaxValue, converter.ToInt64(int.MaxValue)); Assert.Equal(1UL, converter.ToUInt64((long)1)); Assert.Equal((long)(ulong)long.MaxValue, converter.ToInt64(long.MaxValue)); + + // general decimal <-> Decimal128 checks + Assert.Equal(123.45m, converter.ToDecimal(new Decimal128(123.45m))); + Assert.Equal(-123.45m, converter.ToDecimal(new Decimal128(-123.45m))); + Assert.Equal(Decimal128.MaxDecimalValue, converter.ToDecimal128(decimal.MaxValue)); + Assert.Equal(Decimal128.MinDecimalValue, converter.ToDecimal128(decimal.MinValue)); + Assert.Equal(decimal.MaxValue, converter.ToDecimal(Decimal128.MaxDecimalValue)); + Assert.Equal(decimal.MinValue, converter.ToDecimal(Decimal128.MinDecimalValue)); + Assert.Equal(decimal.MaxValue, converter.ToDecimal(Decimal128.MaxValue)); + Assert.Equal(decimal.MinValue, converter.ToDecimal(Decimal128.MinValue)); } [Theory] From 07e289b21efffc1226aa990cb298ba609d5fcae0 Mon Sep 17 00:00:00 2001 From: Lukas Vosyka Date: Thu, 27 Nov 2025 09:06:33 +0100 Subject: [PATCH 2/2] CSHARP-5792: Restore previous RepresentationConverter behavior for decimal.MaxValue and decimal.MinValue. Fix Decimal128.ToDecimal conversion and add checks for Min and MaxValue. --- src/MongoDB.Bson/ObjectModel/Decimal128.cs | 24 ++++++++----------- .../Options/RepresentationConverter.cs | 10 ++++---- .../ObjectModel/Decimal128Tests.cs | 2 ++ .../Options/RepresentationConverterTests.cs | 7 +++--- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/MongoDB.Bson/ObjectModel/Decimal128.cs b/src/MongoDB.Bson/ObjectModel/Decimal128.cs index 49293ddbefd..2b2ce4f816a 100644 --- a/src/MongoDB.Bson/ObjectModel/Decimal128.cs +++ b/src/MongoDB.Bson/ObjectModel/Decimal128.cs @@ -42,29 +42,17 @@ public struct Decimal128 : IConvertible, IComparable, IEquatable - /// Gets the maximum Decimal128 value. + /// Gets the maximum value. /// public static Decimal128 MaxValue => __maxValue; /// - /// Gets the minimum Decimal128 value. + /// Gets the minimum value. /// public static Decimal128 MinValue => __minValue; - /// - /// Gets the maximum System.Decimal value. - /// - public static Decimal128 MaxDecimalValue => - __maxDecimalValue; - - /// - /// Gets the minimum System.Decimal value. - /// - public static Decimal128 MinDecimalValue => - __minDecimalValue; - /// /// Represents negative infinity. /// @@ -751,6 +739,14 @@ public static byte ToByte(Decimal128 d) /// A equivalent to . public static decimal ToDecimal(Decimal128 d) { + if (d == Decimal128.MaxValue) + { + return decimal.MaxValue; + } + else if (d == Decimal128.MinValue) + { + return decimal.MinValue; + } if (Flags.IsFirstForm(d._highBits)) { if (Decimal128.Compare(d, __minDecimalValue) < 0 || Decimal128.Compare(d, __maxDecimalValue) > 0) diff --git a/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs b/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs index acbb4ebb82c..ed5f6965a9f 100644 --- a/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs +++ b/src/MongoDB.Bson/Serialization/Options/RepresentationConverter.cs @@ -78,13 +78,11 @@ obj is RepresentationConverter other && /// A Decimal. public decimal ToDecimal(Decimal128 value) { - // comparison against Decimal128.MaxValue remains valid for backwards compat. - if (value == Decimal128.MaxValue || value == Decimal128.MaxDecimalValue) + if (value == Decimal128.MaxValue) { return decimal.MaxValue; } - // comparison against Decimal128.MinValue remains valid for backwards compat. - else if (value == Decimal128.MinValue || value == Decimal128.MinDecimalValue) + else if (value == Decimal128.MinValue) { return decimal.MinValue; } @@ -168,11 +166,11 @@ public Decimal128 ToDecimal128(decimal value) { if (value == decimal.MaxValue) { - return Decimal128.MaxDecimalValue; + return Decimal128.MaxValue; } else if (value == decimal.MinValue) { - return Decimal128.MinDecimalValue; + return Decimal128.MinValue; } // conversion from decimal to Decimal128 is lossless so need to check for overflow or truncation diff --git a/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs b/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs index 10cd3c5aa52..5b8b1a6c665 100644 --- a/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs +++ b/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs @@ -76,6 +76,8 @@ public void Decimal(string valueString, string expectedResult) [InlineData("1E-99", "0")] [InlineData("1E-6111", "0")] [InlineData("10000.0000000000000000000000001", "10000.000000000000000000000000")] // see: CSHARP-2001 + [InlineData("9999999999999999999999999999999999E+6111", "79228162514264337593543950335")] // see: CSHARP-5792 + [InlineData("-9999999999999999999999999999999999E+6111", "-79228162514264337593543950335")] public void ToDecimal_should_return_expected_result(string valueString, string expectedResultString) { var subject = Decimal128.Parse(valueString); diff --git a/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs index f8260437673..f69fcbbe9fc 100644 --- a/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs +++ b/tests/MongoDB.Bson.Tests/Serialization/Options/RepresentationConverterTests.cs @@ -123,10 +123,9 @@ public void TestConversions() // general decimal <-> Decimal128 checks Assert.Equal(123.45m, converter.ToDecimal(new Decimal128(123.45m))); Assert.Equal(-123.45m, converter.ToDecimal(new Decimal128(-123.45m))); - Assert.Equal(Decimal128.MaxDecimalValue, converter.ToDecimal128(decimal.MaxValue)); - Assert.Equal(Decimal128.MinDecimalValue, converter.ToDecimal128(decimal.MinValue)); - Assert.Equal(decimal.MaxValue, converter.ToDecimal(Decimal128.MaxDecimalValue)); - Assert.Equal(decimal.MinValue, converter.ToDecimal(Decimal128.MinDecimalValue)); + // System.Decimal should be mapped to Decimal128.MaxValue and vice versa + Assert.Equal(Decimal128.MaxValue, converter.ToDecimal128(decimal.MaxValue)); + Assert.Equal(Decimal128.MinValue, converter.ToDecimal128(decimal.MinValue)); Assert.Equal(decimal.MaxValue, converter.ToDecimal(Decimal128.MaxValue)); Assert.Equal(decimal.MinValue, converter.ToDecimal(Decimal128.MinValue)); }