Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create test projects #149

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions DllImportGenerator/Demo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ partial class NativeExportsNE
public static partial void Sum(int a, ref int b);
}

unsafe class Program
class Program
{
static void Main(string[] args)
{
Expand All @@ -31,13 +31,6 @@ static void Main(string[] args)
c = b;
NativeExportsNE.Sum(a, ref c);
Console.WriteLine($"{a} + {b} = {c}");

SafeHandleTests tests = new SafeHandleTests();

tests.ReturnValue_CreatesSafeHandle();
tests.ByValue_CorrectlyUnwrapsHandle();
tests.ByRefSameValue_UsesSameHandleInstance();
tests.ByRefDifferentValue_UsesNewHandleInstance();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Ancillary.Interop\Ancillary.Interop.csproj" />
<ProjectReference Include="..\DllImportGenerator\DllImportGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\TestAssets\NativeExports\NativeExports.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@

using System.Runtime.InteropServices;

using Microsoft.Win32.SafeHandles;
using Xunit;

namespace Demo
namespace DllImportGenerator.IntegrationTests
{
partial class NativeExportsNE
{
public class NativeExportsSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private NativeExportsSafeHandle() : base(true)
{
}
private NativeExportsSafeHandle() : base(ownsHandle: true)
{ }

protected override bool ReleaseHandle()
{
Assert.True(NativeExportsNE.ReleaseHandle(handle));
return true;
bool didRelease = NativeExportsNE.ReleaseHandle(handle);
Assert.True(didRelease);
return didRelease;
}
}

Expand Down Expand Up @@ -57,7 +57,7 @@ public void ByRefSameValue_UsesSameHandleInstance()
{
using NativeExportsNE.NativeExportsSafeHandle handleToDispose = NativeExportsNE.AllocateHandle();
NativeExportsNE.NativeExportsSafeHandle handle = handleToDispose;
NativeExportsNE.ModifyHandle(ref handle, false);
NativeExportsNE.ModifyHandle(ref handle, newHandle: false);
Assert.Same(handleToDispose, handle);
}

Expand All @@ -66,7 +66,7 @@ public void ByRefDifferentValue_UsesNewHandleInstance()
{
using NativeExportsNE.NativeExportsSafeHandle handleToDispose = NativeExportsNE.AllocateHandle();
NativeExportsNE.NativeExportsSafeHandle handle = handleToDispose;
NativeExportsNE.ModifyHandle(ref handle, true);
NativeExportsNE.ModifyHandle(ref handle, newHandle: true);
Assert.NotSame(handleToDispose, handle);
handle.Dispose();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;

namespace DllImportGenerator.Test
namespace DllImportGenerator.UnitTests
{
internal static class CodeSnippets
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Threading.Tasks;
using Xunit;

namespace DllImportGenerator.Test
namespace DllImportGenerator.UnitTests
{
public class CompileFails
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Threading.Tasks;
using Xunit;

namespace DllImportGenerator.Test
namespace DllImportGenerator.UnitTests
{
public class Compiles
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using Xunit;
using static Microsoft.Interop.ManualTypeMarshallingAnalyzer;

using VerifyCS = DllImportGenerator.Test.Verifiers.CSharpAnalyzerVerifier<Microsoft.Interop.ManualTypeMarshallingAnalyzer>;
using VerifyCS = DllImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier<Microsoft.Interop.ManualTypeMarshallingAnalyzer>;

namespace DllImportGenerator.Test
namespace DllImportGenerator.UnitTests
{
public class ManualTypeMarshallingAnalyzerTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading.Tasks;
using Xunit;

namespace DllImportGenerator.Test
namespace DllImportGenerator.UnitTests
{
internal static class TestUtils
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;

namespace DllImportGenerator.Test.Verifiers
namespace DllImportGenerator.UnitTests.Verifiers
{
public static class CSharpAnalyzerVerifier<TAnalyzer>
where TAnalyzer : DiagnosticAnalyzer, new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace DllImportGenerator.Test.Verifiers
namespace DllImportGenerator.UnitTests.Verifiers
{
internal static class CSharpVerifierHelper
{
Expand Down
10 changes: 8 additions & 2 deletions DllImportGenerator/DllImportGenerator.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ VisualStudioVersion = 16.0.30204.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator", "DllImportGenerator\DllImportGenerator.csproj", "{0E14E01F-A582-4D22-8737-BF9DE5270435}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator.Test", "DllImportGenerator.Test\DllImportGenerator.Test.csproj", "{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator.UnitTests", "DllImportGenerator.UnitTests\DllImportGenerator.UnitTests.csproj", "{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "Demo\Demo.csproj", "{E478EE77-E072-4A42-B453-EBFDA7728717}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ancillary.Interop", "Ancillary.Interop\Ancillary.Interop.csproj", "{E59F0B6A-1137-4179-A91D-33464A775DEB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestAssets", "TestAssets", "{2CFB9A7A-4AAF-4B6A-8CC8-540F64C3B45F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeExports", "TestAssets\NativeExports\NativeExports.csproj", "{32FDA079-0E9F-4A36-ADA5-6593B67A54AC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeExports", "TestAssets\NativeExports\NativeExports.csproj", "{32FDA079-0E9F-4A36-ADA5-6593B67A54AC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllImportGenerator.IntegrationTests", "DllImportGenerator.IntegrationTests\DllImportGenerator.IntegrationTests.csproj", "{162C204A-ED59-4EF3-A5FA-E58CC06FAB4D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{69D56AC9-232B-4E76-B6C1-33A7B06B6855}"
EndProject
Expand Down Expand Up @@ -49,6 +51,10 @@ Global
{6FD4AF19-0CAA-413C-A2BD-C888AA2E8CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD4AF19-0CAA-413C-A2BD-C888AA2E8CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FD4AF19-0CAA-413C-A2BD-C888AA2E8CFB}.Release|Any CPU.Build.0 = Release|Any CPU
{162C204A-ED59-4EF3-A5FA-E58CC06FAB4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{162C204A-ED59-4EF3-A5FA-E58CC06FAB4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{162C204A-ED59-4EF3-A5FA-E58CC06FAB4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{162C204A-ED59-4EF3-A5FA-E58CC06FAB4D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;

namespace NativeExports
{
public unsafe class ScalarOps
public static unsafe class Demo
{
[UnmanagedCallersOnly(EntryPoint = "sumi")]
public static int Sum(int a, int b)
Expand Down
30 changes: 16 additions & 14 deletions DllImportGenerator/TestAssets/NativeExports/Handles.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;


namespace NativeExports
{
public static unsafe class Handles
{
/// <summary>
/// Using <see cref="Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid"/> in tests.
/// </summary>
private const nint InvalidHandle = -1;

private static nint LastHandle = 0;

private static HashSet<nint> ActiveHandles = new HashSet<nint>();
private static readonly HashSet<nint> ActiveHandles = new HashSet<nint>();

[UnmanagedCallersOnly(EntryPoint = "alloc_handle")]
public static nint AllocateHandle()
{
return AllocateHandleCore();
}

private static nint AllocateHandleCore()
{
if (LastHandle == int.MaxValue)
{
return InvalidHandle;
}

nint newHandle = ++LastHandle;
ActiveHandles.Add(newHandle);
return newHandle;
}

[UnmanagedCallersOnly(EntryPoint = "release_handle")]
public static byte ReleaseHandle(nint handle)
{
Expand All @@ -50,5 +40,17 @@ public static void ModifyHandle(nint* handle, byte newHandle)
*handle = AllocateHandleCore();
}
}

private static nint AllocateHandleCore()
{
if (LastHandle == int.MaxValue)
{
return InvalidHandle;
}

nint newHandle = ++LastHandle;
ActiveHandles.Add(newHandle);
return newHandle;
}
}
}
33 changes: 21 additions & 12 deletions DllImportGenerator/readme.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
# DllImport Generator

See [P/Invoke source generator proposal](https://github.com/dotnet/runtime/blob/master/docs/design/features/source-generator-pinvokes.md) for design and goals.
Work on this project can be tracked and discussed via the [official issue](https://github.com/dotnet/runtime/issues/43060) in `dotnet/runtime`. The [P/Invoke source generator proposal](https://github.com/dotnet/runtime/blob/master/docs/design/features/source-generator-pinvokes.md) contains additional details.

## Additional work
## Example

Below are additional work items that are not presently captured in this repository.
The [Demo project](./DllImportGenerator/Demo) project is designed to be immediately consumable by everyone. It demonstrates a simple use case where the marshalling code is generated and a native function call with only [blittable types](https://docs.microsoft.com/dotnet/framework/interop/blittable-and-non-blittable-types) is made. A managed assembly with [native exports](./DllImportGenerator/TestAssets/NativeExports) is used in the P/Invoke scenario.

### Required
### Recommended scenarios:

* Step into the `Demo` application and observe the generated code for the `Sum` functions.
* Find the implementation of the `sumrefi` function and set a breakpoint. Run the debugger and explore the stack.
* Add a new export in the `NativeExports` project and update the `Demo` application to call the new export.
* Consider the differences and try the above scenarios when building in `Debug` or `Release`.

* Add `GeneratedDllImportAttribute` to the BCL. See [`GeneratedDllImportAttribute.cs`](./Ancillary.Interop/GeneratedDllImportAttribute.cs).
* Add support for calling [`SetLastError()`](https://docs.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror) from managed code with the expected semantics. During P/Invoke transitions the runtime manipulates the associated thread's error code and thus breaks `SetLastError()` semantics.
## Designs

* APIs to handle [`SafeHandle`](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.safehandle) manipulation.
- [Code generation pipeline](./designs/Pipeline.md)
- [Struct Marshalling](./designs/StructMarshalling.md)

### Optional
## Workflow

* A tool to compare the resulting IL from the generated source to that generated by the built-in IL Marshaller system. This would help with validation of what is being generated.
On Windows, loading the [solution](./DllImportGenerator.sln) in [Visual Studio](https://visualstudio.microsoft.com/) 2019 or later will enable the edit, build, debug inner dev loop. All features of Visual Studio are expected to operate correctly (e.g. Debugger, Test runner, Profiler).

## Designs
On non-Windows platforms, all features of the `dotnet` command line tool are supported for the respective project types (e.g. `build`, `run`, `test`).

- [Code generation pipeline](./designs/Pipeline.md)
- [Struct Marshalling](./designs/StructMarshalling.md)
A consistent cross-platform inner dev loop is also supported in [Visual Studio Code](https://code.visualstudio.com/) when appropriate .NET extensions are loaded.

Most of the above options have [official tutorials](https://docs.microsoft.com/dotnet/core/tutorials/). It is an aim of this project to follow canonical workflows that are intuitive to all developers.

### Testing assets

This project has no explicit native build system and should remain that way. The [`DNNE`](https://github.com/AaronRobinsonMSFT/DNNE/) project is be leveraged to create native exports that can be called from the P/Invokes during testing.