using System.Linq; using Microsoft.CodeAnalysis; using UnitTestSharp; namespace Ariadne.Generator.UnitTests { /// /// Passages of arc classes that were built into another assembly by the generator, which a script here calls or /// inherits. /// public class MetadataPassageTests : TestFixture { public const string HostLibrary = @" public abstract partial class Host : Arc { public int Total; protected void Count(string context) { int waited = 0; count: while (waited < 3) { waited++; Yield(); } Total += waited; } protected int Measure(string context) { int waited = 0; measure: while (waited < 2) { waited++; Yield(); } return waited; } }"; public const string PlantLibrary = @" public partial class Plant : Arc { public int Grown; public void Grow(string context) { int waited = 0; grow: while (waited < 3) { waited++; Yield(); } Grown += waited; } public int Measure(string context) { int waited = 0; measure: while (waited < 2) { waited++; Yield(); } return waited; } protected override void Run(string context) { } }"; public const string OwnedFrameLibrary = @" public abstract partial class Steps : Arc { protected void Hold(string context, X kept) { hold: while (context.Length == 0 && kept != null) { Yield(); } } protected void Descend(string context, int depth) { if (depth > 0) { again: Descend(context, depth - 1); } stop: while (context.Length == 0) { Yield(); } } } public partial class Garden : Arc { public void Hold(string context, X kept) { hold: while (context.Length == 0 && kept != null) { Yield(); } } public void Descend(string context, int depth) { if (depth > 0) { again: Descend(context, depth - 1); } stop: while (context.Length == 0) { Yield(); } } protected override void Run(string context) { } }"; public class OwnedFrameTests : TestFixture { public void GenericBasePassage_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Steps", OwnedFrameLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Steps { protected override void Run(string context) { hold: Hold(context, 3); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Hold__Frame")); } public void RecursiveBasePassage_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Steps", OwnedFrameLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Steps { protected override void Run(string context) { descend: Descend(context, 3); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Descend__Frame")); } public void GenericPassageOfAnotherArc_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Steps", OwnedFrameLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Garden Plot = new Garden(); protected override void Run(string context) { hold: Plot.Hold(context, 3); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Garden.Hold__Frame")); } public void RecursivePassageOfAnotherArc_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Steps", OwnedFrameLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Garden Plot = new Garden(); protected override void Run(string context) { descend: Plot.Descend(context, 3); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckTrue(run.CodeBehind.Contains("Garden.Descend__Frame")); } } public class InheritedPassageTests : TestFixture { public void CallToABasePassage_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { protected override void Run(string context) { count: Count(context); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); } public void CallToABasePassage_RunsTheResumableCopyOnTheDerivedFrame() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { protected override void Run(string context) { count: Count(context); } }"); CheckTrue(run.CodeBehind.Contains("Count__Passage(")); } public void CallToABasePassage_SavesTheBasePassagesLocalsThroughItsOwnMethod() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { protected override void Run(string context) { count: Count(context); } }"); CheckTrue(run.CodeBehind.Contains("Count__LocalsToSave(")); } public void CallToABasePassageInsideAnExpression_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { public int Seen; protected override void Run(string context) { measure: Seen = 10 + Measure(context); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); } public void CallToABasePassageWhereItCannotPause_IsReported() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { protected override void Run(string context) { foreach (char each in context) { Count(context); } } }"); CheckTrue(run.Reported.Contains("ARI0004:Count(context)")); } public void PassageNamedLikeABasePassage_IsReported() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Hosts", HostLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Derived : Host { protected void Count(string context, int extra) { count: while (extra > 0) { extra--; Yield(); } } protected override void Run(string context) { } }"); CheckTrue(run.Reported.Any(each => each.StartsWith("ARI0012:"))); } } public class OtherArcTests : TestFixture { public void CallToAPassageOfAnotherAssembliesArc_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Plants", PlantLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Plant Garden = new Plant(); protected override void Run(string context) { grow: Garden.Grow(context); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); } public void CallToAPassageOfAnotherAssembliesArc_RunsItOnThatArc() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Plants", PlantLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Plant Garden = new Plant(); protected override void Run(string context) { grow: Garden.Grow(context); } }"); CheckTrue(run.CodeBehind.Contains("Grow__Passage(")); CheckTrue(run.CodeBehind.Contains("Grow__LocalsToSave(")); } public void CallInsideALargerExpression_CompilesWithoutComplaint() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Plants", PlantLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Plant Garden = new Plant(); public int Seen; protected override void Run(string context) { measure: Seen = 10 + Garden.Measure(context); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); } public void CallWhereItCannotPause_IsReported() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Plants", PlantLibrary); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Plant Garden = new Plant(); protected override void Run(string context) { foreach (char each in context) { Garden.Grow(context); } } }"); CheckTrue(run.Reported.Contains("ARI0004:Garden.Grow(context)")); } public void MethodOfAnotherAssembliesArcThatDoesntPause_IsCalledLikeAnyObject() { MetadataReference library = GeneratorRun.CompileGeneratedLibrary("Plants", @" public partial class Plain : Arc { public void Note(string context) { } protected override void Run(string context) { } }"); GeneratorRun run = GeneratorRun.Of(library, @" public partial class Mission : Arc { public Plain Other = new Plain(); protected override void Run(string context) { note: Other.Note(context); } }"); CheckEqual(0, run.Reported.Count); CheckEqual(0, run.Compiled.Count); CheckFalse(run.CodeBehind.Contains("NewFrame")); } } } }