Skip to content

Commit

Permalink
[GH-38] - Adding tests for external sources
Browse files Browse the repository at this point in the history
  • Loading branch information
tpodolak committed Sep 29, 2018
1 parent a57b4fc commit 6a74ac9
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}

var codeAction = CodeAction.Create("my name", token => CreateChangedDocument(token, compilationUnitSyntax, document), nameof(AbstractSubstituteForInternalMemberCodeFixProvider<TInvocationExpressionSyntax, TExpressionSyntax, TCompilationUnitSyntax>));
var codeAction = CodeAction.Create("Append InternalsVisibleTo attribute", token => CreateChangedDocument(token, compilationUnitSyntax, document), nameof(AbstractSubstituteForInternalMemberCodeFixProvider<TInvocationExpressionSyntax, TExpressionSyntax, TCompilationUnitSyntax>));
context.RegisterCodeFix(codeAction, diagnostic);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders;

Expand All @@ -14,36 +12,5 @@ protected override CompilationOptions GetCompilationOptions()
{
return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
}

protected override IEnumerable<MetadataReference> GetAdditionalMetadataReferences()
{
return new MetadataReference[]
{
Foo()
};
}

private static PortableExecutableReference Foo()
{
var syntaxTree = CSharpSyntaxTree.ParseText(@"
namespace ExternalNamespace
{
internal class InternalFoo
{
}
}");

var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) };
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("Internal", new[] { syntaxTree }, references: references, options: compilationOptions);

using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);

ms.Seek(0, SeekOrigin.Begin);
return MetadataReference.CreateFromStream(ms);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using NSubstitute.Analyzers.CSharp.CodeFixProviders;
using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers;
using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders;
using Xunit;

namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests
{
public class SubstituteForInternalMemberCodeFixActionsTests : CSharpCodeFixActionsVerifier, ISubstituteForInternalMemberCodeFixActionsVerifier
{
[Fact]
public async Task CreatesCorrectCodeFixActions_WhenSourceForInternalType_IsAvailable()
{
var source = @"using NSubstitute.Core;
namespace MyNamespace
{
namespace MyInnerNamespace
{
internal class Foo
{
}
public class FooTests
{
public void Test()
{
var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null);
}
}
}
}";
await VerifyCodeActions(source, "Append InternalsVisibleTo attribute");
}

[Fact]
public async Task Does_Not_CreateCodeFixActions_WhenType_IsNotInternal()
{
var source = @"using NSubstitute.Core;
namespace MyNamespace
{
namespace MyInnerNamespace
{
public class Foo
{
}
public class FooTests
{
public void Test()
{
var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null);
}
}
}
}";
await VerifyCodeActions(source);
}

[Fact]
public async Task Does_Not_CreateCodeFixActions_WhenSourceForInternalType_IsNotAvailable()
{
var source = @"using NSubstitute.Core;
using ExternalNamespace;
namespace MyNamespace
{
namespace MyInnerNamespace
{
public class FooTests
{
public void Test()
{
var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(InternalFoo)}, null);
}
}
}
}";
await VerifyCodeActions(source);
}

protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
{
return new SubstituteAnalyzer();
}

protected override CodeFixProvider GetCodeFixProvider()
{
return new SubstituteForInternalMemberCodeFixProvider();
}

protected override IEnumerable<MetadataReference> GetAdditionalMetadataReferences()
{
return new[] { GetInternalLibraryMetadataReference() };
}

private static PortableExecutableReference GetInternalLibraryMetadataReference()
{
var syntaxTree = CSharpSyntaxTree.ParseText($@"
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo(""{TestProjectName}"")]
namespace ExternalNamespace
{{
internal class InternalFoo
{{
}}
}}");

var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) };
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions);

using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);

if (result.Success == false)
{
var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error);
throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}");
}

ms.Seek(0, SeekOrigin.Begin);
return MetadataReference.CreateFromStream(ms);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Threading.Tasks;

namespace NSubstitute.Analyzers.Tests.Shared.CodeFixProviders
{
public interface ISubstituteForInternalMemberCodeFixActionsVerifier
{
Task CreatesCorrectCodeFixActions_WhenSourceForInternalType_IsAvailable();

Task Does_Not_CreateCodeFixActions_WhenType_IsNotInternal();

Task Does_Not_CreateCodeFixActions_WhenSourceForInternalType_IsNotAvailable();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.VisualBasic;
using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders;
using NSubstitute.Analyzers.VisualBasic.CodeFixProviders;
using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers;
using Xunit;

namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests
{
public class SubstituteForInternalMemberCodeFixActionsTests : VisualBasicCodeFixActionsVerifier, ISubstituteForInternalMemberCodeFixActionsVerifier
{
[Fact]
public async Task CreatesCorrectCodeFixActions_WhenSourceForInternalType_IsAvailable()
{
var source = @"Imports NSubstitute.Core
Namespace MyNamespace
Namespace MyInnerNamespace
Friend Class Foo
End Class
Public Class FooTests
Public Sub Test()
Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing)
End Sub
End Class
End Namespace
End Namespace
";
await VerifyCodeActions(source, "Append InternalsVisibleTo attribute");
}

[Fact]
public async Task Does_Not_CreateCodeFixActions_WhenType_IsNotInternal()
{
var source = @"Imports NSubstitute.Core
Namespace MyNamespace
Namespace MyInnerNamespace
Public Class Foo
End Class
Public Class FooTests
Public Sub Test()
Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing)
End Sub
End Class
End Namespace
End Namespace
";
await VerifyCodeActions(source);
}

[Fact]
public async Task Does_Not_CreateCodeFixActions_WhenSourceForInternalType_IsNotAvailable()
{
var source = @"Imports NSubstitute.Core
Imports ExternalNamespace
Namespace MyNamespace
Namespace MyInnerNamespace
Public Class FooTests
Public Sub Test()
Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(InternalFoo)}, Nothing)
End Sub
End Class
End Namespace
End Namespace
";
await VerifyCodeActions(source);
}

protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
{
return new SubstituteAnalyzer();
}

protected override CodeFixProvider GetCodeFixProvider()
{
return new SubstituteForInternalMemberCodeFixProvider();
}

protected override IEnumerable<MetadataReference> GetAdditionalMetadataReferences()
{
return new[] { GetInternalLibraryMetadataReference() };
}

private static PortableExecutableReference GetInternalLibraryMetadataReference()
{
var syntaxTree = VisualBasicSyntaxTree.ParseText($@"
Imports System.Runtime.CompilerServices
<Assembly: InternalsVisibleTo(""{TestProjectName}"")>
Namespace ExternalNamespace
Friend Class InternalFoo
End Class
End Namespace
");

var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) };
var compilationOptions = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = VisualBasicCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions);

using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);

if (result.Success == false)
{
var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error);
throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}");
}

ms.Seek(0, SeekOrigin.Begin);
return MetadataReference.CreateFromStream(ms);
}
}
}
}

0 comments on commit 6a74ac9

Please sign in to comment.