From d9ddcafa5a2731bfcbf5d0b84ccac39762603ee4 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Wed, 19 Aug 2026 13:46:23 +0300 Subject: [PATCH] Update every package the solution can update, and adapt to xUnit v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dependabot's grouped bump (#3034) fails CI on the new xUnit1069 analyzer, and three further packages are behind. This takes all of them and fixes what the new versions actually break. Bumped: xunit.v3.mtp-off and xunit.runner.visualstudio 4.0.0, Meziantou.Analyzer 3.0.167, Microsoft.CodeAnalysis(.Analyzers|.CSharp) 5.9.0, System.Text.Json 10.0.11, Test262Harness 1.1.2, YantraJS.Core 1.2.462. Everything else is either already current or only has a prerelease ahead of it (BenchmarkDotNet 0.16.0-preview.1, NUnit 5.0.0-beta.1, Verify.NUnit 32.0.0-beta.8, Newtonsoft.Json 13.0.5-beta1, the 11.0.0-preview Microsoft.Extensions/System.Text.Json line), which stays out. The Roslyn floor matches the compiler in the SDK the pipeline installs (10.0.400 ships Roslyn 5.9.0), and Test262Harness.Console in the tool manifest was already 1.1.2. Two code adjustments, both in Jint.Tests: xUnit1069 wants a test carrying a Timeout to reference the test's cancellation token, and it is right that GeneratorTests.YieldInForLoopUpdateExpression did not: the method is synchronous, so xUnit cannot abort it and the ten-second Timeout bought nothing — a regression that reintroduced the infinite loop would have hung the run rather than failing it. Handing the token to the engine as a CancellationConstraint is what makes the Timeout bite; measured, the engine now throws ExecutionCanceledException 2.9 s into a 3 s Timeout instead of spinning. EngineTests.TestDates fed DateTime values through MemberData, and xUnit 4.0.0 changed how a theory's DateTime argument is serialized: SerializationHelper now goes through ToRtf(), i.e. ToUniversalTime().ToString("O"), where it used to format the value as-is. For a DateTimeKind.Unspecified value ToUniversalTime() reinterprets it as the *runner machine's* local time and shifts it, so the test received an instant that depended on where the suite ran — and, being Utc, immediately threw out of `new DateTimeOffset(value, pacificOffset)`. These six dates are wall-clock readings in the Pacific zone, so they now travel as text and are parsed back with an explicit Unspecified kind, which is what they always meant. Green on Jint.Tests, Jint.Tests.PublicInterface (both also under JINT_HOST_CONTRACT_VERIFICATION=1), Jint.Tests.CommonScripts, Jint.Tests.SourceGenerators and Jint.Tests.Test262 (102,394 passed). Co-Authored-By: Claude Opus 5 (1M context) --- Directory.Packages.props | 16 +++++++------- Jint.Tests/Runtime/EngineTests.cs | 33 ++++++++++++++++++---------- Jint.Tests/Runtime/GeneratorTests.cs | 6 ++++- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 6cc82a13f..2ec0d32dd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,12 +12,12 @@ - + - - + + @@ -33,11 +33,11 @@ - - - - - + + + + + diff --git a/Jint.Tests/Runtime/EngineTests.cs b/Jint.Tests/Runtime/EngineTests.cs index 568c1deaf..9a58b78d5 100644 --- a/Jint.Tests/Runtime/EngineTests.cs +++ b/Jint.Tests/Runtime/EngineTests.cs @@ -1233,38 +1233,49 @@ public void ShouldParseAsLocalTime(string date) result.Should().Be(msPriorMidnight); } + /// + /// Wall-clock readings in the Pacific zone, carried as text rather than as . + /// xUnit serializes a theory's argument through , + /// which reinterprets a value as the runner machine's local time and + /// shifts it, so the value arriving here would depend on where the suite ran. + /// public static System.Collections.Generic.IEnumerable TestDates { get { - yield return [new DateTime(2000, 1, 1)]; - yield return [new DateTime(2000, 1, 1, 0, 15, 15, 15)]; - yield return [new DateTime(2000, 6, 1, 0, 15, 15, 15)]; - yield return [new DateTime(1900, 1, 1)]; - yield return [new DateTime(1900, 1, 1, 0, 15, 15, 15)]; - yield return [new DateTime(1900, 6, 1, 0, 15, 15, 15)]; + yield return ["2000-01-01T00:00:00.000"]; + yield return ["2000-01-01T00:15:15.015"]; + yield return ["2000-06-01T00:15:15.015"]; + yield return ["1900-01-01T00:00:00.000"]; + yield return ["1900-01-01T00:15:15.015"]; + yield return ["1900-06-01T00:15:15.015"]; } } - [Theory, MemberData("TestDates")] - public void TestDateToISOStringFormat(DateTime testDate) + private static DateTime ParseTestDate(string testDate) + => DateTime.ParseExact(testDate, "yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture); + + [Theory, MemberData(nameof(TestDates))] + public void TestDateToISOStringFormat(string testDate) { var customTimeZone = _pacificTimeZone; var engine = new Engine(ctx => ctx.LocalTimeZone(customTimeZone)); - var testDateTimeOffset = new DateTimeOffset(testDate, customTimeZone.GetUtcOffset(testDate)); + var date = ParseTestDate(testDate); + var testDateTimeOffset = new DateTimeOffset(date, customTimeZone.GetUtcOffset(date)); engine.Execute( string.Format("var d = new Date({0},{1},{2},{3},{4},{5},{6});", testDateTimeOffset.Year, testDateTimeOffset.Month - 1, testDateTimeOffset.Day, testDateTimeOffset.Hour, testDateTimeOffset.Minute, testDateTimeOffset.Second, testDateTimeOffset.Millisecond)); engine.Evaluate("d.toISOString();").ToString().Should().Be(testDateTimeOffset.UtcDateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture)); } [Theory, MemberData(nameof(TestDates))] - public void TestDateToStringFormat(DateTime testDate) + public void TestDateToStringFormat(string testDate) { var customTimeZone = _pacificTimeZone; var engine = new Engine(ctx => ctx.LocalTimeZone(customTimeZone)); - var dt = new DateTimeOffset(testDate, customTimeZone.GetUtcOffset(testDate)); + var date = ParseTestDate(testDate); + var dt = new DateTimeOffset(date, customTimeZone.GetUtcOffset(date)); var dateScript = $"var d = new Date({dt.Year}, {dt.Month - 1}, {dt.Day}, {dt.Hour}, {dt.Minute}, {dt.Second}, {dt.Millisecond});"; engine.Execute(dateScript); diff --git a/Jint.Tests/Runtime/GeneratorTests.cs b/Jint.Tests/Runtime/GeneratorTests.cs index be5e051f9..0108752e5 100644 --- a/Jint.Tests/Runtime/GeneratorTests.cs +++ b/Jint.Tests/Runtime/GeneratorTests.cs @@ -24,7 +24,11 @@ public void YieldInForLoopUpdateExpression() return str; """; - _engine.Evaluate(Script).Should().Be("01234"); + // A regression here spins forever, and xUnit's Timeout cannot abort a synchronous test method on + // its own. Handing the engine the test's cancellation token is what makes the timeout bite. + var engine = new Engine(options => options.CancellationToken(TestContext.Current.CancellationToken)); + + engine.Evaluate(Script).Should().Be("01234"); } [Fact]