// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using Xunit;
namespace SharpEmu.ShaderCompiler.Metal.Tests;
///
/// Pins the emitted MSL for the synthetic fixtures. Codegen changes show up as a
/// readable text diff instead of a runtime mystery. Regenerate with
/// SHARPEMU_UPDATE_GOLDENS=1 (writes into the source tree) after intentional
/// emitter changes, then review the diff like any other code change.
///
public sealed class MslGoldenTests
{
public static TheoryData FixtureNames()
{
var data = new TheoryData();
foreach (var fixture in Gen5ComputeFixtures.All)
{
data.Add(fixture.Name);
}
return data;
}
[Fact]
public void PixelShaderMatchesGolden()
{
var shader = Gen5ComputeFixtures.CompilePixelOrThrow();
AssertMatchesGolden("pixel", shader.Source);
}
[Fact]
public void VertexShaderMatchesGolden()
{
var shader = Gen5ComputeFixtures.CompileVertexOrThrow(requiredVertexOutputCount: 1);
AssertMatchesGolden("vertex", shader.Source);
}
[Theory]
[MemberData(nameof(FixtureNames))]
public void EmittedMslMatchesGolden(string name)
{
Gen5ComputeFixture? fixture = null;
foreach (var candidate in Gen5ComputeFixtures.All)
{
if (candidate.Name == name)
{
fixture = candidate;
break;
}
}
Assert.NotNull(fixture);
var shader = Gen5ComputeFixtures.CompileOrThrow(fixture);
AssertMatchesGolden(name, shader.Source);
}
private static void AssertMatchesGolden(string name, string source)
{
var goldenPath = Path.Combine(AppContext.BaseDirectory, "Goldens", $"{name}.msl");
if (Environment.GetEnvironmentVariable("SHARPEMU_UPDATE_GOLDENS") == "1")
{
var sourcePath = Path.Combine(
FindSourceDirectory(),
"Goldens",
$"{name}.msl");
Directory.CreateDirectory(Path.GetDirectoryName(sourcePath)!);
File.WriteAllText(sourcePath, source);
return;
}
Assert.True(File.Exists(goldenPath), $"missing golden {goldenPath}; run with SHARPEMU_UPDATE_GOLDENS=1 to create it");
var expected = File.ReadAllText(goldenPath).ReplaceLineEndings();
Assert.Equal(expected, source.ReplaceLineEndings());
}
private static string FindSourceDirectory([System.Runtime.CompilerServices.CallerFilePath] string sourcePath = "")
{
// Binaries land in artifacts/bin (outside the project directory), so
// walking up from the test binary never finds the csproj; the compiler
// records this file's source path instead.
return Path.GetDirectoryName(sourcePath)
?? throw new InvalidOperationException("test project directory not found");
}
}