[release/8.0] Use invariant culture in CBOR date encoding (#92924)
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Wed, 4 Oct 2023 15:55:42 +0000 (08:55 -0700)
committerGitHub <noreply@github.com>
Wed, 4 Oct 2023 15:55:42 +0000 (08:55 -0700)
* Use invariant culture for CBOR tests

* Update src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs

* Add testing for #92539.

---------

Co-authored-by: Filip Navara <navara@emclient.com>
Co-authored-by: Filip Navara <filip.navara@gmail.com>
Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs
src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs
src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Tag.cs
src/libraries/System.Formats.Cbor/tests/System.Formats.Cbor.Tests.csproj
src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Tag.cs

index 2382178..2dd4c4d 100644 (file)
@@ -72,7 +72,7 @@ namespace System.Formats.Cbor
                 string dateString = ReadTextString();
 
                 // TODO determine if conformance modes should allow inexact date sting parsing
-                if (!DateTimeOffset.TryParseExact(dateString, CborWriter.Rfc3339FormatString, null, DateTimeStyles.RoundtripKind, out DateTimeOffset result))
+                if (!DateTimeOffset.TryParseExact(dateString, CborWriter.Rfc3339FormatString, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTimeOffset result))
                 {
                     throw new CborContentException(SR.Cbor_Reader_InvalidDateTimeEncoding);
                 }
index e5e772d..3ca04f0 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Diagnostics;
+using System.Globalization;
 using System.Numerics;
 
 namespace System.Formats.Cbor
@@ -42,8 +43,8 @@ namespace System.Formats.Cbor
 #else
                 value.Offset == TimeSpan.Zero ?
 #endif // NET8_0_OR_GREATER
-                value.UtcDateTime.ToString(Rfc3339FormatString) : // prefer 'Z' over '+00:00'
-                value.ToString(Rfc3339FormatString);
+                value.UtcDateTime.ToString(Rfc3339FormatString, CultureInfo.InvariantCulture) : // prefer 'Z' over '+00:00'
+                value.ToString(Rfc3339FormatString, CultureInfo.InvariantCulture);
 
             WriteTag(CborTag.DateTimeString);
             WriteTextString(dateString);
index af9adfb..c6fba6d 100644 (file)
@@ -2,8 +2,11 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Numerics;
+using System.Threading;
+using Microsoft.DotNet.RemoteExecutor;
 using Test.Cryptography;
 using Xunit;
 
@@ -192,6 +195,31 @@ namespace System.Formats.Cbor.Tests
             Assert.Equal(expectedValue.Offset, result.Offset);
         }
 
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+        [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+        public static void ReadDateTimeOffset_IsCultureInvariant()
+        {
+            // Regression test for https://github.com/dotnet/runtime/pull/92539
+            RemoteExecutor.Invoke(static () =>
+            {
+                DateTimeOffset expectedValue = DateTimeOffset.Parse("2020-04-09T14:31:21.3535941+01:00", CultureInfo.InvariantCulture);
+                byte[] data = "c07821323032302d30342d30395431343a33313a32312e333533353934312b30313a3030".HexToByteArray();
+
+                // Install a non-Gregorian calendar
+                var culture = new CultureInfo("he-IL");
+                culture.DateTimeFormat.Calendar = new HebrewCalendar();
+                Thread.CurrentThread.CurrentCulture = culture;
+
+                var reader = new CborReader(data);
+
+                DateTimeOffset result = reader.ReadDateTimeOffset();
+
+                Assert.Equal(CborReaderState.Finished, reader.PeekState());
+                Assert.Equal(expectedValue, result);
+                Assert.Equal(expectedValue.Offset, result.Offset);
+            }).Dispose();
+        }
+
         [Theory]
         [InlineData("c01a514b67b0")] // string datetime tag with unix time payload
         public static void ReadDateTimeOffset_InvalidTagPayload_ShouldThrowCborContentException(string hexEncoding)
@@ -206,6 +234,7 @@ namespace System.Formats.Cbor.Tests
         [Theory]
         [InlineData("c07330392f30342f323032302031393a35313a3530")] // 0("09/04/2020 19:51:50")
         [InlineData("c06e4c617374204368726973746d6173")] // 0("Last Christmas")
+        [InlineData("c07828d7aad7a922d7a42dd796272dd79822d7955431343a33313a32312e333533353934312b30313a3030")] // Non-Gregorian calendar date.
         public static void ReadDateTimeOffset_InvalidDateString_ShouldThrowCborContentException(string hexEncoding)
         {
             byte[] encoding = hexEncoding.HexToByteArray();
index 2ade4c6..bf7b2f2 100644 (file)
@@ -1,6 +1,7 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
+    <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
     <nullable>enable</nullable>
     <!-- Referenced assembly 'FsCheck' does not have a strong name.-->
     <NoWarn>$(NoWarn);CS8002</NoWarn>
index 3413ead..ff480bc 100644 (file)
@@ -2,8 +2,11 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Numerics;
+using System.Threading;
+using Microsoft.DotNet.RemoteExecutor;
 using Test.Cryptography;
 using Xunit;
 
@@ -88,6 +91,30 @@ namespace System.Formats.Cbor.Tests
             AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding);
         }
 
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+        [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+        public static void WriteDateTimeOffset_IsCultureInvariant()
+        {
+            // Regression test for https://github.com/dotnet/runtime/pull/92539
+            RemoteExecutor.Invoke(static () =>
+            {
+                DateTimeOffset value = DateTimeOffset.Parse("2020-04-09T14:31:21.3535941+01:00", CultureInfo.InvariantCulture);
+                string expectedHexEncoding = "c07821323032302d30342d30395431343a33313a32312e333533353934312b30313a3030";
+
+                // Install a non-Gregorian calendar
+                var culture = new CultureInfo("he-IL");
+                culture.DateTimeFormat.Calendar = new HebrewCalendar();
+                Thread.CurrentThread.CurrentCulture = culture;
+
+                var writer = new CborWriter();
+
+                writer.WriteDateTimeOffset(value);
+
+                byte[] encoding = writer.Encode();
+                AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding);
+            }).Dispose();
+        }
+
         [Theory]
         [InlineData(1363896240, "c11a514b67b0")]
         [InlineData(1586439081, "c11a5e8f23a9")]