using System; using System.Collections.Generic; using System.Collections.Immutable; using Moq; using NUnit.Framework; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; namespace Robust.UnitTesting.Shared.GameObjects { public partial class EntityEventBusTests { [Test] public void SubscribeCompEvent() { // Arrange var entUid = new EntityUid(7); var compInstance = new MetaDataComponent(); var compRegistration = new Mock(); var entManMock = new Mock(); var compManMock = new Mock(); var compFacMock = new Mock(); compRegistration.Setup(m => m.References).Returns(new List {typeof(MetaDataComponent)}); compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object); compManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object); IComponent? outIComponent = compInstance; compManMock.Setup(m => m.TryGetComponent(entUid, typeof(MetaDataComponent), out outIComponent)) .Returns(true); compManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent))) .Returns(compInstance); entManMock.Setup(m => m.ComponentManager).Returns(compManMock.Object); var bus = new EntityEventBus(entManMock.Object); // Subscribe int calledCount = 0; bus.SubscribeLocalEvent(HandleTestEvent); // add a component to the system entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid)); // Raise var evntArgs = new TestEvent(5); bus.RaiseLocalEvent(entUid, evntArgs); // Assert Assert.That(calledCount, Is.EqualTo(1)); void HandleTestEvent(EntityUid uid, MetaDataComponent component, TestEvent args) { calledCount++; Assert.That(uid, Is.EqualTo(entUid)); Assert.That(component, Is.EqualTo(compInstance)); Assert.That(args.TestNumber, Is.EqualTo(5)); } } [Test] public void UnsubscribeCompEvent() { // Arrange var entUid = new EntityUid(7); var compInstance = new MetaDataComponent(); var entManMock = new Mock(); var compRegistration = new Mock(); var compManMock = new Mock(); var compFacMock = new Mock(); compRegistration.Setup(m => m.References).Returns(new List {typeof(MetaDataComponent)}); compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object); compManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object); IComponent? outIComponent = compInstance; compManMock.Setup(m => m.TryGetComponent(entUid, typeof(MetaDataComponent), out outIComponent)) .Returns(true); compManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent))) .Returns(compInstance); entManMock.Setup(m => m.ComponentManager).Returns(compManMock.Object); var bus = new EntityEventBus(entManMock.Object); // Subscribe int calledCount = 0; bus.SubscribeLocalEvent(HandleTestEvent); bus.UnsubscribeLocalEvent(); // add a component to the system entManMock.Raise(m => m.EntityAdded += null, entManMock.Object, entUid); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid)); // Raise var evntArgs = new TestEvent(5); bus.RaiseLocalEvent(entUid, evntArgs); // Assert Assert.That(calledCount, Is.EqualTo(0)); void HandleTestEvent(EntityUid uid, MetaDataComponent component, TestEvent args) { calledCount++; } } [Test] public void SubscribeCompLifeEvent() { // Arrange var entUid = new EntityUid(7); var compInstance = new MetaDataComponent(); var mockEnt = new Mock(); mockEnt.SetupGet(m => m.Uid).Returns(entUid); compInstance.Owner = mockEnt.Object; var entManMock = new Mock(); var compRegistration = new Mock(); var compManMock = new Mock(); var compFacMock = new Mock(); compRegistration.Setup(m => m.References).Returns(new List {typeof(MetaDataComponent)}); compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object); compManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object); IComponent? outIComponent = compInstance; compManMock.Setup(m => m.TryGetComponent(entUid, typeof(MetaDataComponent), out outIComponent)) .Returns(true); compManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent))) .Returns(compInstance); entManMock.Setup(m => m.ComponentManager).Returns(compManMock.Object); var bus = new EntityEventBus(entManMock.Object); // Subscribe int calledCount = 0; bus.SubscribeLocalEvent(HandleTestEvent); // add a component to the system entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid)); // Raise bus.RaiseComponentEvent(compInstance, new ComponentInit()); // Assert Assert.That(calledCount, Is.EqualTo(1)); void HandleTestEvent(EntityUid uid, MetaDataComponent component, ComponentInit args) { calledCount++; Assert.That(uid, Is.EqualTo(entUid)); Assert.That(component, Is.EqualTo(compInstance)); } } [Test] public void CompEventOrdered() { // Arrange var entUid = new EntityUid(7); var entManMock = new Mock(); var compManMock = new Mock(); var compFacMock = new Mock(); void Setup(out T instance) where T : IComponent, new() { IComponent? inst = instance = new T(); var reg = new Mock(); reg.Setup(m => m.References).Returns(new Type[] {typeof(T)}); compFacMock.Setup(m => m.GetRegistration(typeof(T))).Returns(reg.Object); compManMock.Setup(m => m.TryGetComponent(entUid, typeof(T), out inst)).Returns(true); compManMock.Setup(m => m.GetComponent(entUid, typeof(T))).Returns(inst); } Setup(out var instA); Setup(out var instB); Setup(out var instC); compManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object); entManMock.Setup(m => m.ComponentManager).Returns(compManMock.Object); var bus = new EntityEventBus(entManMock.Object); // Subscribe var a = false; var b = false; var c = false; void HandlerA(EntityUid uid, Component comp, TestEvent ev) { Assert.That(b, Is.False, "A should run before B"); Assert.That(c, Is.False, "A should run before C"); a = true; } void HandlerB(EntityUid uid, Component comp, TestEvent ev) { Assert.That(c, Is.True, "B should run after C"); b = true; } void HandlerC(EntityUid uid, Component comp, TestEvent ev) => c = true; bus.SubscribeLocalEvent(HandlerA, typeof(OrderComponentA), before: new []{typeof(OrderComponentB), typeof(OrderComponentC)}); bus.SubscribeLocalEvent(HandlerB, typeof(OrderComponentB), after: new []{typeof(OrderComponentC)}); bus.SubscribeLocalEvent(HandlerC, typeof(OrderComponentC)); // add a component to the system entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instA, entUid)); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instB, entUid)); compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instC, entUid)); // Raise var evntArgs = new TestEvent(5); bus.RaiseLocalEvent(entUid, evntArgs); // Assert Assert.That(a, Is.True, "A did not fire"); Assert.That(b, Is.True, "B did not fire"); Assert.That(c, Is.True, "C did not fire"); } private class DummyComponent : Component { public override string Name => "Dummy"; } private class OrderComponentA : Component { public override string Name => "OrderComponentA"; } private class OrderComponentB : Component { public override string Name => "OrderComponentB"; } private class OrderComponentC : Component { public override string Name => "OrderComponentC"; } private class TestEvent : EntityEventArgs { public int TestNumber { get; } public TestEvent(int testNumber) { TestNumber = testNumber; } } } }