Callstack deminification without parsing JS to support ES2015+ (#82)
* Enable deminifying call stack without parsing JS to support ES2015 * Move exception handling into FunctionMapGenerator
This commit is contained in:
Родитель
263a3bd471
Коммит
ef2988141b
|
@ -17,7 +17,14 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
for (int i = 0; i < DeminifiedStackFrameResults.Count; i++)
|
||||
{
|
||||
StackFrame deminFrame = DeminifiedStackFrameResults[i].DeminifiedStackFrame;
|
||||
StackFrame frame = string.IsNullOrEmpty(deminFrame.MethodName) ? MinifiedStackFrames[i] : deminFrame;
|
||||
|
||||
// Use deminified info wherever possible, merging if necessary so we always print a full frame
|
||||
StackFrame frame = new StackFrame()
|
||||
{
|
||||
MethodName = deminFrame.MethodName ?? MinifiedStackFrames[i].MethodName,
|
||||
SourcePosition = deminFrame.SourcePosition ?? MinifiedStackFrames[i].SourcePosition,
|
||||
FilePath = deminFrame.SourcePosition != null ? deminFrame.FilePath : MinifiedStackFrames[i].FilePath
|
||||
};
|
||||
|
||||
output += $"{Environment.NewLine} {frame}";
|
||||
}
|
||||
|
|
|
@ -20,11 +20,21 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
return null;
|
||||
}
|
||||
|
||||
List<FunctionMapEntry> result = ParseSourceCode(sourceCodeStreamReader);
|
||||
|
||||
foreach (FunctionMapEntry functionMapEntry in result)
|
||||
List<FunctionMapEntry> result;
|
||||
try
|
||||
{
|
||||
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
result = ParseSourceCode(sourceCodeStreamReader);
|
||||
|
||||
foreach (FunctionMapEntry functionMapEntry in result)
|
||||
{
|
||||
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Failed to parse JavaScript source. This is common as the JS parser does not support ES2015+.
|
||||
// Continue to regular source map deminification.
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
/// 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>
|
||||
StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame);
|
||||
StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName);
|
||||
}
|
||||
}
|
|
@ -6,12 +6,12 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <summary>
|
||||
/// This class only deminfies the method name in a stack frame. It does not depend on having a source map available during runtime.
|
||||
/// </summary>
|
||||
internal class SimpleStackFrameDeminifier : IStackFrameDeminifier
|
||||
internal class MethodNameStackFrameDeminifier : IStackFrameDeminifier
|
||||
{
|
||||
protected readonly IFunctionMapConsumer _functionMapConsumer;
|
||||
protected readonly IFunctionMapStore _functionMapStore;
|
||||
|
||||
public SimpleStackFrameDeminifier(IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer)
|
||||
public MethodNameStackFrameDeminifier(IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer)
|
||||
{
|
||||
_functionMapStore = functionMapStore;
|
||||
_functionMapConsumer = functionMapConsumer;
|
||||
|
@ -19,7 +19,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <summary>
|
||||
/// This method will deminify the method name of a single stack from from a minified stack trace.
|
||||
/// </summary>
|
||||
public virtual StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame)
|
||||
public virtual StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName)
|
||||
{
|
||||
StackFrameDeminificationResult result = new StackFrameDeminificationResult
|
||||
{
|
|
@ -66,7 +66,7 @@
|
|||
<Compile Include="IStackFrameDeminifier.cs" />
|
||||
<Compile Include="IStackTraceParser.cs" />
|
||||
<Compile Include="KeyValueCache.cs" />
|
||||
<Compile Include="SimpleStackFrameDeminifier.cs" />
|
||||
<Compile Include="MethodNameStackFrameDeminifier.cs" />
|
||||
<Compile Include="SourceMapStore.cs" />
|
||||
<Compile Include="StackFrame.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
|
|
@ -52,6 +52,11 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
public StackFrame DeminifiedStackFrame { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original name of the symbol at this frame's position
|
||||
/// </summary>
|
||||
public string DeminifiedSymbolName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An enum indicating if any errors occured when deminifying the stack frame.
|
||||
/// </summary>
|
||||
|
|
|
@ -9,20 +9,26 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// 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 ISourceMapStore _sourceMapStore;
|
||||
private readonly MethodNameStackFrameDeminifier _methodNameDeminifier = null;
|
||||
|
||||
public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer) : base (functionMapStore, functionMapConsumer)
|
||||
public StackFrameDeminifier(ISourceMapStore sourceMapStore)
|
||||
{
|
||||
_sourceMapStore = sourceMapStore;
|
||||
}
|
||||
|
||||
public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer) : this(sourceMapStore)
|
||||
{
|
||||
_methodNameDeminifier = new MethodNameStackFrameDeminifier(functionMapStore, 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)
|
||||
public StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName)
|
||||
{
|
||||
if (stackFrame == null)
|
||||
{
|
||||
|
@ -32,7 +38,21 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
SourceMap sourceMap = _sourceMapStore.GetSourceMapForUrl(stackFrame.FilePath);
|
||||
SourcePosition generatedSourcePosition = stackFrame.SourcePosition;
|
||||
|
||||
StackFrameDeminificationResult result = base.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult result = null;
|
||||
if (_methodNameDeminifier != null)
|
||||
{
|
||||
result = _methodNameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName);
|
||||
}
|
||||
|
||||
if (result == null || result.DeminificationError == DeminificationError.NoSourceCodeProvided)
|
||||
{
|
||||
result = new StackFrameDeminificationResult
|
||||
{
|
||||
DeminificationError = DeminificationError.None,
|
||||
DeminifiedStackFrame = new StackFrame { MethodName = callerSymbolName }
|
||||
};
|
||||
}
|
||||
|
||||
if (result.DeminificationError == DeminificationError.None)
|
||||
{
|
||||
MappingEntry generatedSourcePositionMappingEntry =
|
||||
|
@ -53,9 +73,12 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
result.DeminificationError = DeminificationError.NoMatchingMapingInSourceMap;
|
||||
}
|
||||
}
|
||||
|
||||
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry?.OriginalFileName;
|
||||
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry?.OriginalSourcePosition;
|
||||
else
|
||||
{
|
||||
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry.OriginalFileName;
|
||||
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry.OriginalSourcePosition;
|
||||
result.DeminifiedSymbolName = generatedSourcePositionMappingEntry.OriginalName;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -49,7 +49,41 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
|
||||
return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a StackTraceDeminifier which does not depend on JS files, and is ES2015+ compatible.
|
||||
/// StackTrace deminifiers created with this method will keep source maps cached, and thus use significantly more memory during runtime than the ones generated with GetMethodNameOnlyStackTraceDeminfier.
|
||||
/// </summary>
|
||||
/// <param name="sourceMapProvider">Consumers of the API should implement this interface, which provides the source map for a given JavaScript file. Throws ArgumentNullException if the parameter is set to null.</param>
|
||||
public static StackTraceDeminifier GetMapOnlyStackTraceDeminfier(ISourceMapProvider sourceMapProvider)
|
||||
{
|
||||
return GetMapOnlyStackTraceDeminfier(sourceMapProvider, new StackTraceParser());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a StackTraceDeminifier which does not depend on JS files, and is ES2015+ compatible.
|
||||
/// StackTrace deminifiers created with this method will keep source maps cached, and thus use significantly more memory during runtime than the ones generated with GetMethodNameOnlyStackTraceDeminfier.
|
||||
/// </summary>
|
||||
/// <param name="sourceMapProvider">Consumers of the API should implement this interface, which provides the source map for a given JavaScript file. Throws ArgumentNullException if the parameter is set to null.</param>
|
||||
/// <param name="stackTraceParser">Consumers of the API should implement this interface, which provides a parser for the stacktrace. Throws ArgumentNullException if the parameter is set to null.</param>
|
||||
public static StackTraceDeminifier GetMapOnlyStackTraceDeminfier(ISourceMapProvider sourceMapProvider, IStackTraceParser stackTraceParser)
|
||||
{
|
||||
if (sourceMapProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sourceMapProvider));
|
||||
}
|
||||
|
||||
if (stackTraceParser == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stackTraceParser));
|
||||
}
|
||||
|
||||
ISourceMapStore sourceMapStore = new SourceMapStore(sourceMapProvider);
|
||||
IStackFrameDeminifier stackFrameDeminifier = new StackFrameDeminifier(sourceMapStore);
|
||||
|
||||
return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a StackTraceDeminifier that only deminifies the method names. StackTrace deminifiers created with this method will use significantly less memory during runtime than the
|
||||
/// </summary>
|
||||
|
@ -71,7 +105,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
ValidateArguments(sourceMapProvider, generatedCodeProvider, stackTraceParser);
|
||||
|
||||
SourceMapParser sourceMapParser = new SourceMapParser();
|
||||
IStackFrameDeminifier stackFrameDeminifier = new SimpleStackFrameDeminifier(new FunctionMapStore(generatedCodeProvider, (url) => sourceMapParser.ParseSourceMap(sourceMapProvider.GetSourceMapContentsForCallstackUrl(url))), new FunctionMapConsumer());
|
||||
IStackFrameDeminifier stackFrameDeminifier = new MethodNameStackFrameDeminifier(new FunctionMapStore(generatedCodeProvider, (url) => sourceMapParser.ParseSourceMap(sourceMapProvider.GetSourceMapContentsForCallstackUrl(url))), new FunctionMapConsumer());
|
||||
|
||||
return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,14 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
result.Message = message;
|
||||
result.DeminifiedStackFrameResults = new List<StackFrameDeminificationResult>();
|
||||
|
||||
foreach (StackFrame minifiedStackFrame in result.MinifiedStackFrames)
|
||||
// Deminify frames in reverse order so we can pass the symbol name from caller
|
||||
// (i.e. the function name) into the next level's deminification.
|
||||
string callerSymbolName = null;
|
||||
for (int i = result.MinifiedStackFrames.Count - 1; i >= 0; i--)
|
||||
{
|
||||
result.DeminifiedStackFrameResults.Add(_stackFrameDeminifier.DeminifyStackFrame(minifiedStackFrame));
|
||||
var frame = _stackFrameDeminifier.DeminifyStackFrame(result.MinifiedStackFrames[i], callerSymbolName);
|
||||
callerSymbolName = frame?.DeminifiedSymbolName;
|
||||
result.DeminifiedStackFrameResults.Insert(0, frame);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
<Compile Include="KeyValueCacheUnitTests.cs" />
|
||||
<Compile Include="StackFrameDeminifierUnitTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierClosureEndToEndTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierMapOnlyEndToEndTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierWebpackEndToEndTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierEndToEndTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierUnitTests.cs" />
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
if (useSimpleStackFrameDeminier)
|
||||
{
|
||||
return new SimpleStackFrameDeminifier(functionMapStore, functionMapConsumer);
|
||||
return new MethodNameStackFrameDeminifier(functionMapStore, functionMapConsumer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
StackFrame stackFrame = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>( ()=> stackFrameDeminifier.DeminifyStackFrame(stackFrame));
|
||||
Assert.Throws<ArgumentNullException>( ()=> stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -56,7 +56,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies();
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
|
@ -77,7 +77,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, useSimpleStackFrameDeminier:true);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoSourceCodeProvided, stackFrameDeminification.DeminificationError);
|
||||
|
@ -102,7 +102,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoWrapingFunctionFound, stackFrameDeminification.DeminificationError);
|
||||
|
@ -128,7 +128,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.None, stackFrameDeminification.DeminificationError);
|
||||
|
@ -155,7 +155,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoSourceMap, stackFrameDeminification.DeminificationError);
|
||||
|
@ -183,7 +183,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore,functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.SourceMapFailedToParse, stackFrameDeminification.DeminificationError);
|
||||
|
@ -213,7 +213,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore, functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
|
||||
|
||||
// Act
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
|
||||
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoMatchingMapingInSourceMap, stackFrameDeminification.DeminificationError);
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
using Xunit;
|
||||
using Rhino.Mocks;
|
||||
using SourcemapToolkit.SourcemapParser.UnitTests;
|
||||
|
||||
namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
||||
{
|
||||
|
||||
public class StackTraceDeminifierMapOnlyEndToEndTests
|
||||
{
|
||||
private const string GeneratedCodeString = "function causeCrash(){function n(){var n=16;n+=2;t(n)}function t(n){n=n+2;i(n)}function i(n){(function(){var t;console.log(t.length+n)})()}window.onerror=function(n,t,i,r,u){u?document.getElementById(\"callstackdisplay\").innerText=u.stack:window.event.error&&(document.getElementById(\"callstackdisplay\").innerText=window.event.error.stack)};n()}window.onload=function(){document.getElementById(\"crashbutton\").addEventListener(\"click\",function(){causeCrash()})};";
|
||||
private const string SourceMapString = "{\r\n\"version\":3,\r\n\"file\":\"crashcauser.min.js\",\r\n\"lineCount\":1,\r\n\"mappings\":\"AAAAA,SAASA,UAAU,CAAA,CACnB,CACIC,SAASA,CAAM,CAAA,CAAG,CACd,IAAIC,EAAwB,EAAE,CAC9BA,CAAsB,EAAG,CAAC,CAC1BC,CAAM,CAACD,CAAD,CAHQ,CAMlBC,SAASA,CAAM,CAACC,CAAD,CAAQ,CACnBA,CAAM,CAAEA,CAAM,CAAE,CAAC,CACjBC,CAAM,CAACD,CAAD,CAFa,CAKvBC,SAASA,CAAM,CAACD,CAAD,CAAQ,EAClB,QAAQ,CAAA,CAAG,CACR,IAAIE,CAAC,CACLC,OAAOC,IAAI,CAACF,CAACG,OAAQ,CAAEL,CAAZ,CAFH,EAGX,CAAA,CAJkB,CAOvBM,MAAMC,QAAS,CAAEC,QAAS,CAACC,CAAO,CAAEC,CAAM,CAAEC,CAAM,CAAEC,CAAK,CAAEC,CAAjC,CAAwC,CAC1DA,CAAJ,CACIC,QAAQC,eAAe,CAAC,kBAAD,CAAoBC,UAAW,CAAEH,CAAKI,MADjE,CAESX,MAAMY,MAAML,M,GACjBC,QAAQC,eAAe,CAAC,kBAAD,CAAoBC,UAAW,CAAEV,MAAMY,MAAML,MAAMI,OAJhB,C,CAOlEpB,CAAM,CAAA,CA1BV,CA6BAS,MAAMa,OAAQ,CAAEC,QAAS,CAAA,CAAQ,CAC7BN,QAAQC,eAAe,CAAC,aAAD,CAAeM,iBAAiB,CAAC,OAAO,CAAE,QAAS,CAAA,CAAG,CACzEzB,UAAU,CAAA,CAD+D,CAAtB,CAD1B,C\",\r\n\"sources\":[\"crashcauser.js\"],\r\n\"names\":[\"causeCrash\",\"level1\",\"longLocalVariableName\",\"level2\",\"input\",\"level3\",\"x\",\"console\",\"log\",\"length\",\"window\",\"onerror\",\"window.onerror\",\"message\",\"source\",\"lineno\",\"colno\",\"error\",\"document\",\"getElementById\",\"innerText\",\"stack\",\"event\",\"onload\",\"window.onload\",\"addEventListener\"]\r\n}";
|
||||
|
||||
|
||||
private StackTraceDeminifier GetStackTraceDeminifierWithDependencies()
|
||||
{
|
||||
ISourceMapProvider sourceMapProvider = MockRepository.GenerateStrictMock<ISourceMapProvider>();
|
||||
sourceMapProvider.Stub(x => x.GetSourceMapContentsForCallstackUrl("http://localhost:11323/crashcauser.min.js")).Return(UnitTestUtils.StreamReaderFromString(SourceMapString));
|
||||
|
||||
ISourceCodeProvider sourceCodeProvider = MockRepository.GenerateStrictMock<ISourceCodeProvider>();
|
||||
sourceCodeProvider.Stub(x => x.GetSourceCode("http://localhost:11323/crashcauser.min.js")).Return(UnitTestUtils.StreamReaderFromString(GeneratedCodeString));
|
||||
|
||||
return StackTraceDeminfierFactory.GetMapOnlyStackTraceDeminfier(sourceMapProvider);
|
||||
}
|
||||
|
||||
private static void ValidateDeminifyStackTraceResults(DeminifyStackTraceResult results)
|
||||
{
|
||||
Assert.Equal(6, results.DeminifiedStackFrameResults.Count);
|
||||
Assert.Equal(DeminificationError.None, results.DeminifiedStackFrameResults[0].DeminificationError);
|
||||
Assert.Equal(16, results.DeminifiedStackFrameResults[0].DeminifiedStackFrame.SourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal("level3", results.DeminifiedStackFrameResults[1].DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal("level2", results.DeminifiedStackFrameResults[2].DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal("level1", results.DeminifiedStackFrameResults[3].DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal("causeCrash", results.DeminifiedStackFrameResults[4].DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal(32, results.DeminifiedStackFrameResults[5].DeminifiedStackFrame.SourcePosition.ZeroBasedLineNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeminifyStackTrace_ChromeStackTraceString_CorrectDeminificationWhenPossible()
|
||||
{
|
||||
// Arrange
|
||||
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
|
||||
string chromeStackTrace = @"TypeError: Cannot read property 'length' of undefined
|
||||
at http://localhost:11323/crashcauser.min.js:1:125
|
||||
at i (http://localhost:11323/crashcauser.min.js:1:137)
|
||||
at t (http://localhost:11323/crashcauser.min.js:1:75)
|
||||
at n (http://localhost:11323/crashcauser.min.js:1:50)
|
||||
at causeCrash (http://localhost:11323/crashcauser.min.js:1:341)
|
||||
at HTMLButtonElement.<anonymous> (http://localhost:11323/crashcauser.min.js:1:445)";
|
||||
|
||||
// Act
|
||||
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(chromeStackTrace);
|
||||
|
||||
// Assert
|
||||
ValidateDeminifyStackTraceResults(results);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeminifyStackTrace_FireFoxStackTraceString_CorrectDeminificationWhenPossible()
|
||||
{
|
||||
// Arrange
|
||||
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
|
||||
string fireFoxStackTrace = @"i/<@http://localhost:11323/crashcauser.min.js:1:112
|
||||
i@http://localhost:11323/crashcauser.min.js:1:95
|
||||
t@http://localhost:11323/crashcauser.min.js:1:75
|
||||
n@http://localhost:11323/crashcauser.min.js:1:50
|
||||
causeCrash@http://localhost:11323/crashcauser.min.js:1:341
|
||||
window.onload/<@http://localhost:11323/crashcauser.min.js:1:445";
|
||||
|
||||
// Act
|
||||
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(fireFoxStackTrace);
|
||||
|
||||
// Assert
|
||||
ValidateDeminifyStackTraceResults(results);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeminifyStackTrace_IE11StackTraceString_CorrectDeminificationWhenPossible()
|
||||
{
|
||||
// Arrange
|
||||
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
|
||||
string ieStackTrace = @"TypeError: Unable to get property 'length' of undefined or null reference
|
||||
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:112)
|
||||
at i (http://localhost:11323/crashcauser.min.js:1:95)
|
||||
at t (http://localhost:11323/crashcauser.min.js:1:75)
|
||||
at n (http://localhost:11323/crashcauser.min.js:1:50)
|
||||
at causeCrash (http://localhost:11323/crashcauser.min.js:1:341)
|
||||
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:445)";
|
||||
|
||||
// Act
|
||||
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(ieStackTrace);
|
||||
|
||||
// Assert
|
||||
ValidateDeminifyStackTraceResults(results);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeminifyStackTrace_EdgeStackTraceString_CorrectDeminificationWhenPossible()
|
||||
{
|
||||
// Arrange
|
||||
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
|
||||
string dgeStackTrace = @"TypeError: Unable to get property 'length' of undefined or null reference
|
||||
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:112)
|
||||
at i (http://localhost:11323/crashcauser.min.js:1:95)
|
||||
at t (http://localhost:11323/crashcauser.min.js:1:75)
|
||||
at n (http://localhost:11323/crashcauser.min.js:1:50)
|
||||
at causeCrash (http://localhost:11323/crashcauser.min.js:1:341)
|
||||
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:445)";
|
||||
|
||||
// Act
|
||||
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(dgeStackTrace);
|
||||
|
||||
// Assert
|
||||
ValidateDeminifyStackTraceResults(results);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeminifyResultToString_SuccessfullyDeminified_AllLinesDeminified()
|
||||
{
|
||||
// Arrange
|
||||
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
|
||||
string ieStackTrace = @"TypeError: Unable to get property 'length' of undefined or null reference
|
||||
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:112)
|
||||
at i (http://localhost:11323/crashcauser.min.js:1:95)
|
||||
at t (http://localhost:11323/crashcauser.min.js:1:75)
|
||||
at n (http://localhost:11323/crashcauser.min.js:1:50)
|
||||
at causeCrash (http://localhost:11323/crashcauser.min.js:1:341)
|
||||
at http://localhost:11323/crashcauser.min.js:1:445";
|
||||
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(ieStackTrace);
|
||||
string exectedResult = @"TypeError: Unable to get property 'length' of undefined or null reference
|
||||
at Anonymous function in crashcauser.js:17:13
|
||||
at level3 in crashcauser.js:15:10
|
||||
at level2 in crashcauser.js:11:9
|
||||
at level1 in crashcauser.js:6:9
|
||||
at causeCrash in crashcauser.js:28:5
|
||||
at ? in crashcauser.js:33:9";
|
||||
|
||||
// Act
|
||||
string formatted = results.ToString();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(exectedResult.Replace("\r", ""), formatted.Replace("\r", ""));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
stackTraceParser.Stub(x => x.ParseStackTrace(stackTraceString, out string message)).Return(minifiedStackFrames).OutRef("Error example");
|
||||
|
||||
IStackFrameDeminifier stackFrameDeminifier = MockRepository.GenerateStrictMock<IStackFrameDeminifier>();
|
||||
stackFrameDeminifier.Stub(x => x.DeminifyStackFrame(minifiedStackFrames[0])).Return(null);
|
||||
stackFrameDeminifier.Stub(x => x.DeminifyStackFrame(minifiedStackFrames[0], null)).Return(null);
|
||||
|
||||
StackTraceDeminifier stackTraceDeminifier = new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
IStackFrameDeminifier stackFrameDeminifier = MockRepository.GenerateStrictMock<IStackFrameDeminifier>();
|
||||
StackFrameDeminificationResult stackFrameDeminification = new StackFrameDeminificationResult();
|
||||
stackFrameDeminifier.Stub(x => x.DeminifyStackFrame(minifiedStackFrames[0])).Return(stackFrameDeminification);
|
||||
stackFrameDeminifier.Stub(x => x.DeminifyStackFrame(minifiedStackFrames[0], null)).Return(stackFrameDeminification);
|
||||
|
||||
StackTraceDeminifier stackTraceDeminifier = new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче