Skip to content

Commit

Permalink
Merge pull request #35 from AaronRobinsonMSFT/failure_test_case
Browse files Browse the repository at this point in the history
Failure test cases.
  • Loading branch information
AaronRobinsonMSFT authored Jul 29, 2020
2 parents 35c9adc + d2f6f5a commit 48b8361
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 37 deletions.
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

0 comments on commit 48b8361

Please sign in to comment.