diff --git a/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs b/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs index d84023005b..5f8211e89a 100644 --- a/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs +++ b/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs @@ -28,6 +28,10 @@ namespace OpenRA.Test class MockEInfo : MockTraitInfo, Requires { } class MockFInfo : MockTraitInfo, Requires { } + class MockA2Info : MockTraitInfo { } + class MockB2Info : MockTraitInfo { } + class MockC2Info : MockTraitInfo { } + [TestFixture] public class ActorInfoTest { @@ -88,5 +92,65 @@ namespace OpenRA.Test Assert.That(count, Is.EqualTo(Math.Floor(count)), "Should be symmetrical"); } } + + [TestCase(TestName = "Trait inheritance and removal can be composed")] + public void TraitInheritanceAndRemovalCanBeComposed() + { + var baseYaml = @" +^BaseA: + MockA2: +^BaseB: + Inherits@a: ^BaseA + MockB2: +"; + var extendedYaml = @" +Actor: + Inherits@b: ^BaseB + -MockA2: +"; + var mapYaml = @" +^BaseC: + MockC2: +Actor: + Inherits@c: ^BaseC +"; + + var actorInfo = CreateActorInfoFromYaml("Actor", mapYaml, baseYaml, extendedYaml); + Assert.IsFalse(actorInfo.HasTraitInfo(), "Actor should not have the MockA2 trait, but does."); + Assert.IsTrue(actorInfo.HasTraitInfo(), "Actor should have the MockB2 trait, but does not."); + Assert.IsTrue(actorInfo.HasTraitInfo(), "Actor should have the MockC2 trait, but does not."); + } + + [TestCase(TestName = "Trait can be removed after multiple inheritance")] + public void TraitCanBeRemovedAfterMultipleInheritance() + { + var baseYaml = @" +^BaseA: + MockA2: +Actor: + Inherits: ^BaseA + MockA2: +"; + var overrideYaml = @" +Actor: + -MockA2 +"; + + var actorInfo = CreateActorInfoFromYaml("Actor", null, baseYaml, overrideYaml); + Assert.IsFalse(actorInfo.HasTraitInfo(), "Actor should not have the MockA2 trait, but does."); + } + + // This needs to match the logic used in RulesetCache.LoadYamlRules + ActorInfo CreateActorInfoFromYaml(string name, string mapYaml, params string[] yamls) + { + var initialNodes = mapYaml == null ? new List() : MiniYaml.FromString(mapYaml); + var yaml = yamls + .Select(s => MiniYaml.FromString(s)) + .Aggregate(initialNodes, MiniYaml.MergePartial); + var allUnits = yaml.ToDictionary(node => node.Key, node => node.Value); + var unit = allUnits[name]; + var creator = new ObjectCreator(new[] { typeof(ActorInfoTest).Assembly }); + return new ActorInfo(creator, name, unit, allUnits); + } } }