Skip to content

Commit

Permalink
Strengthen ordering of TraitsInConstructOrder.
Browse files Browse the repository at this point in the history
All types that are dependencies of a trait must now occur before it in the construct ordering. Previously, only one type that was a dependency of a trait needed to occur before it.
  • Loading branch information
RoosterDragon committed Mar 29, 2016
1 parent b3b816f commit 3192432
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
6 changes: 3 additions & 3 deletions OpenRA.Game/GameRules/ActorInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public IEnumerable<ITraitInfo> TraitsInConstructOrder()
var unresolved = source.Except(resolved);

var testResolve = new Func<Type, Type, bool>((a, b) => a == b || a.IsAssignableFrom(b));
var more = unresolved.Where(u => u.Dependencies.All(d => resolved.Exists(r => testResolve(d, r.Type))));
var more = unresolved.Where(u => u.Dependencies.All(d => resolved.Exists(r => testResolve(d, r.Type)) && !unresolved.Any(u1 => testResolve(d, u1.Type))));

// Re-evaluate the vars above until sorted
while (more.Any())
Expand All @@ -122,14 +122,14 @@ public IEnumerable<ITraitInfo> TraitsInConstructOrder()
exceptionString += u.Type + ": { " + string.Join(", ", deps) + " }\r\n";
}

throw new Exception(exceptionString);
throw new YamlException(exceptionString);
}

constructOrderCache = resolved.Select(r => r.Trait).ToList();
return constructOrderCache;
}

static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
public static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
{
return info
.GetType()
Expand Down
21 changes: 13 additions & 8 deletions OpenRA.Test/OpenRA.Game/ActorInfoTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NUnit.Framework;
Expand All @@ -34,20 +33,26 @@ public class ActorInfoTest
[TestCase(TestName = "Trait ordering sorts in dependency order correctly")]
public void TraitOrderingSortsCorrectly()
{
var actorInfo = new ActorInfo("test", new MockCInfo(), new MockBInfo(), new MockAInfo());
var unorderedTraits = new ITraitInfo[] { new MockBInfo(), new MockCInfo(), new MockAInfo(), new MockBInfo() };
var actorInfo = new ActorInfo("test", unorderedTraits);
var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray();

var i = new List<ITraitInfo>(actorInfo.TraitsInConstructOrder());
CollectionAssert.AreEquivalent(unorderedTraits, orderedTraits);

Assert.That(i[0], Is.InstanceOf<MockAInfo>());
Assert.That(i[1].GetType().Name, Is.EqualTo("MockBInfo"));
Assert.That(i[2].GetType().Name, Is.EqualTo("MockCInfo"));
for (var i = 0; i < orderedTraits.Length; i++)
{
var traitTypesThatMustOccurBeforeThisTrait = ActorInfo.PrerequisitesOf(orderedTraits[i]);
var traitTypesThatOccurAfterThisTrait = orderedTraits.Skip(i + 1).Select(ti => ti.GetType());
var traitTypesThatShouldOccurEarlier = traitTypesThatOccurAfterThisTrait.Intersect(traitTypesThatMustOccurBeforeThisTrait);
CollectionAssert.IsEmpty(traitTypesThatShouldOccurEarlier, "Dependency order has not been satisfied.");
}
}

[TestCase(TestName = "Trait ordering exception reports missing dependencies")]
public void TraitOrderingReportsMissingDependencies()
{
var actorInfo = new ActorInfo("test", new MockBInfo(), new MockCInfo());
var ex = Assert.Throws<Exception>(() => actorInfo.TraitsInConstructOrder());
var ex = Assert.Throws<YamlException>(() => actorInfo.TraitsInConstructOrder());

StringAssert.Contains(typeof(MockAInfo).Name, ex.Message, "Exception message did not report a missing dependency.");
StringAssert.Contains(typeof(MockBInfo).Name, ex.Message, "Exception message did not report a missing dependency.");
Expand All @@ -60,7 +65,7 @@ public void TraitOrderingReportsMissingDependencies()
public void TraitOrderingReportsCyclicDependencies()
{
var actorInfo = new ActorInfo("test", new MockDInfo(), new MockEInfo(), new MockFInfo());
var ex = Assert.Throws<Exception>(() => actorInfo.TraitsInConstructOrder());
var ex = Assert.Throws<YamlException>(() => actorInfo.TraitsInConstructOrder());

StringAssert.Contains(typeof(MockDInfo).Name, ex.Message, "Exception message should report all cyclic dependencies.");
StringAssert.Contains(typeof(MockEInfo).Name, ex.Message, "Exception message should report all cyclic dependencies.");
Expand Down

0 comments on commit 3192432

Please sign in to comment.