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

Failure test cases. #35

Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 29 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/CodeSnippets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,35 @@ partial class Test
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method(int t = 0);
}
";

/// <summary>
/// Declaration with user defined attributes with prefixed name.
/// </summary>
public static readonly string UserDefinedPrefixedAttributes = @"
using System;
using System.Runtime.InteropServices;

namespace System.Runtime.InteropServices
{
// Prefix with ATTRIBUTE so the lengths will match during check.
sealed class ATTRIBUTEGeneratedDllImportAttribute : Attribute
{
public ATTRIBUTEGeneratedDllImportAttribute(string a) { }
}
}

partial class Test
{
[ATTRIBUTEGeneratedDllImportAttribute(""DoesNotExist"")]
public static partial void Method1();

[ATTRIBUTEGeneratedDllImport(""DoesNotExist"")]
public static partial void Method2();

[System.Runtime.InteropServices.ATTRIBUTEGeneratedDllImport(""DoesNotExist"")]
public static partial void Method3();
}
";
}
}
39 changes: 39 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/CompileFails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using Xunit;

namespace DllImportGenerator.Test
{
public class CompileFails
{
public static IEnumerable<object[]> CodeSnippetsToCompile()
{
yield return new object[] { CodeSnippets.UserDefinedPrefixedAttributes, 3 };
}

[Theory]
[MemberData(nameof(CodeSnippetsToCompile))]
public void ValidateSnippets(string source, int failCount)
{
Compilation comp = TestUtils.CreateCompilation(source);
TestUtils.AssertPreSourceGeneratorCompilation(comp);

var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.DllImportGenerator());
Assert.Empty(generatorDiags);

var newCompDiags = newComp.GetDiagnostics();

// Verify the compilation failed with missing impl.
int missingImplCount = 0;
foreach (var diag in newCompDiags)
{
if ("CS8795".Equals(diag.Id))
{
missingImplCount++;
}
}

Assert.Equal(failCount, missingImplCount);
}
}
}
36 changes: 3 additions & 33 deletions DllImportGenerator/DllImportGenerator.Test/Compiles.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Xunit;

namespace DllImportGenerator.Test
Expand All @@ -26,40 +22,14 @@ public static IEnumerable<object[]> CodeSnippetsToCompile()
[MemberData(nameof(CodeSnippetsToCompile))]
public void ValidateSnippets(string source)
{
Compilation comp = CreateCompilation(source);
var compDiags = comp.GetDiagnostics();
foreach (var diag in compDiags)
{
Assert.True(
"CS8795".Equals(diag.Id) // Partial method impl missing
|| "CS0234".Equals(diag.Id) // Missing type or namespace - GeneratedDllImportAttribute
|| "CS0246".Equals(diag.Id) // Missing type or namespace - GeneratedDllImportAttribute
|| "CS8019".Equals(diag.Id)); // Unnecessary using
}
Compilation comp = TestUtils.CreateCompilation(source);
TestUtils.AssertPreSourceGeneratorCompilation(comp);

var newComp = RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.DllImportGenerator());
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.DllImportGenerator());
Assert.Empty(generatorDiags);

var newCompDiags = newComp.GetDiagnostics();
Assert.Empty(newCompDiags);
}

private static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(outputKind));

private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators)
=> new CSharpGeneratorDriver(c.SyntaxTrees.First().Options,
ImmutableArray.Create(generators),
null,
ImmutableArray<AdditionalText>.Empty);

private static Compilation RunGenerators(Compilation c, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators)
{
CreateDriver(c, generators).RunFullGeneration(c, out var d, out diagnostics);
return d;
}
}
}
61 changes: 61 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/TestUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Xunit;

namespace DllImportGenerator.Test
{
internal static class TestUtils
{
/// <summary>
/// Assert the pre-srouce generator compilation has only
/// the expected failure diagnostics.
/// </summary>
/// <param name="comp"></param>
public static void AssertPreSourceGeneratorCompilation(Compilation comp)
{
var compDiags = comp.GetDiagnostics();
foreach (var diag in compDiags)
{
Assert.True(
"CS8795".Equals(diag.Id) // Partial method impl missing
|| "CS0234".Equals(diag.Id) // Missing type or namespace - GeneratedDllImportAttribute
|| "CS0246".Equals(diag.Id) // Missing type or namespace - GeneratedDllImportAttribute
|| "CS8019".Equals(diag.Id)); // Unnecessary using
}
}

/// <summary>
/// Create a compilation given source
/// </summary>
/// <param name="source">Source to compile</param>
/// <param name="outputKind">Output type</param>
/// <returns>The resulting compilation</returns>
public static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(outputKind));

/// <summary>
/// Run the supplied generators on the compilation.
/// </summary>
/// <param name="comp">Compilation target</param>
/// <param name="diagnostics">Resulting diagnostics</param>
/// <param name="generators">Source generator instances</param>
/// <returns>The resulting compilation</returns>
public static Compilation RunGenerators(Compilation comp, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators)
{
CreateDriver(comp, generators).RunFullGeneration(comp, out var d, out diagnostics);
return d;
}

private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators)
=> new CSharpGeneratorDriver(c.SyntaxTrees.First().Options,
ImmutableArray.Create(generators),
null,
ImmutableArray<AdditionalText>.Empty);
}
}
18 changes: 16 additions & 2 deletions DllImportGenerator/DllImportGenerator/DllImportGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,22 @@ public void Initialize(InitializationContext context)
private static bool IsGeneratedDllImportAttribute(AttributeSyntax attrSyntaxMaybe)
{
var attrName = attrSyntaxMaybe.Name.ToString();
return attrName.EndsWith(GeneratedDllImport)
|| attrName.EndsWith(GeneratedDllImportAttribute);

if (attrName.Length == GeneratedDllImport.Length)
{
return attrName.Equals(GeneratedDllImport);
}
else if (attrName.Length == GeneratedDllImportAttribute.Length)
{
return attrName.Equals(GeneratedDllImportAttribute);
}

// Handle the case where the user defines an attribute with
// the same name but adds a prefix.
const string PrefixedGeneratedDllImport = "." + GeneratedDllImport;
const string PrefixedGeneratedDllImportAttribute = "." + GeneratedDllImportAttribute;
return attrName.EndsWith(PrefixedGeneratedDllImport)
|| attrName.EndsWith(PrefixedGeneratedDllImportAttribute);
}

private IEnumerable<string> ProcessAttributes(
Expand Down
4 changes: 2 additions & 2 deletions DllImportGenerator/DllImportGenerator/DllImportStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ public static DllImportStub Create(IMethodSymbol method, CancellationToken token
// Forward call to generated P/Invoke
var returnMaybe = method.ReturnType.SpecialType == SpecialType.System_Void
? string.Empty
: "return";
: "return ";

var dispatchCall = new StringBuilder($"{returnMaybe} {dllImportName}");
var dispatchCall = new StringBuilder($"{returnMaybe}{dllImportName}");
if (!dllImportParams.Any())
{
dispatchCall.Append("();");
Expand Down