using System.Linq; using UnitTestSharp; namespace Ariadne.Generator.UnitTests { public class TriggerWaitLoweringTests : TestFixture { /// /// Returns a script class whose Run is , with two triggers it can wait on. /// public static string ScriptWith(string body, string members = "") { return @" public partial class Waiting : Arc { private static readonly Trigger A = new Trigger(); private static readonly Trigger B = new Trigger(); " + members + @" protected override void Run(World world) { " + body + @" } }"; } public class WriteTests : TestFixture { public void Wait_BeginsTheWaitThenTestsItAtTheResumePoint() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "__frame.Run____triggers1.Begin(__frame, requiresAll: false); __frame.Run____triggers1.Add(A);")); CheckTrue(run.CodeBehind.Contains("case \"first\": goto first__resume;")); CheckTrue(run.CodeBehind.Contains( "if (!__frame.Run____triggers1.Complete) { __frame.Suspend(); __frame.Mark(\"first\"); " + "return false; }")); } public void Wait_PutsTheResumeLabelBetweenTheBeginAndTheTest() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); int begin = run.CodeBehind.IndexOf("Run____triggers1.Begin("); int resume = run.CodeBehind.IndexOf("first__resume:"); int test = run.CodeBehind.IndexOf("if (!__frame.Run____triggers1.Complete)"); CheckTrue(begin < resume); CheckTrue(resume < test); } public void Wait_BuildsItsTriggerWaitWithTheFrame() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckTrue(run.CodeBehind.Contains( "public global::Ariadne.TriggerWait Run____triggers1 = new global::Ariadne.TriggerWait(1);")); } public void Wait_KeepsItsTriggerWaitAmongTheSavedLocals() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.__triggers1\");")); } public void WaitAny_AddsEveryTriggerAndDoesNotRequireAll() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n WaitAny(A, B);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "__frame.Run____triggers1.Begin(__frame, requiresAll: false); " + "__frame.Run____triggers1.Add(A); __frame.Run____triggers1.Add(B);")); CheckTrue(run.CodeBehind.Contains("new global::Ariadne.TriggerWait(2);")); } public void WaitAll_RequiresAll() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n WaitAll(A, B);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Run____triggers1.Begin(__frame, requiresAll: true);")); } public void TwoWaits_KeepTheirOwnTriggerWaits() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Wait(A);\n second:\n Wait(B);")); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.__triggers1\");")); CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.__triggers2\");")); } public void TwoWaitsUnderOneLabel_GetKeysAfterTheLabel() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);\n Wait(B);")); CheckEqual(0, run.Reported.Count); CheckTrue(run.CodeBehind.Contains("case \"first\": goto first__resume;")); CheckTrue(run.CodeBehind.Contains("case \"first#1\": goto first__1__resume;")); } public void ThirtyTwoTriggers_AreAllowed() { string triggers = string.Join(", ", Enumerable.Repeat("A", 32)); GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n WaitAll(" + triggers + ");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("new global::Ariadne.TriggerWait(32);")); } public void TriggerHeldInALocal_IsNotKeptAcrossTheWait() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " Trigger chosen = A;\n first:\n Wait(chosen);")); CheckEqual(0, run.Compiled.Count); CheckFalse(run.CodeBehind.Contains("\"Run.chosen\"")); } public void TriggerNamedInTheArgument_IsAddedByItsName() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(trigger: A);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Run____triggers1.Add(A);")); } public void WaitInAPassageOtherThanRun_IsPartOfThatPassage() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " outer:\n Helper();", members: " private void Helper()\n {\n inner:\n Wait(A);\n }\n")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Helper____triggers1")); } } public class ResultTests : TestFixture { public void WaitAnyAsAStatement_DropsTheResult() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n WaitAny(A, B);")); CheckFalse(run.CodeBehind.Contains(".Result")); } public void WaitAnyDeclaringALocal_TakesTheResultAfterTheTest() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Trigger fired = WaitAny(A, B);\n" + " world.Open.Add(fired == A ? \"a\" : \"b\");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("fired = __frame.Run____triggers1.Result;")); CheckTrue(run.CodeBehind.IndexOf("Run____triggers1.Complete") < run.CodeBehind.IndexOf("fired = __frame.Run____triggers1.Result;")); } public void ResultUsedRightAway_IsNotKeptAcrossTheWait() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Trigger fired = WaitAny(A, B);\n" + " world.Open.Add(fired == A ? \"a\" : \"b\");")); CheckFalse(run.CodeBehind.Contains("\"Run.fired\"")); } public void ResultUsedAfterALaterPause_IsKept() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Trigger fired = WaitAny(A, B);\n second:\n Yield();\n" + " world.Open.Add(fired == A ? \"a\" : \"b\");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.fired\");")); } public void WaitAllAssigningALocal_TakesTheResultAfterTheTest() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " Trigger last = null;\n first:\n last = WaitAll(A, B);\n" + " world.Open.Add(last == B ? \"b\" : \"a\");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("last = __frame.Run____triggers1.Result;")); CheckFalse(run.CodeBehind.Contains("\"Run.last\"")); } public void WaitAnyAssigningAField_TakesTheResultAfterTheTest() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Last = WaitAny(A, B);", members: " public Trigger Last;\n")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Last = __frame.Run____triggers1.Result;")); } public void WaitAnyReturnedFromAPassage_IsThePassagesResult() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " outer:\n Trigger picked = Pick();", members: " private Trigger Pick()\n {\n inner:\n return WaitAny(A, B);\n }\n")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("__result = __frame.Pick____triggers1.Result;")); } } public class AttachWaitsTests : TestFixture { public const string Lookout = @" public partial class Lookout : Arc { private static readonly Trigger A = new Trigger(); public void Watch(World world) { watch: Wait(A); } protected override void Run(World world) { } } "; public void Wait_HandsTheSlotToItsTriggerWait() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "public override void AttachWaits(global::Ariadne.WakeSlot slot)\r\n {\r\n" + " base.AttachWaits(slot);\r\n this.Run____triggers1.Attach(slot);")); } public void TwoWaits_HandSlotToBothTriggerWaits() { GeneratorRun run = GeneratorRun.Of( ScriptWith(" first:\n Wait(A);\n second:\n Wait(B);")); CheckTrue(run.CodeBehind.Contains("this.Run____triggers1.Attach(slot);")); CheckTrue(run.CodeBehind.Contains("this.Run____triggers2.Attach(slot);")); } public void ScriptThatNeverWaitsOnTriggers_WritesNone() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" int count = 0;\n first:\n Yield();\n" + " ++count;\n second:\n Yield();\n world.Open.Add(\"x\" + count);")); CheckFalse(run.CodeBehind.Contains("AttachWaits")); } public void CallOnAnotherArc_HandsTheSlotToTheFrameOfTheCall() { GeneratorRun run = GeneratorRun.Of(Lookout + @" public partial class Relay : Arc { public Lookout Spot; protected override void Run(World world) { relay: Spot.Watch(world); } }"); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "if (this.Run____call_relay_frame != null) { this.Run____call_relay_frame.AttachWaits(slot); }")); CheckTrue(run.CodeBehind.Contains( "global::System.Runtime.CompilerServices.RuntimeHelpers.EnsureSufficientExecutionStack();\r\n" + " base.AttachWaits(slot);")); } public void PassageThatOwnsItsFrame_HandsTheSlotToTheWaitsInThatFrame() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Trigger picked = Choose(A, 5);", members: " private Trigger Choose(Trigger trigger, ItemType marker)\n {\n" + " inner:\n return WaitAny(trigger, B);\n }\n")); CheckEqual(0, run.Compiled.Count); CheckEqual(2, CountOf(run.CodeBehind, "public override void AttachWaits(")); CheckTrue(run.CodeBehind.Contains("if (this.Run____call_first_frame != null)")); } public void RunInACycle_HandsTheSlotToTheFrameTheArcKeeps() { GeneratorRun run = GeneratorRun.Of(@" public partial class Cycling : Arc { private static readonly Trigger A = new Trigger(); private void Again(World world, int left) { pause: Wait(A); if (left > 0) { back: Run(world); } } protected override void Run(World world) { again: Again(world, 2); } }"); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("this.__runFrame.AttachWaits(slot);")); } public static int CountOf(string text, string part) { int returnMe = 0; int at = text.IndexOf(part, System.StringComparison.Ordinal); while (at >= 0) { ++returnMe; at = text.IndexOf(part, at + part.Length, System.StringComparison.Ordinal); } return returnMe; } } public class EndWaitsTests : TestFixture { public void Wait_ExpiresItsTriggerWait() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "public override void EndWaits()\r\n {\r\n" + " base.EndWaits();\r\n this.Run____triggers1.Expire();")); } public void TwoWaits_ExpireBothTriggerWaits() { GeneratorRun run = GeneratorRun.Of( ScriptWith(" first:\n Wait(A);\n second:\n Wait(B);")); CheckTrue(run.CodeBehind.Contains("this.Run____triggers1.Expire();")); CheckTrue(run.CodeBehind.Contains("this.Run____triggers2.Expire();")); } public void WaitOnConditions_ExpiresItsWaitToo() { GeneratorRun run = GeneratorRun.Of( ConditionWaitLoweringTests.ScriptWith(" first:\n Wait(A);")); CheckTrue(run.CodeBehind.Contains("this.Run____triggers1.Expire();")); } public void ScriptThatNeverWaitsOnTriggers_WritesNone() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" int count = 0;\n first:\n Yield();\n" + " ++count;\n second:\n Yield();\n world.Open.Add(\"x\" + count);")); CheckFalse(run.CodeBehind.Contains("EndWaits")); } public void CallOnAnotherArc_EndsTheWaitsOfTheFrameOfTheCall() { GeneratorRun run = GeneratorRun.Of(AttachWaitsTests.Lookout + @" public partial class Relay : Arc { public Lookout Spot; protected override void Run(World world) { relay: Spot.Watch(world); } }"); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "if (this.Run____call_relay_frame != null) { this.Run____call_relay_frame.EndWaits(); }")); CheckTrue(run.CodeBehind.Contains( "global::System.Runtime.CompilerServices.RuntimeHelpers.EnsureSufficientExecutionStack();\r\n" + " base.EndWaits();")); } public void PassageThatOwnsItsFrame_EndsTheWaitsInThatFrame() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Trigger picked = Choose(A, 5);", members: " private Trigger Choose(Trigger trigger, ItemType marker)\n {\n" + " inner:\n return WaitAny(trigger, B);\n }\n")); CheckEqual(0, run.Compiled.Count); CheckEqual(2, AttachWaitsTests.CountOf(run.CodeBehind, "public override void EndWaits(")); CheckTrue(run.CodeBehind.Contains("if (this.Run____call_first_frame != null)")); } public void RunInACycle_EndsTheWaitsOfTheFrameTheArcKeeps() { GeneratorRun run = GeneratorRun.Of(@" public partial class Cycling : Arc { private static readonly Trigger A = new Trigger(); private void Again(World world, int left) { pause: Wait(A); if (left > 0) { back: Run(world); } } protected override void Run(World world) { again: Again(world, 2); } }"); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("this.__runFrame.EndWaits();")); } } public class TimeoutTests : TestFixture { public const string Limit = "System.TimeSpan.FromSeconds(1)"; public void Wait_SetsTheDeadlineBeforeTheWaitBegins() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A, timeout: " + Limit + ");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); int deadline = run.CodeBehind.IndexOf( "__frame.Run____wait1 = __time.DeadlineAfter(" + Limit + ");"); int begin = run.CodeBehind.IndexOf( "__frame.Run____triggers1.Begin(__frame, requiresAll: false); __frame.Run____triggers1.Add(A);"); CheckTrue(deadline >= 0); CheckTrue(deadline < begin); } public void Wait_PutsTheResumeLabelAfterTheDeadlineAndTheBegin() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A, timeout: " + Limit + ");")); int begin = run.CodeBehind.IndexOf("Run____triggers1.Begin("); int resume = run.CodeBehind.IndexOf("first__resume:"); CheckTrue(begin < resume); } public void Wait_TestsTheDeadlineAndSleepsThenExpiresTheWait() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A, timeout: " + Limit + ");")); CheckTrue(run.CodeBehind.Contains( "if (!__frame.Run____triggers1.Complete) { if (__time.GameTime < __frame.Run____wait1) { " + "__frame.Sleep(__frame.Run____wait1); __frame.Suspend(); __frame.Mark(\"first\"); " + "return false; } __frame.Run____triggers1.Expire(); }")); } public void Wait_KeepsTheDeadlineAmongTheSavedLocals() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A, timeout: " + Limit + ");")); CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.__wait1\");")); } public void Wait_BuildsItsTriggerWaitForTheTriggersAlone() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A, timeout: " + Limit + ");")); CheckTrue(run.CodeBehind.Contains("new global::Ariadne.TriggerWait(1);")); } public void WaitWithoutATimeout_KeepsNoDeadline() { GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);")); CheckFalse(run.CodeBehind.Contains("Run____wait1")); CheckFalse(run.CodeBehind.Contains("__frame.Run____triggers1.Expire()")); } public void Wait_NamedOutOfOrder_AddsTheTrigger() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Wait(timeout: " + Limit + ", trigger: A);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("__frame.Run____triggers1.Add(A);")); CheckFalse(run.CodeBehind.Contains(".Add(System.TimeSpan")); } public void WaitAny_AddsEveryTriggerButNotTheTimeout() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n WaitAny(timeout: " + Limit + ", A, B);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "__frame.Run____triggers1.Begin(__frame, requiresAll: false); " + "__frame.Run____triggers1.Add(A); __frame.Run____triggers1.Add(B);")); CheckTrue(run.CodeBehind.Contains("new global::Ariadne.TriggerWait(2);")); } public void WaitAll_RequiresAllAndAddsEveryTriggerButNotTheTimeout() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n WaitAll(" + Limit + ", A, B);")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "__frame.Run____triggers1.Begin(__frame, requiresAll: true); " + "__frame.Run____triggers1.Add(A); __frame.Run____triggers1.Add(B);")); } public void Wait_DeclaringALocal_TakesTheResultAfterTheTest() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Trigger got = Wait(A, timeout: " + Limit + ");\n" + " world.Open.Add(got == null ? \"none\" : \"a\");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("got = __frame.Run____triggers1.Result;")); CheckTrue(run.CodeBehind.IndexOf("Run____triggers1.Expire()") < run.CodeBehind.IndexOf("got = __frame.Run____triggers1.Result;")); } public void WaitReturnedFromAPassage_IsThePassagesResult() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " outer:\n Trigger picked = Pick();", members: " private Trigger Pick()\n {\n inner:\n return WaitAny(" + Limit + ", A, B);\n }\n")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("__result = __frame.Pick____triggers1.Result;")); CheckTrue(run.CodeBehind.Contains("__frame.Pick____triggers1.Expire();")); } public void TimedWaitsAndASpanWait_NumberTheirDeadlinesTogether() { GeneratorRun run = GeneratorRun.Of(ScriptWith( " first:\n Wait(System.TimeSpan.FromSeconds(2));\n second:\n" + " Wait(A, timeout: " + Limit + ");\n third:\n Wait(B, timeout: " + Limit + ");")); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains( "__frame.Run____wait1 = __time.DeadlineAfter(System.TimeSpan.FromSeconds(2))")); CheckTrue(run.CodeBehind.Contains("__frame.Run____wait2 = __time.DeadlineAfter(" + Limit + ");")); CheckTrue(run.CodeBehind.Contains("__frame.Run____wait3 = __time.DeadlineAfter(" + Limit + ");")); } } public class DiagnosticTests : TestFixture { [IgnoreTest] public GeneratorRun RunOf(string body, string members = "") { return GeneratorRun.Of(ScriptWith(body, members)); } public void TimeoutWithNoTriggers_IsAmbiguousToTheCompiler() { GeneratorRun run = RunOf(" first:\n WaitAny(timeout: System.TimeSpan.Zero);"); CheckEqual(0, run.Reported.Count); CheckTrue(run.Compiled.Count > 0); CheckTrue(run.Compiled.All(error => error.StartsWith("CS0121:", System.StringComparison.Ordinal))); } public void TimeoutWithTriggersPassedAsAnArray_IsReported() { GeneratorRun run = RunOf( " Trigger[] both = { A, B };\n first:\n WaitAll(System.TimeSpan.Zero, both);"); CheckEqual(new[] { "ARI0034:WaitAll(System.TimeSpan.Zero, both)" }, run.Reported); CheckTrue(run.Messages.Single().Contains("one by one")); } public void PassageCallInTheTimeout_IsReported() { GeneratorRun run = RunOf(" first:\n Wait(A, timeout: Next());", members: " private System.TimeSpan Next()\n {\n inner:\n Yield();\n" + " return System.TimeSpan.Zero;\n }\n"); CheckTrue(run.Reported.Contains("ARI0004:Next()")); } public void WaitWithATimeoutInsideALambda_IsReported() { GeneratorRun run = RunOf( " first:\n System.Action wait = () => { Wait(A, timeout: System.TimeSpan.Zero); };"); CheckEqual(new[] { "ARI0031:Wait(A, timeout: System.TimeSpan.Zero)" }, run.Reported); } public void WaitWithATimeoutInsideALargerExpression_IsReported() { GeneratorRun run = RunOf( " first:\n bool none = Wait(A, timeout: System.TimeSpan.Zero) == null;"); CheckEqual(new[] { "ARI0031:Wait(A, timeout: System.TimeSpan.Zero)" }, run.Reported); } public void TriggersPassedAsAnArray_AreReported() { GeneratorRun run = RunOf(" Trigger[] both = { A, B };\n first:\n WaitAny(both);"); CheckEqual(new[] { "ARI0034:WaitAny(both)" }, run.Reported); CheckTrue(run.Messages.Single().Contains("one by one")); } public void ArrayGivenByName_IsReported() { GeneratorRun run = RunOf( " Trigger[] both = { A, B };\n first:\n WaitAll(triggers: both);"); CheckEqual(new[] { "ARI0034:WaitAll(triggers: both)" }, run.Reported); } public void NoTriggers_AreAmbiguousToTheCompiler() { GeneratorRun run = RunOf(" first:\n WaitAny();"); CheckEqual(0, run.Reported.Count); CheckTrue(run.Compiled.Count > 0); CheckTrue(run.Compiled.All(error => error.StartsWith("CS0121:", System.StringComparison.Ordinal))); } public void MoreTriggersThanAWaitHolds_AreReported() { string triggers = string.Join(", ", Enumerable.Repeat("A", 33)); GeneratorRun run = RunOf(" first:\n WaitAny(" + triggers + ");"); CheckEqual(1, run.Reported.Count); CheckTrue(run.Reported[0].StartsWith("ARI0034:", System.StringComparison.Ordinal)); CheckTrue(run.Messages.Single().Contains("at most 32")); } public void WaitWithoutAStepLabel_IsReported() { GeneratorRun run = RunOf(" Wait(A);"); CheckEqual(new[] { "ARI0002:Wait(A)" }, run.Reported); } public void WaitAnyInsideALargerExpression_IsReported() { GeneratorRun run = RunOf(" first:\n bool none = WaitAny(A, B) == null;"); CheckEqual(new[] { "ARI0031:WaitAny(A, B)" }, run.Reported); } public void WaitInsideALambda_IsReported() { GeneratorRun run = RunOf(" first:\n System.Action wait = () => { Wait(A); };"); CheckEqual(new[] { "ARI0031:Wait(A)" }, run.Reported); } public void WaitInAMemberThatIsNotAPassage_IsReported() { GeneratorRun run = RunOf(" first:\n Yield();", members: " private Trigger Pick => WaitAny(A, B);\n"); CheckEqual(new[] { "ARI0031:WaitAny(A, B)" }, run.Reported); } public void PassageCallInTheArgument_IsReported() { GeneratorRun run = RunOf(" first:\n Wait(Next());", members: " private Trigger Next()\n {\n inner:\n Yield();\n return A;\n" + " }\n"); CheckTrue(run.Reported.Contains("ARI0004:Next()")); } } } }