using System; using System.Collections.Generic; using System.Reflection; using NUnit.Framework; using Robust.Client.ComponentTrees; using Robust.Client.GameObjects; using Robust.Server.Debugging; using Robust.Server.GameObjects; using Robust.Server.GameStates; using Robust.Server.Physics; using Robust.Shared.ComponentTrees; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Containers; using Robust.Shared.ContentPack; using Robust.Shared.EntitySerialization.Components; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Reflection; using Robust.Shared.Testing; using Robust.Shared.Threading; using Robust.Shared.Utility; using AppearanceSystem = Robust.Client.GameObjects.AppearanceSystem; using InputSystem = Robust.Server.GameObjects.InputSystem; using MapSystem = Robust.Server.GameObjects.MapSystem; using PointLightComponent = Robust.Client.GameObjects.PointLightComponent; namespace Robust.UnitTesting { public enum UnitTestProject : byte { Server, Client } [Parallelizable] public abstract partial class RobustUnitTest { protected virtual Type[]? ExtraComponents => null; private static Type[] _components = new [] { typeof(EyeComponent), typeof(MapComponent), typeof(MapGridComponent), typeof(ContainerManagerComponent), typeof(MetaDataComponent), typeof(TransformComponent), typeof(PhysicsComponent), typeof(BroadphaseComponent), typeof(FixturesComponent), typeof(JointComponent), typeof(GridTreeComponent), typeof(JointRelayTargetComponent), typeof(OccluderComponent), typeof(OccluderTreeComponent), typeof(SpriteTreeComponent), typeof(LightTreeComponent), typeof(CollisionWakeComponent), typeof(CollideOnAnchorComponent), typeof(ActorComponent) }; public virtual UnitTestProject Project => UnitTestProject.Server; [OneTimeSetUp] public void BaseSetup() { // Clear state across tests. var deps = IoCManager.InitThread(); deps.Clear(); RegisterIoC(); var assemblies = new List(4); switch (Project) { case UnitTestProject.Client: assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Client")); break; case UnitTestProject.Server: assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Server")); break; default: throw new NotSupportedException($"Unknown testing project: {Project}"); } assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Shared")); assemblies.Add(Assembly.GetExecutingAssembly()); var configurationManager = deps.Resolve(); configurationManager.Initialize(Project == UnitTestProject.Server); deps.Resolve().Initialize(); foreach (var assembly in assemblies) { configurationManager.LoadCVarsFromAssembly(assembly); } var contentAssemblies = GetContentAssemblies(); foreach (var assembly in contentAssemblies) { configurationManager.LoadCVarsFromAssembly(assembly); } configurationManager.LoadCVarsFromAssembly(typeof(RTCVars).Assembly); var systems = deps.Resolve(); // Required systems systems.LoadExtraSystemType(); // uhhh so maybe these are the wrong system for the client, but I CBF adding sprite system and all the rest, // and it was like this when I found it. systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); if (Project == UnitTestProject.Client) { systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); } else { systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); systems.LoadExtraSystemType(); } var entMan = deps.Resolve(); // Avoid discovering EntityCommands since they may depend on systems // that aren't available in a unit test context. deps.Resolve().DiscoverCommands = false; // Required components for the engine to work // Why are we still here? Just to suffer? Why can't we just use [RegisterComponent] magic? // TODO End Suffering. // suffering has been alleviated, but still present var compFactory = deps.Resolve(); compFactory.RegisterTypes(_components); if (ExtraComponents != null) compFactory.RegisterTypes(ExtraComponents); compFactory.RegisterClass(); compFactory.RegisterClass(); if (Project != UnitTestProject.Server) { compFactory.RegisterClass(); compFactory.RegisterClass(); } deps.Resolve().Initialize(); // So by default EntityManager does its own EntitySystemManager initialize during Startup. // We want to bypass this and load our own systems hence we will manually initialize it here. entMan.Initialize(); // RobustUnitTest is complete hot garbage. // This makes EventTables ignore *all* the screwed up component abuse it causes. entMan.EventBus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare(); // The nightmare never ends systems.Initialize(); deps.Resolve().LoadAssemblies(assemblies); var modLoader = deps.Resolve(); modLoader.Assemblies = contentAssemblies; modLoader.TryLoadModulesFrom(ResPath.Root, ""); entMan.Startup(); } [OneTimeTearDown] public void BaseTearDown() { IoCManager.Clear(); } /// /// Called after all IoC registration has been done, but before the graph has been built. /// This allows one to add new IoC types or overwrite existing ones if needed. /// protected virtual void OverrideIoC() { } protected virtual Assembly[] GetContentAssemblies() { return Array.Empty(); } } }