Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 3aa4ff64aa4a501731066ede81c50ffc0d6d107e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
... | ... |
@@ -2,7 +2,6 @@ github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d05887 |
2 | 2 |
github.com/Microsoft/hcsshim 672e52e9209d1e53718c1b6a7d68cc9272654ab5 |
3 | 3 |
github.com/Microsoft/go-winio 6c72808b55902eae4c5943626030429ff20f3b63 # v0.4.14 |
4 | 4 |
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a |
5 |
-github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git |
|
6 | 5 |
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a |
7 | 6 |
github.com/google/uuid 0cd6bf5da1e1c83f8b45653022c74f71af0538a4 # v1.1.1 |
8 | 7 |
github.com/gorilla/mux ed099d42384823742bba0bf9a72b53b55c9e2e38 # v1.7.2 |
... | ... |
@@ -13,7 +12,6 @@ github.com/konsorten/go-windows-terminal-sequences f55edac94c9bbba5d6182a4be46d |
13 | 13 |
github.com/mattn/go-shellwords a72fbe27a1b0ed0df2f02754945044ce1456608b # v1.0.5 |
14 | 14 |
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1 |
15 | 15 |
github.com/tchap/go-patricia a7f0089c6f496e8e70402f61733606daa326cac5 # v2.3.0 |
16 |
-github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 # v0.1.0 |
|
17 | 16 |
golang.org/x/net f3200d17e092c607f615320ecaad13d87ad9a2b3 |
18 | 17 |
golang.org/x/sys 4c4f7f33c9ed00de01c4c741d2177abfcfe19307 |
19 | 18 |
github.com/docker/go-units 519db1ee28dcc9fd2474ae59fca29a810482bfb1 # v0.4.0 |
20 | 19 |
deleted file mode 100644 |
... | ... |
@@ -1,25 +0,0 @@ |
1 |
-Gocheck - A rich testing framework for Go |
|
2 |
- |
|
3 |
-Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net> |
|
4 |
- |
|
5 |
-All rights reserved. |
|
6 |
- |
|
7 |
-Redistribution and use in source and binary forms, with or without |
|
8 |
-modification, are permitted provided that the following conditions are met: |
|
9 |
- |
|
10 |
-1. Redistributions of source code must retain the above copyright notice, this |
|
11 |
- list of conditions and the following disclaimer. |
|
12 |
-2. Redistributions in binary form must reproduce the above copyright notice, |
|
13 |
- this list of conditions and the following disclaimer in the documentation |
|
14 |
- and/or other materials provided with the distribution. |
|
15 |
- |
|
16 |
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
17 |
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
19 |
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
|
20 |
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
21 |
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
22 |
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
23 |
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
24 |
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
25 |
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,10 +0,0 @@ |
1 |
-Go-check |
|
2 |
-======== |
|
3 |
- |
|
4 |
-This is a fork of https://github.com/go-check/check |
|
5 |
- |
|
6 |
-The intention of this fork is not to change any of the original behavior, but add |
|
7 |
-some specific behaviors needed for some of my projects already using this test suite. |
|
8 |
-For documentation on the main behavior of go-check see the aforementioned repo. |
|
9 |
- |
|
10 |
-The original branch is intact at `orig_v1` |
11 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,187 +0,0 @@ |
1 |
-// Copyright (c) 2012 The Go Authors. All rights reserved. |
|
2 |
-// |
|
3 |
-// Redistribution and use in source and binary forms, with or without |
|
4 |
-// modification, are permitted provided that the following conditions are |
|
5 |
-// met: |
|
6 |
-// |
|
7 |
-// * Redistributions of source code must retain the above copyright |
|
8 |
-// notice, this list of conditions and the following disclaimer. |
|
9 |
-// * Redistributions in binary form must reproduce the above |
|
10 |
-// copyright notice, this list of conditions and the following disclaimer |
|
11 |
-// in the documentation and/or other materials provided with the |
|
12 |
-// distribution. |
|
13 |
-// * Neither the name of Google Inc. nor the names of its |
|
14 |
-// contributors may be used to endorse or promote products derived from |
|
15 |
-// this software without specific prior written permission. |
|
16 |
-// |
|
17 |
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
18 |
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
19 |
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
20 |
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
21 |
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
22 |
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
23 |
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
24 |
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
25 |
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
26 |
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
27 |
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
28 |
- |
|
29 |
-package check |
|
30 |
- |
|
31 |
-import ( |
|
32 |
- "fmt" |
|
33 |
- "runtime" |
|
34 |
- "time" |
|
35 |
-) |
|
36 |
- |
|
37 |
-var memStats runtime.MemStats |
|
38 |
- |
|
39 |
-// testingB is a type passed to Benchmark functions to manage benchmark |
|
40 |
-// timing and to specify the number of iterations to run. |
|
41 |
-type timer struct { |
|
42 |
- start time.Time // Time test or benchmark started |
|
43 |
- duration time.Duration |
|
44 |
- N int |
|
45 |
- bytes int64 |
|
46 |
- timerOn bool |
|
47 |
- benchTime time.Duration |
|
48 |
- // The initial states of memStats.Mallocs and memStats.TotalAlloc. |
|
49 |
- startAllocs uint64 |
|
50 |
- startBytes uint64 |
|
51 |
- // The net total of this test after being run. |
|
52 |
- netAllocs uint64 |
|
53 |
- netBytes uint64 |
|
54 |
-} |
|
55 |
- |
|
56 |
-// StartTimer starts timing a test. This function is called automatically |
|
57 |
-// before a benchmark starts, but it can also used to resume timing after |
|
58 |
-// a call to StopTimer. |
|
59 |
-func (c *C) StartTimer() { |
|
60 |
- if !c.timerOn { |
|
61 |
- c.start = time.Now() |
|
62 |
- c.timerOn = true |
|
63 |
- |
|
64 |
- runtime.ReadMemStats(&memStats) |
|
65 |
- c.startAllocs = memStats.Mallocs |
|
66 |
- c.startBytes = memStats.TotalAlloc |
|
67 |
- } |
|
68 |
-} |
|
69 |
- |
|
70 |
-// StopTimer stops timing a test. This can be used to pause the timer |
|
71 |
-// while performing complex initialization that you don't |
|
72 |
-// want to measure. |
|
73 |
-func (c *C) StopTimer() { |
|
74 |
- if c.timerOn { |
|
75 |
- c.duration += time.Now().Sub(c.start) |
|
76 |
- c.timerOn = false |
|
77 |
- runtime.ReadMemStats(&memStats) |
|
78 |
- c.netAllocs += memStats.Mallocs - c.startAllocs |
|
79 |
- c.netBytes += memStats.TotalAlloc - c.startBytes |
|
80 |
- } |
|
81 |
-} |
|
82 |
- |
|
83 |
-// ResetTimer sets the elapsed benchmark time to zero. |
|
84 |
-// It does not affect whether the timer is running. |
|
85 |
-func (c *C) ResetTimer() { |
|
86 |
- if c.timerOn { |
|
87 |
- c.start = time.Now() |
|
88 |
- runtime.ReadMemStats(&memStats) |
|
89 |
- c.startAllocs = memStats.Mallocs |
|
90 |
- c.startBytes = memStats.TotalAlloc |
|
91 |
- } |
|
92 |
- c.duration = 0 |
|
93 |
- c.netAllocs = 0 |
|
94 |
- c.netBytes = 0 |
|
95 |
-} |
|
96 |
- |
|
97 |
-// SetBytes informs the number of bytes that the benchmark processes |
|
98 |
-// on each iteration. If this is called in a benchmark it will also |
|
99 |
-// report MB/s. |
|
100 |
-func (c *C) SetBytes(n int64) { |
|
101 |
- c.bytes = n |
|
102 |
-} |
|
103 |
- |
|
104 |
-func (c *C) nsPerOp() int64 { |
|
105 |
- if c.N <= 0 { |
|
106 |
- return 0 |
|
107 |
- } |
|
108 |
- return c.duration.Nanoseconds() / int64(c.N) |
|
109 |
-} |
|
110 |
- |
|
111 |
-func (c *C) mbPerSec() float64 { |
|
112 |
- if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 { |
|
113 |
- return 0 |
|
114 |
- } |
|
115 |
- return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds() |
|
116 |
-} |
|
117 |
- |
|
118 |
-func (c *C) timerString() string { |
|
119 |
- if c.N <= 0 { |
|
120 |
- return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9) |
|
121 |
- } |
|
122 |
- mbs := c.mbPerSec() |
|
123 |
- mb := "" |
|
124 |
- if mbs != 0 { |
|
125 |
- mb = fmt.Sprintf("\t%7.2f MB/s", mbs) |
|
126 |
- } |
|
127 |
- nsop := c.nsPerOp() |
|
128 |
- ns := fmt.Sprintf("%10d ns/op", nsop) |
|
129 |
- if c.N > 0 && nsop < 100 { |
|
130 |
- // The format specifiers here make sure that |
|
131 |
- // the ones digits line up for all three possible formats. |
|
132 |
- if nsop < 10 { |
|
133 |
- ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) |
|
134 |
- } else { |
|
135 |
- ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) |
|
136 |
- } |
|
137 |
- } |
|
138 |
- memStats := "" |
|
139 |
- if c.benchMem { |
|
140 |
- allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N)) |
|
141 |
- allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N)) |
|
142 |
- memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs) |
|
143 |
- } |
|
144 |
- return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats) |
|
145 |
-} |
|
146 |
- |
|
147 |
-func min(x, y int) int { |
|
148 |
- if x > y { |
|
149 |
- return y |
|
150 |
- } |
|
151 |
- return x |
|
152 |
-} |
|
153 |
- |
|
154 |
-func max(x, y int) int { |
|
155 |
- if x < y { |
|
156 |
- return y |
|
157 |
- } |
|
158 |
- return x |
|
159 |
-} |
|
160 |
- |
|
161 |
-// roundDown10 rounds a number down to the nearest power of 10. |
|
162 |
-func roundDown10(n int) int { |
|
163 |
- var tens = 0 |
|
164 |
- // tens = floor(log_10(n)) |
|
165 |
- for n > 10 { |
|
166 |
- n = n / 10 |
|
167 |
- tens++ |
|
168 |
- } |
|
169 |
- // result = 10^tens |
|
170 |
- result := 1 |
|
171 |
- for i := 0; i < tens; i++ { |
|
172 |
- result *= 10 |
|
173 |
- } |
|
174 |
- return result |
|
175 |
-} |
|
176 |
- |
|
177 |
-// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. |
|
178 |
-func roundUp(n int) int { |
|
179 |
- base := roundDown10(n) |
|
180 |
- if n < (2 * base) { |
|
181 |
- return 2 * base |
|
182 |
- } |
|
183 |
- if n < (5 * base) { |
|
184 |
- return 5 * base |
|
185 |
- } |
|
186 |
- return 10 * base |
|
187 |
-} |
188 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,939 +0,0 @@ |
1 |
-// Package check is a rich testing extension for Go's testing package. |
|
2 |
-// |
|
3 |
-// For details about the project, see: |
|
4 |
-// |
|
5 |
-// http://labix.org/gocheck |
|
6 |
-// |
|
7 |
-package check |
|
8 |
- |
|
9 |
-import ( |
|
10 |
- "bytes" |
|
11 |
- "errors" |
|
12 |
- "fmt" |
|
13 |
- "io" |
|
14 |
- "math/rand" |
|
15 |
- "os" |
|
16 |
- "path" |
|
17 |
- "path/filepath" |
|
18 |
- "reflect" |
|
19 |
- "regexp" |
|
20 |
- "runtime" |
|
21 |
- "strconv" |
|
22 |
- "strings" |
|
23 |
- "sync" |
|
24 |
- "sync/atomic" |
|
25 |
- "time" |
|
26 |
-) |
|
27 |
- |
|
28 |
-// ----------------------------------------------------------------------- |
|
29 |
-// Internal type which deals with suite method calling. |
|
30 |
- |
|
31 |
-const ( |
|
32 |
- fixtureKd = iota |
|
33 |
- testKd |
|
34 |
-) |
|
35 |
- |
|
36 |
-type funcKind int |
|
37 |
- |
|
38 |
-const ( |
|
39 |
- succeededSt = iota |
|
40 |
- failedSt |
|
41 |
- skippedSt |
|
42 |
- panickedSt |
|
43 |
- fixturePanickedSt |
|
44 |
- missedSt |
|
45 |
-) |
|
46 |
- |
|
47 |
-type funcStatus uint32 |
|
48 |
- |
|
49 |
-// A method value can't reach its own Method structure. |
|
50 |
-type methodType struct { |
|
51 |
- reflect.Value |
|
52 |
- Info reflect.Method |
|
53 |
-} |
|
54 |
- |
|
55 |
-func newMethod(receiver reflect.Value, i int) *methodType { |
|
56 |
- return &methodType{receiver.Method(i), receiver.Type().Method(i)} |
|
57 |
-} |
|
58 |
- |
|
59 |
-func (method *methodType) PC() uintptr { |
|
60 |
- return method.Info.Func.Pointer() |
|
61 |
-} |
|
62 |
- |
|
63 |
-func (method *methodType) suiteName() string { |
|
64 |
- t := method.Info.Type.In(0) |
|
65 |
- if t.Kind() == reflect.Ptr { |
|
66 |
- t = t.Elem() |
|
67 |
- } |
|
68 |
- return t.Name() |
|
69 |
-} |
|
70 |
- |
|
71 |
-func (method *methodType) String() string { |
|
72 |
- return method.suiteName() + "." + method.Info.Name |
|
73 |
-} |
|
74 |
- |
|
75 |
-func (method *methodType) matches(re *regexp.Regexp) bool { |
|
76 |
- return (re.MatchString(method.Info.Name) || |
|
77 |
- re.MatchString(method.suiteName()) || |
|
78 |
- re.MatchString(method.String())) |
|
79 |
-} |
|
80 |
- |
|
81 |
-type C struct { |
|
82 |
- method *methodType |
|
83 |
- kind funcKind |
|
84 |
- testName string |
|
85 |
- _status funcStatus |
|
86 |
- logb *logger |
|
87 |
- logw io.Writer |
|
88 |
- done chan *C |
|
89 |
- reason string |
|
90 |
- mustFail bool |
|
91 |
- tempDir *tempDir |
|
92 |
- benchMem bool |
|
93 |
- startTime time.Time |
|
94 |
- timer |
|
95 |
-} |
|
96 |
- |
|
97 |
-func (c *C) status() funcStatus { |
|
98 |
- return funcStatus(atomic.LoadUint32((*uint32)(&c._status))) |
|
99 |
-} |
|
100 |
- |
|
101 |
-func (c *C) setStatus(s funcStatus) { |
|
102 |
- atomic.StoreUint32((*uint32)(&c._status), uint32(s)) |
|
103 |
-} |
|
104 |
- |
|
105 |
-func (c *C) stopNow() { |
|
106 |
- runtime.Goexit() |
|
107 |
-} |
|
108 |
- |
|
109 |
-// logger is a concurrency safe byte.Buffer |
|
110 |
-type logger struct { |
|
111 |
- sync.Mutex |
|
112 |
- writer bytes.Buffer |
|
113 |
-} |
|
114 |
- |
|
115 |
-func (l *logger) Write(buf []byte) (int, error) { |
|
116 |
- l.Lock() |
|
117 |
- defer l.Unlock() |
|
118 |
- return l.writer.Write(buf) |
|
119 |
-} |
|
120 |
- |
|
121 |
-func (l *logger) WriteTo(w io.Writer) (int64, error) { |
|
122 |
- l.Lock() |
|
123 |
- defer l.Unlock() |
|
124 |
- return l.writer.WriteTo(w) |
|
125 |
-} |
|
126 |
- |
|
127 |
-func (l *logger) String() string { |
|
128 |
- l.Lock() |
|
129 |
- defer l.Unlock() |
|
130 |
- return l.writer.String() |
|
131 |
-} |
|
132 |
- |
|
133 |
-// ----------------------------------------------------------------------- |
|
134 |
-// Handling of temporary files and directories. |
|
135 |
- |
|
136 |
-type tempDir struct { |
|
137 |
- sync.Mutex |
|
138 |
- path string |
|
139 |
- counter int |
|
140 |
-} |
|
141 |
- |
|
142 |
-func (td *tempDir) newPath() string { |
|
143 |
- td.Lock() |
|
144 |
- defer td.Unlock() |
|
145 |
- if td.path == "" { |
|
146 |
- var err error |
|
147 |
- for i := 0; i != 100; i++ { |
|
148 |
- path := fmt.Sprintf("%s%ccheck-%d", os.TempDir(), os.PathSeparator, rand.Int()) |
|
149 |
- if err = os.Mkdir(path, 0700); err == nil { |
|
150 |
- td.path = path |
|
151 |
- break |
|
152 |
- } |
|
153 |
- } |
|
154 |
- if td.path == "" { |
|
155 |
- panic("Couldn't create temporary directory: " + err.Error()) |
|
156 |
- } |
|
157 |
- } |
|
158 |
- result := filepath.Join(td.path, strconv.Itoa(td.counter)) |
|
159 |
- td.counter += 1 |
|
160 |
- return result |
|
161 |
-} |
|
162 |
- |
|
163 |
-func (td *tempDir) removeAll() { |
|
164 |
- td.Lock() |
|
165 |
- defer td.Unlock() |
|
166 |
- if td.path != "" { |
|
167 |
- err := os.RemoveAll(td.path) |
|
168 |
- if err != nil { |
|
169 |
- fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error()) |
|
170 |
- } |
|
171 |
- } |
|
172 |
-} |
|
173 |
- |
|
174 |
-// Create a new temporary directory which is automatically removed after |
|
175 |
-// the suite finishes running. |
|
176 |
-func (c *C) MkDir() string { |
|
177 |
- path := c.tempDir.newPath() |
|
178 |
- if err := os.Mkdir(path, 0700); err != nil { |
|
179 |
- panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error())) |
|
180 |
- } |
|
181 |
- return path |
|
182 |
-} |
|
183 |
- |
|
184 |
-// ----------------------------------------------------------------------- |
|
185 |
-// Low-level logging functions. |
|
186 |
- |
|
187 |
-func (c *C) log(args ...interface{}) { |
|
188 |
- c.writeLog([]byte(fmt.Sprint(args...) + "\n")) |
|
189 |
-} |
|
190 |
- |
|
191 |
-func (c *C) logf(format string, args ...interface{}) { |
|
192 |
- c.writeLog([]byte(fmt.Sprintf(format+"\n", args...))) |
|
193 |
-} |
|
194 |
- |
|
195 |
-func (c *C) logNewLine() { |
|
196 |
- c.writeLog([]byte{'\n'}) |
|
197 |
-} |
|
198 |
- |
|
199 |
-func (c *C) writeLog(buf []byte) { |
|
200 |
- c.logb.Write(buf) |
|
201 |
- if c.logw != nil { |
|
202 |
- c.logw.Write(buf) |
|
203 |
- } |
|
204 |
-} |
|
205 |
- |
|
206 |
-func hasStringOrError(x interface{}) (ok bool) { |
|
207 |
- _, ok = x.(fmt.Stringer) |
|
208 |
- if ok { |
|
209 |
- return |
|
210 |
- } |
|
211 |
- _, ok = x.(error) |
|
212 |
- return |
|
213 |
-} |
|
214 |
- |
|
215 |
-func (c *C) logValue(label string, value interface{}) { |
|
216 |
- if label == "" { |
|
217 |
- if hasStringOrError(value) { |
|
218 |
- c.logf("... %#v (%q)", value, value) |
|
219 |
- } else { |
|
220 |
- c.logf("... %#v", value) |
|
221 |
- } |
|
222 |
- } else if value == nil { |
|
223 |
- c.logf("... %s = nil", label) |
|
224 |
- } else { |
|
225 |
- if hasStringOrError(value) { |
|
226 |
- fv := fmt.Sprintf("%#v", value) |
|
227 |
- qv := fmt.Sprintf("%q", value) |
|
228 |
- if fv != qv { |
|
229 |
- c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv) |
|
230 |
- return |
|
231 |
- } |
|
232 |
- } |
|
233 |
- if s, ok := value.(string); ok && isMultiLine(s) { |
|
234 |
- c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value)) |
|
235 |
- c.logMultiLine(s) |
|
236 |
- } else { |
|
237 |
- c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value) |
|
238 |
- } |
|
239 |
- } |
|
240 |
-} |
|
241 |
- |
|
242 |
-func (c *C) logMultiLine(s string) { |
|
243 |
- b := make([]byte, 0, len(s)*2) |
|
244 |
- i := 0 |
|
245 |
- n := len(s) |
|
246 |
- for i < n { |
|
247 |
- j := i + 1 |
|
248 |
- for j < n && s[j-1] != '\n' { |
|
249 |
- j++ |
|
250 |
- } |
|
251 |
- b = append(b, "... "...) |
|
252 |
- b = strconv.AppendQuote(b, s[i:j]) |
|
253 |
- if j < n { |
|
254 |
- b = append(b, " +"...) |
|
255 |
- } |
|
256 |
- b = append(b, '\n') |
|
257 |
- i = j |
|
258 |
- } |
|
259 |
- c.writeLog(b) |
|
260 |
-} |
|
261 |
- |
|
262 |
-func isMultiLine(s string) bool { |
|
263 |
- for i := 0; i+1 < len(s); i++ { |
|
264 |
- if s[i] == '\n' { |
|
265 |
- return true |
|
266 |
- } |
|
267 |
- } |
|
268 |
- return false |
|
269 |
-} |
|
270 |
- |
|
271 |
-func (c *C) logString(issue string) { |
|
272 |
- c.log("... ", issue) |
|
273 |
-} |
|
274 |
- |
|
275 |
-func (c *C) logCaller(skip int) { |
|
276 |
- // This is a bit heavier than it ought to be. |
|
277 |
- skip += 1 // Our own frame. |
|
278 |
- pc, callerFile, callerLine, ok := runtime.Caller(skip) |
|
279 |
- if !ok { |
|
280 |
- return |
|
281 |
- } |
|
282 |
- var testFile string |
|
283 |
- var testLine int |
|
284 |
- testFunc := runtime.FuncForPC(c.method.PC()) |
|
285 |
- if runtime.FuncForPC(pc) != testFunc { |
|
286 |
- for { |
|
287 |
- skip += 1 |
|
288 |
- if pc, file, line, ok := runtime.Caller(skip); ok { |
|
289 |
- // Note that the test line may be different on |
|
290 |
- // distinct calls for the same test. Showing |
|
291 |
- // the "internal" line is helpful when debugging. |
|
292 |
- if runtime.FuncForPC(pc) == testFunc { |
|
293 |
- testFile, testLine = file, line |
|
294 |
- break |
|
295 |
- } |
|
296 |
- } else { |
|
297 |
- break |
|
298 |
- } |
|
299 |
- } |
|
300 |
- } |
|
301 |
- if testFile != "" && (testFile != callerFile || testLine != callerLine) { |
|
302 |
- c.logCode(testFile, testLine) |
|
303 |
- } |
|
304 |
- c.logCode(callerFile, callerLine) |
|
305 |
-} |
|
306 |
- |
|
307 |
-func (c *C) logCode(path string, line int) { |
|
308 |
- c.logf("%s:%d:", nicePath(path), line) |
|
309 |
- code, err := printLine(path, line) |
|
310 |
- if code == "" { |
|
311 |
- code = "..." // XXX Open the file and take the raw line. |
|
312 |
- if err != nil { |
|
313 |
- code += err.Error() |
|
314 |
- } |
|
315 |
- } |
|
316 |
- c.log(indent(code, " ")) |
|
317 |
-} |
|
318 |
- |
|
319 |
-var valueGo = filepath.Join("reflect", "value.go") |
|
320 |
-var asmGo = filepath.Join("runtime", "asm_") |
|
321 |
- |
|
322 |
-func (c *C) logPanic(skip int, value interface{}) { |
|
323 |
- skip++ // Our own frame. |
|
324 |
- initialSkip := skip |
|
325 |
- for ; ; skip++ { |
|
326 |
- if pc, file, line, ok := runtime.Caller(skip); ok { |
|
327 |
- if skip == initialSkip { |
|
328 |
- c.logf("... Panic: %s (PC=0x%X)\n", value, pc) |
|
329 |
- } |
|
330 |
- name := niceFuncName(pc) |
|
331 |
- path := nicePath(file) |
|
332 |
- if strings.Contains(path, "/gopkg.in/check.v") { |
|
333 |
- continue |
|
334 |
- } |
|
335 |
- if name == "Value.call" && strings.HasSuffix(path, valueGo) { |
|
336 |
- continue |
|
337 |
- } |
|
338 |
- if (name == "call16" || name == "call32") && strings.Contains(path, asmGo) { |
|
339 |
- continue |
|
340 |
- } |
|
341 |
- c.logf("%s:%d\n in %s", nicePath(file), line, name) |
|
342 |
- } else { |
|
343 |
- break |
|
344 |
- } |
|
345 |
- } |
|
346 |
-} |
|
347 |
- |
|
348 |
-func (c *C) logSoftPanic(issue string) { |
|
349 |
- c.log("... Panic: ", issue) |
|
350 |
-} |
|
351 |
- |
|
352 |
-func (c *C) logArgPanic(method *methodType, expectedType string) { |
|
353 |
- c.logf("... Panic: %s argument should be %s", |
|
354 |
- niceFuncName(method.PC()), expectedType) |
|
355 |
-} |
|
356 |
- |
|
357 |
-// ----------------------------------------------------------------------- |
|
358 |
-// Some simple formatting helpers. |
|
359 |
- |
|
360 |
-var initWD, initWDErr = os.Getwd() |
|
361 |
- |
|
362 |
-func init() { |
|
363 |
- if initWDErr == nil { |
|
364 |
- initWD = strings.Replace(initWD, "\\", "/", -1) + "/" |
|
365 |
- } |
|
366 |
-} |
|
367 |
- |
|
368 |
-func nicePath(path string) string { |
|
369 |
- if initWDErr == nil { |
|
370 |
- if strings.HasPrefix(path, initWD) { |
|
371 |
- return path[len(initWD):] |
|
372 |
- } |
|
373 |
- } |
|
374 |
- return path |
|
375 |
-} |
|
376 |
- |
|
377 |
-func niceFuncPath(pc uintptr) string { |
|
378 |
- function := runtime.FuncForPC(pc) |
|
379 |
- if function != nil { |
|
380 |
- filename, line := function.FileLine(pc) |
|
381 |
- return fmt.Sprintf("%s:%d", nicePath(filename), line) |
|
382 |
- } |
|
383 |
- return "<unknown path>" |
|
384 |
-} |
|
385 |
- |
|
386 |
-func niceFuncName(pc uintptr) string { |
|
387 |
- function := runtime.FuncForPC(pc) |
|
388 |
- if function != nil { |
|
389 |
- name := path.Base(function.Name()) |
|
390 |
- if i := strings.Index(name, "."); i > 0 { |
|
391 |
- name = name[i+1:] |
|
392 |
- } |
|
393 |
- if strings.HasPrefix(name, "(*") { |
|
394 |
- if i := strings.Index(name, ")"); i > 0 { |
|
395 |
- name = name[2:i] + name[i+1:] |
|
396 |
- } |
|
397 |
- } |
|
398 |
- if i := strings.LastIndex(name, ".*"); i != -1 { |
|
399 |
- name = name[:i] + "." + name[i+2:] |
|
400 |
- } |
|
401 |
- if i := strings.LastIndex(name, "·"); i != -1 { |
|
402 |
- name = name[:i] + "." + name[i+2:] |
|
403 |
- } |
|
404 |
- return name |
|
405 |
- } |
|
406 |
- return "<unknown function>" |
|
407 |
-} |
|
408 |
- |
|
409 |
-// ----------------------------------------------------------------------- |
|
410 |
-// Result tracker to aggregate call results. |
|
411 |
- |
|
412 |
-type Result struct { |
|
413 |
- Succeeded int |
|
414 |
- Failed int |
|
415 |
- Skipped int |
|
416 |
- Panicked int |
|
417 |
- FixturePanicked int |
|
418 |
- ExpectedFailures int |
|
419 |
- Missed int // Not even tried to run, related to a panic in the fixture. |
|
420 |
- RunError error // Houston, we've got a problem. |
|
421 |
- WorkDir string // If KeepWorkDir is true |
|
422 |
-} |
|
423 |
- |
|
424 |
-type resultTracker struct { |
|
425 |
- result Result |
|
426 |
- _lastWasProblem bool |
|
427 |
- _waiting int |
|
428 |
- _missed int |
|
429 |
- _expectChan chan *C |
|
430 |
- _doneChan chan *C |
|
431 |
- _stopChan chan bool |
|
432 |
-} |
|
433 |
- |
|
434 |
-func newResultTracker() *resultTracker { |
|
435 |
- return &resultTracker{_expectChan: make(chan *C), // Synchronous |
|
436 |
- _doneChan: make(chan *C, 32), // Asynchronous |
|
437 |
- _stopChan: make(chan bool)} // Synchronous |
|
438 |
-} |
|
439 |
- |
|
440 |
-func (tracker *resultTracker) start() { |
|
441 |
- go tracker._loopRoutine() |
|
442 |
-} |
|
443 |
- |
|
444 |
-func (tracker *resultTracker) waitAndStop() { |
|
445 |
- <-tracker._stopChan |
|
446 |
-} |
|
447 |
- |
|
448 |
-func (tracker *resultTracker) expectCall(c *C) { |
|
449 |
- tracker._expectChan <- c |
|
450 |
-} |
|
451 |
- |
|
452 |
-func (tracker *resultTracker) callDone(c *C) { |
|
453 |
- tracker._doneChan <- c |
|
454 |
-} |
|
455 |
- |
|
456 |
-func (tracker *resultTracker) _loopRoutine() { |
|
457 |
- for { |
|
458 |
- var c *C |
|
459 |
- if tracker._waiting > 0 { |
|
460 |
- // Calls still running. Can't stop. |
|
461 |
- select { |
|
462 |
- // XXX Reindent this (not now to make diff clear) |
|
463 |
- case c = <-tracker._expectChan: |
|
464 |
- tracker._waiting += 1 |
|
465 |
- case c = <-tracker._doneChan: |
|
466 |
- tracker._waiting -= 1 |
|
467 |
- switch c.status() { |
|
468 |
- case succeededSt: |
|
469 |
- if c.kind == testKd { |
|
470 |
- if c.mustFail { |
|
471 |
- tracker.result.ExpectedFailures++ |
|
472 |
- } else { |
|
473 |
- tracker.result.Succeeded++ |
|
474 |
- } |
|
475 |
- } |
|
476 |
- case failedSt: |
|
477 |
- tracker.result.Failed++ |
|
478 |
- case panickedSt: |
|
479 |
- if c.kind == fixtureKd { |
|
480 |
- tracker.result.FixturePanicked++ |
|
481 |
- } else { |
|
482 |
- tracker.result.Panicked++ |
|
483 |
- } |
|
484 |
- case fixturePanickedSt: |
|
485 |
- // Track it as missed, since the panic |
|
486 |
- // was on the fixture, not on the test. |
|
487 |
- tracker.result.Missed++ |
|
488 |
- case missedSt: |
|
489 |
- tracker.result.Missed++ |
|
490 |
- case skippedSt: |
|
491 |
- if c.kind == testKd { |
|
492 |
- tracker.result.Skipped++ |
|
493 |
- } |
|
494 |
- } |
|
495 |
- } |
|
496 |
- } else { |
|
497 |
- // No calls. Can stop, but no done calls here. |
|
498 |
- select { |
|
499 |
- case tracker._stopChan <- true: |
|
500 |
- return |
|
501 |
- case c = <-tracker._expectChan: |
|
502 |
- tracker._waiting += 1 |
|
503 |
- case c = <-tracker._doneChan: |
|
504 |
- panic("Tracker got an unexpected done call.") |
|
505 |
- } |
|
506 |
- } |
|
507 |
- } |
|
508 |
-} |
|
509 |
- |
|
510 |
-// ----------------------------------------------------------------------- |
|
511 |
-// The underlying suite runner. |
|
512 |
- |
|
513 |
-type suiteRunner struct { |
|
514 |
- suite interface{} |
|
515 |
- setUpSuite, tearDownSuite *methodType |
|
516 |
- setUpTest, tearDownTest *methodType |
|
517 |
- onTimeout *methodType |
|
518 |
- tests []*methodType |
|
519 |
- tracker *resultTracker |
|
520 |
- tempDir *tempDir |
|
521 |
- keepDir bool |
|
522 |
- output *outputWriter |
|
523 |
- reportedProblemLast bool |
|
524 |
- benchTime time.Duration |
|
525 |
- benchMem bool |
|
526 |
- checkTimeout time.Duration |
|
527 |
-} |
|
528 |
- |
|
529 |
-type RunConf struct { |
|
530 |
- Output io.Writer |
|
531 |
- Stream bool |
|
532 |
- Verbose bool |
|
533 |
- Filter string |
|
534 |
- Benchmark bool |
|
535 |
- BenchmarkTime time.Duration // Defaults to 1 second |
|
536 |
- BenchmarkMem bool |
|
537 |
- KeepWorkDir bool |
|
538 |
- CheckTimeout time.Duration |
|
539 |
-} |
|
540 |
- |
|
541 |
-// Create a new suiteRunner able to run all methods in the given suite. |
|
542 |
-func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner { |
|
543 |
- var conf RunConf |
|
544 |
- if runConf != nil { |
|
545 |
- conf = *runConf |
|
546 |
- } |
|
547 |
- if conf.Output == nil { |
|
548 |
- conf.Output = os.Stdout |
|
549 |
- } |
|
550 |
- if conf.Benchmark { |
|
551 |
- conf.Verbose = true |
|
552 |
- } |
|
553 |
- |
|
554 |
- suiteType := reflect.TypeOf(suite) |
|
555 |
- suiteNumMethods := suiteType.NumMethod() |
|
556 |
- suiteValue := reflect.ValueOf(suite) |
|
557 |
- |
|
558 |
- runner := &suiteRunner{ |
|
559 |
- suite: suite, |
|
560 |
- output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose), |
|
561 |
- tracker: newResultTracker(), |
|
562 |
- benchTime: conf.BenchmarkTime, |
|
563 |
- benchMem: conf.BenchmarkMem, |
|
564 |
- tempDir: &tempDir{}, |
|
565 |
- keepDir: conf.KeepWorkDir, |
|
566 |
- tests: make([]*methodType, 0, suiteNumMethods), |
|
567 |
- checkTimeout: conf.CheckTimeout, |
|
568 |
- } |
|
569 |
- if runner.benchTime == 0 { |
|
570 |
- runner.benchTime = 1 * time.Second |
|
571 |
- } |
|
572 |
- |
|
573 |
- var filterRegexp *regexp.Regexp |
|
574 |
- if conf.Filter != "" { |
|
575 |
- if regexp, err := regexp.Compile(conf.Filter); err != nil { |
|
576 |
- msg := "Bad filter expression: " + err.Error() |
|
577 |
- runner.tracker.result.RunError = errors.New(msg) |
|
578 |
- return runner |
|
579 |
- } else { |
|
580 |
- filterRegexp = regexp |
|
581 |
- } |
|
582 |
- } |
|
583 |
- |
|
584 |
- for i := 0; i != suiteNumMethods; i++ { |
|
585 |
- method := newMethod(suiteValue, i) |
|
586 |
- switch method.Info.Name { |
|
587 |
- case "SetUpSuite": |
|
588 |
- runner.setUpSuite = method |
|
589 |
- case "TearDownSuite": |
|
590 |
- runner.tearDownSuite = method |
|
591 |
- case "SetUpTest": |
|
592 |
- runner.setUpTest = method |
|
593 |
- case "TearDownTest": |
|
594 |
- runner.tearDownTest = method |
|
595 |
- case "OnTimeout": |
|
596 |
- runner.onTimeout = method |
|
597 |
- default: |
|
598 |
- prefix := "Test" |
|
599 |
- if conf.Benchmark { |
|
600 |
- prefix = "Benchmark" |
|
601 |
- } |
|
602 |
- if !strings.HasPrefix(method.Info.Name, prefix) { |
|
603 |
- continue |
|
604 |
- } |
|
605 |
- if filterRegexp == nil || method.matches(filterRegexp) { |
|
606 |
- runner.tests = append(runner.tests, method) |
|
607 |
- } |
|
608 |
- } |
|
609 |
- } |
|
610 |
- return runner |
|
611 |
-} |
|
612 |
- |
|
613 |
-// Run all methods in the given suite. |
|
614 |
-func (runner *suiteRunner) run() *Result { |
|
615 |
- if runner.tracker.result.RunError == nil && len(runner.tests) > 0 { |
|
616 |
- runner.tracker.start() |
|
617 |
- if runner.checkFixtureArgs() { |
|
618 |
- c := runner.runFixture(runner.setUpSuite, "", nil) |
|
619 |
- if c == nil || c.status() == succeededSt { |
|
620 |
- for i := 0; i != len(runner.tests); i++ { |
|
621 |
- c := runner.runTest(runner.tests[i]) |
|
622 |
- if c.status() == fixturePanickedSt { |
|
623 |
- runner.skipTests(missedSt, runner.tests[i+1:]) |
|
624 |
- break |
|
625 |
- } |
|
626 |
- } |
|
627 |
- } else if c != nil && c.status() == skippedSt { |
|
628 |
- runner.skipTests(skippedSt, runner.tests) |
|
629 |
- } else { |
|
630 |
- runner.skipTests(missedSt, runner.tests) |
|
631 |
- } |
|
632 |
- runner.runFixture(runner.tearDownSuite, "", nil) |
|
633 |
- } else { |
|
634 |
- runner.skipTests(missedSt, runner.tests) |
|
635 |
- } |
|
636 |
- runner.tracker.waitAndStop() |
|
637 |
- if runner.keepDir { |
|
638 |
- runner.tracker.result.WorkDir = runner.tempDir.path |
|
639 |
- } else { |
|
640 |
- runner.tempDir.removeAll() |
|
641 |
- } |
|
642 |
- } |
|
643 |
- return &runner.tracker.result |
|
644 |
-} |
|
645 |
- |
|
646 |
-// Create a call object with the given suite method, and fork a |
|
647 |
-// goroutine with the provided dispatcher for running it. |
|
648 |
-func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C { |
|
649 |
- var logw io.Writer |
|
650 |
- if runner.output.Stream { |
|
651 |
- logw = runner.output |
|
652 |
- } |
|
653 |
- if logb == nil { |
|
654 |
- logb = new(logger) |
|
655 |
- } |
|
656 |
- c := &C{ |
|
657 |
- method: method, |
|
658 |
- kind: kind, |
|
659 |
- testName: testName, |
|
660 |
- logb: logb, |
|
661 |
- logw: logw, |
|
662 |
- tempDir: runner.tempDir, |
|
663 |
- done: make(chan *C, 1), |
|
664 |
- timer: timer{benchTime: runner.benchTime}, |
|
665 |
- startTime: time.Now(), |
|
666 |
- benchMem: runner.benchMem, |
|
667 |
- } |
|
668 |
- runner.tracker.expectCall(c) |
|
669 |
- go (func() { |
|
670 |
- runner.reportCallStarted(c) |
|
671 |
- defer runner.callDone(c) |
|
672 |
- dispatcher(c) |
|
673 |
- })() |
|
674 |
- return c |
|
675 |
-} |
|
676 |
- |
|
677 |
-type timeoutErr struct { |
|
678 |
- method *methodType |
|
679 |
- t time.Duration |
|
680 |
-} |
|
681 |
- |
|
682 |
-func (e timeoutErr) Error() string { |
|
683 |
- return fmt.Sprintf("%s test timed out after %v", e.method.String(), e.t) |
|
684 |
-} |
|
685 |
- |
|
686 |
-func isTimeout(e error) bool { |
|
687 |
- if e == nil { |
|
688 |
- return false |
|
689 |
- } |
|
690 |
- _, ok := e.(timeoutErr) |
|
691 |
- return ok |
|
692 |
-} |
|
693 |
- |
|
694 |
-// Same as forkCall(), but wait for call to finish before returning. |
|
695 |
-func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C { |
|
696 |
- var timeout <-chan time.Time |
|
697 |
- if runner.checkTimeout != 0 { |
|
698 |
- timeout = time.After(runner.checkTimeout) |
|
699 |
- } |
|
700 |
- c := runner.forkCall(method, kind, testName, logb, dispatcher) |
|
701 |
- select { |
|
702 |
- case <-c.done: |
|
703 |
- case <-timeout: |
|
704 |
- if runner.onTimeout != nil { |
|
705 |
- // run the OnTimeout callback, allowing the suite to collect any sort of debug information it can |
|
706 |
- // `runFixture` is syncronous, so run this in a separate goroutine with a timeout |
|
707 |
- cChan := make(chan *C) |
|
708 |
- go func() { |
|
709 |
- cChan <- runner.runFixture(runner.onTimeout, c.testName, c.logb) |
|
710 |
- }() |
|
711 |
- select { |
|
712 |
- case <-cChan: |
|
713 |
- case <-time.After(runner.checkTimeout): |
|
714 |
- } |
|
715 |
- } |
|
716 |
- panic(timeoutErr{method, runner.checkTimeout}) |
|
717 |
- } |
|
718 |
- return c |
|
719 |
-} |
|
720 |
- |
|
721 |
-// Handle a finished call. If there were any panics, update the call status |
|
722 |
-// accordingly. Then, mark the call as done and report to the tracker. |
|
723 |
-func (runner *suiteRunner) callDone(c *C) { |
|
724 |
- value := recover() |
|
725 |
- if value != nil { |
|
726 |
- switch v := value.(type) { |
|
727 |
- case *fixturePanic: |
|
728 |
- if v.status == skippedSt { |
|
729 |
- c.setStatus(skippedSt) |
|
730 |
- } else { |
|
731 |
- c.logSoftPanic("Fixture has panicked (see related PANIC)") |
|
732 |
- c.setStatus(fixturePanickedSt) |
|
733 |
- } |
|
734 |
- default: |
|
735 |
- c.logPanic(1, value) |
|
736 |
- c.setStatus(panickedSt) |
|
737 |
- } |
|
738 |
- } |
|
739 |
- if c.mustFail { |
|
740 |
- switch c.status() { |
|
741 |
- case failedSt: |
|
742 |
- c.setStatus(succeededSt) |
|
743 |
- case succeededSt: |
|
744 |
- c.setStatus(failedSt) |
|
745 |
- c.logString("Error: Test succeeded, but was expected to fail") |
|
746 |
- c.logString("Reason: " + c.reason) |
|
747 |
- } |
|
748 |
- } |
|
749 |
- |
|
750 |
- runner.reportCallDone(c) |
|
751 |
- c.done <- c |
|
752 |
-} |
|
753 |
- |
|
754 |
-// Runs a fixture call synchronously. The fixture will still be run in a |
|
755 |
-// goroutine like all suite methods, but this method will not return |
|
756 |
-// while the fixture goroutine is not done, because the fixture must be |
|
757 |
-// run in a desired order. |
|
758 |
-func (runner *suiteRunner) runFixture(method *methodType, testName string, logb *logger) *C { |
|
759 |
- if method != nil { |
|
760 |
- c := runner.runFunc(method, fixtureKd, testName, logb, func(c *C) { |
|
761 |
- c.ResetTimer() |
|
762 |
- c.StartTimer() |
|
763 |
- defer c.StopTimer() |
|
764 |
- c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
|
765 |
- }) |
|
766 |
- return c |
|
767 |
- } |
|
768 |
- return nil |
|
769 |
-} |
|
770 |
- |
|
771 |
-// Run the fixture method with runFixture(), but panic with a fixturePanic{} |
|
772 |
-// in case the fixture method panics. This makes it easier to track the |
|
773 |
-// fixture panic together with other call panics within forkTest(). |
|
774 |
-func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName string, logb *logger, skipped *bool) *C { |
|
775 |
- if skipped != nil && *skipped { |
|
776 |
- return nil |
|
777 |
- } |
|
778 |
- c := runner.runFixture(method, testName, logb) |
|
779 |
- if c != nil && c.status() != succeededSt { |
|
780 |
- if skipped != nil { |
|
781 |
- *skipped = c.status() == skippedSt |
|
782 |
- } |
|
783 |
- panic(&fixturePanic{c.status(), method}) |
|
784 |
- } |
|
785 |
- return c |
|
786 |
-} |
|
787 |
- |
|
788 |
-type fixturePanic struct { |
|
789 |
- status funcStatus |
|
790 |
- method *methodType |
|
791 |
-} |
|
792 |
- |
|
793 |
-// Run the suite test method, together with the test-specific fixture, |
|
794 |
-// asynchronously. |
|
795 |
-func (runner *suiteRunner) forkTest(method *methodType) *C { |
|
796 |
- testName := method.String() |
|
797 |
- return runner.forkCall(method, testKd, testName, nil, func(c *C) { |
|
798 |
- var skipped bool |
|
799 |
- defer runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, &skipped) |
|
800 |
- defer c.StopTimer() |
|
801 |
- benchN := 1 |
|
802 |
- for { |
|
803 |
- runner.runFixtureWithPanic(runner.setUpTest, testName, c.logb, &skipped) |
|
804 |
- mt := c.method.Type() |
|
805 |
- if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) { |
|
806 |
- // Rather than a plain panic, provide a more helpful message when |
|
807 |
- // the argument type is incorrect. |
|
808 |
- c.setStatus(panickedSt) |
|
809 |
- c.logArgPanic(c.method, "*check.C") |
|
810 |
- return |
|
811 |
- } |
|
812 |
- |
|
813 |
- if strings.HasPrefix(c.method.Info.Name, "Test") { |
|
814 |
- c.ResetTimer() |
|
815 |
- c.StartTimer() |
|
816 |
- c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
|
817 |
- return |
|
818 |
- } |
|
819 |
- |
|
820 |
- if !strings.HasPrefix(c.method.Info.Name, "Benchmark") { |
|
821 |
- panic("unexpected method prefix: " + c.method.Info.Name) |
|
822 |
- } |
|
823 |
- |
|
824 |
- runtime.GC() |
|
825 |
- c.N = benchN |
|
826 |
- c.ResetTimer() |
|
827 |
- c.StartTimer() |
|
828 |
- |
|
829 |
- c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
|
830 |
- c.StopTimer() |
|
831 |
- if c.status() != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 { |
|
832 |
- return |
|
833 |
- } |
|
834 |
- perOpN := int(1e9) |
|
835 |
- if c.nsPerOp() != 0 { |
|
836 |
- perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp()) |
|
837 |
- } |
|
838 |
- |
|
839 |
- // Logic taken from the stock testing package: |
|
840 |
- // - Run more iterations than we think we'll need for a second (1.5x). |
|
841 |
- // - Don't grow too fast in case we had timing errors previously. |
|
842 |
- // - Be sure to run at least one more than last time. |
|
843 |
- benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1) |
|
844 |
- benchN = roundUp(benchN) |
|
845 |
- |
|
846 |
- skipped = true // Don't run the deferred one if this panics. |
|
847 |
- runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, nil) |
|
848 |
- skipped = false |
|
849 |
- } |
|
850 |
- }) |
|
851 |
-} |
|
852 |
- |
|
853 |
-// Same as forkTest(), but wait for the test to finish before returning. |
|
854 |
-func (runner *suiteRunner) runTest(method *methodType) *C { |
|
855 |
- var timeout <-chan time.Time |
|
856 |
- if runner.checkTimeout != 0 { |
|
857 |
- timeout = time.After(runner.checkTimeout) |
|
858 |
- } |
|
859 |
- c := runner.forkTest(method) |
|
860 |
- select { |
|
861 |
- case <-c.done: |
|
862 |
- case <-timeout: |
|
863 |
- if runner.onTimeout != nil { |
|
864 |
- // run the OnTimeout callback, allowing the suite to collect any sort of debug information it can |
|
865 |
- // `runFixture` is syncronous, so run this in a separate goroutine with a timeout |
|
866 |
- cChan := make(chan *C) |
|
867 |
- go func() { |
|
868 |
- cChan <- runner.runFixture(runner.onTimeout, c.testName, c.logb) |
|
869 |
- }() |
|
870 |
- select { |
|
871 |
- case <-cChan: |
|
872 |
- case <-time.After(runner.checkTimeout): |
|
873 |
- } |
|
874 |
- } |
|
875 |
- panic(timeoutErr{method, runner.checkTimeout}) |
|
876 |
- } |
|
877 |
- return c |
|
878 |
-} |
|
879 |
- |
|
880 |
-// Helper to mark tests as skipped or missed. A bit heavy for what |
|
881 |
-// it does, but it enables homogeneous handling of tracking, including |
|
882 |
-// nice verbose output. |
|
883 |
-func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) { |
|
884 |
- for _, method := range methods { |
|
885 |
- runner.runFunc(method, testKd, "", nil, func(c *C) { |
|
886 |
- c.setStatus(status) |
|
887 |
- }) |
|
888 |
- } |
|
889 |
-} |
|
890 |
- |
|
891 |
-// Verify if the fixture arguments are *check.C. In case of errors, |
|
892 |
-// log the error as a panic in the fixture method call, and return false. |
|
893 |
-func (runner *suiteRunner) checkFixtureArgs() bool { |
|
894 |
- succeeded := true |
|
895 |
- argType := reflect.TypeOf(&C{}) |
|
896 |
- for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest, runner.onTimeout} { |
|
897 |
- if method != nil { |
|
898 |
- mt := method.Type() |
|
899 |
- if mt.NumIn() != 1 || mt.In(0) != argType { |
|
900 |
- succeeded = false |
|
901 |
- runner.runFunc(method, fixtureKd, "", nil, func(c *C) { |
|
902 |
- c.logArgPanic(method, "*check.C") |
|
903 |
- c.setStatus(panickedSt) |
|
904 |
- }) |
|
905 |
- } |
|
906 |
- } |
|
907 |
- } |
|
908 |
- return succeeded |
|
909 |
-} |
|
910 |
- |
|
911 |
-func (runner *suiteRunner) reportCallStarted(c *C) { |
|
912 |
- runner.output.WriteCallStarted("START", c) |
|
913 |
-} |
|
914 |
- |
|
915 |
-func (runner *suiteRunner) reportCallDone(c *C) { |
|
916 |
- runner.tracker.callDone(c) |
|
917 |
- switch c.status() { |
|
918 |
- case succeededSt: |
|
919 |
- if c.mustFail { |
|
920 |
- runner.output.WriteCallSuccess("FAIL EXPECTED", c) |
|
921 |
- } else { |
|
922 |
- runner.output.WriteCallSuccess("PASS", c) |
|
923 |
- } |
|
924 |
- case skippedSt: |
|
925 |
- runner.output.WriteCallSuccess("SKIP", c) |
|
926 |
- case failedSt: |
|
927 |
- runner.output.WriteCallProblem("FAIL", c) |
|
928 |
- case panickedSt: |
|
929 |
- runner.output.WriteCallProblem("PANIC", c) |
|
930 |
- case fixturePanickedSt: |
|
931 |
- // That's a testKd call reporting that its fixture |
|
932 |
- // has panicked. The fixture call which caused the |
|
933 |
- // panic itself was tracked above. We'll report to |
|
934 |
- // aid debugging. |
|
935 |
- runner.output.WriteCallProblem("PANIC", c) |
|
936 |
- case missedSt: |
|
937 |
- runner.output.WriteCallSuccess("MISS", c) |
|
938 |
- } |
|
939 |
-} |
940 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,458 +0,0 @@ |
1 |
-package check |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "reflect" |
|
6 |
- "regexp" |
|
7 |
-) |
|
8 |
- |
|
9 |
-// ----------------------------------------------------------------------- |
|
10 |
-// CommentInterface and Commentf helper, to attach extra information to checks. |
|
11 |
- |
|
12 |
-type comment struct { |
|
13 |
- format string |
|
14 |
- args []interface{} |
|
15 |
-} |
|
16 |
- |
|
17 |
-// Commentf returns an infomational value to use with Assert or Check calls. |
|
18 |
-// If the checker test fails, the provided arguments will be passed to |
|
19 |
-// fmt.Sprintf, and will be presented next to the logged failure. |
|
20 |
-// |
|
21 |
-// For example: |
|
22 |
-// |
|
23 |
-// c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i)) |
|
24 |
-// |
|
25 |
-// Note that if the comment is constant, a better option is to |
|
26 |
-// simply use a normal comment right above or next to the line, as |
|
27 |
-// it will also get printed with any errors: |
|
28 |
-// |
|
29 |
-// c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123) |
|
30 |
-// |
|
31 |
-func Commentf(format string, args ...interface{}) CommentInterface { |
|
32 |
- return &comment{format, args} |
|
33 |
-} |
|
34 |
- |
|
35 |
-// CommentInterface must be implemented by types that attach extra |
|
36 |
-// information to failed checks. See the Commentf function for details. |
|
37 |
-type CommentInterface interface { |
|
38 |
- CheckCommentString() string |
|
39 |
-} |
|
40 |
- |
|
41 |
-func (c *comment) CheckCommentString() string { |
|
42 |
- return fmt.Sprintf(c.format, c.args...) |
|
43 |
-} |
|
44 |
- |
|
45 |
-// ----------------------------------------------------------------------- |
|
46 |
-// The Checker interface. |
|
47 |
- |
|
48 |
-// The Checker interface must be provided by checkers used with |
|
49 |
-// the Assert and Check verification methods. |
|
50 |
-type Checker interface { |
|
51 |
- Info() *CheckerInfo |
|
52 |
- Check(params []interface{}, names []string) (result bool, error string) |
|
53 |
-} |
|
54 |
- |
|
55 |
-// See the Checker interface. |
|
56 |
-type CheckerInfo struct { |
|
57 |
- Name string |
|
58 |
- Params []string |
|
59 |
-} |
|
60 |
- |
|
61 |
-func (info *CheckerInfo) Info() *CheckerInfo { |
|
62 |
- return info |
|
63 |
-} |
|
64 |
- |
|
65 |
-// ----------------------------------------------------------------------- |
|
66 |
-// Not checker logic inverter. |
|
67 |
- |
|
68 |
-// The Not checker inverts the logic of the provided checker. The |
|
69 |
-// resulting checker will succeed where the original one failed, and |
|
70 |
-// vice-versa. |
|
71 |
-// |
|
72 |
-// For example: |
|
73 |
-// |
|
74 |
-// c.Assert(a, Not(Equals), b) |
|
75 |
-// |
|
76 |
-func Not(checker Checker) Checker { |
|
77 |
- return ¬Checker{checker} |
|
78 |
-} |
|
79 |
- |
|
80 |
-type notChecker struct { |
|
81 |
- sub Checker |
|
82 |
-} |
|
83 |
- |
|
84 |
-func (checker *notChecker) Info() *CheckerInfo { |
|
85 |
- info := *checker.sub.Info() |
|
86 |
- info.Name = "Not(" + info.Name + ")" |
|
87 |
- return &info |
|
88 |
-} |
|
89 |
- |
|
90 |
-func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
91 |
- result, error = checker.sub.Check(params, names) |
|
92 |
- result = !result |
|
93 |
- return |
|
94 |
-} |
|
95 |
- |
|
96 |
-// ----------------------------------------------------------------------- |
|
97 |
-// IsNil checker. |
|
98 |
- |
|
99 |
-type isNilChecker struct { |
|
100 |
- *CheckerInfo |
|
101 |
-} |
|
102 |
- |
|
103 |
-// The IsNil checker tests whether the obtained value is nil. |
|
104 |
-// |
|
105 |
-// For example: |
|
106 |
-// |
|
107 |
-// c.Assert(err, IsNil) |
|
108 |
-// |
|
109 |
-var IsNil Checker = &isNilChecker{ |
|
110 |
- &CheckerInfo{Name: "IsNil", Params: []string{"value"}}, |
|
111 |
-} |
|
112 |
- |
|
113 |
-func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
114 |
- return isNil(params[0]), "" |
|
115 |
-} |
|
116 |
- |
|
117 |
-func isNil(obtained interface{}) (result bool) { |
|
118 |
- if obtained == nil { |
|
119 |
- result = true |
|
120 |
- } else { |
|
121 |
- switch v := reflect.ValueOf(obtained); v.Kind() { |
|
122 |
- case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: |
|
123 |
- return v.IsNil() |
|
124 |
- } |
|
125 |
- } |
|
126 |
- return |
|
127 |
-} |
|
128 |
- |
|
129 |
-// ----------------------------------------------------------------------- |
|
130 |
-// NotNil checker. Alias for Not(IsNil), since it's so common. |
|
131 |
- |
|
132 |
-type notNilChecker struct { |
|
133 |
- *CheckerInfo |
|
134 |
-} |
|
135 |
- |
|
136 |
-// The NotNil checker verifies that the obtained value is not nil. |
|
137 |
-// |
|
138 |
-// For example: |
|
139 |
-// |
|
140 |
-// c.Assert(iface, NotNil) |
|
141 |
-// |
|
142 |
-// This is an alias for Not(IsNil), made available since it's a |
|
143 |
-// fairly common check. |
|
144 |
-// |
|
145 |
-var NotNil Checker = ¬NilChecker{ |
|
146 |
- &CheckerInfo{Name: "NotNil", Params: []string{"value"}}, |
|
147 |
-} |
|
148 |
- |
|
149 |
-func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
150 |
- return !isNil(params[0]), "" |
|
151 |
-} |
|
152 |
- |
|
153 |
-// ----------------------------------------------------------------------- |
|
154 |
-// Equals checker. |
|
155 |
- |
|
156 |
-type equalsChecker struct { |
|
157 |
- *CheckerInfo |
|
158 |
-} |
|
159 |
- |
|
160 |
-// The Equals checker verifies that the obtained value is equal to |
|
161 |
-// the expected value, according to usual Go semantics for ==. |
|
162 |
-// |
|
163 |
-// For example: |
|
164 |
-// |
|
165 |
-// c.Assert(value, Equals, 42) |
|
166 |
-// |
|
167 |
-var Equals Checker = &equalsChecker{ |
|
168 |
- &CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}}, |
|
169 |
-} |
|
170 |
- |
|
171 |
-func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
172 |
- defer func() { |
|
173 |
- if v := recover(); v != nil { |
|
174 |
- result = false |
|
175 |
- error = fmt.Sprint(v) |
|
176 |
- } |
|
177 |
- }() |
|
178 |
- return params[0] == params[1], "" |
|
179 |
-} |
|
180 |
- |
|
181 |
-// ----------------------------------------------------------------------- |
|
182 |
-// DeepEquals checker. |
|
183 |
- |
|
184 |
-type deepEqualsChecker struct { |
|
185 |
- *CheckerInfo |
|
186 |
-} |
|
187 |
- |
|
188 |
-// The DeepEquals checker verifies that the obtained value is deep-equal to |
|
189 |
-// the expected value. The check will work correctly even when facing |
|
190 |
-// slices, interfaces, and values of different types (which always fail |
|
191 |
-// the test). |
|
192 |
-// |
|
193 |
-// For example: |
|
194 |
-// |
|
195 |
-// c.Assert(value, DeepEquals, 42) |
|
196 |
-// c.Assert(array, DeepEquals, []string{"hi", "there"}) |
|
197 |
-// |
|
198 |
-var DeepEquals Checker = &deepEqualsChecker{ |
|
199 |
- &CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}}, |
|
200 |
-} |
|
201 |
- |
|
202 |
-func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
203 |
- return reflect.DeepEqual(params[0], params[1]), "" |
|
204 |
-} |
|
205 |
- |
|
206 |
-// ----------------------------------------------------------------------- |
|
207 |
-// HasLen checker. |
|
208 |
- |
|
209 |
-type hasLenChecker struct { |
|
210 |
- *CheckerInfo |
|
211 |
-} |
|
212 |
- |
|
213 |
-// The HasLen checker verifies that the obtained value has the |
|
214 |
-// provided length. In many cases this is superior to using Equals |
|
215 |
-// in conjuction with the len function because in case the check |
|
216 |
-// fails the value itself will be printed, instead of its length, |
|
217 |
-// providing more details for figuring the problem. |
|
218 |
-// |
|
219 |
-// For example: |
|
220 |
-// |
|
221 |
-// c.Assert(list, HasLen, 5) |
|
222 |
-// |
|
223 |
-var HasLen Checker = &hasLenChecker{ |
|
224 |
- &CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}}, |
|
225 |
-} |
|
226 |
- |
|
227 |
-func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
228 |
- n, ok := params[1].(int) |
|
229 |
- if !ok { |
|
230 |
- return false, "n must be an int" |
|
231 |
- } |
|
232 |
- value := reflect.ValueOf(params[0]) |
|
233 |
- switch value.Kind() { |
|
234 |
- case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String: |
|
235 |
- default: |
|
236 |
- return false, "obtained value type has no length" |
|
237 |
- } |
|
238 |
- return value.Len() == n, "" |
|
239 |
-} |
|
240 |
- |
|
241 |
-// ----------------------------------------------------------------------- |
|
242 |
-// ErrorMatches checker. |
|
243 |
- |
|
244 |
-type errorMatchesChecker struct { |
|
245 |
- *CheckerInfo |
|
246 |
-} |
|
247 |
- |
|
248 |
-// The ErrorMatches checker verifies that the error value |
|
249 |
-// is non nil and matches the regular expression provided. |
|
250 |
-// |
|
251 |
-// For example: |
|
252 |
-// |
|
253 |
-// c.Assert(err, ErrorMatches, "perm.*denied") |
|
254 |
-// |
|
255 |
-var ErrorMatches Checker = errorMatchesChecker{ |
|
256 |
- &CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}}, |
|
257 |
-} |
|
258 |
- |
|
259 |
-func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) { |
|
260 |
- if params[0] == nil { |
|
261 |
- return false, "Error value is nil" |
|
262 |
- } |
|
263 |
- err, ok := params[0].(error) |
|
264 |
- if !ok { |
|
265 |
- return false, "Value is not an error" |
|
266 |
- } |
|
267 |
- params[0] = err.Error() |
|
268 |
- names[0] = "error" |
|
269 |
- return matches(params[0], params[1]) |
|
270 |
-} |
|
271 |
- |
|
272 |
-// ----------------------------------------------------------------------- |
|
273 |
-// Matches checker. |
|
274 |
- |
|
275 |
-type matchesChecker struct { |
|
276 |
- *CheckerInfo |
|
277 |
-} |
|
278 |
- |
|
279 |
-// The Matches checker verifies that the string provided as the obtained |
|
280 |
-// value (or the string resulting from obtained.String()) matches the |
|
281 |
-// regular expression provided. |
|
282 |
-// |
|
283 |
-// For example: |
|
284 |
-// |
|
285 |
-// c.Assert(err, Matches, "perm.*denied") |
|
286 |
-// |
|
287 |
-var Matches Checker = &matchesChecker{ |
|
288 |
- &CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}}, |
|
289 |
-} |
|
290 |
- |
|
291 |
-func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
292 |
- return matches(params[0], params[1]) |
|
293 |
-} |
|
294 |
- |
|
295 |
-func matches(value, regex interface{}) (result bool, error string) { |
|
296 |
- reStr, ok := regex.(string) |
|
297 |
- if !ok { |
|
298 |
- return false, "Regex must be a string" |
|
299 |
- } |
|
300 |
- valueStr, valueIsStr := value.(string) |
|
301 |
- if !valueIsStr { |
|
302 |
- if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr { |
|
303 |
- valueStr, valueIsStr = valueWithStr.String(), true |
|
304 |
- } |
|
305 |
- } |
|
306 |
- if valueIsStr { |
|
307 |
- matches, err := regexp.MatchString("^"+reStr+"$", valueStr) |
|
308 |
- if err != nil { |
|
309 |
- return false, "Can't compile regex: " + err.Error() |
|
310 |
- } |
|
311 |
- return matches, "" |
|
312 |
- } |
|
313 |
- return false, "Obtained value is not a string and has no .String()" |
|
314 |
-} |
|
315 |
- |
|
316 |
-// ----------------------------------------------------------------------- |
|
317 |
-// Panics checker. |
|
318 |
- |
|
319 |
-type panicsChecker struct { |
|
320 |
- *CheckerInfo |
|
321 |
-} |
|
322 |
- |
|
323 |
-// The Panics checker verifies that calling the provided zero-argument |
|
324 |
-// function will cause a panic which is deep-equal to the provided value. |
|
325 |
-// |
|
326 |
-// For example: |
|
327 |
-// |
|
328 |
-// c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}). |
|
329 |
-// |
|
330 |
-// |
|
331 |
-var Panics Checker = &panicsChecker{ |
|
332 |
- &CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}}, |
|
333 |
-} |
|
334 |
- |
|
335 |
-func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
336 |
- f := reflect.ValueOf(params[0]) |
|
337 |
- if f.Kind() != reflect.Func || f.Type().NumIn() != 0 { |
|
338 |
- return false, "Function must take zero arguments" |
|
339 |
- } |
|
340 |
- defer func() { |
|
341 |
- // If the function has not panicked, then don't do the check. |
|
342 |
- if error != "" { |
|
343 |
- return |
|
344 |
- } |
|
345 |
- params[0] = recover() |
|
346 |
- names[0] = "panic" |
|
347 |
- result = reflect.DeepEqual(params[0], params[1]) |
|
348 |
- }() |
|
349 |
- f.Call(nil) |
|
350 |
- return false, "Function has not panicked" |
|
351 |
-} |
|
352 |
- |
|
353 |
-type panicMatchesChecker struct { |
|
354 |
- *CheckerInfo |
|
355 |
-} |
|
356 |
- |
|
357 |
-// The PanicMatches checker verifies that calling the provided zero-argument |
|
358 |
-// function will cause a panic with an error value matching |
|
359 |
-// the regular expression provided. |
|
360 |
-// |
|
361 |
-// For example: |
|
362 |
-// |
|
363 |
-// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`). |
|
364 |
-// |
|
365 |
-// |
|
366 |
-var PanicMatches Checker = &panicMatchesChecker{ |
|
367 |
- &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}}, |
|
368 |
-} |
|
369 |
- |
|
370 |
-func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) { |
|
371 |
- f := reflect.ValueOf(params[0]) |
|
372 |
- if f.Kind() != reflect.Func || f.Type().NumIn() != 0 { |
|
373 |
- return false, "Function must take zero arguments" |
|
374 |
- } |
|
375 |
- defer func() { |
|
376 |
- // If the function has not panicked, then don't do the check. |
|
377 |
- if errmsg != "" { |
|
378 |
- return |
|
379 |
- } |
|
380 |
- obtained := recover() |
|
381 |
- names[0] = "panic" |
|
382 |
- if e, ok := obtained.(error); ok { |
|
383 |
- params[0] = e.Error() |
|
384 |
- } else if _, ok := obtained.(string); ok { |
|
385 |
- params[0] = obtained |
|
386 |
- } else { |
|
387 |
- errmsg = "Panic value is not a string or an error" |
|
388 |
- return |
|
389 |
- } |
|
390 |
- result, errmsg = matches(params[0], params[1]) |
|
391 |
- }() |
|
392 |
- f.Call(nil) |
|
393 |
- return false, "Function has not panicked" |
|
394 |
-} |
|
395 |
- |
|
396 |
-// ----------------------------------------------------------------------- |
|
397 |
-// FitsTypeOf checker. |
|
398 |
- |
|
399 |
-type fitsTypeChecker struct { |
|
400 |
- *CheckerInfo |
|
401 |
-} |
|
402 |
- |
|
403 |
-// The FitsTypeOf checker verifies that the obtained value is |
|
404 |
-// assignable to a variable with the same type as the provided |
|
405 |
-// sample value. |
|
406 |
-// |
|
407 |
-// For example: |
|
408 |
-// |
|
409 |
-// c.Assert(value, FitsTypeOf, int64(0)) |
|
410 |
-// c.Assert(value, FitsTypeOf, os.Error(nil)) |
|
411 |
-// |
|
412 |
-var FitsTypeOf Checker = &fitsTypeChecker{ |
|
413 |
- &CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}}, |
|
414 |
-} |
|
415 |
- |
|
416 |
-func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
417 |
- obtained := reflect.ValueOf(params[0]) |
|
418 |
- sample := reflect.ValueOf(params[1]) |
|
419 |
- if !obtained.IsValid() { |
|
420 |
- return false, "" |
|
421 |
- } |
|
422 |
- if !sample.IsValid() { |
|
423 |
- return false, "Invalid sample value" |
|
424 |
- } |
|
425 |
- return obtained.Type().AssignableTo(sample.Type()), "" |
|
426 |
-} |
|
427 |
- |
|
428 |
-// ----------------------------------------------------------------------- |
|
429 |
-// Implements checker. |
|
430 |
- |
|
431 |
-type implementsChecker struct { |
|
432 |
- *CheckerInfo |
|
433 |
-} |
|
434 |
- |
|
435 |
-// The Implements checker verifies that the obtained value |
|
436 |
-// implements the interface specified via a pointer to an interface |
|
437 |
-// variable. |
|
438 |
-// |
|
439 |
-// For example: |
|
440 |
-// |
|
441 |
-// var e os.Error |
|
442 |
-// c.Assert(err, Implements, &e) |
|
443 |
-// |
|
444 |
-var Implements Checker = &implementsChecker{ |
|
445 |
- &CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}}, |
|
446 |
-} |
|
447 |
- |
|
448 |
-func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
|
449 |
- obtained := reflect.ValueOf(params[0]) |
|
450 |
- ifaceptr := reflect.ValueOf(params[1]) |
|
451 |
- if !obtained.IsValid() { |
|
452 |
- return false, "" |
|
453 |
- } |
|
454 |
- if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface { |
|
455 |
- return false, "ifaceptr should be a pointer to an interface variable" |
|
456 |
- } |
|
457 |
- return obtained.Type().Implements(ifaceptr.Elem().Type()), "" |
|
458 |
-} |
459 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,231 +0,0 @@ |
1 |
-package check |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "strings" |
|
6 |
- "time" |
|
7 |
-) |
|
8 |
- |
|
9 |
-// TestName returns the current test name in the form "SuiteName.TestName" |
|
10 |
-func (c *C) TestName() string { |
|
11 |
- return c.testName |
|
12 |
-} |
|
13 |
- |
|
14 |
-// ----------------------------------------------------------------------- |
|
15 |
-// Basic succeeding/failing logic. |
|
16 |
- |
|
17 |
-// Failed returns whether the currently running test has already failed. |
|
18 |
-func (c *C) Failed() bool { |
|
19 |
- return c.status() == failedSt |
|
20 |
-} |
|
21 |
- |
|
22 |
-// Fail marks the currently running test as failed. |
|
23 |
-// |
|
24 |
-// Something ought to have been previously logged so the developer can tell |
|
25 |
-// what went wrong. The higher level helper functions will fail the test |
|
26 |
-// and do the logging properly. |
|
27 |
-func (c *C) Fail() { |
|
28 |
- c.setStatus(failedSt) |
|
29 |
-} |
|
30 |
- |
|
31 |
-// FailNow marks the currently running test as failed and stops running it. |
|
32 |
-// Something ought to have been previously logged so the developer can tell |
|
33 |
-// what went wrong. The higher level helper functions will fail the test |
|
34 |
-// and do the logging properly. |
|
35 |
-func (c *C) FailNow() { |
|
36 |
- c.Fail() |
|
37 |
- c.stopNow() |
|
38 |
-} |
|
39 |
- |
|
40 |
-// Succeed marks the currently running test as succeeded, undoing any |
|
41 |
-// previous failures. |
|
42 |
-func (c *C) Succeed() { |
|
43 |
- c.setStatus(succeededSt) |
|
44 |
-} |
|
45 |
- |
|
46 |
-// SucceedNow marks the currently running test as succeeded, undoing any |
|
47 |
-// previous failures, and stops running the test. |
|
48 |
-func (c *C) SucceedNow() { |
|
49 |
- c.Succeed() |
|
50 |
- c.stopNow() |
|
51 |
-} |
|
52 |
- |
|
53 |
-// ExpectFailure informs that the running test is knowingly broken for |
|
54 |
-// the provided reason. If the test does not fail, an error will be reported |
|
55 |
-// to raise attention to this fact. This method is useful to temporarily |
|
56 |
-// disable tests which cover well known problems until a better time to |
|
57 |
-// fix the problem is found, without forgetting about the fact that a |
|
58 |
-// failure still exists. |
|
59 |
-func (c *C) ExpectFailure(reason string) { |
|
60 |
- if reason == "" { |
|
61 |
- panic("Missing reason why the test is expected to fail") |
|
62 |
- } |
|
63 |
- c.mustFail = true |
|
64 |
- c.reason = reason |
|
65 |
-} |
|
66 |
- |
|
67 |
-// Skip skips the running test for the provided reason. If run from within |
|
68 |
-// SetUpTest, the individual test being set up will be skipped, and if run |
|
69 |
-// from within SetUpSuite, the whole suite is skipped. |
|
70 |
-func (c *C) Skip(reason string) { |
|
71 |
- if reason == "" { |
|
72 |
- panic("Missing reason why the test is being skipped") |
|
73 |
- } |
|
74 |
- c.reason = reason |
|
75 |
- c.setStatus(skippedSt) |
|
76 |
- c.stopNow() |
|
77 |
-} |
|
78 |
- |
|
79 |
-// ----------------------------------------------------------------------- |
|
80 |
-// Basic logging. |
|
81 |
- |
|
82 |
-// GetTestLog returns the current test error output. |
|
83 |
-func (c *C) GetTestLog() string { |
|
84 |
- return c.logb.String() |
|
85 |
-} |
|
86 |
- |
|
87 |
-// Log logs some information into the test error output. |
|
88 |
-// The provided arguments are assembled together into a string with fmt.Sprint. |
|
89 |
-func (c *C) Log(args ...interface{}) { |
|
90 |
- c.log(args...) |
|
91 |
-} |
|
92 |
- |
|
93 |
-// Log logs some information into the test error output. |
|
94 |
-// The provided arguments are assembled together into a string with fmt.Sprintf. |
|
95 |
-func (c *C) Logf(format string, args ...interface{}) { |
|
96 |
- c.logf(format, args...) |
|
97 |
-} |
|
98 |
- |
|
99 |
-// Output enables *C to be used as a logger in functions that require only |
|
100 |
-// the minimum interface of *log.Logger. |
|
101 |
-func (c *C) Output(calldepth int, s string) error { |
|
102 |
- d := time.Now().Sub(c.startTime) |
|
103 |
- msec := d / time.Millisecond |
|
104 |
- sec := d / time.Second |
|
105 |
- min := d / time.Minute |
|
106 |
- |
|
107 |
- c.Logf("[LOG] %d:%02d.%03d %s", min, sec%60, msec%1000, s) |
|
108 |
- return nil |
|
109 |
-} |
|
110 |
- |
|
111 |
-// Error logs an error into the test error output and marks the test as failed. |
|
112 |
-// The provided arguments are assembled together into a string with fmt.Sprint. |
|
113 |
-func (c *C) Error(args ...interface{}) { |
|
114 |
- c.logCaller(1) |
|
115 |
- c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...))) |
|
116 |
- c.logNewLine() |
|
117 |
- c.Fail() |
|
118 |
-} |
|
119 |
- |
|
120 |
-// Errorf logs an error into the test error output and marks the test as failed. |
|
121 |
-// The provided arguments are assembled together into a string with fmt.Sprintf. |
|
122 |
-func (c *C) Errorf(format string, args ...interface{}) { |
|
123 |
- c.logCaller(1) |
|
124 |
- c.logString(fmt.Sprintf("Error: "+format, args...)) |
|
125 |
- c.logNewLine() |
|
126 |
- c.Fail() |
|
127 |
-} |
|
128 |
- |
|
129 |
-// Fatal logs an error into the test error output, marks the test as failed, and |
|
130 |
-// stops the test execution. The provided arguments are assembled together into |
|
131 |
-// a string with fmt.Sprint. |
|
132 |
-func (c *C) Fatal(args ...interface{}) { |
|
133 |
- c.logCaller(1) |
|
134 |
- c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...))) |
|
135 |
- c.logNewLine() |
|
136 |
- c.FailNow() |
|
137 |
-} |
|
138 |
- |
|
139 |
-// Fatlaf logs an error into the test error output, marks the test as failed, and |
|
140 |
-// stops the test execution. The provided arguments are assembled together into |
|
141 |
-// a string with fmt.Sprintf. |
|
142 |
-func (c *C) Fatalf(format string, args ...interface{}) { |
|
143 |
- c.logCaller(1) |
|
144 |
- c.logString(fmt.Sprint("Error: ", fmt.Sprintf(format, args...))) |
|
145 |
- c.logNewLine() |
|
146 |
- c.FailNow() |
|
147 |
-} |
|
148 |
- |
|
149 |
-// ----------------------------------------------------------------------- |
|
150 |
-// Generic checks and assertions based on checkers. |
|
151 |
- |
|
152 |
-// Check verifies if the first value matches the expected value according |
|
153 |
-// to the provided checker. If they do not match, an error is logged, the |
|
154 |
-// test is marked as failed, and the test execution continues. |
|
155 |
-// |
|
156 |
-// Some checkers may not need the expected argument (e.g. IsNil). |
|
157 |
-// |
|
158 |
-// Extra arguments provided to the function are logged next to the reported |
|
159 |
-// problem when the matching fails. |
|
160 |
-func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool { |
|
161 |
- return c.internalCheck("Check", obtained, checker, args...) |
|
162 |
-} |
|
163 |
- |
|
164 |
-// Assert ensures that the first value matches the expected value according |
|
165 |
-// to the provided checker. If they do not match, an error is logged, the |
|
166 |
-// test is marked as failed, and the test execution stops. |
|
167 |
-// |
|
168 |
-// Some checkers may not need the expected argument (e.g. IsNil). |
|
169 |
-// |
|
170 |
-// Extra arguments provided to the function are logged next to the reported |
|
171 |
-// problem when the matching fails. |
|
172 |
-func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) { |
|
173 |
- if !c.internalCheck("Assert", obtained, checker, args...) { |
|
174 |
- c.stopNow() |
|
175 |
- } |
|
176 |
-} |
|
177 |
- |
|
178 |
-func (c *C) internalCheck(funcName string, obtained interface{}, checker Checker, args ...interface{}) bool { |
|
179 |
- if checker == nil { |
|
180 |
- c.logCaller(2) |
|
181 |
- c.logString(fmt.Sprintf("%s(obtained, nil!?, ...):", funcName)) |
|
182 |
- c.logString("Oops.. you've provided a nil checker!") |
|
183 |
- c.logNewLine() |
|
184 |
- c.Fail() |
|
185 |
- return false |
|
186 |
- } |
|
187 |
- |
|
188 |
- // If the last argument is a bug info, extract it out. |
|
189 |
- var comment CommentInterface |
|
190 |
- if len(args) > 0 { |
|
191 |
- if c, ok := args[len(args)-1].(CommentInterface); ok { |
|
192 |
- comment = c |
|
193 |
- args = args[:len(args)-1] |
|
194 |
- } |
|
195 |
- } |
|
196 |
- |
|
197 |
- params := append([]interface{}{obtained}, args...) |
|
198 |
- info := checker.Info() |
|
199 |
- |
|
200 |
- if len(params) != len(info.Params) { |
|
201 |
- names := append([]string{info.Params[0], info.Name}, info.Params[1:]...) |
|
202 |
- c.logCaller(2) |
|
203 |
- c.logString(fmt.Sprintf("%s(%s):", funcName, strings.Join(names, ", "))) |
|
204 |
- c.logString(fmt.Sprintf("Wrong number of parameters for %s: want %d, got %d", info.Name, len(names), len(params)+1)) |
|
205 |
- c.logNewLine() |
|
206 |
- c.Fail() |
|
207 |
- return false |
|
208 |
- } |
|
209 |
- |
|
210 |
- // Copy since it may be mutated by Check. |
|
211 |
- names := append([]string{}, info.Params...) |
|
212 |
- |
|
213 |
- // Do the actual check. |
|
214 |
- result, error := checker.Check(params, names) |
|
215 |
- if !result || error != "" { |
|
216 |
- c.logCaller(2) |
|
217 |
- for i := 0; i != len(params); i++ { |
|
218 |
- c.logValue(names[i], params[i]) |
|
219 |
- } |
|
220 |
- if comment != nil { |
|
221 |
- c.logString(comment.CheckCommentString()) |
|
222 |
- } |
|
223 |
- if error != "" { |
|
224 |
- c.logString(error) |
|
225 |
- } |
|
226 |
- c.logNewLine() |
|
227 |
- c.Fail() |
|
228 |
- return false |
|
229 |
- } |
|
230 |
- return true |
|
231 |
-} |
232 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,168 +0,0 @@ |
1 |
-package check |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "bytes" |
|
5 |
- "go/ast" |
|
6 |
- "go/parser" |
|
7 |
- "go/printer" |
|
8 |
- "go/token" |
|
9 |
- "os" |
|
10 |
-) |
|
11 |
- |
|
12 |
-func indent(s, with string) (r string) { |
|
13 |
- eol := true |
|
14 |
- for i := 0; i != len(s); i++ { |
|
15 |
- c := s[i] |
|
16 |
- switch { |
|
17 |
- case eol && c == '\n' || c == '\r': |
|
18 |
- case c == '\n' || c == '\r': |
|
19 |
- eol = true |
|
20 |
- case eol: |
|
21 |
- eol = false |
|
22 |
- s = s[:i] + with + s[i:] |
|
23 |
- i += len(with) |
|
24 |
- } |
|
25 |
- } |
|
26 |
- return s |
|
27 |
-} |
|
28 |
- |
|
29 |
-func printLine(filename string, line int) (string, error) { |
|
30 |
- fset := token.NewFileSet() |
|
31 |
- file, err := os.Open(filename) |
|
32 |
- if err != nil { |
|
33 |
- return "", err |
|
34 |
- } |
|
35 |
- fnode, err := parser.ParseFile(fset, filename, file, parser.ParseComments) |
|
36 |
- if err != nil { |
|
37 |
- return "", err |
|
38 |
- } |
|
39 |
- config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: 4} |
|
40 |
- lp := &linePrinter{fset: fset, fnode: fnode, line: line, config: config} |
|
41 |
- ast.Walk(lp, fnode) |
|
42 |
- result := lp.output.Bytes() |
|
43 |
- // Comments leave \n at the end. |
|
44 |
- n := len(result) |
|
45 |
- for n > 0 && result[n-1] == '\n' { |
|
46 |
- n-- |
|
47 |
- } |
|
48 |
- return string(result[:n]), nil |
|
49 |
-} |
|
50 |
- |
|
51 |
-type linePrinter struct { |
|
52 |
- config *printer.Config |
|
53 |
- fset *token.FileSet |
|
54 |
- fnode *ast.File |
|
55 |
- line int |
|
56 |
- output bytes.Buffer |
|
57 |
- stmt ast.Stmt |
|
58 |
-} |
|
59 |
- |
|
60 |
-func (lp *linePrinter) emit() bool { |
|
61 |
- if lp.stmt != nil { |
|
62 |
- lp.trim(lp.stmt) |
|
63 |
- lp.printWithComments(lp.stmt) |
|
64 |
- lp.stmt = nil |
|
65 |
- return true |
|
66 |
- } |
|
67 |
- return false |
|
68 |
-} |
|
69 |
- |
|
70 |
-func (lp *linePrinter) printWithComments(n ast.Node) { |
|
71 |
- nfirst := lp.fset.Position(n.Pos()).Line |
|
72 |
- nlast := lp.fset.Position(n.End()).Line |
|
73 |
- for _, g := range lp.fnode.Comments { |
|
74 |
- cfirst := lp.fset.Position(g.Pos()).Line |
|
75 |
- clast := lp.fset.Position(g.End()).Line |
|
76 |
- if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column { |
|
77 |
- for _, c := range g.List { |
|
78 |
- lp.output.WriteString(c.Text) |
|
79 |
- lp.output.WriteByte('\n') |
|
80 |
- } |
|
81 |
- } |
|
82 |
- if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash { |
|
83 |
- // The printer will not include the comment if it starts past |
|
84 |
- // the node itself. Trick it into printing by overlapping the |
|
85 |
- // slash with the end of the statement. |
|
86 |
- g.List[0].Slash = n.End() - 1 |
|
87 |
- } |
|
88 |
- } |
|
89 |
- node := &printer.CommentedNode{n, lp.fnode.Comments} |
|
90 |
- lp.config.Fprint(&lp.output, lp.fset, node) |
|
91 |
-} |
|
92 |
- |
|
93 |
-func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) { |
|
94 |
- if n == nil { |
|
95 |
- if lp.output.Len() == 0 { |
|
96 |
- lp.emit() |
|
97 |
- } |
|
98 |
- return nil |
|
99 |
- } |
|
100 |
- first := lp.fset.Position(n.Pos()).Line |
|
101 |
- last := lp.fset.Position(n.End()).Line |
|
102 |
- if first <= lp.line && last >= lp.line { |
|
103 |
- // Print the innermost statement containing the line. |
|
104 |
- if stmt, ok := n.(ast.Stmt); ok { |
|
105 |
- if _, ok := n.(*ast.BlockStmt); !ok { |
|
106 |
- lp.stmt = stmt |
|
107 |
- } |
|
108 |
- } |
|
109 |
- if first == lp.line && lp.emit() { |
|
110 |
- return nil |
|
111 |
- } |
|
112 |
- return lp |
|
113 |
- } |
|
114 |
- return nil |
|
115 |
-} |
|
116 |
- |
|
117 |
-func (lp *linePrinter) trim(n ast.Node) bool { |
|
118 |
- stmt, ok := n.(ast.Stmt) |
|
119 |
- if !ok { |
|
120 |
- return true |
|
121 |
- } |
|
122 |
- line := lp.fset.Position(n.Pos()).Line |
|
123 |
- if line != lp.line { |
|
124 |
- return false |
|
125 |
- } |
|
126 |
- switch stmt := stmt.(type) { |
|
127 |
- case *ast.IfStmt: |
|
128 |
- stmt.Body = lp.trimBlock(stmt.Body) |
|
129 |
- case *ast.SwitchStmt: |
|
130 |
- stmt.Body = lp.trimBlock(stmt.Body) |
|
131 |
- case *ast.TypeSwitchStmt: |
|
132 |
- stmt.Body = lp.trimBlock(stmt.Body) |
|
133 |
- case *ast.CaseClause: |
|
134 |
- stmt.Body = lp.trimList(stmt.Body) |
|
135 |
- case *ast.CommClause: |
|
136 |
- stmt.Body = lp.trimList(stmt.Body) |
|
137 |
- case *ast.BlockStmt: |
|
138 |
- stmt.List = lp.trimList(stmt.List) |
|
139 |
- } |
|
140 |
- return true |
|
141 |
-} |
|
142 |
- |
|
143 |
-func (lp *linePrinter) trimBlock(stmt *ast.BlockStmt) *ast.BlockStmt { |
|
144 |
- if !lp.trim(stmt) { |
|
145 |
- return lp.emptyBlock(stmt) |
|
146 |
- } |
|
147 |
- stmt.Rbrace = stmt.Lbrace |
|
148 |
- return stmt |
|
149 |
-} |
|
150 |
- |
|
151 |
-func (lp *linePrinter) trimList(stmts []ast.Stmt) []ast.Stmt { |
|
152 |
- for i := 0; i != len(stmts); i++ { |
|
153 |
- if !lp.trim(stmts[i]) { |
|
154 |
- stmts[i] = lp.emptyStmt(stmts[i]) |
|
155 |
- break |
|
156 |
- } |
|
157 |
- } |
|
158 |
- return stmts |
|
159 |
-} |
|
160 |
- |
|
161 |
-func (lp *linePrinter) emptyStmt(n ast.Node) *ast.ExprStmt { |
|
162 |
- return &ast.ExprStmt{&ast.Ellipsis{n.Pos(), nil}} |
|
163 |
-} |
|
164 |
- |
|
165 |
-func (lp *linePrinter) emptyBlock(n ast.Node) *ast.BlockStmt { |
|
166 |
- p := n.Pos() |
|
167 |
- return &ast.BlockStmt{p, []ast.Stmt{lp.emptyStmt(n)}, p} |
|
168 |
-} |
169 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,88 +0,0 @@ |
1 |
-package check |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "io" |
|
6 |
- "sync" |
|
7 |
-) |
|
8 |
- |
|
9 |
-// ----------------------------------------------------------------------- |
|
10 |
-// Output writer manages atomic output writing according to settings. |
|
11 |
- |
|
12 |
-type outputWriter struct { |
|
13 |
- m sync.Mutex |
|
14 |
- writer io.Writer |
|
15 |
- wroteCallProblemLast bool |
|
16 |
- Stream bool |
|
17 |
- Verbose bool |
|
18 |
-} |
|
19 |
- |
|
20 |
-func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter { |
|
21 |
- return &outputWriter{writer: writer, Stream: stream, Verbose: verbose} |
|
22 |
-} |
|
23 |
- |
|
24 |
-func (ow *outputWriter) Write(content []byte) (n int, err error) { |
|
25 |
- ow.m.Lock() |
|
26 |
- n, err = ow.writer.Write(content) |
|
27 |
- ow.m.Unlock() |
|
28 |
- return |
|
29 |
-} |
|
30 |
- |
|
31 |
-func (ow *outputWriter) WriteCallStarted(label string, c *C) { |
|
32 |
- if ow.Stream { |
|
33 |
- header := renderCallHeader(label, c, "", "\n") |
|
34 |
- ow.m.Lock() |
|
35 |
- ow.writer.Write([]byte(header)) |
|
36 |
- ow.m.Unlock() |
|
37 |
- } |
|
38 |
-} |
|
39 |
- |
|
40 |
-func (ow *outputWriter) WriteCallProblem(label string, c *C) { |
|
41 |
- var prefix string |
|
42 |
- if !ow.Stream { |
|
43 |
- prefix = "\n-----------------------------------" + |
|
44 |
- "-----------------------------------\n" |
|
45 |
- } |
|
46 |
- header := renderCallHeader(label, c, prefix, "\n\n") |
|
47 |
- ow.m.Lock() |
|
48 |
- ow.wroteCallProblemLast = true |
|
49 |
- ow.writer.Write([]byte(header)) |
|
50 |
- if !ow.Stream { |
|
51 |
- c.logb.WriteTo(ow.writer) |
|
52 |
- } |
|
53 |
- ow.m.Unlock() |
|
54 |
-} |
|
55 |
- |
|
56 |
-func (ow *outputWriter) WriteCallSuccess(label string, c *C) { |
|
57 |
- if ow.Stream || (ow.Verbose && c.kind == testKd) { |
|
58 |
- // TODO Use a buffer here. |
|
59 |
- var suffix string |
|
60 |
- if c.reason != "" { |
|
61 |
- suffix = " (" + c.reason + ")" |
|
62 |
- } |
|
63 |
- if c.status() == succeededSt { |
|
64 |
- suffix += "\t" + c.timerString() |
|
65 |
- } |
|
66 |
- suffix += "\n" |
|
67 |
- if ow.Stream { |
|
68 |
- suffix += "\n" |
|
69 |
- } |
|
70 |
- header := renderCallHeader(label, c, "", suffix) |
|
71 |
- ow.m.Lock() |
|
72 |
- // Resist temptation of using line as prefix above due to race. |
|
73 |
- if !ow.Stream && ow.wroteCallProblemLast { |
|
74 |
- header = "\n-----------------------------------" + |
|
75 |
- "-----------------------------------\n" + |
|
76 |
- header |
|
77 |
- } |
|
78 |
- ow.wroteCallProblemLast = false |
|
79 |
- ow.writer.Write([]byte(header)) |
|
80 |
- ow.m.Unlock() |
|
81 |
- } |
|
82 |
-} |
|
83 |
- |
|
84 |
-func renderCallHeader(label string, c *C, prefix, suffix string) string { |
|
85 |
- pc := c.method.PC() |
|
86 |
- return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc), |
|
87 |
- niceFuncName(pc), suffix) |
|
88 |
-} |
89 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,183 +0,0 @@ |
1 |
-package check |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "bufio" |
|
5 |
- "flag" |
|
6 |
- "fmt" |
|
7 |
- "os" |
|
8 |
- "testing" |
|
9 |
- "time" |
|
10 |
-) |
|
11 |
- |
|
12 |
-// ----------------------------------------------------------------------- |
|
13 |
-// Test suite registry. |
|
14 |
- |
|
15 |
-var allSuites []interface{} |
|
16 |
- |
|
17 |
-// Suite registers the given value as a test suite to be run. Any methods |
|
18 |
-// starting with the Test prefix in the given value will be considered as |
|
19 |
-// a test method. |
|
20 |
-func Suite(suite interface{}) interface{} { |
|
21 |
- allSuites = append(allSuites, suite) |
|
22 |
- return suite |
|
23 |
-} |
|
24 |
- |
|
25 |
-// ----------------------------------------------------------------------- |
|
26 |
-// Public running interface. |
|
27 |
- |
|
28 |
-var ( |
|
29 |
- oldFilterFlag = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run") |
|
30 |
- oldVerboseFlag = flag.Bool("gocheck.v", false, "Verbose mode") |
|
31 |
- oldStreamFlag = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)") |
|
32 |
- oldBenchFlag = flag.Bool("gocheck.b", false, "Run benchmarks") |
|
33 |
- oldBenchTime = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark") |
|
34 |
- oldListFlag = flag.Bool("gocheck.list", false, "List the names of all tests that will be run") |
|
35 |
- oldWorkFlag = flag.Bool("gocheck.work", false, "Display and do not remove the test working directory") |
|
36 |
- |
|
37 |
- newFilterFlag = flag.String("check.f", "", "Regular expression selecting which tests and/or suites to run") |
|
38 |
- newVerboseFlag = flag.Bool("check.v", false, "Verbose mode") |
|
39 |
- newStreamFlag = flag.Bool("check.vv", false, "Super verbose mode (disables output caching)") |
|
40 |
- newBenchFlag = flag.Bool("check.b", false, "Run benchmarks") |
|
41 |
- newBenchTime = flag.Duration("check.btime", 1*time.Second, "approximate run time for each benchmark") |
|
42 |
- newBenchMem = flag.Bool("check.bmem", false, "Report memory benchmarks") |
|
43 |
- newListFlag = flag.Bool("check.list", false, "List the names of all tests that will be run") |
|
44 |
- newWorkFlag = flag.Bool("check.work", false, "Display and do not remove the test working directory") |
|
45 |
- checkTimeout = flag.String("check.timeout", "", "Panic if test runs longer than specified duration") |
|
46 |
-) |
|
47 |
- |
|
48 |
-// TestingT runs all test suites registered with the Suite function, |
|
49 |
-// printing results to stdout, and reporting any failures back to |
|
50 |
-// the "testing" package. |
|
51 |
-func TestingT(testingT *testing.T) { |
|
52 |
- benchTime := *newBenchTime |
|
53 |
- if benchTime == 1*time.Second { |
|
54 |
- benchTime = *oldBenchTime |
|
55 |
- } |
|
56 |
- conf := &RunConf{ |
|
57 |
- Filter: *oldFilterFlag + *newFilterFlag, |
|
58 |
- Verbose: *oldVerboseFlag || *newVerboseFlag, |
|
59 |
- Stream: *oldStreamFlag || *newStreamFlag, |
|
60 |
- Benchmark: *oldBenchFlag || *newBenchFlag, |
|
61 |
- BenchmarkTime: benchTime, |
|
62 |
- BenchmarkMem: *newBenchMem, |
|
63 |
- KeepWorkDir: *oldWorkFlag || *newWorkFlag, |
|
64 |
- } |
|
65 |
- if *checkTimeout != "" { |
|
66 |
- timeout, err := time.ParseDuration(*checkTimeout) |
|
67 |
- if err != nil { |
|
68 |
- testingT.Fatalf("error parsing specified timeout flag: %v", err) |
|
69 |
- } |
|
70 |
- conf.CheckTimeout = timeout |
|
71 |
- } |
|
72 |
- if *oldListFlag || *newListFlag { |
|
73 |
- w := bufio.NewWriter(os.Stdout) |
|
74 |
- for _, name := range ListAll(conf) { |
|
75 |
- fmt.Fprintln(w, name) |
|
76 |
- } |
|
77 |
- w.Flush() |
|
78 |
- return |
|
79 |
- } |
|
80 |
- result := RunAll(conf) |
|
81 |
- println(result.String()) |
|
82 |
- if !result.Passed() { |
|
83 |
- testingT.Fail() |
|
84 |
- } |
|
85 |
-} |
|
86 |
- |
|
87 |
-// RunAll runs all test suites registered with the Suite function, using the |
|
88 |
-// provided run configuration. |
|
89 |
-func RunAll(runConf *RunConf) *Result { |
|
90 |
- result := Result{} |
|
91 |
- for _, suite := range allSuites { |
|
92 |
- result.Add(Run(suite, runConf)) |
|
93 |
- } |
|
94 |
- return &result |
|
95 |
-} |
|
96 |
- |
|
97 |
-// Run runs the provided test suite using the provided run configuration. |
|
98 |
-func Run(suite interface{}, runConf *RunConf) *Result { |
|
99 |
- runner := newSuiteRunner(suite, runConf) |
|
100 |
- return runner.run() |
|
101 |
-} |
|
102 |
- |
|
103 |
-// ListAll returns the names of all the test functions registered with the |
|
104 |
-// Suite function that will be run with the provided run configuration. |
|
105 |
-func ListAll(runConf *RunConf) []string { |
|
106 |
- var names []string |
|
107 |
- for _, suite := range allSuites { |
|
108 |
- names = append(names, List(suite, runConf)...) |
|
109 |
- } |
|
110 |
- return names |
|
111 |
-} |
|
112 |
- |
|
113 |
-// List returns the names of the test functions in the given |
|
114 |
-// suite that will be run with the provided run configuration. |
|
115 |
-func List(suite interface{}, runConf *RunConf) []string { |
|
116 |
- var names []string |
|
117 |
- runner := newSuiteRunner(suite, runConf) |
|
118 |
- for _, t := range runner.tests { |
|
119 |
- names = append(names, t.String()) |
|
120 |
- } |
|
121 |
- return names |
|
122 |
-} |
|
123 |
- |
|
124 |
-// ----------------------------------------------------------------------- |
|
125 |
-// Result methods. |
|
126 |
- |
|
127 |
-func (r *Result) Add(other *Result) { |
|
128 |
- r.Succeeded += other.Succeeded |
|
129 |
- r.Skipped += other.Skipped |
|
130 |
- r.Failed += other.Failed |
|
131 |
- r.Panicked += other.Panicked |
|
132 |
- r.FixturePanicked += other.FixturePanicked |
|
133 |
- r.ExpectedFailures += other.ExpectedFailures |
|
134 |
- r.Missed += other.Missed |
|
135 |
- if r.WorkDir != "" && other.WorkDir != "" { |
|
136 |
- r.WorkDir += ":" + other.WorkDir |
|
137 |
- } else if other.WorkDir != "" { |
|
138 |
- r.WorkDir = other.WorkDir |
|
139 |
- } |
|
140 |
-} |
|
141 |
- |
|
142 |
-func (r *Result) Passed() bool { |
|
143 |
- return (r.Failed == 0 && r.Panicked == 0 && |
|
144 |
- r.FixturePanicked == 0 && r.Missed == 0 && |
|
145 |
- r.RunError == nil) |
|
146 |
-} |
|
147 |
- |
|
148 |
-func (r *Result) String() string { |
|
149 |
- if r.RunError != nil { |
|
150 |
- return "ERROR: " + r.RunError.Error() |
|
151 |
- } |
|
152 |
- |
|
153 |
- var value string |
|
154 |
- if r.Failed == 0 && r.Panicked == 0 && r.FixturePanicked == 0 && |
|
155 |
- r.Missed == 0 { |
|
156 |
- value = "OK: " |
|
157 |
- } else { |
|
158 |
- value = "OOPS: " |
|
159 |
- } |
|
160 |
- value += fmt.Sprintf("%d passed", r.Succeeded) |
|
161 |
- if r.Skipped != 0 { |
|
162 |
- value += fmt.Sprintf(", %d skipped", r.Skipped) |
|
163 |
- } |
|
164 |
- if r.ExpectedFailures != 0 { |
|
165 |
- value += fmt.Sprintf(", %d expected failures", r.ExpectedFailures) |
|
166 |
- } |
|
167 |
- if r.Failed != 0 { |
|
168 |
- value += fmt.Sprintf(", %d FAILED", r.Failed) |
|
169 |
- } |
|
170 |
- if r.Panicked != 0 { |
|
171 |
- value += fmt.Sprintf(", %d PANICKED", r.Panicked) |
|
172 |
- } |
|
173 |
- if r.FixturePanicked != 0 { |
|
174 |
- value += fmt.Sprintf(", %d FIXTURE-PANICKED", r.FixturePanicked) |
|
175 |
- } |
|
176 |
- if r.Missed != 0 { |
|
177 |
- value += fmt.Sprintf(", %d MISSED", r.Missed) |
|
178 |
- } |
|
179 |
- if r.WorkDir != "" { |
|
180 |
- value += "\nWORK=" + r.WorkDir |
|
181 |
- } |
|
182 |
- return value |
|
183 |
-} |
184 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,191 +0,0 @@ |
1 |
- |
|
2 |
- Apache License |
|
3 |
- Version 2.0, January 2004 |
|
4 |
- https://www.apache.org/licenses/ |
|
5 |
- |
|
6 |
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
7 |
- |
|
8 |
- 1. Definitions. |
|
9 |
- |
|
10 |
- "License" shall mean the terms and conditions for use, reproduction, |
|
11 |
- and distribution as defined by Sections 1 through 9 of this document. |
|
12 |
- |
|
13 |
- "Licensor" shall mean the copyright owner or entity authorized by |
|
14 |
- the copyright owner that is granting the License. |
|
15 |
- |
|
16 |
- "Legal Entity" shall mean the union of the acting entity and all |
|
17 |
- other entities that control, are controlled by, or are under common |
|
18 |
- control with that entity. For the purposes of this definition, |
|
19 |
- "control" means (i) the power, direct or indirect, to cause the |
|
20 |
- direction or management of such entity, whether by contract or |
|
21 |
- otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
22 |
- outstanding shares, or (iii) beneficial ownership of such entity. |
|
23 |
- |
|
24 |
- "You" (or "Your") shall mean an individual or Legal Entity |
|
25 |
- exercising permissions granted by this License. |
|
26 |
- |
|
27 |
- "Source" form shall mean the preferred form for making modifications, |
|
28 |
- including but not limited to software source code, documentation |
|
29 |
- source, and configuration files. |
|
30 |
- |
|
31 |
- "Object" form shall mean any form resulting from mechanical |
|
32 |
- transformation or translation of a Source form, including but |
|
33 |
- not limited to compiled object code, generated documentation, |
|
34 |
- and conversions to other media types. |
|
35 |
- |
|
36 |
- "Work" shall mean the work of authorship, whether in Source or |
|
37 |
- Object form, made available under the License, as indicated by a |
|
38 |
- copyright notice that is included in or attached to the work |
|
39 |
- (an example is provided in the Appendix below). |
|
40 |
- |
|
41 |
- "Derivative Works" shall mean any work, whether in Source or Object |
|
42 |
- form, that is based on (or derived from) the Work and for which the |
|
43 |
- editorial revisions, annotations, elaborations, or other modifications |
|
44 |
- represent, as a whole, an original work of authorship. For the purposes |
|
45 |
- of this License, Derivative Works shall not include works that remain |
|
46 |
- separable from, or merely link (or bind by name) to the interfaces of, |
|
47 |
- the Work and Derivative Works thereof. |
|
48 |
- |
|
49 |
- "Contribution" shall mean any work of authorship, including |
|
50 |
- the original version of the Work and any modifications or additions |
|
51 |
- to that Work or Derivative Works thereof, that is intentionally |
|
52 |
- submitted to Licensor for inclusion in the Work by the copyright owner |
|
53 |
- or by an individual or Legal Entity authorized to submit on behalf of |
|
54 |
- the copyright owner. For the purposes of this definition, "submitted" |
|
55 |
- means any form of electronic, verbal, or written communication sent |
|
56 |
- to the Licensor or its representatives, including but not limited to |
|
57 |
- communication on electronic mailing lists, source code control systems, |
|
58 |
- and issue tracking systems that are managed by, or on behalf of, the |
|
59 |
- Licensor for the purpose of discussing and improving the Work, but |
|
60 |
- excluding communication that is conspicuously marked or otherwise |
|
61 |
- designated in writing by the copyright owner as "Not a Contribution." |
|
62 |
- |
|
63 |
- "Contributor" shall mean Licensor and any individual or Legal Entity |
|
64 |
- on behalf of whom a Contribution has been received by Licensor and |
|
65 |
- subsequently incorporated within the Work. |
|
66 |
- |
|
67 |
- 2. Grant of Copyright License. Subject to the terms and conditions of |
|
68 |
- this License, each Contributor hereby grants to You a perpetual, |
|
69 |
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
70 |
- copyright license to reproduce, prepare Derivative Works of, |
|
71 |
- publicly display, publicly perform, sublicense, and distribute the |
|
72 |
- Work and such Derivative Works in Source or Object form. |
|
73 |
- |
|
74 |
- 3. Grant of Patent License. Subject to the terms and conditions of |
|
75 |
- this License, each Contributor hereby grants to You a perpetual, |
|
76 |
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
77 |
- (except as stated in this section) patent license to make, have made, |
|
78 |
- use, offer to sell, sell, import, and otherwise transfer the Work, |
|
79 |
- where such license applies only to those patent claims licensable |
|
80 |
- by such Contributor that are necessarily infringed by their |
|
81 |
- Contribution(s) alone or by combination of their Contribution(s) |
|
82 |
- with the Work to which such Contribution(s) was submitted. If You |
|
83 |
- institute patent litigation against any entity (including a |
|
84 |
- cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
85 |
- or a Contribution incorporated within the Work constitutes direct |
|
86 |
- or contributory patent infringement, then any patent licenses |
|
87 |
- granted to You under this License for that Work shall terminate |
|
88 |
- as of the date such litigation is filed. |
|
89 |
- |
|
90 |
- 4. Redistribution. You may reproduce and distribute copies of the |
|
91 |
- Work or Derivative Works thereof in any medium, with or without |
|
92 |
- modifications, and in Source or Object form, provided that You |
|
93 |
- meet the following conditions: |
|
94 |
- |
|
95 |
- (a) You must give any other recipients of the Work or |
|
96 |
- Derivative Works a copy of this License; and |
|
97 |
- |
|
98 |
- (b) You must cause any modified files to carry prominent notices |
|
99 |
- stating that You changed the files; and |
|
100 |
- |
|
101 |
- (c) You must retain, in the Source form of any Derivative Works |
|
102 |
- that You distribute, all copyright, patent, trademark, and |
|
103 |
- attribution notices from the Source form of the Work, |
|
104 |
- excluding those notices that do not pertain to any part of |
|
105 |
- the Derivative Works; and |
|
106 |
- |
|
107 |
- (d) If the Work includes a "NOTICE" text file as part of its |
|
108 |
- distribution, then any Derivative Works that You distribute must |
|
109 |
- include a readable copy of the attribution notices contained |
|
110 |
- within such NOTICE file, excluding those notices that do not |
|
111 |
- pertain to any part of the Derivative Works, in at least one |
|
112 |
- of the following places: within a NOTICE text file distributed |
|
113 |
- as part of the Derivative Works; within the Source form or |
|
114 |
- documentation, if provided along with the Derivative Works; or, |
|
115 |
- within a display generated by the Derivative Works, if and |
|
116 |
- wherever such third-party notices normally appear. The contents |
|
117 |
- of the NOTICE file are for informational purposes only and |
|
118 |
- do not modify the License. You may add Your own attribution |
|
119 |
- notices within Derivative Works that You distribute, alongside |
|
120 |
- or as an addendum to the NOTICE text from the Work, provided |
|
121 |
- that such additional attribution notices cannot be construed |
|
122 |
- as modifying the License. |
|
123 |
- |
|
124 |
- You may add Your own copyright statement to Your modifications and |
|
125 |
- may provide additional or different license terms and conditions |
|
126 |
- for use, reproduction, or distribution of Your modifications, or |
|
127 |
- for any such Derivative Works as a whole, provided Your use, |
|
128 |
- reproduction, and distribution of the Work otherwise complies with |
|
129 |
- the conditions stated in this License. |
|
130 |
- |
|
131 |
- 5. Submission of Contributions. Unless You explicitly state otherwise, |
|
132 |
- any Contribution intentionally submitted for inclusion in the Work |
|
133 |
- by You to the Licensor shall be under the terms and conditions of |
|
134 |
- this License, without any additional terms or conditions. |
|
135 |
- Notwithstanding the above, nothing herein shall supersede or modify |
|
136 |
- the terms of any separate license agreement you may have executed |
|
137 |
- with Licensor regarding such Contributions. |
|
138 |
- |
|
139 |
- 6. Trademarks. This License does not grant permission to use the trade |
|
140 |
- names, trademarks, service marks, or product names of the Licensor, |
|
141 |
- except as required for reasonable and customary use in describing the |
|
142 |
- origin of the Work and reproducing the content of the NOTICE file. |
|
143 |
- |
|
144 |
- 7. Disclaimer of Warranty. Unless required by applicable law or |
|
145 |
- agreed to in writing, Licensor provides the Work (and each |
|
146 |
- Contributor provides its Contributions) on an "AS IS" BASIS, |
|
147 |
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
148 |
- implied, including, without limitation, any warranties or conditions |
|
149 |
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
150 |
- PARTICULAR PURPOSE. You are solely responsible for determining the |
|
151 |
- appropriateness of using or redistributing the Work and assume any |
|
152 |
- risks associated with Your exercise of permissions under this License. |
|
153 |
- |
|
154 |
- 8. Limitation of Liability. In no event and under no legal theory, |
|
155 |
- whether in tort (including negligence), contract, or otherwise, |
|
156 |
- unless required by applicable law (such as deliberate and grossly |
|
157 |
- negligent acts) or agreed to in writing, shall any Contributor be |
|
158 |
- liable to You for damages, including any direct, indirect, special, |
|
159 |
- incidental, or consequential damages of any character arising as a |
|
160 |
- result of this License or out of the use or inability to use the |
|
161 |
- Work (including but not limited to damages for loss of goodwill, |
|
162 |
- work stoppage, computer failure or malfunction, or any and all |
|
163 |
- other commercial damages or losses), even if such Contributor |
|
164 |
- has been advised of the possibility of such damages. |
|
165 |
- |
|
166 |
- 9. Accepting Warranty or Additional Liability. While redistributing |
|
167 |
- the Work or Derivative Works thereof, You may choose to offer, |
|
168 |
- and charge a fee for, acceptance of support, warranty, indemnity, |
|
169 |
- or other liability obligations and/or rights consistent with this |
|
170 |
- License. However, in accepting such obligations, You may act only |
|
171 |
- on Your own behalf and on Your sole responsibility, not on behalf |
|
172 |
- of any other Contributor, and only if You agree to indemnify, |
|
173 |
- defend, and hold each Contributor harmless for any liability |
|
174 |
- incurred by, or claims asserted against, such Contributor by reason |
|
175 |
- of your accepting any such warranty or additional liability. |
|
176 |
- |
|
177 |
- END OF TERMS AND CONDITIONS |
|
178 |
- |
|
179 |
- Copyright 2015-2016 Vincent Demeester |
|
180 |
- |
|
181 |
- Licensed under the Apache License, Version 2.0 (the "License"); |
|
182 |
- you may not use this file except in compliance with the License. |
|
183 |
- You may obtain a copy of the License at |
|
184 |
- |
|
185 |
- https://www.apache.org/licenses/LICENSE-2.0 |
|
186 |
- |
|
187 |
- Unless required by applicable law or agreed to in writing, software |
|
188 |
- distributed under the License is distributed on an "AS IS" BASIS, |
|
189 |
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
190 |
- See the License for the specific language governing permissions and |
|
191 |
- limitations under the License. |
192 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,30 +0,0 @@ |
1 |
-# Shakers |
|
2 |
-🐹 + 🐙 = 😽 [![Circle CI](https://circleci.com/gh/vdemeester/shakers.svg?style=svg)](https://circleci.com/gh/vdemeester/shakers) |
|
3 |
- |
|
4 |
-A collection of `go-check` Checkers to ease the use of it. |
|
5 |
- |
|
6 |
-## Building and testing it |
|
7 |
- |
|
8 |
-You need either [docker](https://github.com/docker/docker), or `go` |
|
9 |
-and `glide` in order to build and test shakers. |
|
10 |
- |
|
11 |
-### Using Docker and Makefile |
|
12 |
- |
|
13 |
-You need to run the ``test-unit`` target. |
|
14 |
-```bash |
|
15 |
-$ make test-unit |
|
16 |
-docker build -t "shakers-dev:master" . |
|
17 |
-# […] |
|
18 |
-docker run --rm -it "shakers-dev:master" ./script/make.sh test-unit |
|
19 |
-+ go test -cover -coverprofile=cover.out . |
|
20 |
-ok github.com/vdemeester/shakers 0.015s coverage: 96.0% of statements |
|
21 |
- |
|
22 |
-Test success |
|
23 |
-``` |
|
24 |
- |
|
25 |
-### Using glide and `GO15VENDOREXPERIMENT` |
|
26 |
- |
|
27 |
-- Get the dependencies with `glide up` (or use `go get` but you have no garantuees over the version of the dependencies) |
|
28 |
-- If you're using glide (and not standard `go get`) export `GO15VENDOREXPERIMENT` with `export GO15VENDOREXPERIMENT=1` |
|
29 |
-- Run tests with `go test .` |
30 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,46 +0,0 @@ |
1 |
-package shakers |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "github.com/go-check/check" |
|
5 |
-) |
|
6 |
- |
|
7 |
-// True checker verifies the obtained value is true |
|
8 |
-// |
|
9 |
-// c.Assert(myBool, True) |
|
10 |
-// |
|
11 |
-var True check.Checker = &boolChecker{ |
|
12 |
- &check.CheckerInfo{ |
|
13 |
- Name: "True", |
|
14 |
- Params: []string{"obtained"}, |
|
15 |
- }, |
|
16 |
- true, |
|
17 |
-} |
|
18 |
- |
|
19 |
-// False checker verifies the obtained value is false |
|
20 |
-// |
|
21 |
-// c.Assert(myBool, False) |
|
22 |
-// |
|
23 |
-var False check.Checker = &boolChecker{ |
|
24 |
- &check.CheckerInfo{ |
|
25 |
- Name: "False", |
|
26 |
- Params: []string{"obtained"}, |
|
27 |
- }, |
|
28 |
- false, |
|
29 |
-} |
|
30 |
- |
|
31 |
-type boolChecker struct { |
|
32 |
- *check.CheckerInfo |
|
33 |
- expected bool |
|
34 |
-} |
|
35 |
- |
|
36 |
-func (checker *boolChecker) Check(params []interface{}, names []string) (bool, string) { |
|
37 |
- return is(checker.expected, params[0]) |
|
38 |
-} |
|
39 |
- |
|
40 |
-func is(expected bool, obtained interface{}) (bool, string) { |
|
41 |
- obtainedBool, ok := obtained.(bool) |
|
42 |
- if !ok { |
|
43 |
- return false, "obtained value must be a bool." |
|
44 |
- } |
|
45 |
- return obtainedBool == expected, "" |
|
46 |
-} |
47 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,310 +0,0 @@ |
1 |
-package shakers |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "reflect" |
|
5 |
- "time" |
|
6 |
- |
|
7 |
- "github.com/go-check/check" |
|
8 |
-) |
|
9 |
- |
|
10 |
-// As a commodity, we bring all check.Checker variables into the current namespace to avoid having |
|
11 |
-// to think about check.X versus checker.X. |
|
12 |
-var ( |
|
13 |
- DeepEquals = check.DeepEquals |
|
14 |
- ErrorMatches = check.ErrorMatches |
|
15 |
- FitsTypeOf = check.FitsTypeOf |
|
16 |
- HasLen = check.HasLen |
|
17 |
- Implements = check.Implements |
|
18 |
- IsNil = check.IsNil |
|
19 |
- Matches = check.Matches |
|
20 |
- Not = check.Not |
|
21 |
- NotNil = check.NotNil |
|
22 |
- PanicMatches = check.PanicMatches |
|
23 |
- Panics = check.Panics |
|
24 |
-) |
|
25 |
- |
|
26 |
-// Equaler is an interface implemented if the type has a Equal method. |
|
27 |
-// This is used to compare struct using shakers.Equals. |
|
28 |
-type Equaler interface { |
|
29 |
- Equal(Equaler) bool |
|
30 |
-} |
|
31 |
- |
|
32 |
-// Equals checker verifies the obtained value is equal to the specified one. |
|
33 |
-// It's is smart in a wait that it supports several *types* (built-in, Equaler, |
|
34 |
-// time.Time) |
|
35 |
-// |
|
36 |
-// c.Assert(myStruct, Equals, aStruct, check.Commentf("bouuuhh")) |
|
37 |
-// c.Assert(myTime, Equals, aTime, check.Commentf("bouuuhh")) |
|
38 |
-// |
|
39 |
-var Equals check.Checker = &equalChecker{ |
|
40 |
- &check.CheckerInfo{ |
|
41 |
- Name: "Equals", |
|
42 |
- Params: []string{"obtained", "expected"}, |
|
43 |
- }, |
|
44 |
-} |
|
45 |
- |
|
46 |
-type equalChecker struct { |
|
47 |
- *check.CheckerInfo |
|
48 |
-} |
|
49 |
- |
|
50 |
-func (checker *equalChecker) Check(params []interface{}, names []string) (bool, string) { |
|
51 |
- return isEqual(params[0], params[1]) |
|
52 |
-} |
|
53 |
- |
|
54 |
-func isEqual(obtained, expected interface{}) (bool, string) { |
|
55 |
- switch obtained.(type) { |
|
56 |
- case time.Time: |
|
57 |
- return timeEquals(obtained, expected) |
|
58 |
- case Equaler: |
|
59 |
- return equalerEquals(obtained, expected) |
|
60 |
- default: |
|
61 |
- if reflect.TypeOf(obtained) != reflect.TypeOf(expected) { |
|
62 |
- return false, "obtained value and expected value have not the same type." |
|
63 |
- } |
|
64 |
- return obtained == expected, "" |
|
65 |
- } |
|
66 |
-} |
|
67 |
- |
|
68 |
-func equalerEquals(obtained, expected interface{}) (bool, string) { |
|
69 |
- expectedEqualer, ok := expected.(Equaler) |
|
70 |
- if !ok { |
|
71 |
- return false, "expected value must be an Equaler - implementing Equal(Equaler)." |
|
72 |
- } |
|
73 |
- obtainedEqualer, ok := obtained.(Equaler) |
|
74 |
- if !ok { |
|
75 |
- return false, "obtained value must be an Equaler - implementing Equal(Equaler)." |
|
76 |
- } |
|
77 |
- return obtainedEqualer.Equal(expectedEqualer), "" |
|
78 |
-} |
|
79 |
- |
|
80 |
-// GreaterThan checker verifies the obtained value is greater than the specified one. |
|
81 |
-// It's is smart in a wait that it supports several *types* (built-in, time.Time) |
|
82 |
-// |
|
83 |
-// c.Assert(myTime, GreaterThan, aTime, check.Commentf("bouuuhh")) |
|
84 |
-// c.Assert(myInt, GreaterThan, 2, check.Commentf("bouuuhh")) |
|
85 |
-// |
|
86 |
-var GreaterThan check.Checker = &greaterThanChecker{ |
|
87 |
- &check.CheckerInfo{ |
|
88 |
- Name: "GreaterThan", |
|
89 |
- Params: []string{"obtained", "expected"}, |
|
90 |
- }, |
|
91 |
-} |
|
92 |
- |
|
93 |
-type greaterThanChecker struct { |
|
94 |
- *check.CheckerInfo |
|
95 |
-} |
|
96 |
- |
|
97 |
-func (checker *greaterThanChecker) Check(params []interface{}, names []string) (bool, string) { |
|
98 |
- return greaterThan(params[0], params[1]) |
|
99 |
-} |
|
100 |
- |
|
101 |
-func greaterThan(obtained, expected interface{}) (bool, string) { |
|
102 |
- if _, ok := obtained.(time.Time); ok { |
|
103 |
- return isAfter(obtained, expected) |
|
104 |
- } |
|
105 |
- if reflect.TypeOf(obtained) != reflect.TypeOf(expected) { |
|
106 |
- return false, "obtained value and expected value have not the same type." |
|
107 |
- } |
|
108 |
- switch v := obtained.(type) { |
|
109 |
- case float32: |
|
110 |
- return v > expected.(float32), "" |
|
111 |
- case float64: |
|
112 |
- return v > expected.(float64), "" |
|
113 |
- case int: |
|
114 |
- return v > expected.(int), "" |
|
115 |
- case int8: |
|
116 |
- return v > expected.(int8), "" |
|
117 |
- case int16: |
|
118 |
- return v > expected.(int16), "" |
|
119 |
- case int32: |
|
120 |
- return v > expected.(int32), "" |
|
121 |
- case int64: |
|
122 |
- return v > expected.(int64), "" |
|
123 |
- case uint: |
|
124 |
- return v > expected.(uint), "" |
|
125 |
- case uint8: |
|
126 |
- return v > expected.(uint8), "" |
|
127 |
- case uint16: |
|
128 |
- return v > expected.(uint16), "" |
|
129 |
- case uint32: |
|
130 |
- return v > expected.(uint32), "" |
|
131 |
- case uint64: |
|
132 |
- return v > expected.(uint64), "" |
|
133 |
- default: |
|
134 |
- return false, "obtained value type not supported." |
|
135 |
- } |
|
136 |
-} |
|
137 |
- |
|
138 |
-// GreaterOrEqualThan checker verifies the obtained value is greater or equal than the specified one. |
|
139 |
-// It's is smart in a wait that it supports several *types* (built-in, time.Time) |
|
140 |
-// |
|
141 |
-// c.Assert(myTime, GreaterOrEqualThan, aTime, check.Commentf("bouuuhh")) |
|
142 |
-// c.Assert(myInt, GreaterOrEqualThan, 2, check.Commentf("bouuuhh")) |
|
143 |
-// |
|
144 |
-var GreaterOrEqualThan check.Checker = &greaterOrEqualThanChecker{ |
|
145 |
- &check.CheckerInfo{ |
|
146 |
- Name: "GreaterOrEqualThan", |
|
147 |
- Params: []string{"obtained", "expected"}, |
|
148 |
- }, |
|
149 |
-} |
|
150 |
- |
|
151 |
-type greaterOrEqualThanChecker struct { |
|
152 |
- *check.CheckerInfo |
|
153 |
-} |
|
154 |
- |
|
155 |
-func (checker *greaterOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) { |
|
156 |
- return greaterOrEqualThan(params[0], params[1]) |
|
157 |
-} |
|
158 |
- |
|
159 |
-func greaterOrEqualThan(obtained, expected interface{}) (bool, string) { |
|
160 |
- if _, ok := obtained.(time.Time); ok { |
|
161 |
- return isAfter(obtained, expected) |
|
162 |
- } |
|
163 |
- if reflect.TypeOf(obtained) != reflect.TypeOf(expected) { |
|
164 |
- return false, "obtained value and expected value have not the same type." |
|
165 |
- } |
|
166 |
- switch v := obtained.(type) { |
|
167 |
- case float32: |
|
168 |
- return v >= expected.(float32), "" |
|
169 |
- case float64: |
|
170 |
- return v >= expected.(float64), "" |
|
171 |
- case int: |
|
172 |
- return v >= expected.(int), "" |
|
173 |
- case int8: |
|
174 |
- return v >= expected.(int8), "" |
|
175 |
- case int16: |
|
176 |
- return v >= expected.(int16), "" |
|
177 |
- case int32: |
|
178 |
- return v >= expected.(int32), "" |
|
179 |
- case int64: |
|
180 |
- return v >= expected.(int64), "" |
|
181 |
- case uint: |
|
182 |
- return v >= expected.(uint), "" |
|
183 |
- case uint8: |
|
184 |
- return v >= expected.(uint8), "" |
|
185 |
- case uint16: |
|
186 |
- return v >= expected.(uint16), "" |
|
187 |
- case uint32: |
|
188 |
- return v >= expected.(uint32), "" |
|
189 |
- case uint64: |
|
190 |
- return v >= expected.(uint64), "" |
|
191 |
- default: |
|
192 |
- return false, "obtained value type not supported." |
|
193 |
- } |
|
194 |
-} |
|
195 |
- |
|
196 |
-// LessThan checker verifies the obtained value is less than the specified one. |
|
197 |
-// It's is smart in a wait that it supports several *types* (built-in, time.Time) |
|
198 |
-// |
|
199 |
-// c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh")) |
|
200 |
-// c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh")) |
|
201 |
-// |
|
202 |
-var LessThan check.Checker = &lessThanChecker{ |
|
203 |
- &check.CheckerInfo{ |
|
204 |
- Name: "LessThan", |
|
205 |
- Params: []string{"obtained", "expected"}, |
|
206 |
- }, |
|
207 |
-} |
|
208 |
- |
|
209 |
-type lessThanChecker struct { |
|
210 |
- *check.CheckerInfo |
|
211 |
-} |
|
212 |
- |
|
213 |
-func (checker *lessThanChecker) Check(params []interface{}, names []string) (bool, string) { |
|
214 |
- return lessThan(params[0], params[1]) |
|
215 |
-} |
|
216 |
- |
|
217 |
-func lessThan(obtained, expected interface{}) (bool, string) { |
|
218 |
- if _, ok := obtained.(time.Time); ok { |
|
219 |
- return isBefore(obtained, expected) |
|
220 |
- } |
|
221 |
- if reflect.TypeOf(obtained) != reflect.TypeOf(expected) { |
|
222 |
- return false, "obtained value and expected value have not the same type." |
|
223 |
- } |
|
224 |
- switch v := obtained.(type) { |
|
225 |
- case float32: |
|
226 |
- return v < expected.(float32), "" |
|
227 |
- case float64: |
|
228 |
- return v < expected.(float64), "" |
|
229 |
- case int: |
|
230 |
- return v < expected.(int), "" |
|
231 |
- case int8: |
|
232 |
- return v < expected.(int8), "" |
|
233 |
- case int16: |
|
234 |
- return v < expected.(int16), "" |
|
235 |
- case int32: |
|
236 |
- return v < expected.(int32), "" |
|
237 |
- case int64: |
|
238 |
- return v < expected.(int64), "" |
|
239 |
- case uint: |
|
240 |
- return v < expected.(uint), "" |
|
241 |
- case uint8: |
|
242 |
- return v < expected.(uint8), "" |
|
243 |
- case uint16: |
|
244 |
- return v < expected.(uint16), "" |
|
245 |
- case uint32: |
|
246 |
- return v < expected.(uint32), "" |
|
247 |
- case uint64: |
|
248 |
- return v < expected.(uint64), "" |
|
249 |
- default: |
|
250 |
- return false, "obtained value type not supported." |
|
251 |
- } |
|
252 |
-} |
|
253 |
- |
|
254 |
-// LessOrEqualThan checker verifies the obtained value is less or equal than the specified one. |
|
255 |
-// It's is smart in a wait that it supports several *types* (built-in, time.Time) |
|
256 |
-// |
|
257 |
-// c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh")) |
|
258 |
-// c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh")) |
|
259 |
-// |
|
260 |
-var LessOrEqualThan check.Checker = &lessOrEqualThanChecker{ |
|
261 |
- &check.CheckerInfo{ |
|
262 |
- Name: "LessOrEqualThan", |
|
263 |
- Params: []string{"obtained", "expected"}, |
|
264 |
- }, |
|
265 |
-} |
|
266 |
- |
|
267 |
-type lessOrEqualThanChecker struct { |
|
268 |
- *check.CheckerInfo |
|
269 |
-} |
|
270 |
- |
|
271 |
-func (checker *lessOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) { |
|
272 |
- return lessOrEqualThan(params[0], params[1]) |
|
273 |
-} |
|
274 |
- |
|
275 |
-func lessOrEqualThan(obtained, expected interface{}) (bool, string) { |
|
276 |
- if _, ok := obtained.(time.Time); ok { |
|
277 |
- return isBefore(obtained, expected) |
|
278 |
- } |
|
279 |
- if reflect.TypeOf(obtained) != reflect.TypeOf(expected) { |
|
280 |
- return false, "obtained value and expected value have not the same type." |
|
281 |
- } |
|
282 |
- switch v := obtained.(type) { |
|
283 |
- case float32: |
|
284 |
- return v <= expected.(float32), "" |
|
285 |
- case float64: |
|
286 |
- return v <= expected.(float64), "" |
|
287 |
- case int: |
|
288 |
- return v <= expected.(int), "" |
|
289 |
- case int8: |
|
290 |
- return v <= expected.(int8), "" |
|
291 |
- case int16: |
|
292 |
- return v <= expected.(int16), "" |
|
293 |
- case int32: |
|
294 |
- return v <= expected.(int32), "" |
|
295 |
- case int64: |
|
296 |
- return v <= expected.(int64), "" |
|
297 |
- case uint: |
|
298 |
- return v <= expected.(uint), "" |
|
299 |
- case uint8: |
|
300 |
- return v <= expected.(uint8), "" |
|
301 |
- case uint16: |
|
302 |
- return v <= expected.(uint16), "" |
|
303 |
- case uint32: |
|
304 |
- return v <= expected.(uint32), "" |
|
305 |
- case uint64: |
|
306 |
- return v <= expected.(uint64), "" |
|
307 |
- default: |
|
308 |
- return false, "obtained value type not supported." |
|
309 |
- } |
|
310 |
-} |
311 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,168 +0,0 @@ |
1 |
-// Package shakers provide some checker implementation the go-check.Checker interface. |
|
2 |
-package shakers |
|
3 |
- |
|
4 |
-import ( |
|
5 |
- "fmt" |
|
6 |
- "strings" |
|
7 |
- |
|
8 |
- "github.com/go-check/check" |
|
9 |
-) |
|
10 |
- |
|
11 |
-// Contains checker verifies that obtained value contains a substring. |
|
12 |
-var Contains check.Checker = &substringChecker{ |
|
13 |
- &check.CheckerInfo{ |
|
14 |
- Name: "Contains", |
|
15 |
- Params: []string{"obtained", "substring"}, |
|
16 |
- }, |
|
17 |
- strings.Contains, |
|
18 |
-} |
|
19 |
- |
|
20 |
-// ContainsAny checker verifies that any Unicode code points in chars |
|
21 |
-// are in the obtained string. |
|
22 |
-var ContainsAny check.Checker = &substringChecker{ |
|
23 |
- &check.CheckerInfo{ |
|
24 |
- Name: "ContainsAny", |
|
25 |
- Params: []string{"obtained", "chars"}, |
|
26 |
- }, |
|
27 |
- strings.ContainsAny, |
|
28 |
-} |
|
29 |
- |
|
30 |
-// HasPrefix checker verifies that obtained value has the specified substring as prefix |
|
31 |
-var HasPrefix check.Checker = &substringChecker{ |
|
32 |
- &check.CheckerInfo{ |
|
33 |
- Name: "HasPrefix", |
|
34 |
- Params: []string{"obtained", "prefix"}, |
|
35 |
- }, |
|
36 |
- strings.HasPrefix, |
|
37 |
-} |
|
38 |
- |
|
39 |
-// HasSuffix checker verifies that obtained value has the specified substring as prefix |
|
40 |
-var HasSuffix check.Checker = &substringChecker{ |
|
41 |
- &check.CheckerInfo{ |
|
42 |
- Name: "HasSuffix", |
|
43 |
- Params: []string{"obtained", "suffix"}, |
|
44 |
- }, |
|
45 |
- strings.HasSuffix, |
|
46 |
-} |
|
47 |
- |
|
48 |
-// EqualFold checker verifies that obtained value is, interpreted as UTF-8 strings, are equal under Unicode case-folding. |
|
49 |
-var EqualFold check.Checker = &substringChecker{ |
|
50 |
- &check.CheckerInfo{ |
|
51 |
- Name: "EqualFold", |
|
52 |
- Params: []string{"obtained", "expected"}, |
|
53 |
- }, |
|
54 |
- strings.EqualFold, |
|
55 |
-} |
|
56 |
- |
|
57 |
-type substringChecker struct { |
|
58 |
- *check.CheckerInfo |
|
59 |
- substringFunction func(string, string) bool |
|
60 |
-} |
|
61 |
- |
|
62 |
-func (checker *substringChecker) Check(params []interface{}, names []string) (bool, string) { |
|
63 |
- obtained := params[0] |
|
64 |
- substring := params[1] |
|
65 |
- substringStr, ok := substring.(string) |
|
66 |
- if !ok { |
|
67 |
- return false, fmt.Sprintf("%s value must be a string.", names[1]) |
|
68 |
- } |
|
69 |
- obtainedString, obtainedIsStr := obtained.(string) |
|
70 |
- if !obtainedIsStr { |
|
71 |
- if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer { |
|
72 |
- obtainedString, obtainedIsStr = obtainedWithStringer.String(), true |
|
73 |
- } |
|
74 |
- } |
|
75 |
- if obtainedIsStr { |
|
76 |
- return checker.substringFunction(obtainedString, substringStr), "" |
|
77 |
- } |
|
78 |
- return false, "obtained value is not a string and has no .String()." |
|
79 |
-} |
|
80 |
- |
|
81 |
-// IndexAny checker verifies that the index of the first instance of any Unicode code point from chars in the obtained value is equal to expected |
|
82 |
-var IndexAny check.Checker = &substringCountChecker{ |
|
83 |
- &check.CheckerInfo{ |
|
84 |
- Name: "IndexAny", |
|
85 |
- Params: []string{"obtained", "chars", "expected"}, |
|
86 |
- }, |
|
87 |
- strings.IndexAny, |
|
88 |
-} |
|
89 |
- |
|
90 |
-// Index checker verifies that the index of the first instance of sep in the obtained value is equal to expected |
|
91 |
-var Index check.Checker = &substringCountChecker{ |
|
92 |
- &check.CheckerInfo{ |
|
93 |
- Name: "Index", |
|
94 |
- Params: []string{"obtained", "sep", "expected"}, |
|
95 |
- }, |
|
96 |
- strings.Index, |
|
97 |
-} |
|
98 |
- |
|
99 |
-// Count checker verifies that obtained value has the specified number of non-overlapping instances of sep |
|
100 |
-var Count check.Checker = &substringCountChecker{ |
|
101 |
- &check.CheckerInfo{ |
|
102 |
- Name: "Count", |
|
103 |
- Params: []string{"obtained", "sep", "expected"}, |
|
104 |
- }, |
|
105 |
- strings.Count, |
|
106 |
-} |
|
107 |
- |
|
108 |
-type substringCountChecker struct { |
|
109 |
- *check.CheckerInfo |
|
110 |
- substringFunction func(string, string) int |
|
111 |
-} |
|
112 |
- |
|
113 |
-func (checker *substringCountChecker) Check(params []interface{}, names []string) (bool, string) { |
|
114 |
- obtained := params[0] |
|
115 |
- substring := params[1] |
|
116 |
- expected := params[2] |
|
117 |
- substringStr, ok := substring.(string) |
|
118 |
- if !ok { |
|
119 |
- return false, fmt.Sprintf("%s value must be a string.", names[1]) |
|
120 |
- } |
|
121 |
- obtainedString, obtainedIsStr := obtained.(string) |
|
122 |
- if !obtainedIsStr { |
|
123 |
- if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer { |
|
124 |
- obtainedString, obtainedIsStr = obtainedWithStringer.String(), true |
|
125 |
- } |
|
126 |
- } |
|
127 |
- if obtainedIsStr { |
|
128 |
- return checker.substringFunction(obtainedString, substringStr) == expected, "" |
|
129 |
- } |
|
130 |
- return false, "obtained value is not a string and has no .String()." |
|
131 |
-} |
|
132 |
- |
|
133 |
-// IsLower checker verifies that the obtained value is in lower case |
|
134 |
-var IsLower check.Checker = &stringTransformChecker{ |
|
135 |
- &check.CheckerInfo{ |
|
136 |
- Name: "IsLower", |
|
137 |
- Params: []string{"obtained"}, |
|
138 |
- }, |
|
139 |
- strings.ToLower, |
|
140 |
-} |
|
141 |
- |
|
142 |
-// IsUpper checker verifies that the obtained value is in lower case |
|
143 |
-var IsUpper check.Checker = &stringTransformChecker{ |
|
144 |
- &check.CheckerInfo{ |
|
145 |
- Name: "IsUpper", |
|
146 |
- Params: []string{"obtained"}, |
|
147 |
- }, |
|
148 |
- strings.ToUpper, |
|
149 |
-} |
|
150 |
- |
|
151 |
-type stringTransformChecker struct { |
|
152 |
- *check.CheckerInfo |
|
153 |
- stringFunction func(string) string |
|
154 |
-} |
|
155 |
- |
|
156 |
-func (checker *stringTransformChecker) Check(params []interface{}, names []string) (bool, string) { |
|
157 |
- obtained := params[0] |
|
158 |
- obtainedString, obtainedIsStr := obtained.(string) |
|
159 |
- if !obtainedIsStr { |
|
160 |
- if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer { |
|
161 |
- obtainedString, obtainedIsStr = obtainedWithStringer.String(), true |
|
162 |
- } |
|
163 |
- } |
|
164 |
- if obtainedIsStr { |
|
165 |
- return checker.stringFunction(obtainedString) == obtainedString, "" |
|
166 |
- } |
|
167 |
- return false, "obtained value is not a string and has no .String()." |
|
168 |
-} |
169 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,234 +0,0 @@ |
1 |
-package shakers |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "time" |
|
6 |
- |
|
7 |
- "github.com/go-check/check" |
|
8 |
-) |
|
9 |
- |
|
10 |
-// Default format when parsing (in addition to RFC and default time formats..) |
|
11 |
-const shortForm = "2006-01-02" |
|
12 |
- |
|
13 |
-// IsBefore checker verifies the specified value is before the specified time. |
|
14 |
-// It is exclusive. |
|
15 |
-// |
|
16 |
-// c.Assert(myTime, IsBefore, theTime, check.Commentf("bouuuhhh")) |
|
17 |
-// |
|
18 |
-var IsBefore check.Checker = &isBeforeChecker{ |
|
19 |
- &check.CheckerInfo{ |
|
20 |
- Name: "IsBefore", |
|
21 |
- Params: []string{"obtained", "expected"}, |
|
22 |
- }, |
|
23 |
-} |
|
24 |
- |
|
25 |
-type isBeforeChecker struct { |
|
26 |
- *check.CheckerInfo |
|
27 |
-} |
|
28 |
- |
|
29 |
-func (checker *isBeforeChecker) Check(params []interface{}, names []string) (bool, string) { |
|
30 |
- return isBefore(params[0], params[1]) |
|
31 |
-} |
|
32 |
- |
|
33 |
-func isBefore(value, t interface{}) (bool, string) { |
|
34 |
- tTime, ok := parseTime(t) |
|
35 |
- if !ok { |
|
36 |
- return false, "expected must be a Time struct, or parseable." |
|
37 |
- } |
|
38 |
- valueTime, valueIsTime := parseTime(value) |
|
39 |
- if valueIsTime { |
|
40 |
- return valueTime.Before(tTime), "" |
|
41 |
- } |
|
42 |
- return false, "obtained value is not a time.Time struct or parseable as a time." |
|
43 |
-} |
|
44 |
- |
|
45 |
-// IsAfter checker verifies the specified value is before the specified time. |
|
46 |
-// It is exclusive. |
|
47 |
-// |
|
48 |
-// c.Assert(myTime, IsAfter, theTime, check.Commentf("bouuuhhh")) |
|
49 |
-// |
|
50 |
-var IsAfter check.Checker = &isAfterChecker{ |
|
51 |
- &check.CheckerInfo{ |
|
52 |
- Name: "IsAfter", |
|
53 |
- Params: []string{"obtained", "expected"}, |
|
54 |
- }, |
|
55 |
-} |
|
56 |
- |
|
57 |
-type isAfterChecker struct { |
|
58 |
- *check.CheckerInfo |
|
59 |
-} |
|
60 |
- |
|
61 |
-func (checker *isAfterChecker) Check(params []interface{}, names []string) (bool, string) { |
|
62 |
- return isAfter(params[0], params[1]) |
|
63 |
-} |
|
64 |
- |
|
65 |
-func isAfter(value, t interface{}) (bool, string) { |
|
66 |
- tTime, ok := parseTime(t) |
|
67 |
- if !ok { |
|
68 |
- return false, "expected must be a Time struct, or parseable." |
|
69 |
- } |
|
70 |
- valueTime, valueIsTime := parseTime(value) |
|
71 |
- if valueIsTime { |
|
72 |
- return valueTime.After(tTime), "" |
|
73 |
- } |
|
74 |
- return false, "obtained value is not a time.Time struct or parseable as a time." |
|
75 |
-} |
|
76 |
- |
|
77 |
-// IsBetween checker verifies the specified time is between the specified start |
|
78 |
-// and end. It's exclusive so if the specified time is at the tip of the interval. |
|
79 |
-// |
|
80 |
-// c.Assert(myTime, IsBetween, startTime, endTime, check.Commentf("bouuuhhh")) |
|
81 |
-// |
|
82 |
-var IsBetween check.Checker = &isBetweenChecker{ |
|
83 |
- &check.CheckerInfo{ |
|
84 |
- Name: "IsBetween", |
|
85 |
- Params: []string{"obtained", "start", "end"}, |
|
86 |
- }, |
|
87 |
-} |
|
88 |
- |
|
89 |
-type isBetweenChecker struct { |
|
90 |
- *check.CheckerInfo |
|
91 |
-} |
|
92 |
- |
|
93 |
-func (checker *isBetweenChecker) Check(params []interface{}, names []string) (bool, string) { |
|
94 |
- return isBetween(params[0], params[1], params[2]) |
|
95 |
-} |
|
96 |
- |
|
97 |
-func isBetween(value, start, end interface{}) (bool, string) { |
|
98 |
- startTime, ok := parseTime(start) |
|
99 |
- if !ok { |
|
100 |
- return false, "start must be a Time struct, or parseable." |
|
101 |
- } |
|
102 |
- endTime, ok := parseTime(end) |
|
103 |
- if !ok { |
|
104 |
- return false, "end must be a Time struct, or parseable." |
|
105 |
- } |
|
106 |
- valueTime, valueIsTime := parseTime(value) |
|
107 |
- if valueIsTime { |
|
108 |
- return valueTime.After(startTime) && valueTime.Before(endTime), "" |
|
109 |
- } |
|
110 |
- return false, "obtained value is not a time.Time struct or parseable as a time." |
|
111 |
-} |
|
112 |
- |
|
113 |
-// TimeEquals checker verifies the specified time is the equal to the expected |
|
114 |
-// time. |
|
115 |
-// |
|
116 |
-// c.Assert(myTime, TimeEquals, expected, check.Commentf("bouhhh")) |
|
117 |
-// |
|
118 |
-// It's possible to ignore some part of the time (like hours, minutes, etc..) using |
|
119 |
-// the TimeIgnore checker with it. |
|
120 |
-// |
|
121 |
-// c.Assert(myTime, TimeIgnore(TimeEquals, time.Hour), expected, check.Commentf("... bouh..")) |
|
122 |
-// |
|
123 |
-var TimeEquals check.Checker = &timeEqualsChecker{ |
|
124 |
- &check.CheckerInfo{ |
|
125 |
- Name: "TimeEquals", |
|
126 |
- Params: []string{"obtained", "expected"}, |
|
127 |
- }, |
|
128 |
-} |
|
129 |
- |
|
130 |
-type timeEqualsChecker struct { |
|
131 |
- *check.CheckerInfo |
|
132 |
-} |
|
133 |
- |
|
134 |
-func (checker *timeEqualsChecker) Check(params []interface{}, names []string) (bool, string) { |
|
135 |
- return timeEquals(params[0], params[1]) |
|
136 |
-} |
|
137 |
- |
|
138 |
-func timeEquals(obtained, expected interface{}) (bool, string) { |
|
139 |
- expectedTime, ok := parseTime(expected) |
|
140 |
- if !ok { |
|
141 |
- return false, "expected must be a Time struct, or parseable." |
|
142 |
- } |
|
143 |
- valueTime, valueIsTime := parseTime(obtained) |
|
144 |
- if valueIsTime { |
|
145 |
- return valueTime.Equal(expectedTime), "" |
|
146 |
- } |
|
147 |
- return false, "obtained value is not a time.Time struct or parseable as a time." |
|
148 |
-} |
|
149 |
- |
|
150 |
-// TimeIgnore checker will ignore some part of the time on the encapsulated checker. |
|
151 |
-// |
|
152 |
-// c.Assert(myTime, TimeIgnore(IsBetween, time.Second), start, end) |
|
153 |
-// |
|
154 |
-// FIXME use interface{} for ignore (to enable "Month", .. |
|
155 |
-func TimeIgnore(checker check.Checker, ignore time.Duration) check.Checker { |
|
156 |
- return &timeIgnoreChecker{ |
|
157 |
- sub: checker, |
|
158 |
- ignore: ignore, |
|
159 |
- } |
|
160 |
-} |
|
161 |
- |
|
162 |
-type timeIgnoreChecker struct { |
|
163 |
- sub check.Checker |
|
164 |
- ignore time.Duration |
|
165 |
-} |
|
166 |
- |
|
167 |
-func (checker *timeIgnoreChecker) Info() *check.CheckerInfo { |
|
168 |
- info := *checker.sub.Info() |
|
169 |
- info.Name = fmt.Sprintf("TimeIgnore(%s, %v)", info.Name, checker.ignore) |
|
170 |
- return &info |
|
171 |
-} |
|
172 |
- |
|
173 |
-func (checker *timeIgnoreChecker) Check(params []interface{}, names []string) (bool, string) { |
|
174 |
- // Naive implementation : all params are supposed to be date |
|
175 |
- mParams := make([]interface{}, len(params)) |
|
176 |
- for index, param := range params { |
|
177 |
- paramTime, ok := parseTime(param) |
|
178 |
- if !ok { |
|
179 |
- return false, fmt.Sprintf("%s must be a Time struct, or parseable.", names[index]) |
|
180 |
- } |
|
181 |
- year := paramTime.Year() |
|
182 |
- month := paramTime.Month() |
|
183 |
- day := paramTime.Day() |
|
184 |
- hour := paramTime.Hour() |
|
185 |
- min := paramTime.Minute() |
|
186 |
- sec := paramTime.Second() |
|
187 |
- nsec := paramTime.Nanosecond() |
|
188 |
- location := paramTime.Location() |
|
189 |
- switch checker.ignore { |
|
190 |
- case time.Hour: |
|
191 |
- hour = 0 |
|
192 |
- fallthrough |
|
193 |
- case time.Minute: |
|
194 |
- min = 0 |
|
195 |
- fallthrough |
|
196 |
- case time.Second: |
|
197 |
- sec = 0 |
|
198 |
- fallthrough |
|
199 |
- case time.Millisecond: |
|
200 |
- fallthrough |
|
201 |
- case time.Microsecond: |
|
202 |
- fallthrough |
|
203 |
- case time.Nanosecond: |
|
204 |
- nsec = 0 |
|
205 |
- } |
|
206 |
- mParams[index] = time.Date(year, month, day, hour, min, sec, nsec, location) |
|
207 |
- } |
|
208 |
- return checker.sub.Check(mParams, names) |
|
209 |
-} |
|
210 |
- |
|
211 |
-func parseTime(datetime interface{}) (time.Time, bool) { |
|
212 |
- switch datetime.(type) { |
|
213 |
- case time.Time: |
|
214 |
- return datetime.(time.Time), true |
|
215 |
- case string: |
|
216 |
- return parseTimeAsString(datetime.(string)) |
|
217 |
- default: |
|
218 |
- if datetimeWithStr, ok := datetime.(fmt.Stringer); ok { |
|
219 |
- return parseTimeAsString(datetimeWithStr.String()) |
|
220 |
- } |
|
221 |
- return time.Time{}, false |
|
222 |
- } |
|
223 |
-} |
|
224 |
- |
|
225 |
-func parseTimeAsString(timeAsStr string) (time.Time, bool) { |
|
226 |
- forms := []string{shortForm, time.RFC3339, time.RFC3339Nano, time.RFC822, time.RFC822Z} |
|
227 |
- for _, form := range forms { |
|
228 |
- datetime, err := time.Parse(form, timeAsStr) |
|
229 |
- if err == nil { |
|
230 |
- return datetime, true |
|
231 |
- } |
|
232 |
- } |
|
233 |
- return time.Time{}, false |
|
234 |
-} |