diff --git a/packages/cultmath/tests/CultMath.Tests/GlslLowering.cs b/packages/cultmath/tests/CultMath.Tests/GlslLowering.cs index e5ccb88f..eff40196 100644 --- a/packages/cultmath/tests/CultMath.Tests/GlslLowering.cs +++ b/packages/cultmath/tests/CultMath.Tests/GlslLowering.cs @@ -73,10 +73,7 @@ internal static class GlslLowering source = Regex.Replace(source, @"(?ms)^\w+ \w+\([^)]*\b(Texture2D|SamplerState)\b[^)]*\)\s*\{.*?^\}[ \t]*$", string.Empty); // 3. Type names: floatN, intN, uintN and boolN become vecN, ivecN, uvecN and bvecN. - source = Regex.Replace(source, @"\bfloat([234])\b", "vec$1"); - source = Regex.Replace(source, @"\bint([234])\b", "ivec$1"); - source = Regex.Replace(source, @"\buint([234])\b", "uvec$1"); - source = Regex.Replace(source, @"\bbool([234])\b", "bvec$1"); + source = LowerTypeNames(source); // 4. File-scope `static const` becomes `const`. source = Regex.Replace(source, @"(?m)^static const ", "const "); @@ -103,6 +100,15 @@ internal static class GlslLowering return provenance + "\n#ifndef " + guard + "\n#define " + guard + "\n" + source.Trim('\n') + "\n\n#endif\n"; } + /// Step 3 alone; GlslMirrorTests maps the HLSL signatures with it to compare overloads. + internal static string LowerTypeNames(string source) + { + source = Regex.Replace(source, @"\bfloat([234])\b", "vec$1"); + source = Regex.Replace(source, @"\bint([234])\b", "ivec$1"); + source = Regex.Replace(source, @"\buint([234])\b", "uvec$1"); + return Regex.Replace(source, @"\bbool([234])\b", "bvec$1"); + } + private static readonly Regex Cast = new(@"\((float|int|uint)\)"); private static string LowerCasts(string source) diff --git a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs index 129fa7de..945c2cd2 100644 --- a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs @@ -61,14 +61,21 @@ public sealed class GlslMirrorTests private static readonly Regex Definition = new(@"(?m)^\w+\s+(cultmath_\w+)\s*\(([^)]*)\)"); + // A definition's signature, its name and parameter types, so an overload counts on its own: + // "cultmath_pcg3d(vec2)". HLSL type names are mapped by the lowering's own step 3. + private static string Signature(Match definition) => + definition.Groups[1].Value + "(" + string.Join(", ", definition.Groups[2].Value + .Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Select(parameter => GlslLowering.LowerTypeNames(string.Join(' ', Regex.Split(parameter, @"\s+")[..^1])))) + ")"; + [Fact] public void EveryPublicFunctionIsLowered() { var lowered = Lowered; var hlsl = Definition.Matches(Hlsl).Where(m => !Regex.IsMatch(m.Groups[2].Value, @"\b(Texture2D|SamplerState)\b")) - .Select(m => m.Groups[1].Value).ToHashSet(); - var glsl = lowered.SelectMany(output => Definition.Matches(output.Text)).Select(m => m.Groups[1].Value).ToHashSet(); - Assert.Contains("cultmath_snoise", glsl); + .Select(Signature).ToHashSet(); + var glsl = lowered.SelectMany(output => Definition.Matches(output.Text)).Select(Signature).ToHashSet(); + Assert.Contains("cultmath_pcg3d(vec2)", glsl); Assert.True(hlsl.SetEquals(glsl), "HLSL only: " + string.Join(", ", hlsl.Except(glsl)) + "; GLSL only: " + string.Join(", ", glsl.Except(hlsl))); // The MPL-2.0 code is in its own file and nowhere in the MIT library. @@ -81,6 +88,26 @@ public sealed class GlslMirrorTests } } + // The two-file contract a consumer relies on when it concatenates CultMath.Phacelle.glsl after + // CultMath.glsl: distinct guards (a shared one would hide the second file's body), each provenance + // line naming its file's licence, and the MIT file pointing at the one that holds cultmath_phacelle. + [Fact] + public void TwoFileHeaderContract() + { + var lowered = Lowered; + var guards = lowered.Select(output => Regex.Match(output.Text, @"^[^\n]*\n#ifndef (\w+)\n#define \1\n").Groups[1].Value).ToArray(); + Assert.All(guards, guard => Assert.NotEqual(string.Empty, guard)); + Assert.Equal(guards.Length, guards.Distinct().Count()); + + var library = lowered.Single(output => output.File == "CultMath.glsl").Text.Split('\n')[0]; + var phacelle = lowered.Single(output => output.File == "CultMath.Phacelle.glsl").Text.Split('\n')[0]; + Assert.Contains(" MIT.", library); + Assert.DoesNotContain("MPL", library); + Assert.Contains("cultmath_phacelle is in CultMath.Phacelle.glsl", library); + Assert.Contains(" MPL-2.0;", phacelle); + Assert.DoesNotContain("MIT", phacelle); + } + [Fact] public void GoldenFixtureMatchesCSharp() {