-
Notifications
You must be signed in to change notification settings - Fork 37
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
Support reading embedded source #16
Changes from 1 commit
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,194 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Roslyn.Test.Utilities; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using System.IO.Compression; | ||
using System.Reflection.Metadata; | ||
using Xunit; | ||
|
||
namespace Microsoft.DiaSymReader.PortablePdb.UnitTests | ||
{ | ||
using System.Linq; | ||
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. Are these intentionally here, or could they be move up? 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. SymTestHelpers copied from elsewhere, causes ctrl + . to put more usings next to it. I'll move System.Linq. |
||
using static SymTestHelpers; | ||
|
||
public class EmbeddedSourceTests | ||
{ | ||
[Fact] | ||
public void EmbeddedSource_Portable() | ||
{ | ||
EmbeddedSource(TestResources.EmbeddedSource.PortableDllAndPdb); | ||
} | ||
|
||
// TODO: Once native PDB support is implemented, add /embed to EmbeddedSource.cmd | ||
// native command line, run it to regenerate native dll and PDB, and unskip this test. | ||
[Fact(Skip = "Native support not yet implemented.")] | ||
public void EmbeddedSource_Native() | ||
{ | ||
EmbeddedSource(TestResources.EmbeddedSource.DllAndPdb); | ||
} | ||
|
||
private void EmbeddedSource(KeyValuePair<byte[], byte[]> dllAndPdb) | ||
{ | ||
ISymUnmanagedReader symReader = CreateSymReaderFromResource(dllAndPdb); | ||
|
||
foreach (string file in new[] { @"C:\EmbeddedSource.cs", @"C:\EmbeddedSourceSmall.cs" }) | ||
{ | ||
bool hasEmbeddedSource; | ||
int length, bytesRead; | ||
ISymUnmanagedDocument doc; | ||
Assert.Equal(HResult.S_OK, symReader.GetDocument(file, default(Guid), default(Guid), default(Guid), out doc)); | ||
Assert.Equal(HResult.S_OK, doc.HasEmbeddedSource(out hasEmbeddedSource)); | ||
Assert.Equal(HResult.S_OK, doc.GetSourceLength(out length)); | ||
Assert.True(hasEmbeddedSource); | ||
|
||
var blob = new byte[length]; | ||
Assert.Equal(HResult.S_OK, doc.GetSourceRange(0, 0, int.MaxValue, int.MaxValue, length, out bytesRead, blob)); | ||
Assert.Equal(length, bytesRead); | ||
|
||
Assert.True(length >= sizeof(int)); | ||
|
||
int uncompressedSize; | ||
unsafe | ||
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.
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. OK. |
||
{ | ||
fixed (byte* bytes = blob) | ||
{ | ||
uncompressedSize = new BlobReader(bytes, length).ReadInt32(); | ||
} | ||
} | ||
|
||
byte[] expectedContent; | ||
if (uncompressedSize == 0) | ||
{ | ||
Assert.Equal(@"C:\EmbeddedSourceSmall.cs", file); | ||
expectedContent = TestResources.EmbeddedSource.CSSmall; | ||
} | ||
else | ||
{ | ||
Assert.Equal(@"C:\EmbeddedSource.cs", file); | ||
expectedContent = TestResources.EmbeddedSource.CS; | ||
|
||
} | ||
|
||
AssertEx.Equal(expectedContent, Decode(blob, uncompressedSize)); | ||
} | ||
} | ||
|
||
[Fact] | ||
public void NoEmbeddedSource_Portable() | ||
{ | ||
NoEmbeddedSource(TestResources.Documents.PortableDllAndPdb); | ||
} | ||
|
||
[Fact] | ||
public void NoEmbeddedSource_Native() | ||
{ | ||
NoEmbeddedSource(TestResources.Documents.DllAndPdb); | ||
} | ||
|
||
private void NoEmbeddedSource(KeyValuePair<byte[], byte[]> dllAndPdb) | ||
{ | ||
ISymUnmanagedReader symReader = CreateSymReaderFromResource(dllAndPdb); | ||
|
||
ISymUnmanagedDocument doc; | ||
Assert.Equal(HResult.S_OK, symReader.GetDocument(@"C:\Documents.cs", default(Guid), default(Guid), default(Guid), out doc)); | ||
|
||
bool hasEmbeddedSource; | ||
Assert.Equal(HResult.S_OK, doc.HasEmbeddedSource(out hasEmbeddedSource)); | ||
Assert.False(hasEmbeddedSource); | ||
|
||
int length; | ||
Assert.Equal(HResult.S_OK, doc.GetSourceLength(out length)); | ||
Assert.Equal(0, length); | ||
|
||
Assert.Equal(HResult.S_FALSE, doc.GetSourceRange(0, 0, -1, -1, 0, out length, null)); | ||
Assert.Equal(HResult.S_FALSE, doc.GetSourceRange(0, 0, int.MaxValue, int.MaxValue, 0, out length, null)); | ||
} | ||
|
||
[Fact] | ||
public void BadArgs_Portable() | ||
{ | ||
BadArgs(TestResources.EmbeddedSource.PortableDllAndPdb); | ||
} | ||
|
||
[Fact] | ||
public void BadArgs_Native() | ||
{ | ||
BadArgs(TestResources.EmbeddedSource.DllAndPdb); | ||
} | ||
|
||
private void BadArgs(KeyValuePair<byte[], byte[]> dllAndPdb) | ||
{ | ||
ISymUnmanagedReader symReader = CreateSymReaderFromResource(dllAndPdb); | ||
|
||
ISymUnmanagedDocument doc; | ||
Assert.Equal(HResult.S_OK, symReader.GetDocument(@"C:\EmbeddedSource.cs", default(Guid), default(Guid), default(Guid), out doc)); | ||
|
||
int count; | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(-1, 0, int.MaxValue, int.MaxValue, 0, out count, null)); | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(0, -1, int.MaxValue, int.MaxValue, 0, out count, null)); | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(0, 0, 1, int.MaxValue, 0, out count, null)); | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(0, 0, int.MaxValue, 1, 0, out count, null)); | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(0, 0, int.MaxValue, int.MaxValue, 1, out count, null)); | ||
|
||
// negative bufferLength test does not apply to native as it uses uint arguments. | ||
if (dllAndPdb.Equals(TestResources.EmbeddedSource.PortableDllAndPdb)) | ||
{ | ||
Assert.Equal(HResult.E_INVALIDARG, doc.GetSourceRange(0, 0, int.MaxValue, int.MaxValue, -1, out count, new byte[1])); | ||
} | ||
} | ||
|
||
private byte[] Decode(byte[] blob, int uncompressedSize) | ||
{ | ||
Assert.True(uncompressedSize >= 0); | ||
|
||
if (uncompressedSize == 0) | ||
{ | ||
byte[] content = new byte[blob.Length - sizeof(int)]; | ||
Array.Copy(blob, sizeof(int), content, 0, content.Length); | ||
return content; | ||
} | ||
else | ||
{ | ||
var compressed = new MemoryStream(blob, sizeof(int), blob.Length - sizeof(int)); | ||
using (var decompressor = new DeflateStream(compressed, CompressionMode.Decompress)) | ||
using (var decompressed = new MemoryStream(uncompressedSize)) | ||
{ | ||
decompressor.CopyTo(decompressed); | ||
Assert.Equal(uncompressedSize, decompressed.Length); | ||
return decompressed.ToArray(); | ||
} | ||
} | ||
} | ||
|
||
// Portable PDB has a leading format indicator that is not exposed via the COM API. Check it for consistency. | ||
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. This is left over. Will remove. |
||
private static void CheckPortableFormatHeader(byte[] portablePdb, string file, bool isCompressed) | ||
{ | ||
using (var provider = MetadataReaderProvider.FromPortablePdbImage(ImmutableArray.Create(portablePdb))) | ||
{ | ||
var portablePdbReader = provider.GetMetadataReader(); | ||
var document = GetDocumentHandle(portablePdbReader, file); | ||
var customDebugInfo = portablePdbReader.GetCustomDebugInformation(document, MetadataUtilities.EmbeddedSourceId); | ||
var blobReader = portablePdbReader.GetBlobReader(customDebugInfo); | ||
Assert.Equal(isCompressed ? 1 : 0, blobReader.ReadUInt16()); | ||
} | ||
} | ||
|
||
private static DocumentHandle GetDocumentHandle(MetadataReader portablePdbReader, string file) | ||
{ | ||
foreach (var handle in portablePdbReader.Documents) | ||
{ | ||
var document = portablePdbReader.GetDocument(handle); | ||
if (portablePdbReader.StringComparer.Equals(document.Name, file)) | ||
{ | ||
return handle; | ||
} | ||
} | ||
|
||
Assert.False(true, "Document not found."); | ||
throw null; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
csc /target:library /debug:portable /optimize- /deterministic /pathmap:%~dp0=C:\ /embed EmbeddedSource.cs EmbeddedSourceSmall.cs | ||
copy /y EmbeddedSource.pdb EmbeddedSource.pdbx | ||
copy /y EmbeddedSource.dll EmbeddedSource.dllx | ||
|
||
@REM -- TODO: Native support not there yet, hence no /embed, add it when implemented and unskip EmbeddedSource_Native test. | ||
csc /target:library /debug+ /optimize- /deterministic /pathmap:%~dp0=C:\ EmbeddedSource.cs EmbeddedSourceSmall.cs | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// should be higher than compression threshold (200 chars) | ||
|
||
using System; | ||
|
||
namespace Test | ||
{ | ||
public static class SomeCode | ||
{ | ||
public static int SomeMethod(int value) | ||
{ | ||
if (value < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(value)); | ||
} | ||
|
||
return checked(value + 42); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// should be less than compression threshold (200 chars) | ||
public class Small | ||
{ | ||
} |
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.
Test explorer adds this. I'm tired of reverting it. OK to leave it?
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.
OK.