-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Add Rebuild.UnitTests #51778
Add Rebuild.UnitTests #51778
Changes from all commits
9d83e11
5341001
a3187d7
e29d5b2
cc0e63e
2cb6884
e828978
09f238a
b83579f
5fa70d1
9b047b2
c6533e8
57047c3
c51ec95
42b3d6e
aa78ba5
1a7d1a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. --> | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Library</OutputType> | ||
<RootNamespace>Microsoft.CodeAnalysis.Rebuild.UnitTests</RootNamespace> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<TargetFrameworks>net5.0;net472</TargetFrameworks> | ||
</PropertyGroup> | ||
<ItemGroup Label="Project References"> | ||
<ProjectReference Include="..\Portable\Microsoft.CodeAnalysis.csproj" /> | ||
<ProjectReference Include="..\..\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj" /> | ||
<ProjectReference Include="..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" /> | ||
<ProjectReference Include="..\..\Test\Core\Microsoft.CodeAnalysis.Test.Utilities.csproj" /> | ||
<ProjectReference Include="..\..\Test\Resources\Core\Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj" /> | ||
<ProjectReference Include="..\..\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" /> | ||
<ProjectReference Include="..\Rebuild\Rebuild.csproj" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System; | ||
using System.Reflection.PortableExecutable; | ||
using BuildValidator; | ||
using Castle.Core.Logging; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; | ||
using Microsoft.CodeAnalysis.Emit; | ||
using Microsoft.CodeAnalysis.Test.Utilities; | ||
using Microsoft.Extensions.Logging; | ||
using Xunit; | ||
using System.IO; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis.VisualBasic; | ||
using System.Text; | ||
|
||
namespace Microsoft.CodeAnalysis.Rebuild.UnitTests | ||
{ | ||
public class OptionRoundTripTests : CSharpTestBase | ||
{ | ||
public static readonly object[][] s_platforms = ((Platform[])Enum.GetValues(typeof(Platform))).Select(p => new[] { (object)p }).ToArray(); | ||
|
||
[Theory] | ||
[MemberData(nameof(s_platforms))] | ||
public void Platform_RoundTrip(Platform platform) | ||
{ | ||
const string path = "test"; | ||
|
||
var original = CreateCompilation( | ||
"class C { static void Main() { } }", | ||
options: TestOptions.DebugExe.WithPlatform(platform)); | ||
|
||
original.VerifyDiagnostics(); | ||
|
||
var originalBytes = original.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded)); | ||
var peReader = new PEReader(originalBytes); | ||
Assert.True(peReader.TryOpenAssociatedPortablePdb(path, path => null, out var provider, out _)); | ||
var pdbReader = provider!.GetMetadataReader(); | ||
|
||
var factory = LoggerFactory.Create(configure => { }); | ||
var logger = factory.CreateLogger(path); | ||
// TODO: shouldn't need to pass a logger. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we need an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but it feels like users of the public API shouldn't be required to provide a logger, and shouldn't provide it as its own parameter. Maybe a property on an options object that can be specified if the user wants, but not a parameter to public API that they have to deal with. |
||
var bc = new BuildConstructor(logger); | ||
|
||
var optionsReader = new CompilationOptionsReader(logger, pdbReader, peReader); | ||
|
||
var sources = original.SyntaxTrees.Select(st => | ||
{ | ||
var text = st.GetText(); | ||
return new ResolvedSource(OnDiskPath: null, text, new SourceFileInfo(path, text.ChecksumAlgorithm, text.GetChecksum().ToArray(), text, embeddedCompressedHash: null)); | ||
}).ToImmutableArray(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this project is missing an IVT to MS.CA for this. I will punt on it for now if that's ok. |
||
var references = original.References.ToImmutableArray(); | ||
var (compilation, isError) = bc.CreateCompilation(optionsReader, path, sources, references); | ||
|
||
Assert.False(isError); | ||
Assert.Equal(platform, compilation!.Options.Platform); | ||
|
||
// TODO: we should be able to get byte-for-byte equality here. | ||
// it will probably be necessary to expose some diagnostic facility in the Rebuild API to figure out what's wrong here. | ||
|
||
// using var rebuildStream = new MemoryStream(); | ||
// var result = BuildConstructor.Emit(rebuildStream, new FileInfo(path), optionsReader, compilation, logger, CancellationToken.None); | ||
// Assert.Empty(result.Diagnostics); | ||
// Assert.True(result.Success); | ||
// Assert.Equal(originalBytes.ToArray(), rebuildStream.ToArray()); | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(s_platforms))] | ||
public void Platform_RoundTrip_VB(Platform platform) | ||
{ | ||
const string path = "test"; | ||
|
||
var original = CreateVisualBasicCompilation( | ||
path, | ||
compilationOptions: new VisualBasicCompilationOptions(outputKind: OutputKind.ConsoleApplication, platform: platform), | ||
encoding: Encoding.UTF8, | ||
code: @" | ||
Class C | ||
Shared Sub Main() | ||
End Sub | ||
End Class"); | ||
|
||
original.VerifyDiagnostics(); | ||
|
||
var originalBytes = original.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded)); | ||
var peReader = new PEReader(originalBytes); | ||
Assert.True(peReader.TryOpenAssociatedPortablePdb(path, path => null, out var provider, out _)); | ||
var pdbReader = provider!.GetMetadataReader(); | ||
|
||
var factory = LoggerFactory.Create(configure => { }); | ||
var logger = factory.CreateLogger(path); | ||
// TODO: shouldn't need to pass a logger. | ||
var bc = new BuildConstructor(logger); | ||
|
||
var optionsReader = new CompilationOptionsReader(logger, pdbReader, peReader); | ||
|
||
var sources = original.SyntaxTrees.Select(st => | ||
{ | ||
var text = st.GetText(); | ||
return new ResolvedSource(OnDiskPath: null, text, new SourceFileInfo(path, text.ChecksumAlgorithm, text.GetChecksum().ToArray(), text, embeddedCompressedHash: null)); | ||
}).ToImmutableArray(); | ||
var references = original.References.ToImmutableArray(); | ||
var (compilation, isError) = bc.CreateCompilation(optionsReader, path, sources, references); | ||
|
||
Assert.False(isError); | ||
Assert.Equal(platform, compilation!.Options.Platform); | ||
|
||
// TODO: we should be able to get byte-for-byte equality here. | ||
// it will probably be necessary to expose some diagnostic facility in the Rebuild API to figure out what's wrong here. | ||
|
||
// using var rebuildStream = new MemoryStream(); | ||
// var result = BuildConstructor.Emit(rebuildStream, new FileInfo(path), optionsReader, compilation, logger, CancellationToken.None); | ||
// Assert.Empty(result.Diagnostics); | ||
// Assert.True(result.Success); | ||
// Assert.Equal(originalBytes.ToArray(), rebuildStream.ToArray()); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Platform can't be determined from the CLR/PE header flags of the dll? Seems like it should be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be possible, but I wasn't able to get all the values to round trip. The CoffHeader.Machine, for example, is not enough information. There must be other bits that imply
Platform.AnyCpu
andPlatform.AnyCpu32BitPreferred
that I just wasn't able to find.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are stored in CorHeader flags:
https://source.dot.net/#System.Reflection.Metadata/System/Reflection/PortableExecutable/CorHeader.cs,1f6cfc9c2185aaf4,references
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #51941 to make sure we get to this. Thanks