From 105c58b380536873e9ffbd32e1796a766e381274 Mon Sep 17 00:00:00 2001 From: Slick Daddy <129640104+slick-daddy@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:59:03 +0300 Subject: [PATCH] [Tests] Isolate Gen5 scalar fallback test from parallel static mutation (#488) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ScalarLoadReadsTrackedFallbackMemory swaps the process-global static Gen5ShaderScalarEvaluator.FallbackMemoryReader under a lock private to the test class. The SharpEmu.Libs [ModuleInitializer] (AgcShaderCompilerHooks) assigns the same static to TryReadShaderGuestMemory the first time any Libs type is touched, and it does not take that lock. Under xUnit's default cross-class parallelism a concurrent Libs test could fire the initializer mid-test, clobbering the swapped-in reader — observed on CI (linux-x64) as the fallback returning all zeros: Expected [1181044592, 4, 1319632096, 4], Actual [0, 0, 0, 0]. Put the test in a DisableParallelization collection, matching the existing convention for shared-mutable-static tests (KernelMemoryCompatState, AjmState, AvPlayerPathState). The collection runs alone in the non-parallel phase, so no other test can mutate the static while this one holds it. Co-authored-by: slick-daddy --- .../Agc/Gen5ScalarMemoryFallbackTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/SharpEmu.Libs.Tests/Agc/Gen5ScalarMemoryFallbackTests.cs b/tests/SharpEmu.Libs.Tests/Agc/Gen5ScalarMemoryFallbackTests.cs index 63a43eb1..dc16bb34 100644 --- a/tests/SharpEmu.Libs.Tests/Agc/Gen5ScalarMemoryFallbackTests.cs +++ b/tests/SharpEmu.Libs.Tests/Agc/Gen5ScalarMemoryFallbackTests.cs @@ -8,6 +8,20 @@ using Xunit; namespace SharpEmu.Libs.Tests.Agc; +// Gen5ShaderScalarEvaluator.FallbackMemoryReader is a process-global static. This +// test swaps it, but the SharpEmu.Libs [ModuleInitializer] (AgcShaderCompilerHooks) +// reassigns the same static the first time any Libs type is touched. Under xUnit's +// default cross-class parallelism a Libs test running concurrently can fire that +// initializer mid-test and clobber the swapped-in reader (observed as all-zero +// reads on CI). A DisableParallelization collection runs alone in the non-parallel +// phase, so nothing else can mutate the static while this test holds it. +[CollectionDefinition(Gen5ScalarEvaluatorStateCollection.Name, DisableParallelization = true)] +public sealed class Gen5ScalarEvaluatorStateCollection +{ + public const string Name = "Gen5ScalarEvaluatorState"; +} + +[Collection(Gen5ScalarEvaluatorStateCollection.Name)] public sealed class Gen5ScalarMemoryFallbackTests { private const ulong ScalarTableAddress = 0x4_4665_4FD0;