Keep track of any error cases encountered when attempting to deminify a StackFrame. Instead of returning a list of StackFrames in DeminifyStackTraceResult, we will return a StackFrameDeminificationResult, which contains the deminified StackFrame as well as an enum indicating if any error cases were hit. This result can be used to help provide information of any error cases in the SourceMapToolkit without having to debug.

This commit is contained in:
thomabr 2016-11-16 13:15:05 -08:00
Родитель fe82867b62
Коммит 690cea98a0
8 изменённых файлов: 276 добавлений и 191 удалений

Просмотреть файл

@ -5,7 +5,7 @@
/// <summary>
/// This method will deminify a single stack from from a minified stack trace.
/// </summary>
/// <returns>Returns a StackFrameDeminificationResult that contains a stack trace that has been translated to the original source code. The DeminificationError Property indicates if the StackFrame could not be deminified. DeminifiedStackFrame will not be null, but any properties of DeminifiedStackFrame could be null if the value could not be extracted. </returns>
/// <returns>Returns a stack trace that has been translated to the original source code. Returns null if it could not be deminified.</returns>
StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame);
}
}

Просмотреть файл

@ -38,7 +38,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="AjaxMin, Version=5.14.5506.26196, Culture=neutral, PublicKeyToken=21ef50ce11b5d80f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AjaxMin.5.14.5506.26202\lib\net40\AjaxMin.dll</HintPath>
<HintPath>D:\NugetCache\AjaxMin.5.14.5506.26202\lib\net40\AjaxMin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

Просмотреть файл

@ -9,30 +9,25 @@ namespace SourcemapToolkit.CallstackDeminifier
/// <summary>
/// Enum indicating if there were any errors encountered when attempting to deminify the StakFrame.
/// </summary>
public enum DeminificationError
public enum DeminificationError
{
/// <summary>
/// No error was encountered durring deminification of the StackFrame.
/// </summary>
None,
/// <summary>
/// There was no source code provided by the ISourceCodeProvider.
/// </summary>
NoSourceCodeProvided,
/// <summary>
/// The function that wraps the minified stack frame could not be determined.
/// </summary>
NoWrapingFunctionFound,
NoWrapingFunction,
/// <summary>
/// There was not a valid source map returned by ISourceMapProvider.GetSourceMapForUrl.
/// There was an error when there was not a valid source map returned by ISourceMapProvider.GetSourceMapForUrl.
/// </summary>
NoSourceMap,
/// <summary>
/// A mapping entry was not found for the source position of the minified stack frame.
/// There was not a mapping entry found for the source position of the minified stack frame.
/// </summary>
NoMatchingMapingInSourceMap,

Просмотреть файл

@ -1,64 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SourcemapToolkit.SourcemapParser;
namespace SourcemapToolkit.CallstackDeminifier
{
/// <summary>
/// Class responsible for deminifying a single stack frame in a minified stack trace.
/// This method of deminification relies on a source map being available at runtime.
/// Since source maps take up a large amount of memory, this class consumes considerably
/// more memory than SimpleStackFrame Deminifier during runtime.
/// </summary>
internal class StackFrameDeminifier : SimpleStackFrameDeminifier
internal class StackFrameDeminifier : IStackFrameDeminifier
{
private readonly IFunctionMapConsumer _functionMapConsumer;
private readonly IFunctionMapStore _functionMapStore;
private readonly ISourceMapStore _sourceMapStore;
public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer) : base (functionMapStore, functionMapConsumer)
public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer)
{
_functionMapStore = functionMapStore;
_sourceMapStore = sourceMapStore;
_functionMapConsumer = functionMapConsumer;
}
/// <summary>
/// This method will deminify a single stack from from a minified stack trace.
/// </summary>
/// <returns>Returns a StackFrameDeminificationResult that contains a stack trace that has been translated to the original source code. The DeminificationError Property indicates if the StackFrame could not be deminified. DeminifiedStackFrame will not be null, but any properties of DeminifiedStackFrame could be null if the value could not be extracted. </returns>
public override StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame)
/// <returns>Returns a stack trace that has been translated to a best guess of the original source code. Any of the fields in the stack frame may be null</returns>
public StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame)
{
if (stackFrame == null)
{
throw new ArgumentNullException(nameof(stackFrame));
}
FunctionMapEntry wrappingFunction = null;
SourceMap sourceMap = _sourceMapStore.GetSourceMapForUrl(stackFrame.FilePath);
SourcePosition generatedSourcePosition = stackFrame.SourcePosition;
StackFrameDeminificationResult result = base.DeminifyStackFrame(stackFrame);
if (result.DeminificationError == DeminificationError.None)
// This code deminifies the stack frame by finding the wrapping function in
// the generated code and then using the source map to find the name and
// and original source location.
List<FunctionMapEntry> functionMap = _functionMapStore.GetFunctionMapForSourceCode(stackFrame.FilePath);
if (functionMap != null)
{
MappingEntry generatedSourcePositionMappingEntry =
sourceMap?.GetMappingEntryForGeneratedSourcePosition(generatedSourcePosition);
if (generatedSourcePositionMappingEntry == null)
{
if (sourceMap == null)
{
result.DeminificationError = DeminificationError.NoSourceMap;
}
else if (sourceMap.ParsedMappings == null)
{
result.DeminificationError = DeminificationError.SourceMapFailedToParse;
}
else
{
result.DeminificationError = DeminificationError.NoMatchingMapingInSourceMap;
}
}
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry?.OriginalFileName;
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry?.OriginalSourcePosition;
wrappingFunction =
_functionMapConsumer.GetWrappingFunctionForSourceLocation(stackFrame.SourcePosition, functionMap);
}
return result;
return ExtractFrameInformationFromSourceMap(wrappingFunction, sourceMap, stackFrame.SourcePosition);
}
/// <summary>
/// Gets the information necessary for a deminified stack frame from the relevant source map.
/// </summary>
/// <param name="wrappingFunction">The function that wraps the current stack frame location</param>
/// <param name="sourceMap">The relevant source map for this generated code</param>
/// <param name="generatedSourcePosition">The location that should be translated to original source code location in the deminified stack frame.</param>
/// <returns>Returns a StackFrameDeminificationResult object with a StackFrame that is the best guess values for each property. Any of the properties on the StackResult may be null if no match was found. The DeminificationError enum will provide information of any error cases hit.</returns>
internal static StackFrameDeminificationResult ExtractFrameInformationFromSourceMap(FunctionMapEntry wrappingFunction, SourceMap sourceMap, SourcePosition generatedSourcePosition)
{
StackFrameDeminificationResult deminificationResult = new StackFrameDeminificationResult { DeminificationError = DeminificationError.None };
StackFrame deobfuscatedFrame = new StackFrame();
if (wrappingFunction?.Bindings != null && wrappingFunction.Bindings.Count > 0)
{
string methodName = null;
if (wrappingFunction.Bindings.Count == 2)
{
MappingEntry objectProtoypeMappingEntry =
sourceMap?.GetMappingEntryForGeneratedSourcePosition(wrappingFunction.Bindings[0].SourcePosition);
methodName = objectProtoypeMappingEntry?.OriginalName;
}
MappingEntry mappingEntry =
sourceMap?.GetMappingEntryForGeneratedSourcePosition(wrappingFunction.Bindings.Last().SourcePosition);
if (mappingEntry != null)
{
if (mappingEntry.OriginalName != null)
{
if (methodName != null)
{
methodName = methodName + "." + mappingEntry.OriginalName;
}
else
{
methodName = mappingEntry.OriginalName;
}
}
deobfuscatedFrame.MethodName = methodName;
}
else if (sourceMap == null)
{
deminificationResult.DeminificationError = DeminificationError.NoSourceMap;
}
else if (sourceMap.ParsedMappings == null)
{
deminificationResult.DeminificationError = DeminificationError.SourceMapFailedToParse;
}
else
{
deminificationResult.DeminificationError = DeminificationError.NoMatchingMapingInSourceMap;
}
}
else
{
deminificationResult.DeminificationError = DeminificationError.NoWrapingFunction;
}
MappingEntry generatedSourcePositionMappingEntry = sourceMap?.GetMappingEntryForGeneratedSourcePosition(generatedSourcePosition);
deobfuscatedFrame.FilePath = generatedSourcePositionMappingEntry?.OriginalFileName;
deobfuscatedFrame.SourcePosition = generatedSourcePositionMappingEntry?.OriginalSourcePosition;
deminificationResult.DeminifiedStackFrame = deobfuscatedFrame;
return deminificationResult;
}
}
}

Просмотреть файл

@ -45,8 +45,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform">
<HintPath>D:\NugetCache\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
@ -116,12 +116,14 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
<Error Condition="!Exists('D:\NugetCache\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', 'D:\NugetCache\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('D:\NugetCache\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', 'D:\NugetCache\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
-->
<UsingTask AssemblyFile="..\..\packages\ajaxmin.5.14.5506.26202\tools\net40\AjaxMinTask.dll" TaskName="AjaxMin" />
<UsingTask AssemblyFile="..\..\packages\ajaxmin.5.14.5506.26202\tools\net40\AjaxMinTask.dll" TaskName="AjaxMin" />
<Target Name="AfterBuild">
<ItemGroup>
<JS Include="crashcauser.js" />

Просмотреть файл

@ -38,7 +38,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>D:\NugetCache\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

Просмотреть файл

@ -42,7 +42,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Rhino.Mocks, Version=3.6.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL">
<HintPath>..\..\packages\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll</HintPath>
<HintPath>D:\NugetCache\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

Просмотреть файл

@ -8,32 +8,25 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
{
[TestClass]
public class StackFrameDeminifierUnitTests
{
private IStackFrameDeminifier GetStackFrameDeminifierWithMockDependencies(ISourceMapStore sourceMapStore = null, IFunctionMapStore functionMapStore = null, IFunctionMapConsumer functionMapConsumer = null, bool useSimpleStackFrameDeminier = false)
{
private IStackFrameDeminifier GetStackFrameDeminifierWithMockDependencies(ISourceMapStore sourceMapStore = null, IFunctionMapStore functionMapStore = null, IFunctionMapConsumer functionMapConsumer = null)
{
if (sourceMapStore == null)
{
sourceMapStore = MockRepository.GenerateStub<ISourceMapStore>();
sourceMapStore = MockRepository.GenerateStrictMock<ISourceMapStore>();
}
if (functionMapStore == null)
{
functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore = MockRepository.GenerateStrictMock<IFunctionMapStore>();
}
if (functionMapConsumer == null)
{
functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer = MockRepository.GenerateStrictMock<IFunctionMapConsumer>();
}
if (useSimpleStackFrameDeminier)
{
return new SimpleStackFrameDeminifier(functionMapStore, functionMapConsumer);
}
else
{
return new StackFrameDeminifier(sourceMapStore, functionMapStore, functionMapConsumer);
}
return new StackFrameDeminifier(sourceMapStore, functionMapStore, functionMapConsumer);
}
[TestMethod]
@ -49,14 +42,15 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
}
[TestMethod]
public void DeminifyStackFrame_StackFrameNullProperties_DoesNotThrowException()
public void ExtractFrameInformationFromSourceMap_NullInputs_DoesNotThrowException()
{
// Arrange
StackFrame stackFrame = new StackFrame();
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies();
FunctionMapEntry functionMapEntry = null;
SourceMap sourceMap = null;
SourcePosition generatedSourcePosition = null;
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.MethodName);
@ -65,162 +59,201 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
}
[TestMethod]
public void SimpleStackFrameDeminierDeminifyStackFrame_FunctionMapReturnsNull_NoFunctionMapDeminificationError()
public void ExtractFrameInformationFromSourceMap_NoBinding_ReturnNullMethodName()
{
// Arrange
string filePath = "foo";
StackFrame stackFrame = new StackFrame {FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(null);
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, useSimpleStackFrameDeminier:true);
FunctionMapEntry functionMapEntry = new FunctionMapEntry();
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
SourcePosition generatedSourcePosition = new SourcePosition();
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.NoSourceCodeProvided, stackFrameDeminification.DeminificationError);
Assert.AreEqual(DeminificationError.NoWrapingFunction, stackFrameDeminification.DeminificationError);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
sourceMap.VerifyAllExpectations();
}
[TestMethod]
public void SimpleStackFrameDeminierDeminifyStackFrame_GetWRappingFunctionForSourceLocationReturnsNull_NoWrapingFunctionDeminificationError()
public void ExtractFrameInformationFromSourceMap_HasSingleBindingSourceMapNotParsed_ReturnNullMethodName()
{
// Arrange
string filePath = "foo";
StackFrame stackFrame = new StackFrame { FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(new List<FunctionMapEntry>());
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
.Return(null);
FunctionMapEntry functionMapEntry = new FunctionMapEntry
{
Bindings =
new List<BindingInformation>
{
new BindingInformation
{
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 15}
}
}
};
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
sourceMap.Stub(x => x.GetMappingEntryForGeneratedSourcePosition(Arg<SourcePosition>.Is.Anything)).Return(null);
// SourceMap failed to parse
sourceMap.ParsedMappings = null;
SourcePosition generatedSourcePosition = new SourcePosition();
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
// Assert
Assert.AreEqual(DeminificationError.NoWrapingFunctionFound, stackFrameDeminification.DeminificationError);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
}
[TestMethod]
public void SimpleStackFrameDeminierDeminifyStackFrame_WrapingFunctionFound_NoDeminificationError()
{
// Arrange
string filePath = "foo";
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry {DeminfifiedMethodName = "DeminifiedFoo"};
StackFrame stackFrame = new StackFrame { FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(new List<FunctionMapEntry>());
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
.Return(wrapingFunctionMapEntry);
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
// Assert
Assert.AreEqual(DeminificationError.None, stackFrameDeminification.DeminificationError);
Assert.AreEqual(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
}
[TestMethod]
public void StackFrameDeminierDeminifyStackFrame_SourceMapProviderReturnsNull_NoSourcemapProvidedError()
{
// Arrange
string filePath = "foo";
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
StackFrame stackFrame = new StackFrame { FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(new List<FunctionMapEntry>());
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
.Return(wrapingFunctionMapEntry);
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
// Assert
Assert.AreEqual(DeminificationError.NoSourceMap, stackFrameDeminification.DeminificationError);
Assert.AreEqual(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
}
[TestMethod]
public void StackFrameDeminierDeminifyStackFrame_SourceMapParsingNull_SourceMapFailedToParseError()
{
// Arrange
string filePath = "foo";
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
StackFrame stackFrame = new StackFrame { FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(new List<FunctionMapEntry>());
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
.Return(wrapingFunctionMapEntry);
ISourceMapStore sourceMapStore = MockRepository.GenerateStub<ISourceMapStore>();
sourceMapStore.Stub(c => c.GetSourceMapForUrl(Arg<string>.Is.Anything)).Return(new SourceMap());
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore,functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.SourceMapFailedToParse, stackFrameDeminification.DeminificationError);
Assert.AreEqual(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.MethodName);
sourceMap.VerifyAllExpectations();
}
[TestMethod]
public void StackFrameDeminierDeminifyStackFrame_SourceMapGeneratedMappingEntryNull_NoMatchingMapingInSourceMapError()
public void ExtractFrameInformationFromSourceMap_HasSingleBindingNoMatchingMapping_ReturnNullMethodName()
{
// Arrange
string filePath = "foo";
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
StackFrame stackFrame = new StackFrame { FilePath = filePath };
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
.Return(new List<FunctionMapEntry>());
ISourceMapStore sourceMapStore = MockRepository.GenerateStub<ISourceMapStore>();
SourceMap sourceMap = new SourceMap() {ParsedMappings = new List<MappingEntry>()};
FunctionMapEntry functionMapEntry = new FunctionMapEntry
{
Bindings =
new List<BindingInformation>
{
new BindingInformation
{
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 15}
}
}
};
sourceMapStore.Stub(c => c.GetSourceMapForUrl(Arg<string>.Is.Anything)).Return(sourceMap);
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
.Return(wrapingFunctionMapEntry);
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
sourceMap.Stub(x => x.GetMappingEntryForGeneratedSourcePosition(Arg<SourcePosition>.Is.Anything)).Return(null);
sourceMap.ParsedMappings = new List<MappingEntry>();
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore, functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
SourcePosition generatedSourcePosition = new SourcePosition();
// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.NoMatchingMapingInSourceMap, stackFrameDeminification.DeminificationError);
Assert.AreEqual(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.FilePath);
Assert.IsNull(stackFrameDeminification.DeminifiedStackFrame.MethodName);
sourceMap.VerifyAllExpectations();
}
[TestMethod]
public void ExtractFrameInformationFromSourceMap_HasSingleBindingMatchingMapping_ReturnsStackFrameWithMethodName()
{
// Arrange
FunctionMapEntry functionMapEntry = new FunctionMapEntry
{
Bindings =
new List<BindingInformation>
{
new BindingInformation
{
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 5, ZeroBasedColumnNumber = 8}
}
}
};
SourcePosition generatedSourcePosition = new SourcePosition
{
ZeroBasedColumnNumber = 25,
ZeroBasedLineNumber = 85
};
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
sourceMap.Stub(
x =>
x.GetMappingEntryForGeneratedSourcePosition(
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 8)))
.Return(new MappingEntry
{
OriginalName = "foo",
});
// Act
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.None, stackFrameDeminification.DeminificationError);
Assert.AreEqual("foo", stackFrameDeminification.DeminifiedStackFrame.MethodName);
sourceMap.VerifyAllExpectations();
}
[TestMethod]
public void ExtractFrameInformationFromSourceMap_MatchingMappingMultipleBindings_ReturnsStackFrameWithFullBinding()
{
// Arrange
FunctionMapEntry functionMapEntry = new FunctionMapEntry
{
Bindings =
new List<BindingInformation>
{
new BindingInformation
{
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 5, ZeroBasedColumnNumber = 5}
},
new BindingInformation
{
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 10}
}
}
};
SourcePosition generatedSourcePosition = new SourcePosition {ZeroBasedColumnNumber = 39, ZeroBasedLineNumber = 31};
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
sourceMap.Stub(
x =>
x.GetMappingEntryForGeneratedSourcePosition(
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 5)))
.Return(new MappingEntry
{
OriginalName = "bar"
});
sourceMap.Stub(
x =>
x.GetMappingEntryForGeneratedSourcePosition(
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 20 && y.ZeroBasedColumnNumber == 10)))
.Return(new MappingEntry
{
OriginalName = "baz",
});
// Act
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.None, stackFrameDeminification.DeminificationError);
Assert.AreEqual("bar.baz", stackFrameDeminification.DeminifiedStackFrame.MethodName);
sourceMap.VerifyAllExpectations();
}
[TestMethod]
public void ExtractFrameInformationFromSourceMap_HasMatchingGeneratedPositionMapping_ReturnsStackFrameWithSourcePositionAndFileName()
{
// Arrange
FunctionMapEntry functionMapEntry = null;
SourcePosition generatedSourcePosition = new SourcePosition
{
ZeroBasedColumnNumber = 25,
ZeroBasedLineNumber = 85
};
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
sourceMap.Stub(x => x.GetMappingEntryForGeneratedSourcePosition(generatedSourcePosition)).Return(new MappingEntry
{
OriginalSourcePosition = new SourcePosition { ZeroBasedColumnNumber = 10, ZeroBasedLineNumber = 20 }
});
// Act
StackFrameDeminificationResult stackFrameDeminification = StackFrameDeminifier.ExtractFrameInformationFromSourceMap(functionMapEntry, sourceMap, generatedSourcePosition);
// Assert
Assert.AreEqual(DeminificationError.NoWrapingFunction, stackFrameDeminification.DeminificationError);
Assert.AreEqual(10, stackFrameDeminification.DeminifiedStackFrame.SourcePosition.ZeroBasedColumnNumber);
Assert.AreEqual(20, stackFrameDeminification.DeminifiedStackFrame.SourcePosition.ZeroBasedLineNumber);
}
}
}
}