using System.Linq;
using UnitTestSharp;
namespace Ariadne.Generator.UnitTests
{
public class ConditionWaitLoweringTests : TestFixture
{
public const string Limit = "System.TimeSpan.FromSeconds(2)";
///
/// Returns a script class whose Run is , with two latches and a trigger it can wait on.
///
public static string ScriptWith(string body, string members = "")
{
return @"
public partial class Waiting : Arc
{
private static readonly Latch A = new Latch();
private static readonly Latch B = new Latch();
private static readonly Trigger T = new Trigger();
" + members + @"
protected override void Run(World world)
{
" + body + @"
}
}";
}
public class WriteTests : TestFixture
{
public void Wait_BuildsAWaitOnConditions()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);"));
CheckEqual(0, run.Reported.Count);
CheckEqual(0, run.Compiled.Count);
CheckTrue(run.CodeBehind.Contains(
"public global::Ariadne.TriggerWait Run____triggers1 = " +
"new global::Ariadne.TriggerWait(1, onConditions: true);"));
}
public void Wait_BeginsTheWaitThenTestsItAtTheResumePoint()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);"));
CheckTrue(run.CodeBehind.Contains(
"__frame.Run____triggers1.Begin(__frame, requiresAll: false); __frame.Run____triggers1.Add(A);"));
CheckTrue(run.CodeBehind.Contains(
"if (!__frame.Run____triggers1.Complete) { __frame.Suspend(); __frame.Mark(\"first\"); " +
"return false; }"));
}
public void Wait_OnTheInverse_AddsTheInverse()
{
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.Add(!A);"));
}
public void Wait_DiscardingTheValue_FinishesTheWaitAfterTheTest()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);"));
CheckTrue(run.CodeBehind.Contains("return false; } __frame.Run____triggers1.Finish();"));
CheckFalse(run.CodeBehind.Contains(".Result"));
}
public void Wait_KeepsItsWaitAmongTheSavedLocals()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(" first:\n Wait(A);"));
CheckTrue(run.CodeBehind.Contains("lister.Local(\"Run.__triggers1\");"));
CheckTrue(run.CodeBehind.Contains("this.Run____triggers1.Attach(slot);"));
}
public void WaitOnALatchAndWaitOnATrigger_EachBuildTheirOwnKindOfWait()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" first:\n Wait(A);\n second:\n Wait(T);"));
CheckEqual(0, run.Reported.Count);
CheckEqual(0, run.Compiled.Count);
CheckTrue(run.CodeBehind.Contains(
"Run____triggers1 = new global::Ariadne.TriggerWait(1, onConditions: true);"));
CheckTrue(run.CodeBehind.Contains("Run____triggers2 = new global::Ariadne.TriggerWait(1);"));
CheckTrue(run.CodeBehind.Contains("Run____triggers1.Finish();"));
CheckFalse(run.CodeBehind.Contains("Run____triggers2.Finish();"));
}
public void Wait_DeclaringALocal_TakesTheResultFromFinishing()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" first:\n Condition 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.Finish();"));
CheckTrue(run.CodeBehind.IndexOf("Run____triggers1.Expire()") <
run.CodeBehind.IndexOf("got = __frame.Run____triggers1.Finish();"));
}
public void Wait_AssigningAVariable_TakesTheResultFromFinishing()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" Condition got = null;\n first:\n 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.Finish();"));
}
public void WaitReturnedFromAPassage_IsThePassagesResult()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" outer:\n Condition picked = Pick();",
members: " private Condition Pick()\n {\n inner:\n return Wait(A, timeout: " +
Limit + ");\n }\n"));
CheckEqual(0, run.Reported.Count);
CheckEqual(0, run.Compiled.Count);
CheckTrue(run.CodeBehind.Contains("__result = __frame.Pick____triggers1.Finish();"));
CheckTrue(run.CodeBehind.Contains("__frame.Pick____triggers1.Expire();"));
}
public void WaitAny_AddsEveryConditionButNotTheTimeoutAndDoesNotRequireAll()
{
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("new global::Ariadne.TriggerWait(2, onConditions: true);"));
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("Run____triggers1.Expire();"));
}
public void WaitAll_RequiresAllAndTakesTheResultFromFinishing()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" first:\n Condition last = WaitAll(A, B);\n" +
" world.Open.Add(last == B ? \"b last\" : \"a last\");"));
CheckEqual(0, run.Reported.Count);
CheckEqual(0, run.Compiled.Count);
CheckTrue(run.CodeBehind.Contains("Run____triggers1.Begin(__frame, requiresAll: true);"));
CheckTrue(run.CodeBehind.Contains("last = __frame.Run____triggers1.Finish();"));
}
public void WaitAllWithATimeout_AddsEveryConditionButNotTheTimeout()
{
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);"));
CheckFalse(run.CodeBehind.Contains(".Add(System.TimeSpan"));
}
public void TimedWait_KeepsItsDeadlineAndSleepsTheArcTillIt()
{
GeneratorRun run = GeneratorRun.Of(ScriptWith(
" first:\n Wait(A, timeout: " + Limit + ");"));
CheckEqual(0, run.Reported.Count);
CheckEqual(0, run.Compiled.Count);
CheckTrue(run.CodeBehind.Contains("__frame.Run____wait1 = __time.DeadlineAfter(" + Limit + ");"));
CheckTrue(run.CodeBehind.Contains("__frame.Sleep(__frame.Run____wait1); __frame.Suspend();"));
}
}
public class DiagnosticTests : TestFixture
{
[IgnoreTest]
public GeneratorRun RunOf(string body)
{
return GeneratorRun.Of(ScriptWith(body));
}
public void WaitAnyOfATriggerAndALatch_IsReported()
{
GeneratorRun run = RunOf(" first:\n WaitAny(T, A);");
CheckEqual(new[] { "ARI0034:WaitAny(T, A)" }, run.Reported);
CheckTrue(run.Messages.Single().Contains("not both"));
}
public void WaitAllOfALatchAndATriggerWithATimeout_IsReported()
{
GeneratorRun run = RunOf(" first:\n WaitAll(timeout: " + Limit + ", A, T);");
CheckEqual(new[] { "ARI0034:WaitAll(timeout: " + Limit + ", A, T)" }, run.Reported);
CheckTrue(run.Messages.Single().Contains("not both"));
}
public void WaitAnyOfValuesTypedAsWaitable_IsReported()
{
GeneratorRun run = RunOf(" Waitable one = A;\n first:\n WaitAny(one);");
CheckEqual(new[] { "ARI0034:WaitAny(one)" }, run.Reported);
CheckTrue(run.Messages.Single().Contains("not both"));
}
public void ConditionsPassedAsAnArray_AreReported()
{
GeneratorRun run = RunOf(" Latch[] both = { A, B };\n first:\n WaitAny(both);");
CheckEqual(new[] { "ARI0034:WaitAny(both)" }, run.Reported);
CheckTrue(run.Messages.Single().Contains("Pass the conditions one by one"));
}
public void MoreConditionsThanAWaitHolds_AreReported()
{
string conditions = string.Join(", ", Enumerable.Repeat("A", 33));
GeneratorRun run = RunOf(" first:\n WaitAll(" + conditions + ");");
CheckEqual(1, run.Reported.Count);
CheckTrue(run.Messages.Single().Contains("at most 32 conditions"));
}
public void WaitAnyOfNothing_IsAmbiguousToTheCompiler()
{
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)));
}
}
}
}