From 5aac445fe71840d693386dd1f520f9d698ca8e91 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sun, 28 Jul 2024 02:03:43 +0200 Subject: [PATCH 01/42] some setup --- Dapper.AOT.sln | 14 +++++ ...er.AOT.Test.Integration.Executables.csproj | 31 +++++++++++ .../IExecutable.cs | 8 +++ .../Models/DbStringPoco.cs | 9 +++ .../UserCode/DbStringUsage.cs | 13 +++++ .../Dapper.AOT.Test.Integration.csproj | 44 +++++++++++++++ .../InterceptorsIntegratedTestsBase.cs | 55 +++++++++++++++++++ .../PostgresqlFixture.cs | 52 ++++++++++++++++++ .../Tests/DbStringIntegrationTests.cs | 30 ++++++++++ 9 files changed, 256 insertions(+) create mode 100644 test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj create mode 100644 test/Dapper.AOT.Test.Integration.Executables/IExecutable.cs create mode 100644 test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs create mode 100644 test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs create mode 100644 test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj create mode 100644 test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs create mode 100644 test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs create mode 100644 test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs diff --git a/Dapper.AOT.sln b/Dapper.AOT.sln index 15a5e283..857f70a9 100644 --- a/Dapper.AOT.sln +++ b/Dapper.AOT.sln @@ -40,6 +40,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UsageVanilla", "test\UsageVanilla\UsageVanilla.csproj", "{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{247DE17A-F9D1-466B-B5C2-32D694D95A9D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration.Executables", "test\Dapper.AOT.Test.Integration.Executables\Dapper.AOT.Test.Integration.Executables.csproj", "{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -78,6 +82,14 @@ Global {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.Build.0 = Release|Any CPU + {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Release|Any CPU.Build.0 = Release|Any CPU + {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -91,6 +103,8 @@ Global {A77B633C-573E-43CD-85A4-8063B33143B4} = {FE215D4B-811B-47BB-9F05-6382DD1C6729} {C6527566-38F4-43CC-9E0E-91C4B8854774} = {1135D4FD-770E-41DF-920B-A8F75E42A832} {840EA1CA-62FF-409E-89F5-CD3BB269BAE3} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} + {247DE17A-F9D1-466B-B5C2-32D694D95A9D} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} + {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A89CDAFA-494F-4168-9648-1138BA738D43} diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj new file mode 100644 index 00000000..9067c714 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -0,0 +1,31 @@ + + + + net8.0;net6.0;net48 + enable + enable + + Dapper.AOT.Test.Integration.Executables + + + + + + + + + + + + + + + + + + + diff --git a/test/Dapper.AOT.Test.Integration.Executables/IExecutable.cs b/test/Dapper.AOT.Test.Integration.Executables/IExecutable.cs new file mode 100644 index 00000000..98a062d4 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/IExecutable.cs @@ -0,0 +1,8 @@ +using System.Data; + +namespace Dapper.AOT.Test.Integration.Executables; + +public interface IExecutable +{ + public T Execute(IDbConnection connection); +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs new file mode 100644 index 00000000..d4e70f9c --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs @@ -0,0 +1,9 @@ +namespace Dapper.AOT.Test.Integration.Executables.Models; + +public class DbStringPoco +{ + public const string TableName = "dbString_test"; + + public int Id { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs new file mode 100644 index 00000000..aa99eb60 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs @@ -0,0 +1,13 @@ +using System.Data; +using Dapper.AOT.Test.Integration.Executables.Models; + +namespace Dapper.AOT.Test.Integration.Executables.UserCode; + +public class DbStringUsage : IExecutable +{ + public DbStringPoco Execute(IDbConnection connection) + { + var results = connection.Query($"select * from {DbStringPoco.TableName}"); + return results.First(); + } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj new file mode 100644 index 00000000..095d625f --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -0,0 +1,44 @@ + + + + net6.0;net48 + Dapper.AOT.Test.Integration + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + + + + + + diff --git a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs new file mode 100644 index 00000000..902d5098 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs @@ -0,0 +1,55 @@ +using System; +using System.Data; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace Dapper.AOT.Test.Integration; + +[Collection(SharedPostgresqlClient.Collection)] +public abstract class InterceptorsIntegratedTestsBase +{ + private readonly IDbConnection _dbConnection; + + public InterceptorsIntegratedTestsBase(PostgresqlFixture fixture) + { + _dbConnection = fixture.NpgsqlConnection; + SetupDatabase(_dbConnection); + } + + /// + /// Use this to make a setup for the test. Works once for the class. + /// Example: create a table on which you will be running tests on. + /// + /// a connection to database tests are running against + protected virtual void SetupDatabase(IDbConnection dbConnection) + { + } + + protected TResult ExecuteUserCode() + { + var name = GetUserSourceCode(); + + var compilation = CSharpCompilation.Create( + assemblyName: "Test.dll", + syntaxTrees: [], + references: GetTestCompilationMetadataReferences(typeof(TExecutable)), + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + throw new Exception(); + } + + string GetUserSourceCode() + { + return typeof(T).Name; + } + + MetadataReference[] GetTestCompilationMetadataReferences(Type userCodeType) => + [ + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // dotnet + MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper + MetadataReference.CreateFromFile(typeof(Microsoft.Data.SqlClient.SqlConnection).Assembly.Location), // Microsoft.Data.SqlClient + + MetadataReference.CreateFromFile(userCodeType.Assembly.Location), // assembly with user code + ]; +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs b/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs new file mode 100644 index 00000000..59329192 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs @@ -0,0 +1,52 @@ +using Npgsql; +using System.Threading.Tasks; +using Testcontainers.PostgreSql; +using Xunit; + +namespace Dapper.AOT.Test.Integration; + +[CollectionDefinition(Collection)] +public class SharedPostgresqlClient : ICollectionFixture +{ + public const string Collection = nameof(SharedPostgresqlClient); +} + +public sealed class PostgresqlFixture : IAsyncLifetime +{ + private readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder() + .WithImage("postgres:15-alpine") + .Build(); + + public string ConnectionString { get; private set; } = null!; + + private NpgsqlConnection? _sharedConnection; + + public NpgsqlConnection NpgsqlConnection + => _sharedConnection ??= CreateOpenConnection(); + + public NpgsqlConnection CreateOpenConnection() + { + var conn = new NpgsqlConnection(ConnectionString); + conn.Open(); + return conn; + } + + async Task IAsyncLifetime.InitializeAsync() + { + await _postgresContainer.StartAsync(); + ConnectionString = _postgresContainer.GetConnectionString(); + } + + async Task IAsyncLifetime.DisposeAsync() + { + await using (_postgresContainer) + { + var tmp = _sharedConnection; + _sharedConnection = null; + if (tmp is not null) + { + await tmp.DisposeAsync(); + } + } + } +} diff --git a/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs b/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs new file mode 100644 index 00000000..57c1fa34 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs @@ -0,0 +1,30 @@ +using System.Data; +using Dapper.AOT.Test.Integration.Executables.Models; +using Dapper.AOT.Test.Integration.Executables.UserCode; +using Xunit; + +namespace Dapper.AOT.Test.Integration.Tests; + +[Collection(SharedPostgresqlClient.Collection)] +public class DbStringIntegrationTests : InterceptorsIntegratedTestsBase +{ + public DbStringIntegrationTests(PostgresqlFixture fixture) + : base(fixture) + { + } + + [Fact] + public void SimpleDbString_RunsAgainstDatabase() + { + var result = ExecuteUserCode(); + Assert.NotNull(result); + } + + protected override void SetupDatabase(IDbConnection dbConnection) => dbConnection.Execute(""" + CREATE TABLE IF NOT EXISTS dbString_test( + id integer PRIMARY KEY, + name varchar(40) NOT NULL + ); + TRUNCATE dbString_test; + """); +} \ No newline at end of file From 74115ec96b0dbdd0e9841c5151fa2446ca12c0f7 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sun, 28 Jul 2024 15:46:50 +0200 Subject: [PATCH 02/42] make it build and execute without AOT --- ...er.AOT.Test.Integration.Executables.csproj | 22 ++--- .../UserCode/.gitignore | 1 + .../UserCode/DbStringUsage.cs | 1 + .../InterceptorsIntegratedTestsBase.cs | 96 +++++++++++++++++-- .../Tests/DbStringIntegrationTests.cs | 5 + 5 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 9067c714..c7a2352c 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -2,9 +2,6 @@ net8.0;net6.0;net48 - enable - enable - Dapper.AOT.Test.Integration.Executables @@ -14,18 +11,19 @@ - + - + - + - - + + + + $([System.String]::Copy(%(Filename)).Replace('.txt', '.cs')) + + + diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore b/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore new file mode 100644 index 00000000..ce525563 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore @@ -0,0 +1 @@ +**.txt \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs index aa99eb60..7b44c32f 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Linq; using Dapper.AOT.Test.Integration.Executables.Models; namespace Dapper.AOT.Test.Integration.Executables.UserCode; diff --git a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs index 902d5098..ffbe951e 100644 --- a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs @@ -1,7 +1,17 @@ using System; +using System.Collections.Generic; using System.Data; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Dapper.AOT.Test.Integration.Executables; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace Dapper.AOT.Test.Integration; @@ -9,6 +19,8 @@ namespace Dapper.AOT.Test.Integration; [Collection(SharedPostgresqlClient.Collection)] public abstract class InterceptorsIntegratedTestsBase { + const string UserCodeDir = "UserCode"; + private readonly IDbConnection _dbConnection; public InterceptorsIntegratedTestsBase(PostgresqlFixture fixture) @@ -27,29 +39,99 @@ protected virtual void SetupDatabase(IDbConnection dbConnection) } protected TResult ExecuteUserCode() + where TExecutable : IExecutable { - var name = GetUserSourceCode(); + var userCodeSource = ReadUserSourceCode(); + var userCodeSyntaxTree = BuildInterceptorEnabledSyntaxTree("UserCode.cs", userCodeSource); var compilation = CSharpCompilation.Create( assemblyName: "Test.dll", - syntaxTrees: [], + syntaxTrees: [ userCodeSyntaxTree ], references: GetTestCompilationMetadataReferences(typeof(TExecutable)), options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - throw new Exception(); + var assembly = Compile(compilation); + var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); + var executableInstance = (IExecutable)Activator.CreateInstance(type)!; + + return executableInstance.Execute(_dbConnection); + } + + string ReadUserSourceCode() + { + var filePath = Path.Combine(UserCodeDir, $"{typeof(T).Name}.txt"); + if (!File.Exists(filePath)) + { + throw new FileNotFoundException(message: typeof(T).Name, fileName: filePath); + } + + return File.ReadAllText(filePath); + } + + static SyntaxTree BuildInterceptorEnabledSyntaxTree(string filename, string text) + { + var options = new CSharpParseOptions(LanguageVersion.Preview) + .WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), + new KeyValuePair("Features", "InterceptorsPreview"), + new KeyValuePair("LangVersion", "preview"), + }); + + var stringText = SourceText.From(text, Encoding.UTF8); + return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); } - string GetUserSourceCode() + static Assembly Compile(Compilation compilation) { - return typeof(T).Name; + using var peStream = new MemoryStream(); + using var pdbstream = new MemoryStream(); + var dbg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; + var emitResult = compilation.Emit(peStream, pdbstream, null, null, null, new EmitOptions(false, dbg)); + if (!emitResult.Success) + { + TryThrowErrors(emitResult.Diagnostics); + } + + peStream.Position = pdbstream.Position = 0; + return Assembly.Load(peStream.ToArray(), pdbstream.ToArray()); + + static void TryThrowErrors(IEnumerable items) + { + var errors = new List(); + foreach (var item in items) + { + if (item.Severity == DiagnosticSeverity.Error) + { + errors.Add(item.GetMessage(CultureInfo.InvariantCulture)); + } + } + + if (errors.Count > 0) + { + throw new ExpressionParsingException(errors); + } + } } MetadataReference[] GetTestCompilationMetadataReferences(Type userCodeType) => [ - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // dotnet + // dotnet + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Data.IDbConnection).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location), + +#if !NET48 + MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), +#endif + + // external nugets MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper MetadataReference.CreateFromFile(typeof(Microsoft.Data.SqlClient.SqlConnection).Assembly.Location), // Microsoft.Data.SqlClient - MetadataReference.CreateFromFile(userCodeType.Assembly.Location), // assembly with user code + // user code + MetadataReference.CreateFromFile(userCodeType.Assembly.Location), ]; + + class ExpressionParsingException(IEnumerable errors) : Exception(string.Join(Environment.NewLine, errors)); } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs b/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs index 57c1fa34..26c111b5 100644 --- a/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs +++ b/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs @@ -26,5 +26,10 @@ CREATE TABLE IF NOT EXISTS dbString_test( name varchar(40) NOT NULL ); TRUNCATE dbString_test; + + INSERT INTO dbString_test(id, name) + VALUES + (1, 'my-string'), + (2, 'another-string'); """); } \ No newline at end of file From db947b67948de6e301098339a49d70f154cbc6ba Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sun, 28 Jul 2024 21:55:07 +0200 Subject: [PATCH 03/42] at this moment - i dont know --- .../InterceptsLocationAttribute.cs | 2 +- ...er.AOT.Test.Integration.Executables.csproj | 5 +- .../UserCode/DbStringUsage.cs | 17 +++- .../Dapper.AOT.Test.Integration.csproj | 2 +- .../InterceptorsIntegratedTestsBase.cs | 87 +++++++++++++++---- 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs b/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs index 996bc00a..163a9606 100644 --- a/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs +++ b/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs @@ -3,7 +3,7 @@ // this type is needed by the compiler to implement interceptors - it doesn't need to // come from the runtime itself, though - [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate + // [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] sealed file class InterceptsLocationAttribute : global::System.Attribute { diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index c7a2352c..eb3386b5 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -3,11 +3,15 @@ net8.0;net6.0;net48 Dapper.AOT.Test.Integration.Executables + + $(InterceptorsPreviewNamespaces);Dapper.AOT + + @@ -23,7 +27,6 @@ $([System.String]::Copy(%(Filename)).Replace('.txt', '.cs')) - diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs index 7b44c32f..8cb971aa 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs @@ -4,11 +4,24 @@ namespace Dapper.AOT.Test.Integration.Executables.UserCode; +[DapperAot] public class DbStringUsage : IExecutable { public DbStringPoco Execute(IDbConnection connection) { - var results = connection.Query($"select * from {DbStringPoco.TableName}"); - return results.First(); + var a = GetSomething(); + return new DbStringPoco() + { + Id = 1, + Name = a + }; + + // var results = connection.Query($"select * from {DbStringPoco.TableName}"); + // return results.First(); + } + + static string GetSomething() + { + return "qwe"; } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index 095d625f..e63876c6 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -1,7 +1,7 @@  - net6.0;net48 + net8.0;net6.0;net48 Dapper.AOT.Test.Integration diff --git a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs index ffbe951e..1927afde 100644 --- a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Text; using Dapper.AOT.Test.Integration.Executables; +using Dapper.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; @@ -44,17 +45,70 @@ protected TResult ExecuteUserCode() var userCodeSource = ReadUserSourceCode(); var userCodeSyntaxTree = BuildInterceptorEnabledSyntaxTree("UserCode.cs", userCodeSource); - var compilation = CSharpCompilation.Create( + var anotherCodeSyntax = BuildInterceptorEnabledSyntaxTree("Generated.cs", """ + namespace Dapper.AOT // interceptors must be in a known namespace + { + file static class DapperGeneratedInterceptors + { + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("UserCode.cs", 14, 34)] + internal static global::System.Collections.Generic.IEnumerable Query0( + this global::System.Data.IDbConnection cnn, string sql) + { + throw new global::System.Exception("this is my test"); + + return new System.Collections.Generic.List(); + } + + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("UserCode.cs", 12, 17)] + internal static string GetSomethingInt() + { + throw new global::System.Exception("this is my test"); + + return "not qwe"; + } + } + } + + namespace System.Runtime.CompilerServices + { + // this type is needed by the compiler to implement interceptors - it doesn't need to + // come from the runtime itself, though + + // [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate + [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] + sealed file class InterceptsLocationAttribute : global::System.Attribute + { + public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) + { + _ = path; + _ = lineNumber; + _ = columnNumber; + } + } + } + """); + + var inputCompilation = CSharpCompilation.Create( assemblyName: "Test.dll", - syntaxTrees: [ userCodeSyntaxTree ], + syntaxTrees: [ userCodeSyntaxTree, anotherCodeSyntax ], references: GetTestCompilationMetadataReferences(typeof(TExecutable)), options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + // var generator = new DapperInterceptorGenerator(); + // GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: InterceptorsEnabledParseOptions); + // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + + // var assembly = Compile(outputCompilation); + var assembly = Compile(inputCompilation); - var assembly = Compile(compilation); + var assemblyAttributes = inputCompilation.Assembly.GetAttributes(); + var moduleAttributes = assembly.Modules.SelectMany(x => x.CustomAttributes); + var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); var executableInstance = (IExecutable)Activator.CreateInstance(type)!; - return executableInstance.Execute(_dbConnection); + var result = executableInstance.Execute(_dbConnection); + return result; } string ReadUserSourceCode() @@ -70,16 +124,8 @@ string ReadUserSourceCode() static SyntaxTree BuildInterceptorEnabledSyntaxTree(string filename, string text) { - var options = new CSharpParseOptions(LanguageVersion.Preview) - .WithFeatures(new[] - { - new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), - new KeyValuePair("Features", "InterceptorsPreview"), - new KeyValuePair("LangVersion", "preview"), - }); - var stringText = SourceText.From(text, Encoding.UTF8); - return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); + return SyntaxFactory.ParseSyntaxTree(stringText, InterceptorsEnabledParseOptions, filename); } static Assembly Compile(Compilation compilation) @@ -120,18 +166,29 @@ MetadataReference[] GetTestCompilationMetadataReferences(Type userCodeType) => MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Data.IDbConnection).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Collections.Generic.List<>).Assembly.Location), #if !NET48 MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), #endif // external nugets - MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper - MetadataReference.CreateFromFile(typeof(Microsoft.Data.SqlClient.SqlConnection).Assembly.Location), // Microsoft.Data.SqlClient + MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Microsoft.Data.SqlClient.SqlConnection).Assembly.Location), // user code MetadataReference.CreateFromFile(userCodeType.Assembly.Location), + + // DAPPER.AOT ! + MetadataReference.CreateFromFile(Assembly.Load("Dapper.AOT").Location), ]; + static CSharpParseOptions InterceptorsEnabledParseOptions + => new CSharpParseOptions().WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT;Dapper;Dapper.AOT.Test.Integration.Executables.UserCode"), + new KeyValuePair("LangVersion", "preview"), + }); + class ExpressionParsingException(IEnumerable errors) : Exception(string.Join(Environment.NewLine, errors)); } \ No newline at end of file From 1f464293b56f6fe524e0e99447485b62d7e744fc Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 02:37:22 +0200 Subject: [PATCH 04/42] minimal assembly references --- ...er.AOT.Test.Integration.Executables.csproj | 2 - .../UserCode/DbStringUsage.cs | 16 +------ .../InterceptorsIntegratedTestsBase.cs | 48 ++++++------------- 3 files changed, 16 insertions(+), 50 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index eb3386b5..dfee70e1 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -3,8 +3,6 @@ net8.0;net6.0;net48 Dapper.AOT.Test.Integration.Executables - - $(InterceptorsPreviewNamespaces);Dapper.AOT diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs index 8cb971aa..735ae4f8 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs @@ -9,19 +9,7 @@ public class DbStringUsage : IExecutable { public DbStringPoco Execute(IDbConnection connection) { - var a = GetSomething(); - return new DbStringPoco() - { - Id = 1, - Name = a - }; - - // var results = connection.Query($"select * from {DbStringPoco.TableName}"); - // return results.First(); - } - - static string GetSomething() - { - return "qwe"; + var results = connection.Query($"select * from {DbStringPoco.TableName}"); + return results.First(); } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs index 1927afde..29f81237 100644 --- a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs @@ -8,7 +8,6 @@ using System.Runtime.InteropServices; using System.Text; using Dapper.AOT.Test.Integration.Executables; -using Dapper.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; @@ -52,20 +51,15 @@ file static class DapperGeneratedInterceptors { [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("UserCode.cs", 14, 34)] internal static global::System.Collections.Generic.IEnumerable Query0( - this global::System.Data.IDbConnection cnn, string sql) + this global::System.Data.IDbConnection cnn, + string sql, + object? param = null, + global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) { throw new global::System.Exception("this is my test"); return new System.Collections.Generic.List(); } - - [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("UserCode.cs", 12, 17)] - internal static string GetSomethingInt() - { - throw new global::System.Exception("this is my test"); - - return "not qwe"; - } } } @@ -74,7 +68,6 @@ namespace System.Runtime.CompilerServices // this type is needed by the compiler to implement interceptors - it doesn't need to // come from the runtime itself, though - // [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] sealed file class InterceptsLocationAttribute : global::System.Attribute { @@ -100,9 +93,6 @@ public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber // var assembly = Compile(outputCompilation); var assembly = Compile(inputCompilation); - - var assemblyAttributes = inputCompilation.Assembly.GetAttributes(); - var moduleAttributes = assembly.Modules.SelectMany(x => x.CustomAttributes); var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); var executableInstance = (IExecutable)Activator.CreateInstance(type)!; @@ -162,32 +152,22 @@ static void TryThrowErrors(IEnumerable items) MetadataReference[] GetTestCompilationMetadataReferences(Type userCodeType) => [ - // dotnet - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), - MetadataReference.CreateFromFile(typeof(System.Data.IDbConnection).Assembly.Location), - MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location), - MetadataReference.CreateFromFile(typeof(System.Collections.Generic.List<>).Assembly.Location), - -#if !NET48 - MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), -#endif + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? + MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? - // external nugets - MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Microsoft.Data.SqlClient.SqlConnection).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper + MetadataReference.CreateFromFile(typeof(DapperAotAttribute).Assembly.Location), // Dapper.AOT - // user code - MetadataReference.CreateFromFile(userCodeType.Assembly.Location), + MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq + MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common - // DAPPER.AOT ! - MetadataReference.CreateFromFile(Assembly.Load("Dapper.AOT").Location), + MetadataReference.CreateFromFile(userCodeType.Assembly.Location), // UserCode ]; static CSharpParseOptions InterceptorsEnabledParseOptions - => new CSharpParseOptions().WithFeatures(new[] - { - new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT;Dapper;Dapper.AOT.Test.Integration.Executables.UserCode"), - new KeyValuePair("LangVersion", "preview"), + => new CSharpParseOptions(LanguageVersion.Preview).WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), }); class ExpressionParsingException(IEnumerable errors) : Exception(string.Join(Environment.NewLine, errors)); From 72db8ac1e81333bf0eb1b306edcb1880b3150e87 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 02:53:12 +0200 Subject: [PATCH 05/42] bump packages and then it does not work still... --- Directory.Packages.props | 76 +++++++++---------- ...er.AOT.Test.Integration.Executables.csproj | 8 +- .../Dapper.AOT.Test.Integration.csproj | 32 +++----- test/Dapper.AOT.Test/Dapper.AOT.Test.csproj | 8 +- 4 files changed, 59 insertions(+), 65 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e7f3774c..f55151ed 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index dfee70e1..dcb3aa8e 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -6,7 +6,7 @@ - + @@ -26,5 +26,11 @@ $([System.String]::Copy(%(Filename)).Replace('.txt', '.cs')) + + + + + + diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index e63876c6..f5a92af4 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -6,39 +6,25 @@ - + + + + + - - - - + - - - - - - + + + all runtime; build; native; contentfiles; analyzers - - - - - - - - - - - - diff --git a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj index 67a758e5..d03ac661 100644 --- a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj +++ b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj @@ -29,15 +29,13 @@ - - + - @@ -59,4 +57,8 @@ + + + + From dd2914ffc5c5b57d40269883c31b4597c82dc091 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 10:42:38 +0200 Subject: [PATCH 06/42] do it iteratively --- Dapper.AOT.sln | 14 +- .../Dapper.AOT.Test.Integration.csproj | 43 +++-- .../InterceptorsIntegratedTestsBase.cs | 174 ----------------- .../PostgresqlFixture.cs | 52 ----- .../Tests/DbStringIntegrationTests.cs | 35 ---- test/Dapper.AOT.Test.Integration/UnitTest1.cs | 179 ++++++++++++++++++ 6 files changed, 210 insertions(+), 287 deletions(-) delete mode 100644 test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs delete mode 100644 test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs delete mode 100644 test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs create mode 100644 test/Dapper.AOT.Test.Integration/UnitTest1.cs diff --git a/Dapper.AOT.sln b/Dapper.AOT.sln index 857f70a9..12dc26d7 100644 --- a/Dapper.AOT.sln +++ b/Dapper.AOT.sln @@ -40,10 +40,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UsageVanilla", "test\UsageVanilla\UsageVanilla.csproj", "{840EA1CA-62FF-409E-89F5-CD3BB269BAE3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{247DE17A-F9D1-466B-B5C2-32D694D95A9D}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration.Executables", "test\Dapper.AOT.Test.Integration.Executables\Dapper.AOT.Test.Integration.Executables.csproj", "{9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,14 +82,14 @@ Global {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {840EA1CA-62FF-409E-89F5-CD3BB269BAE3}.Release|Any CPU.Build.0 = Release|Any CPU - {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {247DE17A-F9D1-466B-B5C2-32D694D95A9D}.Release|Any CPU.Build.0 = Release|Any CPU {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Debug|Any CPU.Build.0 = Debug|Any CPU {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.ActiveCfg = Release|Any CPU {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8}.Release|Any CPU.Build.0 = Release|Any CPU + {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -103,8 +103,8 @@ Global {A77B633C-573E-43CD-85A4-8063B33143B4} = {FE215D4B-811B-47BB-9F05-6382DD1C6729} {C6527566-38F4-43CC-9E0E-91C4B8854774} = {1135D4FD-770E-41DF-920B-A8F75E42A832} {840EA1CA-62FF-409E-89F5-CD3BB269BAE3} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} - {247DE17A-F9D1-466B-B5C2-32D694D95A9D} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} + {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A89CDAFA-494F-4168-9648-1138BA738D43} diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index f5a92af4..331aaa3e 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -1,30 +1,35 @@ - + - net8.0;net6.0;net48 + net8.0 Dapper.AOT.Test.Integration + enable + + + false + true - - - + + + + + - - - - - + + + + + + - - - - all - runtime; build; native; contentfiles; analyzers - + + + - - - + + + diff --git a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs b/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs deleted file mode 100644 index 29f81237..00000000 --- a/test/Dapper.AOT.Test.Integration/InterceptorsIntegratedTestsBase.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Dapper.AOT.Test.Integration.Executables; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Text; -using Xunit; - -namespace Dapper.AOT.Test.Integration; - -[Collection(SharedPostgresqlClient.Collection)] -public abstract class InterceptorsIntegratedTestsBase -{ - const string UserCodeDir = "UserCode"; - - private readonly IDbConnection _dbConnection; - - public InterceptorsIntegratedTestsBase(PostgresqlFixture fixture) - { - _dbConnection = fixture.NpgsqlConnection; - SetupDatabase(_dbConnection); - } - - /// - /// Use this to make a setup for the test. Works once for the class. - /// Example: create a table on which you will be running tests on. - /// - /// a connection to database tests are running against - protected virtual void SetupDatabase(IDbConnection dbConnection) - { - } - - protected TResult ExecuteUserCode() - where TExecutable : IExecutable - { - var userCodeSource = ReadUserSourceCode(); - var userCodeSyntaxTree = BuildInterceptorEnabledSyntaxTree("UserCode.cs", userCodeSource); - - var anotherCodeSyntax = BuildInterceptorEnabledSyntaxTree("Generated.cs", """ - namespace Dapper.AOT // interceptors must be in a known namespace - { - file static class DapperGeneratedInterceptors - { - [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("UserCode.cs", 14, 34)] - internal static global::System.Collections.Generic.IEnumerable Query0( - this global::System.Data.IDbConnection cnn, - string sql, - object? param = null, - global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) - { - throw new global::System.Exception("this is my test"); - - return new System.Collections.Generic.List(); - } - } - } - - namespace System.Runtime.CompilerServices - { - // this type is needed by the compiler to implement interceptors - it doesn't need to - // come from the runtime itself, though - - [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] - sealed file class InterceptsLocationAttribute : global::System.Attribute - { - public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) - { - _ = path; - _ = lineNumber; - _ = columnNumber; - } - } - } - """); - - var inputCompilation = CSharpCompilation.Create( - assemblyName: "Test.dll", - syntaxTrees: [ userCodeSyntaxTree, anotherCodeSyntax ], - references: GetTestCompilationMetadataReferences(typeof(TExecutable)), - options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - - // var generator = new DapperInterceptorGenerator(); - // GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: InterceptorsEnabledParseOptions); - // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); - - // var assembly = Compile(outputCompilation); - var assembly = Compile(inputCompilation); - - var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); - var executableInstance = (IExecutable)Activator.CreateInstance(type)!; - - var result = executableInstance.Execute(_dbConnection); - return result; - } - - string ReadUserSourceCode() - { - var filePath = Path.Combine(UserCodeDir, $"{typeof(T).Name}.txt"); - if (!File.Exists(filePath)) - { - throw new FileNotFoundException(message: typeof(T).Name, fileName: filePath); - } - - return File.ReadAllText(filePath); - } - - static SyntaxTree BuildInterceptorEnabledSyntaxTree(string filename, string text) - { - var stringText = SourceText.From(text, Encoding.UTF8); - return SyntaxFactory.ParseSyntaxTree(stringText, InterceptorsEnabledParseOptions, filename); - } - - static Assembly Compile(Compilation compilation) - { - using var peStream = new MemoryStream(); - using var pdbstream = new MemoryStream(); - var dbg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; - var emitResult = compilation.Emit(peStream, pdbstream, null, null, null, new EmitOptions(false, dbg)); - if (!emitResult.Success) - { - TryThrowErrors(emitResult.Diagnostics); - } - - peStream.Position = pdbstream.Position = 0; - return Assembly.Load(peStream.ToArray(), pdbstream.ToArray()); - - static void TryThrowErrors(IEnumerable items) - { - var errors = new List(); - foreach (var item in items) - { - if (item.Severity == DiagnosticSeverity.Error) - { - errors.Add(item.GetMessage(CultureInfo.InvariantCulture)); - } - } - - if (errors.Count > 0) - { - throw new ExpressionParsingException(errors); - } - } - } - - MetadataReference[] GetTestCompilationMetadataReferences(Type userCodeType) => - [ - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? - MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? - - MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper - MetadataReference.CreateFromFile(typeof(DapperAotAttribute).Assembly.Location), // Dapper.AOT - - MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq - MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common - - MetadataReference.CreateFromFile(userCodeType.Assembly.Location), // UserCode - ]; - - static CSharpParseOptions InterceptorsEnabledParseOptions - => new CSharpParseOptions(LanguageVersion.Preview).WithFeatures(new[] - { - new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), - }); - - class ExpressionParsingException(IEnumerable errors) : Exception(string.Join(Environment.NewLine, errors)); -} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs b/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs deleted file mode 100644 index 59329192..00000000 --- a/test/Dapper.AOT.Test.Integration/PostgresqlFixture.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Npgsql; -using System.Threading.Tasks; -using Testcontainers.PostgreSql; -using Xunit; - -namespace Dapper.AOT.Test.Integration; - -[CollectionDefinition(Collection)] -public class SharedPostgresqlClient : ICollectionFixture -{ - public const string Collection = nameof(SharedPostgresqlClient); -} - -public sealed class PostgresqlFixture : IAsyncLifetime -{ - private readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder() - .WithImage("postgres:15-alpine") - .Build(); - - public string ConnectionString { get; private set; } = null!; - - private NpgsqlConnection? _sharedConnection; - - public NpgsqlConnection NpgsqlConnection - => _sharedConnection ??= CreateOpenConnection(); - - public NpgsqlConnection CreateOpenConnection() - { - var conn = new NpgsqlConnection(ConnectionString); - conn.Open(); - return conn; - } - - async Task IAsyncLifetime.InitializeAsync() - { - await _postgresContainer.StartAsync(); - ConnectionString = _postgresContainer.GetConnectionString(); - } - - async Task IAsyncLifetime.DisposeAsync() - { - await using (_postgresContainer) - { - var tmp = _sharedConnection; - _sharedConnection = null; - if (tmp is not null) - { - await tmp.DisposeAsync(); - } - } - } -} diff --git a/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs b/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs deleted file mode 100644 index 26c111b5..00000000 --- a/test/Dapper.AOT.Test.Integration/Tests/DbStringIntegrationTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Data; -using Dapper.AOT.Test.Integration.Executables.Models; -using Dapper.AOT.Test.Integration.Executables.UserCode; -using Xunit; - -namespace Dapper.AOT.Test.Integration.Tests; - -[Collection(SharedPostgresqlClient.Collection)] -public class DbStringIntegrationTests : InterceptorsIntegratedTestsBase -{ - public DbStringIntegrationTests(PostgresqlFixture fixture) - : base(fixture) - { - } - - [Fact] - public void SimpleDbString_RunsAgainstDatabase() - { - var result = ExecuteUserCode(); - Assert.NotNull(result); - } - - protected override void SetupDatabase(IDbConnection dbConnection) => dbConnection.Execute(""" - CREATE TABLE IF NOT EXISTS dbString_test( - id integer PRIMARY KEY, - name varchar(40) NOT NULL - ); - TRUNCATE dbString_test; - - INSERT INTO dbString_test(id, name) - VALUES - (1, 'my-string'), - (2, 'another-string'); - """); -} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/UnitTest1.cs b/test/Dapper.AOT.Test.Integration/UnitTest1.cs new file mode 100644 index 00000000..34b86304 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/UnitTest1.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Dapper.AOT.Test.Integration.Executables.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Data.SqlClient; + +namespace Dapper.AOT.Test.Integration; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + string connection = "data source=DMKOR_PC;initial catalog=dapper-experiments;trusted_connection=true;TrustServerCertificate=True"; + IDbConnection dbConnection = new SqlConnection(connection); + // var items = dbConnection.Query("select * from Product"); + // var res = items.FirstOrDefault()?.Name; + + var userCode = Parse("UserCode.cs", $$""" + namespace ProgramNamespace + { + using System; + using System.Linq; + using System.Data; + using Dapper; + using Dapper.AOT.Test.Integration.Executables.Models; + + public static class Program + { + public static DbStringPoco RunCode(IDbConnection dbConnection) + { + var results = dbConnection.Query("select * from table"); + return results.First(); + } + } + } + """); + + var generatedCode = Parse("AnotherFile.cs", $$""" + namespace Dapper.AOT + { + file static class D + { + [System.Runtime.CompilerServices.InterceptsLocation(path: "UserCode.cs", lineNumber: 13, columnNumber: 40)] + internal static global::System.Collections.Generic.IEnumerable Query0( + this global::System.Data.IDbConnection cnn, + string sql, + object? param = null, + global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) + { + return new global::System.Collections.Generic.List() + { + new global::Dapper.AOT.Test.Integration.Executables.Models.DbStringPoco() { Name = "something" } + }; + } + } + + } + """); + + var interceptorsLocationAttributeCode = Parse("InterceptorsLocationAttribute.cs", $$""" + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public sealed class InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) : Attribute + { + } + } + """); + + var compilation = CSharpCompilation.Create( + assemblyName: "Test.dll", + syntaxTrees: [interceptorsLocationAttributeCode, userCode, generatedCode], + references: [ + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? + MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? + + MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper + MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq + + MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common + + MetadataReference.CreateFromFile(typeof(Dapper.AOT.Test.Integration.Executables.UserCode.DbStringUsage).Assembly.Location), // Dapper.AOT.Test.Integration.Executables + ], + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + + var assembly = Compile(compilation); + var type = assembly.GetTypes().Single(t => t.FullName == "ProgramNamespace.Program"); + var mainMethod = type.GetMethod("RunCode", BindingFlags.Public | BindingFlags.Static); + var result = mainMethod!.Invoke(obj: null, [ dbConnection ]); + + Assert.NotNull(result); + if (result is not DbStringPoco typedResult) + { + Assert.Fail($"invocation result is expected to be of type {typeof(DbStringPoco)}"); + return; + } + + Assert.True(typedResult.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); + } + + Assembly Compile(Compilation compilation) + { + using var peStream = new MemoryStream(); + using var pdbstream = new MemoryStream(); + var dbg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; + + var emitResult = compilation.Emit(peStream, pdbstream, null, null, null, new EmitOptions(false, dbg)); + if (!emitResult.Success) + { + TryThrowErrors(emitResult.Diagnostics); + } + + peStream.Position = pdbstream.Position = 0; + return Assembly.Load(peStream.ToArray(), pdbstream.ToArray()); + } + + void TryThrowErrors(IEnumerable items) + { + var errors = new List(); + foreach (var item in items) + { + if (item.Severity == DiagnosticSeverity.Error) + { + errors.Add(item.GetMessage(CultureInfo.InvariantCulture)); + } + } + + if (errors.Count > 0) + { + throw new ExpressionParsingException(errors); + } + } + + SyntaxTree Parse(string filename, string text) + { + var options = new CSharpParseOptions(LanguageVersion.Preview) + .WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), + }); + + var stringText = SourceText.From(text, Encoding.UTF8); + return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); + } + + public class Poco + { + public string Name { get; set; } + } + + public class ExpressionParsingException : Exception + { + public IEnumerable Errors { get; private set; } + + public ExpressionParsingException(IEnumerable errors) + : base(string.Join(Environment.NewLine, errors)) + { + this.Errors = errors; + } + + public ExpressionParsingException(params string[] errors) + : base(string.Join(Environment.NewLine, errors)) + { + this.Errors = errors; + } + } +} \ No newline at end of file From 6622ce8c051c4d2cc6d536f12e29e8c07502d663 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 11:19:05 +0200 Subject: [PATCH 07/42] move pieces around --- .../{UnitTest1.cs => DbStringTests.cs} | 112 ++---------------- .../Helpers/CompilationExtensions.cs | 46 +++++++ .../Setup/ExpressionParsingException.cs | 9 ++ .../Setup/IntegrationTestsBase.cs | 55 +++++++++ 4 files changed, 117 insertions(+), 105 deletions(-) rename test/Dapper.AOT.Test.Integration/{UnitTest1.cs => DbStringTests.cs} (52%) create mode 100644 test/Dapper.AOT.Test.Integration/Helpers/CompilationExtensions.cs create mode 100644 test/Dapper.AOT.Test.Integration/Setup/ExpressionParsingException.cs create mode 100644 test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs diff --git a/test/Dapper.AOT.Test.Integration/UnitTest1.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs similarity index 52% rename from test/Dapper.AOT.Test.Integration/UnitTest1.cs rename to test/Dapper.AOT.Test.Integration/DbStringTests.cs index 34b86304..9b52e9e5 100644 --- a/test/Dapper.AOT.Test.Integration/UnitTest1.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -1,31 +1,28 @@ using System; using System.Collections.Generic; using System.Data; -using System.Globalization; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; using System.Text; using Dapper.AOT.Test.Integration.Executables.Models; +using Dapper.AOT.Test.Integration.Executables.UserCode; +using Dapper.AOT.Test.Integration.Helpers; +using Dapper.AOT.Test.Integration.Setup; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Text; using Microsoft.Data.SqlClient; namespace Dapper.AOT.Test.Integration; -public class UnitTest1 +public class DbStringTests : IntegrationTestsBase { [Fact] public void Test1() { string connection = "data source=DMKOR_PC;initial catalog=dapper-experiments;trusted_connection=true;TrustServerCertificate=True"; IDbConnection dbConnection = new SqlConnection(connection); - // var items = dbConnection.Query("select * from Product"); - // var res = items.FirstOrDefault()?.Name; - + var userCode = Parse("UserCode.cs", $$""" namespace ProgramNamespace { @@ -78,102 +75,7 @@ public sealed class InterceptsLocationAttribute(string path, int lineNumber, int } """); - var compilation = CSharpCompilation.Create( - assemblyName: "Test.dll", - syntaxTrees: [interceptorsLocationAttributeCode, userCode, generatedCode], - references: [ - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? - MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? - - MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper - MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq - - MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common - - MetadataReference.CreateFromFile(typeof(Dapper.AOT.Test.Integration.Executables.UserCode.DbStringUsage).Assembly.Location), // Dapper.AOT.Test.Integration.Executables - ], - options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - - - var assembly = Compile(compilation); - var type = assembly.GetTypes().Single(t => t.FullName == "ProgramNamespace.Program"); - var mainMethod = type.GetMethod("RunCode", BindingFlags.Public | BindingFlags.Static); - var result = mainMethod!.Invoke(obj: null, [ dbConnection ]); - - Assert.NotNull(result); - if (result is not DbStringPoco typedResult) - { - Assert.Fail($"invocation result is expected to be of type {typeof(DbStringPoco)}"); - return; - } - - Assert.True(typedResult.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); - } - - Assembly Compile(Compilation compilation) - { - using var peStream = new MemoryStream(); - using var pdbstream = new MemoryStream(); - var dbg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; - - var emitResult = compilation.Emit(peStream, pdbstream, null, null, null, new EmitOptions(false, dbg)); - if (!emitResult.Success) - { - TryThrowErrors(emitResult.Diagnostics); - } - - peStream.Position = pdbstream.Position = 0; - return Assembly.Load(peStream.ToArray(), pdbstream.ToArray()); - } - - void TryThrowErrors(IEnumerable items) - { - var errors = new List(); - foreach (var item in items) - { - if (item.Severity == DiagnosticSeverity.Error) - { - errors.Add(item.GetMessage(CultureInfo.InvariantCulture)); - } - } - - if (errors.Count > 0) - { - throw new ExpressionParsingException(errors); - } - } - - SyntaxTree Parse(string filename, string text) - { - var options = new CSharpParseOptions(LanguageVersion.Preview) - .WithFeatures(new[] - { - new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), - }); - - var stringText = SourceText.From(text, Encoding.UTF8); - return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); - } - - public class Poco - { - public string Name { get; set; } - } - - public class ExpressionParsingException : Exception - { - public IEnumerable Errors { get; private set; } - - public ExpressionParsingException(IEnumerable errors) - : base(string.Join(Environment.NewLine, errors)) - { - this.Errors = errors; - } - - public ExpressionParsingException(params string[] errors) - : base(string.Join(Environment.NewLine, errors)) - { - this.Errors = errors; - } + var result = ExecuteInterceptedUserCode(dbConnection, [ userCode, generatedCode, interceptorsLocationAttributeCode ]); + Assert.True(result.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Helpers/CompilationExtensions.cs b/test/Dapper.AOT.Test.Integration/Helpers/CompilationExtensions.cs new file mode 100644 index 00000000..d004eaf0 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Helpers/CompilationExtensions.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Dapper.AOT.Test.Integration.Setup; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Emit; + +namespace Dapper.AOT.Test.Integration.Helpers; + +internal static class CompilationExtensions +{ + public static Assembly CompileToAssembly(this Compilation compilation) + { + using var peStream = new MemoryStream(); + using var pdbstream = new MemoryStream(); + var dbg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; + + var emitResult = compilation.Emit(peStream, pdbstream, null, null, null, new EmitOptions(false, dbg)); + if (!emitResult.Success) + { + TryThrowErrors(emitResult.Diagnostics); + } + + peStream.Position = pdbstream.Position = 0; + return Assembly.Load(peStream.ToArray(), pdbstream.ToArray()); + } + + static void TryThrowErrors(IEnumerable items) + { + var errors = new List(); + foreach (var item in items) + { + if (item.Severity == DiagnosticSeverity.Error) + { + errors.Add(item.GetMessage(CultureInfo.InvariantCulture)); + } + } + + if (errors.Count > 0) + { + throw new ExpressionParsingException(errors); + } + } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Setup/ExpressionParsingException.cs b/test/Dapper.AOT.Test.Integration/Setup/ExpressionParsingException.cs new file mode 100644 index 00000000..46ef7fc2 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Setup/ExpressionParsingException.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; + +namespace Dapper.AOT.Test.Integration.Setup; + +class ExpressionParsingException(IEnumerable errors) + : Exception(string.Join(Environment.NewLine, errors)) +{ +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs new file mode 100644 index 00000000..cb12dbde --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using Dapper.AOT.Test.Integration.Helpers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +namespace Dapper.AOT.Test.Integration.Setup; + +public abstract class IntegrationTestsBase +{ + protected TResult ExecuteInterceptedUserCode( + IDbConnection dbConnection, + SyntaxTree[] syntaxTrees) + { + + var compilation = CSharpCompilation.Create( + assemblyName: "Test.dll", + syntaxTrees: syntaxTrees, + references: [ + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? + MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? + + MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper + MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq + + MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common + + MetadataReference.CreateFromFile(typeof(Dapper.AOT.Test.Integration.Executables.UserCode.DbStringUsage).Assembly.Location), // Dapper.AOT.Test.Integration.Executables + ], + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var assembly = compilation.CompileToAssembly(); + var type = assembly.GetTypes().Single(t => t.FullName == "ProgramNamespace.Program"); + var mainMethod = type.GetMethod("RunCode", BindingFlags.Public | BindingFlags.Static); + var result = mainMethod!.Invoke(obj: null, [ dbConnection ]); + + return (TResult)result!; + } + + protected SyntaxTree Parse(string filename, string text) + { + var options = new CSharpParseOptions(LanguageVersion.Preview) + .WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), + }); + + var stringText = SourceText.From(text, Encoding.UTF8); + return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); + } +} \ No newline at end of file From 5854b98e2a7b44ac6f593fe5a43b72a187177e9e Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 15:20:32 +0200 Subject: [PATCH 08/42] make it work with executable assembly! --- .../DbStringTests.cs | 44 ++++++++++--------- .../Setup/IntegrationTestsBase.cs | 26 ++++++++--- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration/DbStringTests.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs index 9b52e9e5..42db87d8 100644 --- a/test/Dapper.AOT.Test.Integration/DbStringTests.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -44,26 +44,26 @@ public static DbStringPoco RunCode(IDbConnection dbConnection) """); var generatedCode = Parse("AnotherFile.cs", $$""" - namespace Dapper.AOT - { - file static class D - { - [System.Runtime.CompilerServices.InterceptsLocation(path: "UserCode.cs", lineNumber: 13, columnNumber: 40)] - internal static global::System.Collections.Generic.IEnumerable Query0( - this global::System.Data.IDbConnection cnn, - string sql, - object? param = null, - global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) - { - return new global::System.Collections.Generic.List() - { - new global::Dapper.AOT.Test.Integration.Executables.Models.DbStringPoco() { Name = "something" } - }; - } - } - - } - """); + namespace Dapper.AOT + { + file static class D + { + [System.Runtime.CompilerServices.InterceptsLocation(path: "UserCode.cs", lineNumber: 12, columnNumber: 34)] + internal static global::System.Collections.Generic.IEnumerable Query0( + this global::System.Data.IDbConnection cnn, + string sql, + object? param = null, + global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) + { + return new global::System.Collections.Generic.List() + { + new global::Dapper.AOT.Test.Integration.Executables.Models.DbStringPoco() { Id = 42, Name = "something" } + }; + } + } + + } + """); var interceptorsLocationAttributeCode = Parse("InterceptorsLocationAttribute.cs", $$""" namespace System.Runtime.CompilerServices @@ -75,7 +75,9 @@ public sealed class InterceptsLocationAttribute(string path, int lineNumber, int } """); - var result = ExecuteInterceptedUserCode(dbConnection, [ userCode, generatedCode, interceptorsLocationAttributeCode ]); + var result = ExecuteInterceptedUserCode(dbConnection, [ generatedCode, interceptorsLocationAttributeCode ]); + + Assert.True(result.Id.Equals(42)); Assert.True(result.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index cb12dbde..0a83673c 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Data; +using System.IO; using System.Linq; using System.Reflection; using System.Text; +using Dapper.AOT.Test.Integration.Executables; using Dapper.AOT.Test.Integration.Helpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -14,9 +17,12 @@ public abstract class IntegrationTestsBase { protected TResult ExecuteInterceptedUserCode( IDbConnection dbConnection, - SyntaxTree[] syntaxTrees) + IList syntaxTrees) { - + var userSourceCode = ReadUserSourceCode(); + var userSourceCodeSyntaxTree = Parse("UserCode.cs", userSourceCode); + syntaxTrees.Add(userSourceCodeSyntaxTree); + var compilation = CSharpCompilation.Create( assemblyName: "Test.dll", syntaxTrees: syntaxTrees, @@ -25,6 +31,7 @@ protected TResult ExecuteInterceptedUserCode( MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper + MetadataReference.CreateFromFile(typeof(Dapper.CommandFactory).Assembly.Location), // Dapper.AOT MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common @@ -34,9 +41,10 @@ protected TResult ExecuteInterceptedUserCode( options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var assembly = compilation.CompileToAssembly(); - var type = assembly.GetTypes().Single(t => t.FullName == "ProgramNamespace.Program"); - var mainMethod = type.GetMethod("RunCode", BindingFlags.Public | BindingFlags.Static); - var result = mainMethod!.Invoke(obj: null, [ dbConnection ]); + var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); + var executableInstance = Activator.CreateInstance(type); + var mainMethod = type.GetMethod(nameof(IExecutable.Execute), BindingFlags.Public | BindingFlags.Instance); + var result = mainMethod!.Invoke(obj: executableInstance, [ dbConnection ]); return (TResult)result!; } @@ -52,4 +60,10 @@ protected SyntaxTree Parse(string filename, string text) var stringText = SourceText.From(text, Encoding.UTF8); return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); } + + private static string ReadUserSourceCode() + { + var userTypeName = typeof(TExecutable).Name; + return File.ReadAllText(Path.Combine("UserCode", $"{userTypeName}.txt")); + } } \ No newline at end of file From eac14e33b4068c9868ffa35d0e4edebccc96d967 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 15:47:42 +0200 Subject: [PATCH 09/42] omg it works. --- .../Dapper.AOT.Test.Integration.csproj | 1 + .../DbStringTests.cs | 10 +--- .../Setup/IntegrationTestsBase.cs | 46 +++++++++++-------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index 331aaa3e..488abb9f 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -29,6 +29,7 @@ + diff --git a/test/Dapper.AOT.Test.Integration/DbStringTests.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs index 42db87d8..2d339126 100644 --- a/test/Dapper.AOT.Test.Integration/DbStringTests.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -1,16 +1,8 @@ using System; -using System.Collections.Generic; using System.Data; -using System.Linq; -using System.Reflection; -using System.Text; using Dapper.AOT.Test.Integration.Executables.Models; using Dapper.AOT.Test.Integration.Executables.UserCode; -using Dapper.AOT.Test.Integration.Helpers; using Dapper.AOT.Test.Integration.Setup; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; using Microsoft.Data.SqlClient; namespace Dapper.AOT.Test.Integration; @@ -75,7 +67,7 @@ public sealed class InterceptsLocationAttribute(string path, int lineNumber, int } """); - var result = ExecuteInterceptedUserCode(dbConnection, [ generatedCode, interceptorsLocationAttributeCode ]); + var result = ExecuteInterceptedUserCode(dbConnection); Assert.True(result.Id.Equals(42)); Assert.True(result.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index 0a83673c..188f18c6 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -7,6 +7,7 @@ using System.Text; using Dapper.AOT.Test.Integration.Executables; using Dapper.AOT.Test.Integration.Helpers; +using Dapper.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; @@ -15,32 +16,45 @@ namespace Dapper.AOT.Test.Integration.Setup; public abstract class IntegrationTestsBase { - protected TResult ExecuteInterceptedUserCode( - IDbConnection dbConnection, - IList syntaxTrees) + static readonly CSharpParseOptions InterceptorSupportedParseOptions = new CSharpParseOptions(LanguageVersion.Preview) + .WithFeatures(new[] + { + new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), + }); + + protected TResult ExecuteInterceptedUserCode(IDbConnection dbConnection) { var userSourceCode = ReadUserSourceCode(); - var userSourceCodeSyntaxTree = Parse("UserCode.cs", userSourceCode); - syntaxTrees.Add(userSourceCodeSyntaxTree); - var compilation = CSharpCompilation.Create( + var inputCompilation = CSharpCompilation.Create( assemblyName: "Test.dll", - syntaxTrees: syntaxTrees, + syntaxTrees: [ Parse("UserCode.cs", userSourceCode) ], references: [ - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // System.Runtime ? - MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), // System.Runtime ? + // dotnet System.Runtime + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), + // Dapper and Dapper.AOT MetadataReference.CreateFromFile(typeof(Dapper.SqlMapper).Assembly.Location), // Dapper MetadataReference.CreateFromFile(typeof(Dapper.CommandFactory).Assembly.Location), // Dapper.AOT - MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), // System.Linq + // user code + MetadataReference.CreateFromFile(typeof(Dapper.AOT.Test.Integration.Executables.UserCode.DbStringUsage).Assembly.Location), // Dapper.AOT.Test.Integration.Executables + + // dependencies + MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location), // System.Data.Common - MetadataReference.CreateFromFile(typeof(Dapper.AOT.Test.Integration.Executables.UserCode.DbStringUsage).Assembly.Location), // Dapper.AOT.Test.Integration.Executables + // Additional stuff required by Dapper.AOT generators + MetadataReference.CreateFromFile(Assembly.Load("System.Collections").Location), // System.Collections ], options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var generator = new DapperInterceptorGenerator(); + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: InterceptorSupportedParseOptions); + driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); - var assembly = compilation.CompileToAssembly(); + var assembly = outputCompilation.CompileToAssembly(); var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); var executableInstance = Activator.CreateInstance(type); var mainMethod = type.GetMethod(nameof(IExecutable.Execute), BindingFlags.Public | BindingFlags.Instance); @@ -51,14 +65,8 @@ protected TResult ExecuteInterceptedUserCode( protected SyntaxTree Parse(string filename, string text) { - var options = new CSharpParseOptions(LanguageVersion.Preview) - .WithFeatures(new[] - { - new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), - }); - var stringText = SourceText.From(text, Encoding.UTF8); - return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); + return SyntaxFactory.ParseSyntaxTree(stringText, InterceptorSupportedParseOptions, filename); } private static string ReadUserSourceCode() From 4eec1c3bc446aa115252c14939c9e5595cc31c44 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 16:08:26 +0200 Subject: [PATCH 10/42] use existing local machine table name --- .../Models/DbStringPoco.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs index d4e70f9c..a1d1cc9c 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs @@ -2,7 +2,7 @@ public class DbStringPoco { - public const string TableName = "dbString_test"; + public const string TableName = "Product"; public int Id { get; set; } public string Name { get; set; } From 0a7d0de7882bf512848a89b42c26537ea8dc6501 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Thu, 1 Aug 2024 20:57:13 +0200 Subject: [PATCH 11/42] record stack traces --- .../DapperInterceptorGenerator.cs | 28 +++++++++- ...er.AOT.Test.Integration.Executables.csproj | 1 + .../ExceptedCodeInterceptorRecorder.cs | 51 +++++++++++++++++++ .../Recording/IInterceptorRecorder.cs | 19 +++++++ .../Recording/InterceptorRecorderResolver.cs | 9 ++++ .../Setup/IntegrationTestsBase.cs | 13 ++++- 6 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 test/Dapper.AOT.Test.Integration.Executables/ExceptedCodeInterceptorRecorder.cs create mode 100644 test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs create mode 100644 test/Dapper.AOT.Test.Integration.Executables/Recording/InterceptorRecorderResolver.cs diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs index 702feb08..006efcfe 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs @@ -16,7 +16,6 @@ using System.Diagnostics; using System.Globalization; using System.Linq; -using System.Runtime.InteropServices.ComTypes; using System.Text; using System.Threading; using static Dapper.Internal.Inspection; @@ -26,12 +25,32 @@ namespace Dapper.CodeAnalysis; [Generator(LanguageNames.CSharp), DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed partial class DapperInterceptorGenerator : InterceptorGeneratorBase { + private readonly bool _withInterceptionRecording = false; + public override ImmutableArray SupportedDiagnostics => DiagnosticsBase.All(); #pragma warning disable CS0067 // unused; retaining for now public event Action? Log; #pragma warning restore CS0067 + /// + /// Creates an interceptor generator for Dapper + /// + public DapperInterceptorGenerator() + { + } + + /// + /// Creates an interceptor generator for Dapper used for Tests. + /// + /// + /// It will insert very specific call with known method name. + /// + internal DapperInterceptorGenerator(bool withInterceptionRecording) + { + _withInterceptionRecording = withInterceptionRecording; + } + public override void Initialize(IncrementalGeneratorInitializationContext context) { var nodes = context.SyntaxProvider.CreateSyntaxProvider(PreFilter, Parse) @@ -360,6 +379,13 @@ internal void Generate(in GenerateState ctx) sb.NewLine(); + if (_withInterceptionRecording) + { + sb.Append("global::Dapper.AOT.Test.Integration.Executables.Recording.InterceptorRecorderResolver.Resolve().Record();").NewLine(); + } + + sb.NewLine(); + if (flags.HasAny(OperationFlags.GetRowParser)) { WriteGetRowParser(sb, resultType, readers); diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index dcb3aa8e..ee0dd780 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -9,6 +9,7 @@ + diff --git a/test/Dapper.AOT.Test.Integration.Executables/ExceptedCodeInterceptorRecorder.cs b/test/Dapper.AOT.Test.Integration.Executables/ExceptedCodeInterceptorRecorder.cs new file mode 100644 index 00000000..76f6c489 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/ExceptedCodeInterceptorRecorder.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Text; +using Dapper.AOT.Test.Integration.Executables.Recording; +using Dapper.CodeAnalysis; + +namespace Dapper.AOT.Test.Integration.Executables; + +public class ExceptedCodeInterceptorRecorder : IInterceptorRecorder +{ + readonly string expectedFileName; + + public ExceptedCodeInterceptorRecorder(string expectedFileName) + { + this.expectedFileName = expectedFileName ?? throw new ArgumentNullException(nameof(expectedFileName)); + } + + public bool WasCalled { get; private set; } + public string? Diagnostics { get; private set; } + + public void Record() + { + WasCalled = true; + var diagnostics = new StringBuilder(); + + var stackTrace = new StackTrace(fNeedFileInfo: true); + var recentFrames = stackTrace.GetFrames().Take(15).ToList(); // we dont need everything + + var userCodeFrameIndex = recentFrames.FindIndex(frame => + frame.GetFileName()?.Contains(expectedFileName) == true && frame.GetMethod()?.Name.Equals(nameof(IExecutable.Execute)) == true); + if (userCodeFrameIndex == -1) + { + diagnostics.AppendLine("- User code execution is not found"); + } + + var dapperInterceptionFrameIndex = recentFrames.FindIndex(frame => + frame.GetFileName()?.Contains(".generated.cs") == true && frame.GetFileName()?.Contains(nameof(DapperInterceptorGenerator)) == true); + if (dapperInterceptionFrameIndex == -1) + { + diagnostics.AppendLine("- User code execution is not found"); + } + + if (userCodeFrameIndex < dapperInterceptionFrameIndex) + { + diagnostics.AppendLine("- User code call should be higher (executed before) on the stack trace than intercepted code"); + } + + Diagnostics = diagnostics.ToString(); + } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs b/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs new file mode 100644 index 00000000..1689330f --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs @@ -0,0 +1,19 @@ +namespace Dapper.AOT.Test.Integration.Executables.Recording; + +public interface IInterceptorRecorder +{ + /// + /// returns true if expected interception was called + /// + public bool WasCalled { get; } + + /// + /// Returns diagnostics of recording + /// + public string Diagnostics { get; } + + /// + /// Is executed in the interception + /// + public void Record(); +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration.Executables/Recording/InterceptorRecorderResolver.cs b/test/Dapper.AOT.Test.Integration.Executables/Recording/InterceptorRecorderResolver.cs new file mode 100644 index 00000000..c6119701 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration.Executables/Recording/InterceptorRecorderResolver.cs @@ -0,0 +1,9 @@ +namespace Dapper.AOT.Test.Integration.Executables.Recording; + +public static class InterceptorRecorderResolver +{ + static IInterceptorRecorder? _recorder; + + public static IInterceptorRecorder? Resolve() => _recorder; + public static void Register(IInterceptorRecorder? recorder) => _recorder = recorder; +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index 188f18c6..0913fbf0 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Text; using Dapper.AOT.Test.Integration.Executables; +using Dapper.AOT.Test.Integration.Executables.Recording; using Dapper.AOT.Test.Integration.Helpers; using Dapper.CodeAnalysis; using Microsoft.CodeAnalysis; @@ -16,6 +17,8 @@ namespace Dapper.AOT.Test.Integration.Setup; public abstract class IntegrationTestsBase { + private const string UserCodeFileName = "UserCode.cs"; + static readonly CSharpParseOptions InterceptorSupportedParseOptions = new CSharpParseOptions(LanguageVersion.Preview) .WithFeatures(new[] { @@ -28,7 +31,7 @@ protected TResult ExecuteInterceptedUserCode(IDbConnection var inputCompilation = CSharpCompilation.Create( assemblyName: "Test.dll", - syntaxTrees: [ Parse("UserCode.cs", userSourceCode) ], + syntaxTrees: [ Parse(UserCodeFileName, userSourceCode) ], references: [ // dotnet System.Runtime MetadataReference.CreateFromFile(typeof(object).Assembly.Location), @@ -50,7 +53,10 @@ protected TResult ExecuteInterceptedUserCode(IDbConnection ], options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - var generator = new DapperInterceptorGenerator(); + var interceptorRecorder = new ExceptedCodeInterceptorRecorder(UserCodeFileName); + InterceptorRecorderResolver.Register(interceptorRecorder); + + var generator = new DapperInterceptorGenerator(withInterceptionRecording: true); GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: InterceptorSupportedParseOptions); driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); @@ -60,6 +66,9 @@ protected TResult ExecuteInterceptedUserCode(IDbConnection var mainMethod = type.GetMethod(nameof(IExecutable.Execute), BindingFlags.Public | BindingFlags.Instance); var result = mainMethod!.Invoke(obj: executableInstance, [ dbConnection ]); + Assert.True(interceptorRecorder.WasCalled); + Assert.True(string.IsNullOrEmpty(interceptorRecorder.Diagnostics), userMessage: interceptorRecorder.Diagnostics); + return (TResult)result!; } From fca167536251095227f206911859b42bbd0fb6cb Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 00:39:25 +0200 Subject: [PATCH 12/42] remove package versions --- Directory.Packages.props | 1 + .../DapperInterceptorGenerator.cs | 1 + .../Models/DbStringPoco.cs | 2 +- .../Dapper.AOT.Test.Integration.csproj | 21 +++---- .../DbStringTests.cs | 56 +------------------ 5 files changed, 13 insertions(+), 68 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index f55151ed..9f46eee9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,6 +13,7 @@ + diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs index 006efcfe..1f6a3a87 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs @@ -45,6 +45,7 @@ public DapperInterceptorGenerator() /// /// /// It will insert very specific call with known method name. + /// Users will not have a reference to inserted assembly code, therefore: don't make it public /// internal DapperInterceptorGenerator(bool withInterceptionRecording) { diff --git a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs index a1d1cc9c..d0fa8bf2 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs @@ -4,6 +4,6 @@ public class DbStringPoco { public const string TableName = "Product"; - public int Id { get; set; } + public int ProductId { get; set; } public string Name { get; set; } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index 488abb9f..acc12960 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -11,20 +11,15 @@ - - - - - + + + + + + + + - - - - - - - - diff --git a/test/Dapper.AOT.Test.Integration/DbStringTests.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs index 2d339126..725f5c85 100644 --- a/test/Dapper.AOT.Test.Integration/DbStringTests.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -14,62 +14,10 @@ public void Test1() { string connection = "data source=DMKOR_PC;initial catalog=dapper-experiments;trusted_connection=true;TrustServerCertificate=True"; IDbConnection dbConnection = new SqlConnection(connection); - - var userCode = Parse("UserCode.cs", $$""" - namespace ProgramNamespace - { - using System; - using System.Linq; - using System.Data; - using Dapper; - using Dapper.AOT.Test.Integration.Executables.Models; - - public static class Program - { - public static DbStringPoco RunCode(IDbConnection dbConnection) - { - var results = dbConnection.Query("select * from table"); - return results.First(); - } - } - } - """); - - var generatedCode = Parse("AnotherFile.cs", $$""" - namespace Dapper.AOT - { - file static class D - { - [System.Runtime.CompilerServices.InterceptsLocation(path: "UserCode.cs", lineNumber: 12, columnNumber: 34)] - internal static global::System.Collections.Generic.IEnumerable Query0( - this global::System.Data.IDbConnection cnn, - string sql, - object? param = null, - global::System.Data.IDbTransaction? transaction = null, bool buffered = true, int? commandTimeout = null, global::System.Data.CommandType? commandType = null) - { - return new global::System.Collections.Generic.List() - { - new global::Dapper.AOT.Test.Integration.Executables.Models.DbStringPoco() { Id = 42, Name = "something" } - }; - } - } - - } - """); - - var interceptorsLocationAttributeCode = Parse("InterceptorsLocationAttribute.cs", $$""" - namespace System.Runtime.CompilerServices - { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public sealed class InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) : Attribute - { - } - } - """); var result = ExecuteInterceptedUserCode(dbConnection); - Assert.True(result.Id.Equals(42)); - Assert.True(result.Name.Equals("something", StringComparison.InvariantCultureIgnoreCase)); + Assert.True(result.ProductId.Equals(1)); + Assert.True(result.Name.Equals("MyProduct", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file From a0594849a9e86c570652d953b43fcf3673d57e4f Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 00:54:14 +0200 Subject: [PATCH 13/42] refactor dependencies --- Dapper.AOT.sln | 7 +++++++ ...apper.AOT.Test.Integration.Executables.csproj | 3 +-- .../Dapper.AOT.Test.Integration.csproj | 1 + test/Dapper.AOT.Test/Dapper.AOT.Test.csproj | 9 +++++++-- .../Integration/BatchPostgresql.cs | 1 + .../Integration/PostgresqlFixture.cs | 6 +++--- test/Test.Common/Test.Common.csproj | 16 ++++++++++++++++ 7 files changed, 36 insertions(+), 7 deletions(-) rename test/{Dapper.AOT.Test => Test.Common}/Integration/PostgresqlFixture.cs (93%) create mode 100644 test/Test.Common/Test.Common.csproj diff --git a/Dapper.AOT.sln b/Dapper.AOT.sln index 12dc26d7..21177b1d 100644 --- a/Dapper.AOT.sln +++ b/Dapper.AOT.sln @@ -44,6 +44,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Common", "test\Test.Common\Test.Common.csproj", "{8C0F671E-8A72-4C36-9F84-3A8F79D887CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -90,6 +92,10 @@ Global {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.Build.0 = Release|Any CPU + {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -105,6 +111,7 @@ Global {840EA1CA-62FF-409E-89F5-CD3BB269BAE3} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} + {8C0F671E-8A72-4C36-9F84-3A8F79D887CA} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A89CDAFA-494F-4168-9648-1138BA738D43} diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index ee0dd780..3a6e6ebe 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -12,8 +12,7 @@ - - + diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index acc12960..333b478d 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -26,6 +26,7 @@ + diff --git a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj index d03ac661..dc6719f9 100644 --- a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj +++ b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj @@ -46,8 +46,6 @@ runtime; build; native; contentfiles; analyzers - - @@ -57,6 +55,13 @@ + + + + + + + diff --git a/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs b/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs index 55fb266c..6cf85625 100644 --- a/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs +++ b/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs @@ -1,5 +1,6 @@ using System.Data; using System.Linq; +using Test.Common.Integration; using Xunit; namespace Dapper.AOT.Test.Integration; diff --git a/test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs b/test/Test.Common/Integration/PostgresqlFixture.cs similarity index 93% rename from test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs rename to test/Test.Common/Integration/PostgresqlFixture.cs index 59329192..b7fca378 100644 --- a/test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs +++ b/test/Test.Common/Integration/PostgresqlFixture.cs @@ -1,9 +1,9 @@ -using Npgsql; -using System.Threading.Tasks; +using System.Threading.Tasks; +using Npgsql; using Testcontainers.PostgreSql; using Xunit; -namespace Dapper.AOT.Test.Integration; +namespace Test.Common.Integration; [CollectionDefinition(Collection)] public class SharedPostgresqlClient : ICollectionFixture diff --git a/test/Test.Common/Test.Common.csproj b/test/Test.Common/Test.Common.csproj new file mode 100644 index 00000000..cc47a7ef --- /dev/null +++ b/test/Test.Common/Test.Common.csproj @@ -0,0 +1,16 @@ + + + + net8.0;net6.0;net48 + enable + + Test.Common + + + + + + + + + From a642e60c6fe016161476e42fbcd69bdab2b735a6 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 01:16:13 +0200 Subject: [PATCH 14/42] YES!!! YES!!! YES!!! YES!!! YES!!! YES!!! YES!!! --- Dapper.AOT.sln | 7 --- ...er.AOT.Test.Integration.Executables.csproj | 10 +--- .../Models/DbStringPoco.cs | 4 +- .../Dapper.AOT.Test.Integration.csproj | 4 +- .../DbStringTests.cs | 34 ++++++++++--- .../Setup/IntegrationTestsBase.cs | 13 ++++- .../Setup/PostgresqlFixture.cs | 51 +++++++++++++++++++ .../Integration/BatchPostgresql.cs | 1 - .../Integration/PostgresqlFixture.cs | 2 +- test/Test.Common/Test.Common.csproj | 16 ------ 10 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs rename test/{Test.Common => Dapper.AOT.Test}/Integration/PostgresqlFixture.cs (97%) delete mode 100644 test/Test.Common/Test.Common.csproj diff --git a/Dapper.AOT.sln b/Dapper.AOT.sln index 21177b1d..12dc26d7 100644 --- a/Dapper.AOT.sln +++ b/Dapper.AOT.sln @@ -44,8 +44,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.AOT.Test.Integration", "test\Dapper.AOT.Test.Integration\Dapper.AOT.Test.Integration.csproj", "{CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Common", "test\Test.Common\Test.Common.csproj", "{8C0F671E-8A72-4C36-9F84-3A8F79D887CA}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -92,10 +90,6 @@ Global {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB}.Release|Any CPU.Build.0 = Release|Any CPU - {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C0F671E-8A72-4C36-9F84-3A8F79D887CA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -111,7 +105,6 @@ Global {840EA1CA-62FF-409E-89F5-CD3BB269BAE3} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} {9FA6A3B4-5722-40B2-8B58-F418F5D8C9A8} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} {CAB51448-4F0D-497B-A035-2B7ACB2DD9EB} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} - {8C0F671E-8A72-4C36-9F84-3A8F79D887CA} = {9A846B95-90CE-4335-9043-48C5B8EA4FB8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A89CDAFA-494F-4168-9648-1138BA738D43} diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 3a6e6ebe..091d19d8 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -8,6 +8,7 @@ + @@ -22,15 +23,6 @@ - - $([System.String]::Copy(%(Filename)).Replace('.txt', '.cs')) - - - - - - - diff --git a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs index d0fa8bf2..ed41851c 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/Models/DbStringPoco.cs @@ -2,8 +2,8 @@ public class DbStringPoco { - public const string TableName = "Product"; + public const string TableName = "dbStringPoco"; - public int ProductId { get; set; } + public int Id { get; set; } public string Name { get; set; } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index 333b478d..d0242051 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -15,6 +15,9 @@ + + + @@ -26,7 +29,6 @@ - diff --git a/test/Dapper.AOT.Test.Integration/DbStringTests.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs index 725f5c85..afc1497a 100644 --- a/test/Dapper.AOT.Test.Integration/DbStringTests.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -3,21 +3,41 @@ using Dapper.AOT.Test.Integration.Executables.Models; using Dapper.AOT.Test.Integration.Executables.UserCode; using Dapper.AOT.Test.Integration.Setup; -using Microsoft.Data.SqlClient; namespace Dapper.AOT.Test.Integration; +[Collection(SharedPostgresqlClient.Collection)] public class DbStringTests : IntegrationTestsBase { + public DbStringTests(PostgresqlFixture fixture) : base(fixture) + { + } + + protected override void SetupDatabase(IDbConnection dbConnection) + { + base.SetupDatabase(dbConnection); + + dbConnection.Execute($""" + CREATE TABLE IF NOT EXISTS {DbStringPoco.TableName}( + id integer PRIMARY KEY, + name varchar(40) + ); + + TRUNCATE {DbStringPoco.TableName}; + + INSERT INTO {DbStringPoco.TableName} (id, name) + VALUES (1, 'my-dbString'), + (2, 'my-poco'), + (3, 'your-data'); + """); + } + [Fact] public void Test1() { - string connection = "data source=DMKOR_PC;initial catalog=dapper-experiments;trusted_connection=true;TrustServerCertificate=True"; - IDbConnection dbConnection = new SqlConnection(connection); - - var result = ExecuteInterceptedUserCode(dbConnection); + var result = ExecuteInterceptedUserCode(DbConnection); - Assert.True(result.ProductId.Equals(1)); - Assert.True(result.Name.Equals("MyProduct", StringComparison.InvariantCultureIgnoreCase)); + Assert.True(result.Id.Equals(1)); + Assert.True(result.Name.Equals("my-dbString", StringComparison.InvariantCultureIgnoreCase)); } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index 0913fbf0..6b5f9ea9 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -18,12 +18,23 @@ namespace Dapper.AOT.Test.Integration.Setup; public abstract class IntegrationTestsBase { private const string UserCodeFileName = "UserCode.cs"; - static readonly CSharpParseOptions InterceptorSupportedParseOptions = new CSharpParseOptions(LanguageVersion.Preview) .WithFeatures(new[] { new KeyValuePair("InterceptorsPreviewNamespaces", "$(InterceptorsPreviewNamespaces);Dapper.AOT"), }); + + protected readonly IDbConnection DbConnection; + + protected IntegrationTestsBase(PostgresqlFixture fixture) + { + DbConnection = fixture.NpgsqlConnection; + SetupDatabase(DbConnection); + } + + protected virtual void SetupDatabase(IDbConnection dbConnection) + { + } protected TResult ExecuteInterceptedUserCode(IDbConnection dbConnection) { diff --git a/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs b/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs new file mode 100644 index 00000000..60fd87d1 --- /dev/null +++ b/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Npgsql; +using Testcontainers.PostgreSql; + +namespace Dapper.AOT.Test.Integration.Setup; + +[CollectionDefinition(Collection)] +public class SharedPostgresqlClient : ICollectionFixture +{ + public const string Collection = nameof(SharedPostgresqlClient); +} + +public sealed class PostgresqlFixture : IAsyncLifetime +{ + private readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder() + .WithImage("postgres:15-alpine") + .Build(); + + public string ConnectionString { get; private set; } = null!; + + private NpgsqlConnection? _sharedConnection; + + public NpgsqlConnection NpgsqlConnection + => _sharedConnection ??= CreateOpenConnection(); + + public NpgsqlConnection CreateOpenConnection() + { + var conn = new NpgsqlConnection(ConnectionString); + conn.Open(); + return conn; + } + + async Task IAsyncLifetime.InitializeAsync() + { + await _postgresContainer.StartAsync(); + ConnectionString = _postgresContainer.GetConnectionString(); + } + + async Task IAsyncLifetime.DisposeAsync() + { + await using (_postgresContainer) + { + var tmp = _sharedConnection; + _sharedConnection = null; + if (tmp is not null) + { + await tmp.DisposeAsync(); + } + } + } +} diff --git a/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs b/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs index 6cf85625..55fb266c 100644 --- a/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs +++ b/test/Dapper.AOT.Test/Integration/BatchPostgresql.cs @@ -1,6 +1,5 @@ using System.Data; using System.Linq; -using Test.Common.Integration; using Xunit; namespace Dapper.AOT.Test.Integration; diff --git a/test/Test.Common/Integration/PostgresqlFixture.cs b/test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs similarity index 97% rename from test/Test.Common/Integration/PostgresqlFixture.cs rename to test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs index b7fca378..b2b5e506 100644 --- a/test/Test.Common/Integration/PostgresqlFixture.cs +++ b/test/Dapper.AOT.Test/Integration/PostgresqlFixture.cs @@ -3,7 +3,7 @@ using Testcontainers.PostgreSql; using Xunit; -namespace Test.Common.Integration; +namespace Dapper.AOT.Test.Integration; [CollectionDefinition(Collection)] public class SharedPostgresqlClient : ICollectionFixture diff --git a/test/Test.Common/Test.Common.csproj b/test/Test.Common/Test.Common.csproj deleted file mode 100644 index cc47a7ef..00000000 --- a/test/Test.Common/Test.Common.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - net8.0;net6.0;net48 - enable - - Test.Common - - - - - - - - - From 3dede8165374b3ce0bba86649e186706216098f0 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 01:28:44 +0200 Subject: [PATCH 15/42] fix dbstring global namespace + adjust test for DbString --- src/Dapper.AOT.Analyzers/Internal/Inspection.cs | 3 +-- .../UserCode/DbStringUsage.cs | 10 +++++++++- test/Dapper.AOT.Test.Integration/DbStringTests.cs | 2 +- .../Setup/IntegrationTestsBase.cs | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Dapper.AOT.Analyzers/Internal/Inspection.cs b/src/Dapper.AOT.Analyzers/Internal/Inspection.cs index 00c4d359..8c13195a 100644 --- a/src/Dapper.AOT.Analyzers/Internal/Inspection.cs +++ b/src/Dapper.AOT.Analyzers/Internal/Inspection.cs @@ -504,8 +504,7 @@ public DapperSpecialType DapperSpecialType TypeKind: TypeKind.Class, ContainingNamespace: { - Name: "Dapper", - IsGlobalNamespace: true + Name: "Dapper" } }) return DapperSpecialType.DbString; diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs index 735ae4f8..a3181881 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/UserCode/DbStringUsage.cs @@ -9,7 +9,15 @@ public class DbStringUsage : IExecutable { public DbStringPoco Execute(IDbConnection connection) { - var results = connection.Query($"select * from {DbStringPoco.TableName}"); + var results = connection.Query( + $"select * from {DbStringPoco.TableName} where name = @name", + new + { + name = new DbString + { + Value = "my-dbString" + } + }); return results.First(); } } \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/DbStringTests.cs b/test/Dapper.AOT.Test.Integration/DbStringTests.cs index afc1497a..9822803e 100644 --- a/test/Dapper.AOT.Test.Integration/DbStringTests.cs +++ b/test/Dapper.AOT.Test.Integration/DbStringTests.cs @@ -33,7 +33,7 @@ name varchar(40) } [Fact] - public void Test1() + public void DbString_BasicUsage_InterceptsAndReturnsExpectedData() { var result = ExecuteInterceptedUserCode(DbConnection); diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index 6b5f9ea9..f7111dbf 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -83,7 +83,7 @@ protected TResult ExecuteInterceptedUserCode(IDbConnection return (TResult)result!; } - protected SyntaxTree Parse(string filename, string text) + private static SyntaxTree Parse(string filename, string text) { var stringText = SourceText.From(text, Encoding.UTF8); return SyntaxFactory.ParseSyntaxTree(stringText, InterceptorSupportedParseOptions, filename); From d3cfa7f8d1ef77588fe12aebe1485f3a7f9fa699 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 01:31:39 +0200 Subject: [PATCH 16/42] and run tests for new proj --- .github/workflows/dotnet.yml | 3 +++ test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index d3140df0..dc4e1ca7 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -40,6 +40,9 @@ jobs: - name: Test run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration + + - name: Integration Tests + run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --verbosity normal -c Release - name: Pack if: ${{ success() && !github.base_ref }} diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index f7111dbf..5a27eda7 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -69,7 +69,7 @@ protected TResult ExecuteInterceptedUserCode(IDbConnection var generator = new DapperInterceptorGenerator(withInterceptionRecording: true); GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: InterceptorSupportedParseOptions); - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); var assembly = outputCompilation.CompileToAssembly(); var type = assembly.GetTypes().Single(t => t.FullName == typeof(TExecutable).FullName); From 4a3ea61066b6f93289fc2045f63b8f1863fd9330 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 01:42:12 +0200 Subject: [PATCH 17/42] last minute review --- .../CodeAnalysis/DapperInterceptorGenerator.cs | 4 ++-- .../InGeneration/InterceptsLocationAttribute.cs | 2 +- .../Setup/PostgresqlFixture.cs | 4 ++-- test/Dapper.AOT.Test/Dapper.AOT.Test.csproj | 8 ++------ 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs index 1f6a3a87..951a1060 100644 --- a/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs +++ b/src/Dapper.AOT.Analyzers/CodeAnalysis/DapperInterceptorGenerator.cs @@ -382,10 +382,10 @@ internal void Generate(in GenerateState ctx) if (_withInterceptionRecording) { + sb.Append("// record interception for tests assertions").NewLine(); sb.Append("global::Dapper.AOT.Test.Integration.Executables.Recording.InterceptorRecorderResolver.Resolve().Record();").NewLine(); + sb.NewLine(); } - - sb.NewLine(); if (flags.HasAny(OperationFlags.GetRowParser)) { diff --git a/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs b/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs index 163a9606..996bc00a 100644 --- a/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs +++ b/src/Dapper.AOT.Analyzers/InGeneration/InterceptsLocationAttribute.cs @@ -3,7 +3,7 @@ // this type is needed by the compiler to implement interceptors - it doesn't need to // come from the runtime itself, though - // [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate + [global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] sealed file class InterceptsLocationAttribute : global::System.Attribute { diff --git a/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs b/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs index 60fd87d1..0d85fff2 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/PostgresqlFixture.cs @@ -1,5 +1,5 @@ -using System.Threading.Tasks; -using Npgsql; +using Npgsql; +using System.Threading.Tasks; using Testcontainers.PostgreSql; namespace Dapper.AOT.Test.Integration.Setup; diff --git a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj index dc6719f9..663a4053 100644 --- a/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj +++ b/test/Dapper.AOT.Test/Dapper.AOT.Test.csproj @@ -29,6 +29,7 @@ + @@ -36,6 +37,7 @@ + @@ -59,11 +61,5 @@ - - - - - - From fb04933ead56db0984ea79c23039b53abb17216e Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 02:06:25 +0200 Subject: [PATCH 18/42] rollback package updates (they break tests) --- Directory.Packages.props | 78 ++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 9f46eee9..37851bc2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 237d55edf2b8fa74e61bdf6780543006d935cde8 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 2 Aug 2024 02:11:56 +0200 Subject: [PATCH 19/42] remove coverlet collector --- .../Dapper.AOT.Test.Integration.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index d0242051..baf13f64 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -11,7 +11,6 @@ - From 1b405e6efb0168877a465cc06caad5464ff6527e Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 14:01:51 +0200 Subject: [PATCH 20/42] use sln --- .github/workflows/dotnet.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index dc4e1ca7..de5cecd4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -30,16 +30,16 @@ jobs: setAllVars: true - name: Restore dependencies - run: dotnet restore Build.csproj + run: dotnet restore Dapper.AOT.sln - name: Purge run: del src/Dapper.*/bin/Release/Dapper.*.nupkg - name: Build - run: dotnet build Build.csproj --no-restore -c Release + run: dotnet build Dapper.AOT.sln --no-restore -c Release - name: Test - run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration + run: dotnet test Dapper.AOT.sln --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration - name: Integration Tests run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --verbosity normal -c Release From 6e9f7c16a079fdb4a82fbcb3cc91345e6ee35856 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 14:14:31 +0200 Subject: [PATCH 21/42] internal visible to --- src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs diff --git a/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs b/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9b169302 --- /dev/null +++ b/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapper.AOT.Test.Integration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a17ba361da0990b3da23f3c20f2a002242397b452a28f27832d61d49f35edb54a68b98d98557b8a02be79be42142339c7861af309c8917dee972775e2c358dd6b96109a9147987652b25b8dc52e7f61f22a755831674f0a3cea17bef9abb6b23ef1856a02216864a1ffbb04a4c549258d32ba740fe141dad2f298a8130ea56d0")] \ No newline at end of file From 5bf27d123c3dddc96cc2dda6847a558aa6bddfb3 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 14:24:44 +0200 Subject: [PATCH 22/42] try specific routes --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index de5cecd4..9bc93ee3 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -39,7 +39,7 @@ jobs: run: dotnet build Dapper.AOT.sln --no-restore -c Release - name: Test - run: dotnet test Dapper.AOT.sln --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration + run: dotnet test test/Dapper.AOT.Test/Dapper.AOT.Test.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration - name: Integration Tests run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --verbosity normal -c Release From 45bd482221ccc601c18c35b6abe78cf6d0d0926f Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 16:11:13 +0200 Subject: [PATCH 23/42] dont build it --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 9bc93ee3..f6112082 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -42,7 +42,7 @@ jobs: run: dotnet test test/Dapper.AOT.Test/Dapper.AOT.Test.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration - name: Integration Tests - run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --verbosity normal -c Release + run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Release - name: Pack if: ${{ success() && !github.base_ref }} From 23065ae93e426d2c97453bd467772a7832a2070c Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 17:17:08 +0200 Subject: [PATCH 24/42] try with ubuntu agents --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index f6112082..0832b730 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -10,7 +10,7 @@ on: jobs: build: - runs-on: windows-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 From ac7b910c432125a448a9b5db28668de0eb17f20f Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 3 Aug 2024 17:21:41 +0200 Subject: [PATCH 25/42] rollback CI\CD + create another for integrations on ubuntu --- .github/workflows/dotnet-integration.yml | 39 ++++++++++++ .github/workflows/dotnet.yml | 79 ++++++++++++------------ Dapper.AOT.sln | 1 + 3 files changed, 78 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/dotnet-integration.yml diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml new file mode 100644 index 00000000..39424dbe --- /dev/null +++ b/.github/workflows/dotnet-integration.yml @@ -0,0 +1,39 @@ +name: .NET + +on: + workflow_dispatch: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # depth is needed for nbgv + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: | + 6.0.x + 8.0.x + include-prerelease: true + + - uses: dotnet/nbgv@master + with: + setAllVars: true + + - name: Restore dependencies + run: dotnet restore Dapper.AOT.sln + + - name: Build + run: dotnet build Dapper.AOT.sln --no-restore -c Release + + - name: Integration Tests + run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Release \ No newline at end of file diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 0832b730..a45009ae 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -10,46 +10,43 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: windows-latest steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 # depth is needed for nbgv - - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 6.0.x - 8.0.x - include-prerelease: true - - - uses: dotnet/nbgv@master - with: - setAllVars: true - - - name: Restore dependencies - run: dotnet restore Dapper.AOT.sln - - - name: Purge - run: del src/Dapper.*/bin/Release/Dapper.*.nupkg - - - name: Build - run: dotnet build Dapper.AOT.sln --no-restore -c Release - - - name: Test - run: dotnet test test/Dapper.AOT.Test/Dapper.AOT.Test.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration - - - name: Integration Tests - run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Release - - - name: Pack - if: ${{ success() && !github.base_ref }} - run: dotnet pack src/Dapper.AOT/Dapper.AOT.csproj --no-build --verbosity normal -c Release - - - name: Push to MyGet - if: ${{ success() && !github.base_ref }} - run: dotnet nuget push src/Dapper.*/bin/Release/Dapper.*.nupkg --source https://www.myget.org/F/dapper/api/v2/package --api-key "$env:MYGETAPIKEY" - env: - MYGETAPIKEY: ${{ secrets.MYGETAPIKEY }} + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # depth is needed for nbgv + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: | + 6.0.x + 8.0.x + include-prerelease: true + + - uses: dotnet/nbgv@master + with: + setAllVars: true + + - name: Restore dependencies + run: dotnet restore Build.csproj + + - name: Purge + run: del src/Dapper.*/bin/Release/Dapper.*.nupkg + + - name: Build + run: dotnet build Build.csproj --no-restore -c Release + + - name: Test + run: dotnet test Build.csproj --no-build --verbosity normal -c Release -f net6.0 --filter FullyQualifiedName!~Integration + + - name: Pack + if: ${{ success() && !github.base_ref }} + run: dotnet pack src/Dapper.AOT/Dapper.AOT.csproj --no-build --verbosity normal -c Release + + - name: Push to MyGet + if: ${{ success() && !github.base_ref }} + run: dotnet nuget push src/Dapper.*/bin/Release/Dapper.*.nupkg --source https://www.myget.org/F/dapper/api/v2/package --api-key "$env:MYGETAPIKEY" + env: + MYGETAPIKEY: ${{ secrets.MYGETAPIKEY }} \ No newline at end of file diff --git a/Dapper.AOT.sln b/Dapper.AOT.sln index 12dc26d7..0942f68d 100644 --- a/Dapper.AOT.sln +++ b/Dapper.AOT.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.props = Directory.Build.props Directory.Packages.props = Directory.Packages.props .github\workflows\dotnet.yml = .github\workflows\dotnet.yml + .github\workflows\dotnet-integration.yml = .github\workflows\dotnet-integration.yml global.json = global.json nuget.config = nuget.config README.md = README.md From b312ca1b9e5d89c5687c6e650054fad8b62b97d5 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Wed, 7 Aug 2024 11:25:28 +0200 Subject: [PATCH 26/42] fix for dbstring + rename CI --- .github/workflows/dotnet-integration.yml | 2 +- src/Dapper.AOT.Analyzers/Internal/Inspection.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index 39424dbe..423e38aa 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -1,4 +1,4 @@ -name: .NET +name: Integration Tests on: workflow_dispatch: diff --git a/src/Dapper.AOT.Analyzers/Internal/Inspection.cs b/src/Dapper.AOT.Analyzers/Internal/Inspection.cs index 8c13195a..4e172c87 100644 --- a/src/Dapper.AOT.Analyzers/Internal/Inspection.cs +++ b/src/Dapper.AOT.Analyzers/Internal/Inspection.cs @@ -504,7 +504,8 @@ public DapperSpecialType DapperSpecialType TypeKind: TypeKind.Class, ContainingNamespace: { - Name: "Dapper" + Name: "Dapper", + ContainingNamespace.IsGlobalNamespace: true } }) return DapperSpecialType.DbString; From b6eb0886f7e852e07a8777582e04d07c1164a770 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:01:54 +0200 Subject: [PATCH 27/42] debug test --- .github/workflows/dotnet-integration.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index 423e38aa..da6b6427 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -23,17 +23,13 @@ jobs: dotnet-version: | 6.0.x 8.0.x - include-prerelease: true - - - uses: dotnet/nbgv@master - with: - setAllVars: true - - - name: Restore dependencies - run: dotnet restore Dapper.AOT.sln + include-prerelease: true - name: Build - run: dotnet build Dapper.AOT.sln --no-restore -c Release + run: dotnet build Dapper.AOT.sln -c Release + + - name: [Debug] Check Files + run: ls -R - name: Integration Tests run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Release \ No newline at end of file From ea09276d640c548452224525c645bc5dc63aa4a0 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:05:39 +0200 Subject: [PATCH 28/42] fix naming --- .github/workflows/dotnet-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index da6b6427..a6fa97f0 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -28,7 +28,7 @@ jobs: - name: Build run: dotnet build Dapper.AOT.sln -c Release - - name: [Debug] Check Files + - name: '[Debug] Check Files' run: ls -R - name: Integration Tests From fae081fb14eeb98693a9f3002125f99389ce3aee Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:17:39 +0200 Subject: [PATCH 29/42] try publish directory --- .../Dapper.AOT.Test.Integration.Executables.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 091d19d8..01a77bda 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -22,7 +22,7 @@ - + From ae69d7b5f7ca20f9079b525f85afd8ad0d78ad33 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:26:36 +0200 Subject: [PATCH 30/42] move item group --- .../Dapper.AOT.Test.Integration.Executables.csproj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 01a77bda..3c985088 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -20,9 +20,10 @@ + + + + - - - From 1dd69c7752ec20bcef856766018b5c94c479d587 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:33:41 +0200 Subject: [PATCH 31/42] get logs from build --- .github/workflows/dotnet-integration.yml | 2 +- .../Dapper.AOT.Test.Integration.Executables.csproj | 7 +++---- .../Recording/IInterceptorRecorder.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index a6fa97f0..6a9b7420 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,7 +26,7 @@ jobs: include-prerelease: true - name: Build - run: dotnet build Dapper.AOT.sln -c Release + run: dotnet build Dapper.AOT.sln -c Release --verbosity detailed - name: '[Debug] Check Files' run: ls -R diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 3c985088..01a77bda 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -20,10 +20,9 @@ - - - - + + + diff --git a/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs b/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs index 1689330f..02ef13df 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs +++ b/test/Dapper.AOT.Test.Integration.Executables/Recording/IInterceptorRecorder.cs @@ -10,7 +10,7 @@ public interface IInterceptorRecorder /// /// Returns diagnostics of recording /// - public string Diagnostics { get; } + public string? Diagnostics { get; } /// /// Is executed in the interception From bf2d64de11c2df2d65a67419021a31aa4b686a5b Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:37:49 +0200 Subject: [PATCH 32/42] maybe slash can fix it? --- .../Dapper.AOT.Test.Integration.Executables.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index 01a77bda..fb1d8740 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -23,6 +23,7 @@ + From 1da057b8a89ba730e964d5787a4f79673a34c814 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:41:29 +0200 Subject: [PATCH 33/42] remove detailed verbosity --- .github/workflows/dotnet-integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index 6a9b7420..d341855d 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,10 +26,10 @@ jobs: include-prerelease: true - name: Build - run: dotnet build Dapper.AOT.sln -c Release --verbosity detailed + run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug - name: '[Debug] Check Files' run: ls -R - name: Integration Tests - run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Release \ No newline at end of file + run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Debug \ No newline at end of file From 35b6bd9d95bb740c64ad6eb106923fa8004efd97 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 9 Aug 2024 02:44:51 +0200 Subject: [PATCH 34/42] . --- .../Dapper.AOT.Test.Integration.Executables.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index fb1d8740..be767819 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -22,8 +22,7 @@ - - + From 5e379cedd8316730fa07682e94b79fa82e6ef3f5 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 12:23:28 +0200 Subject: [PATCH 35/42] always? --- .github/workflows/dotnet-integration.yml | 2 +- .../Dapper.AOT.Test.Integration.Executables.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index d341855d..f0a303d0 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,7 +26,7 @@ jobs: include-prerelease: true - name: Build - run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug + run: dotnet build Dapper.AOT.sln -c Debug - name: '[Debug] Check Files' run: ls -R diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index be767819..abcef60a 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -22,7 +22,7 @@ - + From 436e611507e29653a119b25d43c9fea12f82aa60 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 12:54:39 +0200 Subject: [PATCH 36/42] test on wsl --- .../Dapper.AOT.Test.Integration.Executables.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index abcef60a..b96051e3 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -1,5 +1,4 @@  - net8.0;net6.0;net48 Dapper.AOT.Test.Integration.Executables @@ -16,13 +15,14 @@ - + + - + + + + - - - From ea553baaa3b832ba1423ae68f012ea0b4c3d195c Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 12:56:41 +0200 Subject: [PATCH 37/42] build only test proj --- .github/workflows/dotnet-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index f0a303d0..d341855d 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,7 +26,7 @@ jobs: include-prerelease: true - name: Build - run: dotnet build Dapper.AOT.sln -c Debug + run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug - name: '[Debug] Check Files' run: ls -R From 17f53c857ab99d54fb977d7b8ebf5c51e81850fd Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 13:03:26 +0200 Subject: [PATCH 38/42] move it to integration directly --- .../Dapper.AOT.Test.Integration.Executables.csproj | 12 ------------ .../Dapper.AOT.Test.Integration.csproj | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj index b96051e3..828f4929 100644 --- a/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj +++ b/test/Dapper.AOT.Test.Integration.Executables/Dapper.AOT.Test.Integration.Executables.csproj @@ -12,17 +12,5 @@ - - - - - - - - - - - - diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index baf13f64..66d4ae55 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -30,4 +30,16 @@ + + + + + + + + + + + + From 9c4fbf5d83cbcd3453a48428296f694249dab523 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 13:24:21 +0200 Subject: [PATCH 39/42] give me logs --- .github/workflows/dotnet-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index d341855d..2e29b5f6 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,7 +26,7 @@ jobs: include-prerelease: true - name: Build - run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug + run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug --verbosity detailed - name: '[Debug] Check Files' run: ls -R From b8d55cb5620e5da8b7a93d62a07bc5076c836330 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 15:11:46 +0200 Subject: [PATCH 40/42] dont use copy at all --- .../UserCode/.gitignore | 1 - .../Dapper.AOT.Test.Integration.csproj | 14 -------------- .../Setup/IntegrationTestsBase.cs | 6 +++++- 3 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore diff --git a/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore b/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore deleted file mode 100644 index ce525563..00000000 --- a/test/Dapper.AOT.Test.Integration.Executables/UserCode/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**.txt \ No newline at end of file diff --git a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj index 66d4ae55..e69aaed0 100644 --- a/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj +++ b/test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj @@ -4,8 +4,6 @@ net8.0 Dapper.AOT.Test.Integration enable - - false true @@ -30,16 +28,4 @@ - - - - - - - - - - - - diff --git a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs index 5a27eda7..762259de 100644 --- a/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs +++ b/test/Dapper.AOT.Test.Integration/Setup/IntegrationTestsBase.cs @@ -92,6 +92,10 @@ private static SyntaxTree Parse(string filename, string text) private static string ReadUserSourceCode() { var userTypeName = typeof(TExecutable).Name; - return File.ReadAllText(Path.Combine("UserCode", $"{userTypeName}.txt")); + + // it's very fragile to get user code cs files into output directory (btw we can't remove them from compilation, because we will use them for assertions) + // so let's simply get back to test\ dir, and try to find Executables.UserCode from there + var testDir = Directory.GetParent(Directory.GetParent(Directory.GetParent(Directory.GetParent(Directory.GetCurrentDirectory())!.FullName)!.FullName)!.FullName); + return File.ReadAllText(Path.Combine(testDir!.FullName, "Dapper.AOT.Test.Integration.Executables", "UserCode", $"{userTypeName}.cs")); } } \ No newline at end of file From 93cb89a8c6721bc8177560bd7632dc58c1a39b22 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Sat, 10 Aug 2024 15:15:10 +0200 Subject: [PATCH 41/42] cleanup debug CI --- .github/workflows/dotnet-integration.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dotnet-integration.yml b/.github/workflows/dotnet-integration.yml index 2e29b5f6..5bd5a8f9 100644 --- a/.github/workflows/dotnet-integration.yml +++ b/.github/workflows/dotnet-integration.yml @@ -26,10 +26,7 @@ jobs: include-prerelease: true - name: Build - run: dotnet build test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj -c Debug --verbosity detailed + run: dotnet build Dapper.AOT.sln -c Debug - - name: '[Debug] Check Files' - run: ls -R - - - name: Integration Tests + - name: E2E Tests run: dotnet test test/Dapper.AOT.Test.Integration/Dapper.AOT.Test.Integration.csproj --no-build --verbosity normal -c Debug \ No newline at end of file From 01203859389fb9e3e00c4af96d1430672fffe8be Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Fri, 23 Aug 2024 11:19:26 +0200 Subject: [PATCH 42/42] move to csproj --- src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj | 4 ++++ src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) delete mode 100644 src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs diff --git a/src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj b/src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj index 47f8010a..0a113eb8 100644 --- a/src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj +++ b/src/Dapper.AOT.Analyzers/Dapper.AOT.Analyzers.csproj @@ -59,4 +59,8 @@ DapperAnalyzer.cs + + + + diff --git a/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs b/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs deleted file mode 100644 index 9b169302..00000000 --- a/src/Dapper.AOT.Analyzers/Properties/AssemblyInfo.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapper.AOT.Test.Integration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a17ba361da0990b3da23f3c20f2a002242397b452a28f27832d61d49f35edb54a68b98d98557b8a02be79be42142339c7861af309c8917dee972775e2c358dd6b96109a9147987652b25b8dc52e7f61f22a755831674f0a3cea17bef9abb6b23ef1856a02216864a1ffbb04a4c549258d32ba740fe141dad2f298a8130ea56d0")] \ No newline at end of file