forked from rzajac/zltest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zltest.go
136 lines (114 loc) · 3.29 KB
/
zltest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Package zltest provides facilities to test zerolog log messages.
package zltest
import (
"bufio"
"bytes"
"encoding/json"
"sync"
"github.com/rs/zerolog"
)
// Tester represents zerolog log tester.
type Tester struct {
mx sync.RWMutex // Guards the buffer.
buf []byte // Buffer zerolog writes to.
cnt int // Number of all log messages (calls to Write).
t T // Test manager.
}
// New creates new instance of zerolog tester.
func New(t T) *Tester {
return &Tester{
buf: make([]byte, 0),
t: t,
}
}
// Write implements io.Writer interface.
func (tst *Tester) Write(p []byte) (n int, err error) {
tst.mx.Lock()
defer tst.mx.Unlock()
tst.cnt++
tst.buf = append(tst.buf, p...)
return len(p), nil
}
// Len returns number of log messages written to the Tester.
func (tst *Tester) Len() int {
return tst.cnt
}
// String implements fmt.Stringer interface and returns everything written
// to the Tester so far. Calls Fatal on error.
func (tst *Tester) String() string {
tst.mx.RLock()
defer tst.mx.RUnlock()
return string(tst.buf)
}
// Entries returns all logged entries. It calls Fatal if
// any of the log entries cannot be decoded.
func (tst *Tester) Entries() Entries {
tst.mx.RLock()
defer tst.mx.RUnlock()
scn := bufio.NewScanner(bytes.NewReader(tst.buf))
ets := make([]*Entry, 0, tst.cnt)
for scn.Scan() {
m := make(map[string]interface{})
if err := json.Unmarshal(scn.Bytes(), &m); err != nil {
tst.t.Fatal(err)
}
ets = append(ets, &Entry{
raw: scn.Text(),
m: m,
t: tst.t,
})
}
if err := scn.Err(); err != nil {
tst.t.Fatal(err)
}
return Entries{e: ets, t: tst.t}
}
// Filter returns only entries matching log level.
func (tst *Tester) Filter(level zerolog.Level) Entries {
ets := make([]*Entry, 0)
for _, ent := range tst.Entries().Get() {
if lvl, _ := ent.Str(zerolog.LevelFieldName); lvl == level.String() {
ets = append(ets, ent)
}
}
return Entries{e: ets, t: tst.t}
}
// FirstEntry returns first log entry or nil if no log entries written
// to the Tester. It calls Fatal if any of the log entries cannot be decoded.
func (tst *Tester) FirstEntry() *Entry {
tst.mx.RLock()
defer tst.mx.RUnlock()
ets := tst.Entries().Get()
if len(ets) == 0 {
return nil
}
return ets[0]
}
// LastEntry returns last log entry or nil if no log entries written
// to the Tester. It calls Fatal if any of the log entries cannot be decoded.
func (tst *Tester) LastEntry() *Entry {
tst.mx.RLock()
defer tst.mx.RUnlock()
ets := tst.Entries().Get()
if len(ets) == 0 {
return nil
}
return ets[len(ets)-1]
}
// T is a subset of testing.TB interface.
// It's primarily used to test zltest package but can be used to implement
// custom actions to be taken on errors.
type T interface {
// Error is equivalent to Log followed by Fail.
Error(args ...interface{})
// Errorf is equivalent to Logf followed by Fail.
Errorf(format string, args ...interface{})
// Fatal is equivalent to Log followed by FailNow.
Fatal(args ...interface{})
// Fatalf is equivalent to Logf followed by FailNow.
Fatalf(format string, args ...interface{})
// Helper marks the calling function as a test helper function.
// When printing file and line information, that function will be skipped.
// Helper may be called simultaneously from multiple goroutines.
Helper()
}