using System.Collections.Generic;
using NUnit.Framework;
using Unity.Pipeline.Compilation;
namespace Unity.Pipeline.Tests.Editor
{
///
/// Push-time host-surface validation
/// (): the editor-side load
/// pass that reports member refs which would resolve to throwing stubs on the player, so
/// reload_file_player_interpreter surfaces binding gaps synchronously in its response instead of after the async
/// device ack (which carries only a count, with the member list buried in the device log).
///
class PushBindingValidationTests
{
static byte[] CompileProbe(string body)
{
var compile = RoslynCompilationService.Compile(new CompilationRequest
{
SourceCode = $@"using UnityEngine;
public static class Probe {{ public static void Run() {{ {body} }} }}",
AssemblyName = "PushValidationProbe",
SkipLoad = true, // validation walks the bytes; no Assembly.Load
});
Assert.IsTrue(compile.Success, "probe source should compile");
return compile.AssemblyBytes;
}
static readonly List ProbeMethods = new List { "Run" };
[Test]
public void UnregisteredBclMember_IsReportedBeforePush()
{
// Environment.ProcessorCount has no AllowBcl shim (TickCount gained one), and the
// auto-bind policy declines System.* — exactly the class of gap that used to surface
// only as a mid-play ScriptRuntimeException on the device.
var bytes = CompileProbe("Debug.Log(System.Environment.ProcessorCount);");
var unbound = InterpreterCodeReloadExecutor.ValidateBindingSurface(bytes, "Probe", ProbeMethods, out _);
Assert.That(unbound, Has.Some.Contains("Environment.get_ProcessorCount"),
"the unregistered BCL member should be named in the validation result");
}
[Test]
public void StandardSurface_IncludingTypeEquality_ReportsNothing()
{
// The gameplay pattern that motivated this check (GetType() comparison via
// Type.op_Equality) plus ordinary standard-surface calls: a clean result here is what
// reload_file_player_interpreter now guarantees before sending.
var bytes = CompileProbe(
"GameObject a = new GameObject(\"push-validate\"); " +
"bool same = a.GetType() == typeof(GameObject); Debug.Log(same);");
var unbound = InterpreterCodeReloadExecutor.ValidateBindingSurface(bytes, "Probe", ProbeMethods, out var note);
Assert.IsEmpty(unbound, $"unexpected unbound members (note: {note ?? "none"})");
}
}
}