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()"));
}
}
}
}