// make it internal to enable unit testing internal StackFrame GetStackFrame(string function, string file, int lineNumber) { var frame = new StackFrame { Function = function, File = file, Line = lineNumber }; if (string.IsNullOrEmpty(file)) { return frame; } IEnumerable<string> lines = null; if (File.Exists(file)) { lines = File.ReadLines(file); } else { // Handle relative paths and embedded files var fileInfo = _fileProvider.GetFileInfo(file); if (fileInfo.Exists) { // ReadLines doesn't accept a stream. Use ReadLines as its more efficient // relative to reading lines via stream reader if (!string.IsNullOrEmpty(fileInfo.PhysicalPath)) { lines = File.ReadLines(fileInfo.PhysicalPath); } else { lines = ReadLines(fileInfo); } } } if (lines != null) { ReadFrameContent(frame, lines, lineNumber, lineNumber); } return frame; }
// make it internal to enable unit testing internal void ReadFrameContent( StackFrame frame, IEnumerable<string> allLines, int errorStartLineNumberInFile, int errorEndLineNumberInFile) { // Get the line boundaries in the file to be read and read all these lines at once into an array. var preErrorLineNumberInFile = Math.Max(errorStartLineNumberInFile - SourceCodeLineCount, 1); var postErrorLineNumberInFile = errorEndLineNumberInFile + SourceCodeLineCount; var codeBlock = allLines .Skip(preErrorLineNumberInFile - 1) .Take(postErrorLineNumberInFile - preErrorLineNumberInFile + 1) .ToArray(); var numOfErrorLines = (errorEndLineNumberInFile - errorStartLineNumberInFile) + 1; var errorStartLineNumberInArray = errorStartLineNumberInFile - preErrorLineNumberInFile; frame.PreContextLine = preErrorLineNumberInFile; frame.PreContextCode = codeBlock.Take(errorStartLineNumberInArray).ToArray(); frame.ContextCode = codeBlock .Skip(errorStartLineNumberInArray) .Take(numOfErrorLines) .ToArray(); frame.PostContextCode = codeBlock .Skip(errorStartLineNumberInArray + numOfErrorLines) .ToArray(); }