From d16f433f4585758d94556fc9db1d389b3f2040a5 Mon Sep 17 00:00:00 2001 From: Acruid Date: Sun, 9 Feb 2020 02:28:47 -0800 Subject: [PATCH] Adds test to make sure that calling IComponent.HandleComponentState() with null states does not throw an exception. Fixes state handling code on components to not throw exceptions when called with null components. --- .../Components/HandheldLightComponent.cs | 5 +- .../Components/Mobs/CombatModeComponent.cs | 3 +- .../GameObjects/Components/StackComponent.cs | 5 +- .../BallisticMagazineWeaponComponent.cs | 5 +- .../GameObjects/Components/WelderComponent.cs | 5 +- .../Components/Items/ItemCooldownComponent.cs | 5 +- .../Mobs/SharedHumanoidAppearanceComponent.cs | 6 +- .../Gamestates/ComponentStateNullTest.cs | 75 +++++++++++++++++++ 8 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 Content.Tests/Shared/Gamestates/ComponentStateNullTest.cs diff --git a/Content.Client/GameObjects/Components/HandheldLightComponent.cs b/Content.Client/GameObjects/Components/HandheldLightComponent.cs index b97f0717e7..d6f4a75aaa 100644 --- a/Content.Client/GameObjects/Components/HandheldLightComponent.cs +++ b/Content.Client/GameObjects/Components/HandheldLightComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Shared.GameObjects.Components; using Robust.Client.Graphics.Drawing; using Robust.Client.UserInterface; @@ -22,7 +22,8 @@ namespace Content.Client.GameObjects.Components public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (HandheldLightComponentState) curState; + if (!(curState is HandheldLightComponentState cast)) + return; Charge = cast.Charge; } diff --git a/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs b/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs index 06b0235838..e003d99569 100644 --- a/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs @@ -31,7 +31,8 @@ namespace Content.Client.GameObjects.Components.Mobs { base.HandleComponentState(curState, nextState); - var state = (CombatModeComponentState) curState; + if (!(curState is CombatModeComponentState state)) + return; IsInCombatMode = state.IsInCombatMode; ActiveZone = state.TargetingZone; diff --git a/Content.Client/GameObjects/Components/StackComponent.cs b/Content.Client/GameObjects/Components/StackComponent.cs index 9c47f69470..717372091a 100644 --- a/Content.Client/GameObjects/Components/StackComponent.cs +++ b/Content.Client/GameObjects/Components/StackComponent.cs @@ -1,4 +1,4 @@ -using Content.Client.UserInterface; +using Content.Client.UserInterface; using Content.Client.Utility; using Content.Shared.GameObjects.Components; using Robust.Client.UserInterface; @@ -22,7 +22,8 @@ namespace Content.Client.GameObjects.Components public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (StackComponentState) curState; + if (!(curState is StackComponentState cast)) + return; Count = cast.Count; MaxCount = cast.MaxCount; diff --git a/Content.Client/GameObjects/Components/Weapons/Ranged/BallisticMagazineWeaponComponent.cs b/Content.Client/GameObjects/Components/Weapons/Ranged/BallisticMagazineWeaponComponent.cs index b5eb8bd044..1917dbcd65 100644 --- a/Content.Client/GameObjects/Components/Weapons/Ranged/BallisticMagazineWeaponComponent.cs +++ b/Content.Client/GameObjects/Components/Weapons/Ranged/BallisticMagazineWeaponComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Client.Animations; using Content.Client.UserInterface; using Content.Client.Utility; @@ -99,7 +99,8 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (BallisticMagazineWeaponComponentState) curState; + if (!(curState is BallisticMagazineWeaponComponentState cast)) + return; Chambered = cast.Chambered; MagazineCount = cast.MagazineCount; diff --git a/Content.Client/GameObjects/Components/WelderComponent.cs b/Content.Client/GameObjects/Components/WelderComponent.cs index 088894e1d3..dc7387b559 100644 --- a/Content.Client/GameObjects/Components/WelderComponent.cs +++ b/Content.Client/GameObjects/Components/WelderComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Client.UserInterface; using Content.Client.Utility; using Content.Shared.GameObjects; @@ -26,7 +26,8 @@ namespace Content.Client.GameObjects.Components public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (WelderComponentState) curState; + if (!(curState is WelderComponentState cast)) + return; FuelCapacity = cast.FuelCapacity; Fuel = cast.Fuel; diff --git a/Content.Shared/GameObjects/Components/Items/ItemCooldownComponent.cs b/Content.Shared/GameObjects/Components/Items/ItemCooldownComponent.cs index 9943c7f9a3..c2425cc9bc 100644 --- a/Content.Shared/GameObjects/Components/Items/ItemCooldownComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/ItemCooldownComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -62,7 +62,8 @@ namespace Content.Shared.GameObjects.Components.Items public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (ItemCooldownComponentState) curState; + if (!(curState is ItemCooldownComponentState cast)) + return; CooldownStart = cast.CooldownStart; CooldownEnd = cast.CooldownEnd; diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs index b50430a8d5..93f13b549e 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Shared.Preferences; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; @@ -43,7 +43,9 @@ namespace Content.Shared.GameObjects.Components.Mobs public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - var cast = (HumanoidAppearanceComponentState) curState; + if (!(curState is HumanoidAppearanceComponentState cast)) + return; + Appearance = cast.Appearance; Sex = cast.Sex; } diff --git a/Content.Tests/Shared/Gamestates/ComponentStateNullTest.cs b/Content.Tests/Shared/Gamestates/ComponentStateNullTest.cs new file mode 100644 index 0000000000..5bf4709ff5 --- /dev/null +++ b/Content.Tests/Shared/Gamestates/ComponentStateNullTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using NUnit.Framework; +using Robust.Shared.ContentPack; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Reflection; +using Robust.Shared.Reflection; + +namespace Content.Tests.Shared.GameStates +{ + [TestFixture] + public class ComponentStateNullTest + { + [Test] + public void HandleComponentState_NullStates_NotThrow() + { + var reflection = ReflectionManagerFactory(); + var comps = reflection.GetAllChildren(); + + foreach (var compType in comps) + { + // Any component should be able to be instantiated without DI injection. + var compInstance = (IComponent) Activator.CreateInstance(compType); + + // Any component should treat this as a null function. + compInstance.HandleComponentState(null, null); + } + } + + private static IReflectionManager ReflectionManagerFactory() + { + AppDomain.CurrentDomain.Load("Robust.Client"); + AppDomain.CurrentDomain.Load("Content.Client"); + AppDomain.CurrentDomain.Load("Robust.Server"); + AppDomain.CurrentDomain.Load("Content.Server"); + AppDomain.CurrentDomain.Load("Robust.Shared"); + AppDomain.CurrentDomain.Load("Content.Shared"); + + var assemblies = new List(7); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Client")); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Content.Client")); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Server")); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Content.Server")); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Robust.Shared")); + assemblies.Add(AppDomain.CurrentDomain.GetAssemblyByName("Content.Shared")); + assemblies.Add(Assembly.GetExecutingAssembly()); + + var reflection = new FullReflectionManager(); + + reflection.LoadAssemblies(assemblies); + + return reflection; + } + + private class FullReflectionManager : ReflectionManager + { + protected override IEnumerable TypePrefixes => Prefixes; + + private static readonly string[] Prefixes = { + "", + + "Robust.Client.", + "Content.Client.", + + "Robust.Shared.", + "Content.Shared.", + + "Robust.Server.", + "Content.Server.", + }; + } + } +}