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

Support reading embedded source #16

Merged
merged 2 commits into from
Aug 4, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions src/DeployCoreClrTestRuntime/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"System.Diagnostics.Tools": "4.0.1",
"System.Dynamic.Runtime": "4.0.11",
"System.Globalization": "4.0.11",
"System.IO.Compression": "4.1.0",
"System.IO.FileSystem": "4.0.1",
"System.IO.FileSystem.Primitives": "4.0.1",
"System.IO.FileSystem.Watcher": "4.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<ItemGroup>
<Compile Include="PdbConverterTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
Copy link
Contributor Author

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

<ImportGroup>
<Import Project="..\..\build\Targets\Imports.targets" />
<Import Project="..\..\build\Toolset\XunitProjectRunAction.targets" />
Expand Down
194 changes: 194 additions & 0 deletions src/Microsoft.DiaSymReader.PortablePdb.Tests/EmbeddedSourceTests.cs
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these intentionally here, or could they be move up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BitConverter.ToInt32(buffer, 0) would probably suffice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Expand Up @@ -77,10 +77,29 @@
<EmbeddedResource Include="Resources\MiscEmbedded.dll">
<LogicalName>MiscEmbedded.dll</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSource.cs">
<LogicalName>EmbeddedSource.cs</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSourceSmall.cs">
<LogicalName>EmbeddedSourceSmall.cs</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSource.dll">
<LogicalName>EmbeddedSource.dll</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSource.pdb">
<LogicalName>EmbeddedSource.pdb</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSource.dllx">
<LogicalName>EmbeddedSource.dllx</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Resources\EmbeddedSource.pdbx">
<LogicalName>EmbeddedSource.pdbx</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Documents.cmd" />
<Content Include="Resources\Documents.cs" />
<Content Include="Resources\EmbeddedSource.cmd" />
<Content Include="Resources\Scopes.cmd" />
<Content Include="Resources\Scopes.cs" />
<Content Include="Resources\Async.cmd" />
Expand All @@ -91,6 +110,7 @@
<Content Include="Resources\MiscEmbedded.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="EmbeddedSourceTests.cs" />
<Compile Include="MethodMapTests.cs" />
<Compile Include="ResourceLoader.cs" />
<Compile Include="SymBinderTests.cs" />
Expand Down
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);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
{
}
26 changes: 24 additions & 2 deletions src/Microsoft.DiaSymReader.PortablePdb.Tests/TestResources.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;

namespace TestResources
Expand Down Expand Up @@ -76,4 +74,28 @@ public static class MiscEmbedded
private static byte[] s_dll;
public static byte[] Dll => ResourceLoader.GetOrCreateResource(ref s_dll, nameof(MiscEmbedded) + ".dll");
}

public static class EmbeddedSource
{
private static byte[] s_portableDll;
public static byte[] PortableDll => ResourceLoader.GetOrCreateResource(ref s_portableDll, nameof(EmbeddedSource) + ".dllx");

private static byte[] s_portablePdb;
public static byte[] PortablePdb => ResourceLoader.GetOrCreateResource(ref s_portablePdb, nameof(EmbeddedSource) + ".pdbx");

private static byte[] s_dll;
public static byte[] Dll => ResourceLoader.GetOrCreateResource(ref s_dll, nameof(EmbeddedSource) + ".dll");

private static byte[] s_pdb;
public static byte[] Pdb => ResourceLoader.GetOrCreateResource(ref s_pdb, nameof(EmbeddedSource) + ".pdb");

private static byte[] s_cs;
public static byte[] CS => ResourceLoader.GetOrCreateResource(ref s_cs, nameof(EmbeddedSource) + ".cs");

private static byte[] s_csSmall;
public static byte[] CSSmall => ResourceLoader.GetOrCreateResource(ref s_csSmall, nameof(EmbeddedSource) + "Small.cs");

public static KeyValuePair<byte[], byte[]> PortableDllAndPdb => new KeyValuePair<byte[], byte[]>(PortableDll, PortablePdb);
public static KeyValuePair<byte[], byte[]> DllAndPdb => new KeyValuePair<byte[], byte[]>(Dll, Pdb);
}
}
1 change: 1 addition & 0 deletions src/Microsoft.DiaSymReader.PortablePdb.Tests/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"System.Runtime": "4.1.0",
"System.Runtime.Extensions": "4.1.0",
"System.Runtime.InteropServices": "4.1.0",
"System.IO.Compression": "4.1.0",
"System.IO.FileSystem": "4.0.1",
"Microsoft.DiaSymReader.Native": "1.5.0-beta1",
"xunit": "2.1.0",
Expand Down
Loading