namespace SceneTests.GameObjects; [TestClass] [DoNotParallelize] public class ComponentEventsTest : SceneTest { [TestMethod] public void Single() { var scene = new Scene(); using var sceneScope = scene.Push(); var go = scene.CreateObject(); var o = go.Components.Create(); Assert.AreEqual( 1, o.AwakeCalls, "Awake wasn't called" ); Assert.AreEqual( 1, o.EnabledCalls, "Enabled wasn't called" ); Assert.AreEqual( 0, o.DisabledCalls, "Disabled shouldn't have been called yet" ); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); go.Enabled = false; scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 0, o.DestroyCalls ); go.Destroy(); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 1, o.DestroyCalls ); } [TestMethod] public void Single_StartComponentDisabled() { var scene = new Scene(); using var sceneScope = scene.Push(); var go = scene.CreateObject(); var o = go.Components.Create( false ); Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 0, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); o.Enabled = true; Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); go.Enabled = false; scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 0, o.DestroyCalls ); go.Destroy(); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 1, o.DestroyCalls ); } [TestMethod] public void Single_StartObjectDisabled() { var scene = new Scene(); using var sceneScope = scene.Push(); var go = scene.CreateObject( false ); var o = go.Components.Create(); Assert.AreEqual( 0, o.AwakeCalls ); // awake shouldn't call until the gameobject is active Assert.AreEqual( 0, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); go.Enabled = true; Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); go.Enabled = false; scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 0, o.DestroyCalls ); go.Destroy(); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 1, o.DestroyCalls ); } [TestMethod] public void Single_Destroy() { var scene = new Scene(); using var sceneScope = scene.Push(); var go = scene.CreateObject(); var o = go.Components.Create(); Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 0, o.StartCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); scene.GameTick(); Assert.AreEqual( 1, o.StartCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); Assert.AreEqual( 0, o.DestroyCalls ); go.Destroy(); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 1, o.DestroyCalls ); } /// /// Parent objects should update their descendants enabled state /// when they toggle . /// [TestMethod] public void Child_StartParentDisabled() { var scene = new Scene(); using var sceneScope = scene.Push(); var parent = new GameObject( name: "Parent", enabled: false ); var child = new GameObject( parent, name: "Child" ); var o = child.Components.Create(); Assert.AreEqual( 0, o.AwakeCalls ); // awake shouldn't call until the gameobject is active Assert.AreEqual( 0, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); parent.Enabled = true; scene.GameTick(); Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); parent.Enabled = false; scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 0, o.DestroyCalls ); parent.Destroy(); scene.GameTick(); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); Assert.AreEqual( 1, o.DestroyCalls ); } /// /// Objects should update their enabled state when changing to an inactive parent. /// [TestMethod] public void Child_MoveToDisabledParent() { var scene = new Scene(); using var sceneScope = scene.Push(); var parent = new GameObject( name: "Parent", enabled: false ); var child = new GameObject( name: "Child" ); var o = child.Components.Create(); Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); scene.GameTick(); // Nest under an inactive parent, should become inactive itself child.Parent = parent; Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 1, o.DisabledCalls ); } /// /// Objects should update their enabled state when changing from an inactive parent. /// [TestMethod] public void Child_MoveFromDisabledParent() { var scene = new Scene(); using var sceneScope = scene.Push(); var parent = new GameObject( name: "Parent", enabled: false ); var child = new GameObject( parent, name: "Child" ); var o = child.Components.Create(); Assert.AreEqual( 0, o.AwakeCalls ); // awake shouldn't call until the gameobject is active Assert.AreEqual( 0, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); scene.GameTick(); // Move to scene root, should become active child.Parent = null; Assert.AreEqual( 1, o.AwakeCalls ); Assert.AreEqual( 1, o.EnabledCalls ); Assert.AreEqual( 0, o.DisabledCalls ); } /// /// Callback batch always runs Enable before Disable, so if an object is disabled then enabled in one batch /// it'll run those callbacks in the wrong order. /// [TestMethod] public void MultipleEnableStateChangesInBatch() { var scene = new Scene(); using var sceneScope = scene.Push(); var go = new GameObject(); var o = go.Components.Create(); scene.GameTick(); Assert.IsTrue( o.EnabledState ); using ( CallbackBatch.Batch() ) { o.Enabled = false; o.Enabled = true; } Assert.IsTrue( o.EnabledState ); } } public class OrderTestComponent : Component { public int AwakeCalls; public int EnabledCalls; public int StartCalls; public int DisabledCalls; public int DestroyCalls; public bool EnabledState; protected override void OnAwake() { Assert.AreEqual( AwakeCalls, 0 ); Assert.AreEqual( EnabledCalls, 0 ); Assert.AreEqual( StartCalls, 0 ); Assert.AreEqual( DisabledCalls, 0 ); AwakeCalls++; } protected override void OnStart() { Assert.AreEqual( AwakeCalls, 1 ); Assert.AreEqual( EnabledCalls, 1 ); StartCalls++; } internal override void OnEnabledInternal() { Assert.IsFalse( EnabledState ); EnabledState = true; base.OnEnabledInternal(); } protected override void OnEnabled() { Assert.AreEqual( AwakeCalls, 1 ); Assert.AreEqual( StartCalls, 0 ); EnabledCalls++; } internal override void OnDisabledInternal() { Assert.IsTrue( EnabledState ); EnabledState = false; base.OnDisabledInternal(); } protected override void OnDisabled() { Assert.AreEqual( AwakeCalls, 1 ); Assert.AreNotEqual( StartCalls, 0 ); Assert.AreNotEqual( EnabledCalls, 0 ); DisabledCalls++; } protected override void OnDestroy() { Assert.AreEqual( AwakeCalls, 1 ); DestroyCalls++; } }