| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package errors | 5 package errors |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | |
| 9 "regexp" | 8 "regexp" |
| 10 "strings" | 9 "strings" |
| 11 "testing" | 10 "testing" |
| 12 | 11 |
| 13 . "github.com/smartystreets/goconvey/convey" | 12 . "github.com/smartystreets/goconvey/convey" |
| 14 ) | 13 ) |
| 15 | 14 |
| 16 var ( | 15 var ( |
| 17 fixSkip = regexp.MustCompile(`skipped \d+ frames`) | 16 fixSkip = regexp.MustCompile(`skipped \d+ frames`) |
| 18 fixNum = regexp.MustCompile(`^#\d+`) | 17 fixNum = regexp.MustCompile(`^#\d+`) |
| 19 fixTestingLine = regexp.MustCompile(`(testing/\w+.go):\d+`) | 18 fixTestingLine = regexp.MustCompile(`(testing/\w+.go):\d+`) |
| 20 ) | 19 ) |
| 21 | 20 |
| 22 func FixForTest(lines Lines) Lines { | 21 func FixForTest(lines []string) []string { |
| 23 for i, l := range lines { | 22 for i, l := range lines { |
| 24 switch { | 23 switch { |
| 25 case strings.HasPrefix(l, "goroutine"): | 24 case strings.HasPrefix(l, "goroutine"): |
| 26 l = "GOROUTINE LINE" | 25 l = "GOROUTINE LINE" |
| 27 case strings.HasPrefix(l, "... skipped"): | 26 case strings.HasPrefix(l, "... skipped"): |
| 28 l = fixSkip.ReplaceAllLiteralString(l, "skipped SOME fra
mes") | 27 l = fixSkip.ReplaceAllLiteralString(l, "skipped SOME fra
mes") |
| 29 } | 28 } |
| 30 l = fixNum.ReplaceAllLiteralString(l, "#?") | 29 l = fixNum.ReplaceAllLiteralString(l, "#?") |
| 31 if strings.HasPrefix(l, "#? testing/") { | 30 if strings.HasPrefix(l, "#? testing/") { |
| 32 l = fixTestingLine.ReplaceAllString(l, "$1:XXX") | 31 l = fixTestingLine.ReplaceAllString(l, "$1:XXX") |
| 33 } | 32 } |
| 34 lines[i] = l | 33 lines[i] = l |
| 35 } | 34 } |
| 36 return lines | 35 return lines |
| 37 } | 36 } |
| 38 | 37 |
| 39 func TestAnnotation(t *testing.T) { | 38 func TestAnnotation(t *testing.T) { |
| 40 t.Parallel() | 39 t.Parallel() |
| 41 | 40 |
| 42 Convey("Test annotation struct", t, func() { | 41 Convey("Test annotation struct", t, func() { |
| 43 » » e := (Annotate(New("bad thing")). | 42 » » e := Annotate(New("bad thing"), "%d some error: %q", 20, "string
y"). |
| 44 » » » Reason("%(first)d some error: %(second)q"). | 43 » » » InternalReason("extra(%.3f)", 8.2).Err() |
| 45 » » » D("extra", 8.2, "%.3f"). | |
| 46 » » » D("first", 20, "0x%08x"). | |
| 47 » » » D("second", "stringy").Err()) | |
| 48 ae := e.(*annotatedError) | 44 ae := e.(*annotatedError) |
| 49 | 45 |
| 50 Convey("annotation can render itself for public usage", func() { | 46 Convey("annotation can render itself for public usage", func() { |
| 51 So(ae.Error(), ShouldEqual, `20 some error: "stringy": b
ad thing`) | 47 So(ae.Error(), ShouldEqual, `20 some error: "stringy": b
ad thing`) |
| 52 }) | 48 }) |
| 53 | 49 |
| 54 Convey("annotation can render itself for internal usage", func()
{ | 50 Convey("annotation can render itself for internal usage", func()
{ |
| 55 » » » lines := RenderStack(e).ToLines( | 51 » » » lines := RenderStack(e, `runtime`, `github.com/jtolds/gl
s`, |
| 56 » » » » `runtime`, `github.com/jtolds/gls`, | |
| 57 `github.com/smartystreets/goconvey/convey`) | 52 `github.com/smartystreets/goconvey/convey`) |
| 58 FixForTest(lines) | 53 FixForTest(lines) |
| 59 | 54 |
| 60 » » » So(lines, ShouldResemble, Lines{ | 55 » » » So(lines, ShouldResemble, []string{ |
| 61 `original error: bad thing`, | 56 `original error: bad thing`, |
| 62 ``, | 57 ``, |
| 63 `GOROUTINE LINE`, | 58 `GOROUTINE LINE`, |
| 64 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:47 - errors.TestAnnotation.func1()`, | 59 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:43 - errors.TestAnnotation.func1()`, |
| 65 » » » » ` reason: "20 some error: \"stringy\""`, | 60 » » » » ` reason: 20 some error: "stringy"`, |
| 66 » » » » ` "extra" = 8.200`, | 61 » » » » ` internal reason: extra(8.200)`, |
| 67 » » » » ` "first" = 0x00000014`, | |
| 68 » » » » ` "second" = "stringy"`, | |
| 69 ``, | 62 ``, |
| 70 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, | 63 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, |
| 71 `... skipped SOME frames in pkg "github.com/jtol
ds/gls"...`, | 64 `... skipped SOME frames in pkg "github.com/jtol
ds/gls"...`, |
| 72 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, | 65 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, |
| 73 ``, | 66 ``, |
| 74 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:110 - errors.TestAnnotation()`, | 67 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:99 - errors.TestAnnotation()`, |
| 75 `#? testing/testing.go:XXX - testing.tRunner()`, | 68 `#? testing/testing.go:XXX - testing.tRunner()`, |
| 76 `... skipped SOME frames in pkg "runtime"...`, | 69 `... skipped SOME frames in pkg "runtime"...`, |
| 77 }) | 70 }) |
| 78 }) | 71 }) |
| 79 | 72 |
| 80 Convey("can render whole stack", func() { | 73 Convey("can render whole stack", func() { |
| 81 » » » e = Annotate(e).Reason("outer frame %(first)s").D("first
", "outer").Err() | 74 » » » e = Annotate(e, "outer frame %s", "outer").Err() |
| 82 » » » lines := RenderStack(e).ToLines( | 75 » » » lines := RenderStack(e, `runtime`, `github.com/jtolds/gl
s`, |
| 83 » » » » `runtime`, `github.com/jtolds/gls`, | |
| 84 `github.com/smartystreets/goconvey/convey`) | 76 `github.com/smartystreets/goconvey/convey`) |
| 85 FixForTest(lines) | 77 FixForTest(lines) |
| 86 | 78 |
| 87 » » » So(lines, ShouldResemble, Lines{ | 79 » » » So(lines, ShouldResemble, []string{ |
| 88 `original error: bad thing`, | 80 `original error: bad thing`, |
| 89 ``, | 81 ``, |
| 90 `GOROUTINE LINE`, | 82 `GOROUTINE LINE`, |
| 91 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:47 - errors.TestAnnotation.func1()`, | 83 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:43 - errors.TestAnnotation.func1()`, |
| 92 ` annotation #0:`, | 84 ` annotation #0:`, |
| 93 » » » » ` reason: "outer frame outer"`, | 85 » » » » ` reason: outer frame outer`, |
| 94 » » » » ` "first" = "outer"`, | |
| 95 ` annotation #1:`, | 86 ` annotation #1:`, |
| 96 » » » » ` reason: "20 some error: \"stringy\""`, | 87 » » » » ` reason: 20 some error: "stringy"`, |
| 97 » » » » ` "extra" = 8.200`, | 88 » » » » ` internal reason: extra(8.200)`, |
| 98 » » » » ` "first" = 0x00000014`, | |
| 99 » » » » ` "second" = "stringy"`, | |
| 100 ``, | 89 ``, |
| 101 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, | 90 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, |
| 102 `... skipped SOME frames in pkg "github.com/jtol
ds/gls"...`, | 91 `... skipped SOME frames in pkg "github.com/jtol
ds/gls"...`, |
| 103 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, | 92 `... skipped SOME frames in pkg "github.com/smar
tystreets/goconvey/convey"...`, |
| 104 ``, | 93 ``, |
| 105 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:110 - errors.TestAnnotation()`, | 94 » » » » `#? github.com/luci/luci-go/common/errors/annota
te_test.go:99 - errors.TestAnnotation()`, |
| 106 `#? testing/testing.go:XXX - testing.tRunner()`, | 95 `#? testing/testing.go:XXX - testing.tRunner()`, |
| 107 `... skipped SOME frames in pkg "runtime"...`, | 96 `... skipped SOME frames in pkg "runtime"...`, |
| 108 }) | 97 }) |
| 109 }) | 98 }) |
| 110 }) | 99 }) |
| 111 } | 100 } |
| 112 | |
| 113 func TestDataFormat(t *testing.T) { | |
| 114 t.Parallel() | |
| 115 | |
| 116 testCases := []struct { | |
| 117 format string | |
| 118 expected string | |
| 119 }{ | |
| 120 {"", ""}, | |
| 121 {"no replacements", `no replacements`}, | |
| 122 {"%(foo)s", `bar`}, | |
| 123 {"%%(foo)s", `%(foo)s`}, | |
| 124 {"%(foo)s|%(foo)s|%(foo)s", `bar|bar|bar`}, | |
| 125 {"|%(foo)s|%(foo)s|%(foo)s|", `|bar|bar|bar|`}, | |
| 126 {"%(missing)s", `MISSING(key="missing")`}, | |
| 127 {"replacing %(foo)q", `replacing "bar"`}, | |
| 128 {"replacing (%(foo)q)", `replacing ("bar")`}, | |
| 129 } | |
| 130 | |
| 131 Convey(`A testing Data object`, t, func() { | |
| 132 data := Data{ | |
| 133 "foo": {"bar", ""}, | |
| 134 } | |
| 135 | |
| 136 for _, testCase := range testCases { | |
| 137 Convey(fmt.Sprintf(`Formatting %q yields: %q`, testCase.
format, testCase.expected), func() { | |
| 138 So(data.Format(testCase.format), ShouldEqual, te
stCase.expected) | |
| 139 }) | |
| 140 } | |
| 141 }) | |
| 142 } | |
| OLD | NEW |