Browse Source

Merge pull request #24 from Thiht/master

Fix tests + optimize SourceLine()
Conrad Irwin 5 năm trước cách đây
mục cha
commit
56d1d8218b
2 tập tin đã thay đổi với 42 bổ sung15 xóa
  1. 22 7
      error_test.go
  2. 20 8
      stackframe.go

+ 22 - 7
error_test.go

@@ -10,6 +10,26 @@ import (
 	"testing"
 )
 
+func BenchmarkStackFormat(b *testing.B) {
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		func() {
+			defer func() {
+				err := recover()
+				if err != 'a' {
+					b.Fatal(err)
+				}
+
+				e := Errorf("hi")
+				_ = string(e.Stack())
+			}()
+
+			a()
+		}()
+	}
+}
+
 func TestStackFormat(t *testing.T) {
 
 	defer func() {
@@ -247,7 +267,7 @@ func c() {
 
 // compareStacks will compare a stack created using the errors package (actual)
 // with a reference stack created with the callers function (expected). The
-// first entry is compared inexact since the actual and expected stacks cannot
+// first entry is not compared  since the actual and expected stacks cannot
 // be created at the exact same program counter position so the first entry
 // will always differ somewhat. Returns nil if the stacks are equal enough and
 // an error containing a detailed error message otherwise.
@@ -256,12 +276,7 @@ func compareStacks(actual, expected []uintptr) error {
 		return stackCompareError("Stacks does not have equal length", actual, expected)
 	}
 	for i, pc := range actual {
-		if i == 0 {
-			firstEntryDiff := (int)(expected[i]) - (int)(pc)
-			if firstEntryDiff < -27 || firstEntryDiff > 27 {
-				return stackCompareError(fmt.Sprintf("First entry PC diff to large (%d)", firstEntryDiff), actual, expected)
-			}
-		} else if pc != expected[i] {
+		if i != 0 && pc != expected[i] {
 			return stackCompareError(fmt.Sprintf("Stacks does not match entry %d (and maybe others)", i), actual, expected)
 		}
 	}

+ 20 - 8
stackframe.go

@@ -1,9 +1,10 @@
 package errors
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"runtime"
 	"strings"
 )
@@ -62,18 +63,29 @@ func (frame *StackFrame) String() string {
 
 // SourceLine gets the line of code (from File and Line) of the original source if possible.
 func (frame *StackFrame) SourceLine() (string, error) {
-	data, err := ioutil.ReadFile(frame.File)
+	if frame.LineNumber <= 0 {
+		return "???", nil
+	}
 
+	file, err := os.Open(frame.File)
 	if err != nil {
 		return "", New(err)
 	}
-
-	lines := bytes.Split(data, []byte{'\n'})
-	if frame.LineNumber <= 0 || frame.LineNumber >= len(lines) {
-		return "???", nil
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	currentLine := 1
+	for scanner.Scan() {
+		if currentLine == frame.LineNumber {
+			return string(bytes.Trim(scanner.Bytes(), " \t")), nil
+		}
+		currentLine++
 	}
-	// -1 because line-numbers are 1 based, but our array is 0 based
-	return string(bytes.Trim(lines[frame.LineNumber-1], " \t")), nil
+	if err := scanner.Err(); err != nil {
+		return "", New(err)
+	}
+
+	return "???", nil
 }
 
 func packageAndName(fn *runtime.Func) (string, string) {