-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWriteVerifier.go
More file actions
132 lines (118 loc) · 4.47 KB
/
Copy pathWriteVerifier.go
File metadata and controls
132 lines (118 loc) · 4.47 KB
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
package testutils
import (
"bytes"
"errors"
"sync"
"testing"
)
const (
// FailWrite is the string that should be sent to a WriteVerfier to test
// Write failures. This string will cause Write calls to return -1,
// errors.New("I was told to fail this!")
FailWrite = "Fail this write!"
)
// WriteVerifier functions as an io.Writer allowing users to test code that should
// write to an io.Writer interface. It calls it's testing.T instance's Error
// on unexpected writes and then the user can call CheckDone to verify all expected
// writes did indeed take place
type WriteVerifier interface {
// Write emulates the Write method of io.Writers but instead compares it
// against an internal set of expected writes. If the write does not match an
// expected write that has yet to take place it will call testing.T.Error
Write(p []byte) (n int, err error)
// CheckDone should be called after all writes to the write should have
// completed. The object then validates that all expected writes were received,
// calling the Error method in the testing.T instance if any were missed.
CheckDone()
}
type parallelWriteVerifier struct {
name string
expectedWrites []string
writeMatch []bool
t *testing.T
lock *sync.RWMutex
}
// NewParallelWV creates a concurrency enabled WriteVerifier for testing code that
// concurrently writes to io.Writers
func NewParallelWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
return ¶llelWriteVerifier{
name: name,
expectedWrites: expectedWrites,
writeMatch: make([]bool, len(expectedWrites)),
t: t,
lock: &sync.RWMutex{},
}
}
// CheckDone should be called after all writes to the write should have
// completed. The object then validates that all expected writes were received,
// calling the Error method in the testing.T instance if any were missed.
func (v *parallelWriteVerifier) CheckDone() {
done := true
for _, m := range v.writeMatch {
if m == false {
done = false
}
}
if !done {
v.t.Errorf("%s writer did not receive all expected writes.\n%#v\n%#v", v.name, v.expectedWrites, v.writeMatch)
}
}
// Write emulates the Write method of io.Writers but instead compares it
// against an internal set of expected writes. If the write does not match an
// expected write that has yet to take place it will call testing.T.Error
func (v *parallelWriteVerifier) Write(p []byte) (int, error) {
v.lock.Lock()
defer v.lock.Unlock()
for i, e := range v.expectedWrites {
if e == string(p) && v.writeMatch[i] == false {
v.writeMatch[i] = true
if bytes.Equal(p, []byte(FailWrite)) {
return -1, errors.New("I was told to fail this!")
}
return len(p), nil
}
}
v.t.Errorf("%s writer received unexpected write: \"%s\"\n%#v\n%#v", v.name, p, v.expectedWrites, v.writeMatch)
return len(p), nil
}
type sequentialWriteVerifier struct {
name string
expectedWrites []string
currentIndex int
t *testing.T
}
// NewSequentialWV creates a sequential WriteVerifier which can be used to test
// code writing to an io.Writer interface non-concurrently
func NewSequentialWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
return &sequentialWriteVerifier{
name: name,
expectedWrites: expectedWrites,
currentIndex: 0,
t: t,
}
}
// CheckDone should be called after all writes to the write should have
// completed. The object then validates that all expected writes were received,
// calling the Error method in the testing.T instance if any were missed.
func (s *sequentialWriteVerifier) CheckDone() {
if s.currentIndex != len(s.expectedWrites) {
s.t.Errorf("%s writer did not receive all expected writes.", s.name)
}
}
// Write emulates the Write method of io.Writers but instead compares it
// against an internal set of expected writes. If the write does not match an
// expected write that has yet to take place it will call testing.T.Error
func (s *sequentialWriteVerifier) Write(p []byte) (int, error) {
if s.currentIndex >= len(s.expectedWrites) {
s.t.Errorf("%s writer was not expecting a write but received \"%s\"", s.name, p)
return len(p), nil
}
if !bytes.Equal(p, []byte(s.expectedWrites[s.currentIndex])) {
s.t.Errorf("%s writer at index %d expected \"%s\" but received \"%s\"", s.name, s.currentIndex, s.expectedWrites[s.currentIndex], p)
}
s.currentIndex++
if bytes.Equal(p, []byte(FailWrite)) {
return -1, errors.New("I was told to fail this!")
}
return len(p), nil
}