From 42dbd7866500b33ec49342eac6f2b1271b0154e1 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Tue, 27 Aug 2024 21:14:46 -0700 Subject: [PATCH] ability to run as a sanity test --- .github/workflows/dotnet.yml | 2 +- ...asic.Reference.Assemblies.UnitTests.csproj | 2 +- .../CompilationUtil.cs | 82 +++++++++++++++++++ .../Extensions.cs | 3 + .../SanityUnitTests.cs | 17 ++++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 Src/Basic.Reference.Assemblies.UnitTests/CompilationUtil.cs diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 1d7971b..139cf26 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -29,7 +29,7 @@ jobs: run: dotnet pack -p:PackageOutputPath="${GITHUB_WORKSPACE}/packages" -p:IncludeSymbols=false -p:RepositoryCommit=${GITHUB_SHA} -p:PackageVersion="0.0.0.1" - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet test --framework net8.0 --no-build --verbosity normal - name: Upload Binary Log uses: actions/upload-artifact@v3 diff --git a/Src/Basic.Reference.Assemblies.UnitTests/Basic.Reference.Assemblies.UnitTests.csproj b/Src/Basic.Reference.Assemblies.UnitTests/Basic.Reference.Assemblies.UnitTests.csproj index 47b5d0f..1d88aa5 100644 --- a/Src/Basic.Reference.Assemblies.UnitTests/Basic.Reference.Assemblies.UnitTests.csproj +++ b/Src/Basic.Reference.Assemblies.UnitTests/Basic.Reference.Assemblies.UnitTests.csproj @@ -1,7 +1,7 @@  - net8.0 + net8.0;net472 false LatestMajor diff --git a/Src/Basic.Reference.Assemblies.UnitTests/CompilationUtil.cs b/Src/Basic.Reference.Assemblies.UnitTests/CompilationUtil.cs new file mode 100644 index 0000000..a2198b7 --- /dev/null +++ b/Src/Basic.Reference.Assemblies.UnitTests/CompilationUtil.cs @@ -0,0 +1,82 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Basic.Reference.Assemblies.UnitTests; +internal static class CompilationUtil +{ + public static MemoryStream CompileToLibrary(string code, string assemblyName) + { + var references = +#if NET + Net80.References.All; +#else + Net461.References.All; +#endif + var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + var compilation = CSharpCompilation.Create( + assemblyName, + [CSharpSyntaxTree.ParseText(code)], + references, + options); + + var peStream = new MemoryStream(); + var emitResult = compilation.Emit(peStream); + if (!emitResult.Success) + { + throw new Exception(GetMessage(emitResult.Diagnostics)); + } + + peStream.Position = 0; + return peStream; + + static string GetMessage(IEnumerable diagnostics) + { + var builder = new StringBuilder(); + builder.AppendLine("Compilation failed with the following errors:"); + foreach (var d in diagnostics) + { + builder.AppendLine(d.ToString()); + } + return builder.ToString(); + } + } + + public static Assembly CompileToLibraryAndLoad(string code, string assemblyName) + { + var stream = CompileToLibrary(code, assemblyName); + return Load(stream, assemblyName); + } + + /// + /// Compile and run the code expecting to find a static Lib.Go method + /// + public static string? CompileAndRun(string code, string assemblyName) + { + var assembly = CompileToLibraryAndLoad(code, assemblyName); + var libType = assembly + .GetTypes() + .Where(x => x.Name == "Lib") + .Single(); + var method = libType.GetMethod("Go", BindingFlags.Static | BindingFlags.NonPublic); + var obj = method!.Invoke(null, null); + return (string?)obj; + } + + public static Assembly Load(MemoryStream stream, string assemblyName) + { + stream.Position = 0; +#if NET + var alc = new System.Runtime.Loader.AssemblyLoadContext(assemblyName); + return alc.LoadFromStream(stream); +#else + return Assembly.Load(stream.ToArray()); +#endif + } +} diff --git a/Src/Basic.Reference.Assemblies.UnitTests/Extensions.cs b/Src/Basic.Reference.Assemblies.UnitTests/Extensions.cs index dd5861a..e4f8518 100644 --- a/Src/Basic.Reference.Assemblies.UnitTests/Extensions.cs +++ b/Src/Basic.Reference.Assemblies.UnitTests/Extensions.cs @@ -1,7 +1,10 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; diff --git a/Src/Basic.Reference.Assemblies.UnitTests/SanityUnitTests.cs b/Src/Basic.Reference.Assemblies.UnitTests/SanityUnitTests.cs index ea551b2..75a3008 100644 --- a/Src/Basic.Reference.Assemblies.UnitTests/SanityUnitTests.cs +++ b/Src/Basic.Reference.Assemblies.UnitTests/SanityUnitTests.cs @@ -176,4 +176,21 @@ static void Main() Assert.True(emitResult.Success); Assert.Empty(emitResult.Diagnostics); } + + [Fact] + public void RunTuple() + { + var source = """ + static class Lib + { + public static string Go() + { + var tuple = (1, 2); + return tuple.ToString(); + } + } + """; + var actual = CompilationUtil.CompileAndRun(source, nameof(RunTuple)); + Assert.Equal("(1, 2)", actual); + } }