acdream/tests/AcDream.App.Tests/Rendering/Gpu/Vk/VulkanLaneOwnershipContractTests.cs
Erik 0275b4ca5a
All checks were successful
CI / linux-portable (push) Successful in 3m40s
CI / windows-gate (push) Successful in 6m16s
CI / release (push) Successful in 2m13s
fix #485: isolate console capture and align Gitea portable test lanes
2026-09-06 11:41:27 +02:00

110 lines
5.1 KiB
C#

using System.Text.RegularExpressions;
namespace AcDream.App.Tests.Rendering.Gpu.Vk;
/// <summary>
/// Keeps the capability-owned pixel witness out of the portable gate while
/// requiring the lavapipe job to execute the complete trait-owned lane.
/// This contract reads repository text only and never initializes Vulkan.
/// </summary>
public sealed class VulkanLaneOwnershipContractTests
{
private const string WitnessMethod =
"CommittedProductionOrdinaryShader_RendersLocalSidecarsAtNonzeroTransformPrefix";
[Fact]
public void HardwareWitness_PortableFilterAndLavapipeOwnerStayAligned()
{
string root = RepositoryRoot();
string witness = File.ReadAllText(Path.Combine(
root,
"tests", "AcDream.App.Tests", "Rendering", "Gpu", "Vk",
"MeshModernSharedIndexOffscreenTests.cs"));
Assert.Matches(
new Regex(
"\\[Trait\\(\"Lane\", \"Vulkan\"\\)\\]\\s*"
+ "\\[Fact\\]\\s*public void " + WitnessMethod + "\\(",
RegexOptions.CultureInvariant),
witness);
Assert.Equal(1, Count(witness, "[Trait(\"Lane\", \"Vulkan\")]"));
string releaseGate = File.ReadAllText(Path.Combine(root, "tools", "run-release-gate.ps1"));
Match defaultFilter = Regex.Match(
releaseGate,
"\\[string\\]\\$TestFilter\\s*=\\s*'(?<filter>[^']+)'",
RegexOptions.CultureInvariant);
Assert.True(defaultFilter.Success, "Could not locate the portable Release gate's default filter.");
Assert.Contains("Lane!=Vulkan", defaultFilter.Groups["filter"].Value, StringComparison.Ordinal);
Assert.Equal(1, Count(defaultFilter.Groups["filter"].Value, "Lane!=Vulkan"));
string workflow = File.ReadAllText(Path.Combine(
root, ".github", "workflows", "headless-portability.yml"));
int install = workflow.IndexOf("- name: Install lavapipe, the Vulkan loader and Xvfb", StringComparison.Ordinal);
int portable = workflow.IndexOf("- name: Test the Vulkan backend's platform-independent decisions", StringComparison.Ordinal);
int hardware = workflow.IndexOf("- name: Test the Vulkan hardware lane on lavapipe", StringComparison.Ordinal);
Assert.True(install >= 0 && install < portable && portable < hardware);
string portableStep = Step(workflow, portable);
Assert.Contains(
"--filter \"FullyQualifiedName~AcDream.App.Tests.Rendering.Gpu.Vk&Lane!=Vulkan\"",
portableStep,
StringComparison.Ordinal);
string hardwareStep = Step(workflow, hardware);
Assert.DoesNotContain("FullyQualifiedName", hardwareStep, StringComparison.Ordinal);
Assert.DoesNotContain(WitnessMethod, hardwareStep, StringComparison.Ordinal);
Assert.Contains("--filter \"Lane=Vulkan\"", hardwareStep, StringComparison.Ordinal);
}
[Fact]
public void GiteaPortableFilters_MatchCanonicalReleaseGateWithOnlyLinuxLaneEnabledOnLinux()
{
string root = RepositoryRoot();
string releaseGate = File.ReadAllText(Path.Combine(root, "tools", "run-release-gate.ps1"));
Match canonical = Regex.Match(
releaseGate,
"\\[string\\]\\$TestFilter\\s*=\\s*'(?<filter>[^']+)'",
RegexOptions.CultureInvariant);
Assert.True(canonical.Success, "Could not locate the canonical portable filter.");
string expected = canonical.Groups["filter"].Value;
string workflow = File.ReadAllText(Path.Combine(root, ".gitea", "workflows", "ci.yml"));
Match windows = Regex.Match(
workflow, "\\$filter\\s*=\\s*'(?<filter>[^']+)'", RegexOptions.CultureInvariant);
Assert.True(windows.Success, "Could not locate Gitea's Windows test filter.");
Assert.Equal(expected, windows.Groups["filter"].Value);
MatchCollection linux = Regex.Matches(
workflow, "--filter\\s+'(?<filter>[^']+)'", RegexOptions.CultureInvariant);
Assert.Equal(2, linux.Count);
string expectedLinux = string.Join('&', expected.Split('&').Where(term => term != "Lane!=Linux"));
foreach (Match filter in linux)
Assert.Equal(expectedLinux, filter.Groups["filter"].Value);
}
private static string Step(string workflow, int start)
{
int next = workflow.IndexOf(" - name:", start + 1, StringComparison.Ordinal);
return next < 0 ? workflow[start..] : workflow[start..next];
}
private static int Count(string value, string needle)
{
int count = 0;
for (int index = 0; (index = value.IndexOf(needle, index, StringComparison.Ordinal)) >= 0;)
{
count++;
index += needle.Length;
}
return count;
}
private static string RepositoryRoot()
{
var directory = new DirectoryInfo(AppContext.BaseDirectory);
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
directory = directory.Parent;
return directory?.FullName
?? throw new InvalidOperationException("Could not locate the repository root.");
}
}