Aetheria/tests/Aetheria.Shared.Tests/GravityShaderMirrorTests.cs
Meta Vens e6d1546b44 Gravity grid-lowering fixes: formula mirror test, verify across moved off-axis bodies and a zero-strength body, map camera wiring, RTS Planet's Gravity Well deleted
GravityShaderMirrorTests compares the expression of GravityField.Potential with gravityPotential in Gravity.cginc.
GravityFieldParityVerify now builds four off-axis bodies (one of mass 0), lowers through three frames with bodies moved
between them, and checks the map screen's gravity camera mask. RTS/Planet.prefab loses the Gravity Well object bound to
the Gravity Field material. Builds: yes (verify passes on Starfire; the new test is unrun until the Yggdrasil job).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:59:15 +02:00

50 lines
2.4 KiB
C#

using System.IO;
using System.Text.RegularExpressions;
using Xunit;
// potential-owns-gravity (aetheria-gravity, cut grid-lowering): Assets/Shaders/Gravity.cginc lowers the potential for
// the GPU and decides nothing, so its gravityPotential must be GravityField.Potential, term for term, zero-strength
// guard and core branch included. The shader cannot be compiled here (GravityFieldParityVerify renders it, on Starfire
// only), so this test is the automated guard: each copy's expression is read from its file, reduced to the same
// spelling (float suffixes, the core radius's name, whitespace and comments), and compared. A drift in either file fails it.
public sealed class GravityShaderMirrorTests
{
private static string Read(string relative) =>
File.ReadAllText(Path.Combine(RunStartTests.FindRepoRoot(), relative));
// The text between `start` and the first `;` after it, comments removed and spellings reduced.
private static string Expression(string source, string start, string then = "")
{
source = Regex.Replace(source, @"//[^\n]*", "");
var from = source.IndexOf(start, System.StringComparison.Ordinal);
Assert.True(from >= 0, $"'{start}' not found");
var body = source.Substring(from + start.Length);
if (then != "")
{
var at = body.IndexOf(then, System.StringComparison.Ordinal);
Assert.True(at >= 0, $"'{then}' not found after '{start}'");
body = body.Substring(at + then.Length);
}
body = body.Substring(0, body.IndexOf(';'));
body = Regex.Replace(body, @"(?<=[\d.])f\b", "");
body = body.Replace("coreRadius", "R");
return Regex.Replace(body, @"\s+", "");
}
private static string CSharpLaw() =>
Expression(Read("Assets/Scripts/ServerShared/GravityField.cs"), "Potential(float c, float coreRadius, float r) =>");
private static string ShaderLaw() =>
Expression(Read("Assets/Shaders/Gravity.cginc"), "float gravityPotential(float c, float R, float r)", "return");
[Fact]
public void TheShaderRunsTheSameLawAsGravityFieldPotential()
{
var law = CSharpLaw();
// The reduction found the whole law, so equality is not two empty strings agreeing.
Assert.Contains("log(r/R)", law);
Assert.Contains("c==0?0:", law);
Assert.Contains("c*r*r/(2*R*R)", law);
Assert.Equal(law, ShaderLaw());
}
}