static void Main(string[] args) { var interpreter = new ExceptionReportInterpreter(); ProcessCommandArgs(interpreter, args); if (ConsoleEx.IsInputRedirected) { interpreter.Translate(Console.In, Console.Out); } else { foreach (var symPath in interpreter.SymbolPaths) { Console.WriteLine("Symbols: {0}", symPath); } Console.WriteLine("Paste a stack trace to analyze (ESC to exit) ..."); while (true) { var reader = new ConsoleTextReader(); interpreter.Translate(reader, Console.Out); if (reader.IsEscapeDetected) { break; } } } }
private void InternalTestException(IsolatedMode mode, string methodSig, string expectedException, LineNumberInfo[] expectedInfos) { // Parse the methodSig var assemblyName = "ProductionStackTrace.Test.Library"; var defaultNamespace = assemblyName; var m = _regexMethodSig.Match(methodSig); if (m == Match.Empty) { throw new ArgumentException("Invalid methodSig: " + methodSig); } var className = m.Groups["Class"].ToString().TrimEnd('.'); var methodName = m.Groups["Method"].ToString(); var methodParams = m.Groups["Params"].ToString(); // Execute in isolated environment with or without access to // PDB symbols information (meaning native stack trace either has // or doesn't have line number info) // // Customization in the .csproj file for this Test project in the // "AfterBuild" target will setup two subfolders - lib and libpdb. // 'lib' will contain just the DLL, and 'libpdb' will have DLL + PDB. // // Also original PDB location will be deleted, so that PDB can only // be found if it's on the Symbols Paths or in the folder as DLL. var env = new IsolatedEnvironment(); env.LibPaths.Add(mode == IsolatedMode.NoSymbols ? "lib" : "libpdb"); var r = env.Run(string.Format("{1}.{2}, {0}", assemblyName, defaultNamespace, className), methodName); Assert.IsNotNull(r.Exception); Assert.IsNotNullOrEmpty(r.ExceptionStackTrace); Assert.IsNotNullOrEmpty(r.ExceptionReport); StringAssert.StartsWith(expectedException + "\r\n", r.ExceptionStackTrace); StringAssert.StartsWith(expectedException + "\r\n", r.ExceptionReport); StringAssert.Contains(" at " + defaultNamespace + "." + methodSig, r.ExceptionStackTrace); Assert.AreNotEqual(r.ExceptionStackTrace, r.ExceptionReport); if (mode == IsolatedMode.NoSymbols) { StringAssert.DoesNotContain(":line ", r.ExceptionStackTrace); } else { StringAssert.Contains(":line ", r.ExceptionStackTrace); } var interpret = new ExceptionReportInterpreter(); var sb = new StringBuilder(); string parsedReport; if (mode != IsolatedMode.NoSymbols) { interpret.SymbolPaths.Add("libpdb"); } // Run interpreter with no access to symbols // It should produce the same stack trace as the internal exception interpret.Translate(new StringReader(r.ExceptionReport), new StringWriter(sb)); parsedReport = sb.ToString(); // Parsed report should be exactly the same as we would obtain // from the original stack trace. // // - If the original stack trace was run without symbols, then // interpreter didn't have access to symbols either, and so // the output should match Assert.AreEqual(r.ExceptionStackTrace, parsedReport.TrimEnd()); if (mode == IsolatedMode.NoSymbols) { // If we ran original report with no access to symbols, then // run it again - now with PDB symbols. The stack trace should now // include line number info sb.Clear(); interpret.SymbolPaths.Add("libpdb"); interpret.Translate(new StringReader(r.ExceptionReport), new StringWriter(sb)); parsedReport = sb.ToString(); StringAssert.DoesNotStartWith(parsedReport, r.ExceptionReport); // check it is different Assert.AreNotEqual(r.ExceptionStackTrace, parsedReport); // check it is not same as default stack trace } // Check that the expected line number info is present foreach (var info in expectedInfos) { StringAssert.Contains("\\" + info.File + ":line " + info.LineNo, parsedReport); // check it has the line info } }