re-vendor

This commit is contained in:
Zack Scholl 2018-06-25 11:59:56 -07:00
parent 181de46313
commit 3e5aa91f34
1595 changed files with 831353 additions and 856 deletions

68
Gopkg.lock generated
View File

@ -1,18 +1,18 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/Nightbug/go-base65536"
packages = ["."]
revision = "ba82e75856c3f7d4db92c6d98246cb4f7e9c1da8"
version = "1.0.0"
[[projects]]
name = "github.com/cihub/seelog"
packages = ["."]
revision = "d2c6e5aa9fbfdd1c624e140287063c7730654115"
version = "v2.6"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/dustin/go-humanize"
@ -49,6 +49,12 @@
packages = ["."]
revision = "8631ce90f28644f54aeedcb3e389a85174e067d1"
[[projects]]
branch = "master"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
[[projects]]
branch = "master"
name = "github.com/mr-tron/base58"
@ -62,10 +68,10 @@
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/schollz/messagebox"
packages = ["keypair"]
revision = "8bb214da539adf4b51b2c4ed0456e771d032d8eb"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/schollz/mnemonicode"
@ -83,7 +89,7 @@
branch = "master"
name = "github.com/schollz/progressbar"
packages = ["."]
revision = "cd5f4bc33956d41669a8920edb38a0f41abde270"
revision = "2283967e9a5af7a9eaddaaacb9f569314977fd03"
[[projects]]
branch = "master"
@ -97,6 +103,12 @@
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert"]
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
name = "github.com/urfave/cli"
packages = ["."]
@ -112,48 +124,26 @@
[[projects]]
branch = "master"
name = "github.com/yudai/hcl"
packages = [
".",
"hcl",
"json"
]
packages = [".","hcl","json"]
revision = "5fa2393b3552119bf33a69adb1402a1160cba23d"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"curve25519",
"internal/subtle",
"nacl/box",
"nacl/secretbox",
"pbkdf2",
"poly1305",
"salsa20/salsa",
"scrypt",
"ssh/terminal"
]
packages = ["curve25519","internal/subtle","nacl/box","nacl/secretbox","pbkdf2","poly1305","salsa20/salsa","scrypt","ssh/terminal"]
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"bpf",
"internal/iana",
"internal/socket",
"ipv4"
]
packages = ["bpf","internal/iana","internal/socket","ipv4"]
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "63fc586f45fe72d95d5240a5d5eb95e6503907d3"
packages = ["unix","windows"]
revision = "a200a19cb90b19de298170992778b1fda7217bd6"
[[projects]]
name = "golang.org/x/text"
@ -170,6 +160,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "61c77dae1b7a75c24ba182fc04218815b058280c4a96d39a8b16d3a851ecbbc6"
inputs-digest = "4bd860ee5e9b724cdb078b452e0b187c03bb5cf71588b09d224bef4d8d87be30"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -45,10 +45,6 @@
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "github.com/schollz/messagebox"
[[constraint]]
name = "github.com/schollz/mnemonicode"
version = "1.0.0"

View File

@ -1,43 +0,0 @@
# go-base65536 [![GoDoc](https://godoc.org/github.com/Nightbug/go-base65536?status.svg)](https://godoc.org/github.com/Nightbug/go-base65536)
Go library for encoding data into [base65536](https://github.com/ferno/base65536).
## Examples
Marshaling
```go
package main
import (
"fmt"
"github.com/Nightbug/go-base65536"
)
func main() {
fmt.Println(base65536.Marshal([]byte("hello world")))
}
```
Unmarshaling
```go
package main
import (
"fmt"
"github.com/Nightbug/go-base65536"
)
func main() {
var out []byte
err := base65536.Marshal([]byte("驨ꍬ啯𒁷ꍲᕤ"), &out)
if err != nil {
panic(err)
}
}
```
## License
MIT

View File

@ -1,56 +0,0 @@
package base65536
import (
"errors"
)
const noByte = -1
// Marshal returns the base65536 encoded version of data.
func Marshal(data []byte) string {
var res string
var b1 int16
var b2 int16
for i := 0; i < len(data); i += 2 {
b1 = int16(data[i])
if i+1 < len(data) {
b2 = int16(data[i+1])
} else {
b2 = noByte
}
res += string(getBlockStart[b2] + int(b1))
}
return res
}
// Unmarshal appends to out the bytes decoded from data. It can return an error,
// in case the decoding failed.
func Unmarshal(data []byte, out *[]byte) error {
done := false
var b1 int16
var b2 int16
var exists bool
var bytesAppend []byte
// We are converting data to a string, because runes
for _, r := range string(data) {
b1 = int16(r) & ((1 << 8) - 1)
b2, exists = getB2[int(r)-int(b1)]
if !exists {
return errors.New("not a valid base65536 code point: " + string(int(r)))
}
bytesAppend = []byte{
byte(b1),
}
if b2 != noByte {
bytesAppend = append(bytesAppend, byte(b2))
}
if len(bytesAppend) == 1 {
if done {
return errors.New("base65536 sequence continued after final byte")
}
done = true
}
*out = append(*out, bytesAppend...)
}
return nil
}

View File

@ -1,261 +0,0 @@
package base65536
var getB2 = map[int]int16{
5376: -1,
13312: 0,
13568: 1,
13824: 2,
14080: 3,
14336: 4,
14592: 5,
14848: 6,
15104: 7,
15360: 8,
15616: 9,
15872: 10,
16128: 11,
16384: 12,
16640: 13,
16896: 14,
17152: 15,
17408: 16,
17664: 17,
17920: 18,
18176: 19,
18432: 20,
18688: 21,
18944: 22,
19200: 23,
19456: 24,
19968: 25,
20224: 26,
20480: 27,
20736: 28,
20992: 29,
21248: 30,
21504: 31,
21760: 32,
22016: 33,
22272: 34,
22528: 35,
22784: 36,
23040: 37,
23296: 38,
23552: 39,
23808: 40,
24064: 41,
24320: 42,
24576: 43,
24832: 44,
25088: 45,
25344: 46,
25600: 47,
25856: 48,
26112: 49,
26368: 50,
26624: 51,
26880: 52,
27136: 53,
27392: 54,
27648: 55,
27904: 56,
28160: 57,
28416: 58,
28672: 59,
28928: 60,
29184: 61,
29440: 62,
29696: 63,
29952: 64,
30208: 65,
30464: 66,
30720: 67,
30976: 68,
31232: 69,
31488: 70,
31744: 71,
32000: 72,
32256: 73,
32512: 74,
32768: 75,
33024: 76,
33280: 77,
33536: 78,
33792: 79,
34048: 80,
34304: 81,
34560: 82,
34816: 83,
35072: 84,
35328: 85,
35584: 86,
35840: 87,
36096: 88,
36352: 89,
36608: 90,
36864: 91,
37120: 92,
37376: 93,
37632: 94,
37888: 95,
38144: 96,
38400: 97,
38656: 98,
38912: 99,
39168: 100,
39424: 101,
39680: 102,
39936: 103,
40192: 104,
40448: 105,
41216: 106,
41472: 107,
41728: 108,
42240: 109,
67072: 110,
73728: 111,
73984: 112,
74240: 113,
77824: 114,
78080: 115,
78336: 116,
78592: 117,
82944: 118,
83200: 119,
92160: 120,
92416: 121,
131072: 122,
131328: 123,
131584: 124,
131840: 125,
132096: 126,
132352: 127,
132608: 128,
132864: 129,
133120: 130,
133376: 131,
133632: 132,
133888: 133,
134144: 134,
134400: 135,
134656: 136,
134912: 137,
135168: 138,
135424: 139,
135680: 140,
135936: 141,
136192: 142,
136448: 143,
136704: 144,
136960: 145,
137216: 146,
137472: 147,
137728: 148,
137984: 149,
138240: 150,
138496: 151,
138752: 152,
139008: 153,
139264: 154,
139520: 155,
139776: 156,
140032: 157,
140288: 158,
140544: 159,
140800: 160,
141056: 161,
141312: 162,
141568: 163,
141824: 164,
142080: 165,
142336: 166,
142592: 167,
142848: 168,
143104: 169,
143360: 170,
143616: 171,
143872: 172,
144128: 173,
144384: 174,
144640: 175,
144896: 176,
145152: 177,
145408: 178,
145664: 179,
145920: 180,
146176: 181,
146432: 182,
146688: 183,
146944: 184,
147200: 185,
147456: 186,
147712: 187,
147968: 188,
148224: 189,
148480: 190,
148736: 191,
148992: 192,
149248: 193,
149504: 194,
149760: 195,
150016: 196,
150272: 197,
150528: 198,
150784: 199,
151040: 200,
151296: 201,
151552: 202,
151808: 203,
152064: 204,
152320: 205,
152576: 206,
152832: 207,
153088: 208,
153344: 209,
153600: 210,
153856: 211,
154112: 212,
154368: 213,
154624: 214,
154880: 215,
155136: 216,
155392: 217,
155648: 218,
155904: 219,
156160: 220,
156416: 221,
156672: 222,
156928: 223,
157184: 224,
157440: 225,
157696: 226,
157952: 227,
158208: 228,
158464: 229,
158720: 230,
158976: 231,
159232: 232,
159488: 233,
159744: 234,
160000: 235,
160256: 236,
160512: 237,
160768: 238,
161024: 239,
161280: 240,
161536: 241,
161792: 242,
162048: 243,
162304: 244,
162560: 245,
162816: 246,
163072: 247,
163328: 248,
163584: 249,
163840: 250,
164096: 251,
164352: 252,
164608: 253,
164864: 254,
165120: 255,
}

View File

@ -1,261 +0,0 @@
package base65536
var getBlockStart = map[int16]int{
-1: 5376,
0: 13312,
1: 13568,
2: 13824,
3: 14080,
4: 14336,
5: 14592,
6: 14848,
7: 15104,
8: 15360,
9: 15616,
10: 15872,
11: 16128,
12: 16384,
13: 16640,
14: 16896,
15: 17152,
16: 17408,
17: 17664,
18: 17920,
19: 18176,
20: 18432,
21: 18688,
22: 18944,
23: 19200,
24: 19456,
25: 19968,
26: 20224,
27: 20480,
28: 20736,
29: 20992,
30: 21248,
31: 21504,
32: 21760,
33: 22016,
34: 22272,
35: 22528,
36: 22784,
37: 23040,
38: 23296,
39: 23552,
40: 23808,
41: 24064,
42: 24320,
43: 24576,
44: 24832,
45: 25088,
46: 25344,
47: 25600,
48: 25856,
49: 26112,
50: 26368,
51: 26624,
52: 26880,
53: 27136,
54: 27392,
55: 27648,
56: 27904,
57: 28160,
58: 28416,
59: 28672,
60: 28928,
61: 29184,
62: 29440,
63: 29696,
64: 29952,
65: 30208,
66: 30464,
67: 30720,
68: 30976,
69: 31232,
70: 31488,
71: 31744,
72: 32000,
73: 32256,
74: 32512,
75: 32768,
76: 33024,
77: 33280,
78: 33536,
79: 33792,
80: 34048,
81: 34304,
82: 34560,
83: 34816,
84: 35072,
85: 35328,
86: 35584,
87: 35840,
88: 36096,
89: 36352,
90: 36608,
91: 36864,
92: 37120,
93: 37376,
94: 37632,
95: 37888,
96: 38144,
97: 38400,
98: 38656,
99: 38912,
100: 39168,
101: 39424,
102: 39680,
103: 39936,
104: 40192,
105: 40448,
106: 41216,
107: 41472,
108: 41728,
109: 42240,
110: 67072,
111: 73728,
112: 73984,
113: 74240,
114: 77824,
115: 78080,
116: 78336,
117: 78592,
118: 82944,
119: 83200,
120: 92160,
121: 92416,
122: 131072,
123: 131328,
124: 131584,
125: 131840,
126: 132096,
127: 132352,
128: 132608,
129: 132864,
130: 133120,
131: 133376,
132: 133632,
133: 133888,
134: 134144,
135: 134400,
136: 134656,
137: 134912,
138: 135168,
139: 135424,
140: 135680,
141: 135936,
142: 136192,
143: 136448,
144: 136704,
145: 136960,
146: 137216,
147: 137472,
148: 137728,
149: 137984,
150: 138240,
151: 138496,
152: 138752,
153: 139008,
154: 139264,
155: 139520,
156: 139776,
157: 140032,
158: 140288,
159: 140544,
160: 140800,
161: 141056,
162: 141312,
163: 141568,
164: 141824,
165: 142080,
166: 142336,
167: 142592,
168: 142848,
169: 143104,
170: 143360,
171: 143616,
172: 143872,
173: 144128,
174: 144384,
175: 144640,
176: 144896,
177: 145152,
178: 145408,
179: 145664,
180: 145920,
181: 146176,
182: 146432,
183: 146688,
184: 146944,
185: 147200,
186: 147456,
187: 147712,
188: 147968,
189: 148224,
190: 148480,
191: 148736,
192: 148992,
193: 149248,
194: 149504,
195: 149760,
196: 150016,
197: 150272,
198: 150528,
199: 150784,
200: 151040,
201: 151296,
202: 151552,
203: 151808,
204: 152064,
205: 152320,
206: 152576,
207: 152832,
208: 153088,
209: 153344,
210: 153600,
211: 153856,
212: 154112,
213: 154368,
214: 154624,
215: 154880,
216: 155136,
217: 155392,
218: 155648,
219: 155904,
220: 156160,
221: 156416,
222: 156672,
223: 156928,
224: 157184,
225: 157440,
226: 157696,
227: 157952,
228: 158208,
229: 158464,
230: 158720,
231: 158976,
232: 159232,
233: 159488,
234: 159744,
235: 160000,
236: 160256,
237: 160512,
238: 160768,
239: 161024,
240: 161280,
241: 161536,
242: 161792,
243: 162048,
244: 162304,
245: 162560,
246: 162816,
247: 163072,
248: 163328,
249: 163584,
250: 163840,
251: 164096,
252: 164352,
253: 164608,
254: 164864,
255: 165120,
}

View File

@ -0,0 +1,124 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"strconv"
"testing"
)
func countSequencedRowsInFile(filePath string) (int64, error) {
bts, err := ioutil.ReadFile(filePath)
if err != nil {
return 0, err
}
bufReader := bufio.NewReader(bytes.NewBuffer(bts))
var gotCounter int64
for {
line, _, bufErr := bufReader.ReadLine()
if bufErr != nil && bufErr != io.EOF {
return 0, bufErr
}
lineString := string(line)
if lineString == "" {
break
}
intVal, atoiErr := strconv.ParseInt(lineString, 10, 64)
if atoiErr != nil {
return 0, atoiErr
}
if intVal != gotCounter {
return 0, fmt.Errorf("wrong order: %d Expected: %d\n", intVal, gotCounter)
}
gotCounter++
}
return gotCounter, nil
}
func Test_Adaptive(t *testing.T) {
fileName := "beh_test_adaptive.log"
count := 100
Current.Close()
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
return
}
defer func() {
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
}
}()
testConfig := `
<seelog type="adaptive" mininterval="1000" maxinterval="1000000" critmsgcount="100">
<outputs formatid="msg">
<file path="` + fileName + `"/>
</outputs>
<formats>
<format id="msg" format="%Msg%n"/>
</formats>
</seelog>`
logger, _ := LoggerFromConfigAsString(testConfig)
err := ReplaceLogger(logger)
if err != nil {
t.Error(err)
return
}
for i := 0; i < count; i++ {
Trace(strconv.Itoa(i))
}
Flush()
gotCount, err := countSequencedRowsInFile(fileName)
if err != nil {
t.Error(err)
return
}
if int64(count) != gotCount {
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
return
}
Current.Close()
}

View File

@ -0,0 +1,133 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"strconv"
"testing"
)
func Test_Asyncloop(t *testing.T) {
fileName := "beh_test_asyncloop.log"
count := 100
Current.Close()
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
return
}
defer func() {
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
}
}()
testConfig := `
<seelog type="asyncloop">
<outputs formatid="msg">
<file path="` + fileName + `"/>
</outputs>
<formats>
<format id="msg" format="%Msg%n"/>
</formats>
</seelog>`
logger, _ := LoggerFromConfigAsString(testConfig)
err := ReplaceLogger(logger)
if err != nil {
t.Error(err)
return
}
for i := 0; i < count; i++ {
Trace(strconv.Itoa(i))
}
Flush()
gotCount, err := countSequencedRowsInFile(fileName)
if err != nil {
t.Error(err)
return
}
if int64(count) != gotCount {
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
return
}
Current.Close()
}
func Test_AsyncloopOff(t *testing.T) {
fileName := "beh_test_asyncloopoff.log"
count := 100
Current.Close()
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
return
}
testConfig := `
<seelog type="asyncloop" levels="off">
<outputs formatid="msg">
<file path="` + fileName + `"/>
</outputs>
<formats>
<format id="msg" format="%Msg%n"/>
</formats>
</seelog>`
logger, _ := LoggerFromConfigAsString(testConfig)
err := ReplaceLogger(logger)
if err != nil {
t.Error(err)
return
}
for i := 0; i < count; i++ {
Trace(strconv.Itoa(i))
}
Flush()
ex, err := fileExists(fileName)
if err != nil {
t.Error(err)
}
if ex {
t.Errorf("logger at level OFF is not expected to create log file at all.")
defer func() {
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
}
}()
}
Current.Close()
}

View File

@ -0,0 +1,83 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"strconv"
"testing"
)
func Test_Asynctimer(t *testing.T) {
fileName := "beh_test_asynctimer.log"
count := 100
Current.Close()
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
return
}
defer func() {
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
}
}()
testConfig := `
<seelog type="asynctimer" asyncinterval="100">
<outputs formatid="msg">
<file path="` + fileName + `"/>
</outputs>
<formats>
<format id="msg" format="%Msg%n"/>
</formats>
</seelog>`
logger, _ := LoggerFromConfigAsString(testConfig)
err := ReplaceLogger(logger)
if err != nil {
t.Error(err)
return
}
for i := 0; i < count; i++ {
Trace(strconv.Itoa(i))
}
Flush()
gotCount, err := countSequencedRowsInFile(fileName)
if err != nil {
t.Error(err)
return
}
if int64(count) != gotCount {
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
return
}
Current.Close()
}

View File

@ -0,0 +1,81 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"strconv"
"testing"
)
func Test_Sync(t *testing.T) {
fileName := "beh_test_sync.log"
count := 100
Current.Close()
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
return
}
defer func() {
if e := tryRemoveFile(fileName); e != nil {
t.Error(e)
}
}()
testConfig := `
<seelog type="sync">
<outputs formatid="msg">
<file path="` + fileName + `"/>
</outputs>
<formats>
<format id="msg" format="%Msg%n"/>
</formats>
</seelog>`
logger, _ := LoggerFromConfigAsString(testConfig)
err := ReplaceLogger(logger)
if err != nil {
t.Error(err)
return
}
for i := 0; i < count; i++ {
Trace(strconv.Itoa(i))
}
gotCount, err := countSequencedRowsInFile(fileName)
if err != nil {
t.Error(err)
return
}
if int64(count) != gotCount {
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
return
}
Current.Close()
}

99
vendor/github.com/cihub/seelog/cfg_logconfig_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"strings"
"testing"
)
func TestConfig(t *testing.T) {
testConfig :=
`
<seelog levels="trace, debug">
<exceptions>
<exception funcpattern="*getFirst*" filepattern="*" minlevel="off" />
<exception funcpattern="*getSecond*" filepattern="*" levels="info, error" />
</exceptions>
</seelog>
`
conf, err := configFromReader(strings.NewReader(testConfig))
if err != nil {
t.Errorf("parse error: %s\n", err.Error())
return
}
context, err := currentContext(nil)
if err != nil {
t.Errorf("cannot get current context:" + err.Error())
return
}
firstContext, err := getFirstContext()
if err != nil {
t.Errorf("cannot get current context:" + err.Error())
return
}
secondContext, err := getSecondContext()
if err != nil {
t.Errorf("cannot get current context:" + err.Error())
return
}
if !conf.IsAllowed(TraceLvl, context) {
t.Errorf("error: deny trace in current context")
}
if conf.IsAllowed(TraceLvl, firstContext) {
t.Errorf("error: allow trace in first context")
}
if conf.IsAllowed(ErrorLvl, context) {
t.Errorf("error: allow error in current context")
}
if !conf.IsAllowed(ErrorLvl, secondContext) {
t.Errorf("error: deny error in second context")
}
// cache test
if !conf.IsAllowed(TraceLvl, context) {
t.Errorf("error: deny trace in current context")
}
if conf.IsAllowed(TraceLvl, firstContext) {
t.Errorf("error: allow trace in first context")
}
if conf.IsAllowed(ErrorLvl, context) {
t.Errorf("error: allow error in current context")
}
if !conf.IsAllowed(ErrorLvl, secondContext) {
t.Errorf("error: deny error in second context")
}
}
func getFirstContext() (LogContextInterface, error) {
return currentContext(nil)
}
func getSecondContext() (LogContextInterface, error) {
return currentContext(nil)
}

1089
vendor/github.com/cihub/seelog/cfg_parser_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
func TestInvalidminMaxConstraints(t *testing.T) {
constr, err := NewMinMaxConstraints(CriticalLvl, WarnLvl)
if err == nil || constr != nil {
t.Errorf("expected an error and a nil value for minmax constraints: min = %d, max = %d. Got: %v, %v",
CriticalLvl, WarnLvl, err, constr)
return
}
}
func TestInvalidLogLevels(t *testing.T) {
var invalidMin uint8 = 123
var invalidMax uint8 = 124
minMaxConstr, errMinMax := NewMinMaxConstraints(LogLevel(invalidMin), LogLevel(invalidMax))
if errMinMax == nil || minMaxConstr != nil {
t.Errorf("expected an error and a nil value for minmax constraints: min = %d, max = %d. Got: %v, %v",
invalidMin, invalidMax, errMinMax, minMaxConstr)
return
}
invalidList := []LogLevel{145}
listConstr, errList := NewListConstraints(invalidList)
if errList == nil || listConstr != nil {
t.Errorf("expected an error and a nil value for constraints list: %v. Got: %v, %v",
invalidList, errList, listConstr)
return
}
}
func TestlistConstraintsWithDuplicates(t *testing.T) {
duplicateList := []LogLevel{TraceLvl, DebugLvl, InfoLvl,
WarnLvl, ErrorLvl, CriticalLvl, CriticalLvl, CriticalLvl}
listConstr, errList := NewListConstraints(duplicateList)
if errList != nil || listConstr == nil {
t.Errorf("expected a valid constraints list struct for: %v, got error: %v, value: %v",
duplicateList, errList, listConstr)
return
}
listLevels := listConstr.AllowedLevels()
if listLevels == nil {
t.Fatalf("listConstr.AllowedLevels() == nil")
return
}
if len(listLevels) != 6 {
t.Errorf("expected: listConstr.AllowedLevels() length == 6. Got: %d", len(listLevels))
return
}
}
func TestlistConstraintsWithOffInList(t *testing.T) {
offList := []LogLevel{TraceLvl, DebugLvl, Off}
listConstr, errList := NewListConstraints(offList)
if errList == nil || listConstr != nil {
t.Errorf("expected an error and a nil value for constraints list with 'Off': %v. Got: %v, %v",
offList, errList, listConstr)
return
}
}
type logLevelTestCase struct {
level LogLevel
allowed bool
}
var minMaxTests = []logLevelTestCase{
{TraceLvl, false},
{DebugLvl, false},
{InfoLvl, true},
{WarnLvl, true},
{ErrorLvl, false},
{CriticalLvl, false},
{123, false},
{6, false},
}
func TestValidminMaxConstraints(t *testing.T) {
constr, err := NewMinMaxConstraints(InfoLvl, WarnLvl)
if err != nil || constr == nil {
t.Errorf("expected a valid constraints struct for minmax constraints: min = %d, max = %d. Got: %v, %v",
InfoLvl, WarnLvl, err, constr)
return
}
for _, minMaxTest := range minMaxTests {
allowed := constr.IsAllowed(minMaxTest.level)
if allowed != minMaxTest.allowed {
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
minMaxTest.allowed, minMaxTest.level, allowed)
return
}
}
}
var listTests = []logLevelTestCase{
{TraceLvl, true},
{DebugLvl, false},
{InfoLvl, true},
{WarnLvl, true},
{ErrorLvl, false},
{CriticalLvl, true},
{123, false},
{6, false},
}
func TestValidlistConstraints(t *testing.T) {
validList := []LogLevel{TraceLvl, InfoLvl, WarnLvl, CriticalLvl}
constr, err := NewListConstraints(validList)
if err != nil || constr == nil {
t.Errorf("expected a valid constraints list struct for: %v. Got error: %v, value: %v",
validList, err, constr)
return
}
for _, minMaxTest := range listTests {
allowed := constr.IsAllowed(minMaxTest.level)
if allowed != minMaxTest.allowed {
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
minMaxTest.allowed, minMaxTest.level, allowed)
return
}
}
}
var offTests = []logLevelTestCase{
{TraceLvl, false},
{DebugLvl, false},
{InfoLvl, false},
{WarnLvl, false},
{ErrorLvl, false},
{CriticalLvl, false},
{123, false},
{6, false},
}
func TestValidListoffConstraints(t *testing.T) {
validList := []LogLevel{Off}
constr, err := NewListConstraints(validList)
if err != nil || constr == nil {
t.Errorf("expected a valid constraints list struct for: %v. Got error: %v, value: %v",
validList, err, constr)
return
}
for _, minMaxTest := range offTests {
allowed := constr.IsAllowed(minMaxTest.level)
if allowed != minMaxTest.allowed {
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
minMaxTest.allowed, minMaxTest.level, allowed)
return
}
}
}

127
vendor/github.com/cihub/seelog/common_context_test.go generated vendored Normal file
View File

@ -0,0 +1,127 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"os"
"path/filepath"
"strings"
"testing"
)
const (
testShortPath = "common_context_test.go"
)
var (
commonPrefix string
testFullPath string
)
func init() {
// Here we remove the hardcoding of the package name which
// may break forks and some CI environments such as jenkins.
_, _, funcName, _, _ := extractCallerInfo(1)
preIndex := strings.Index(funcName, "init·")
if preIndex == -1 {
preIndex = strings.Index(funcName, "init")
}
commonPrefix = funcName[:preIndex]
wd, err := os.Getwd()
if err == nil {
// Transform the file path into a slashed form:
// This is the proper platform-neutral way.
testFullPath = filepath.ToSlash(filepath.Join(wd, testShortPath))
}
}
func TestContext(t *testing.T) {
context, err := currentContext(nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if context == nil {
t.Fatalf("unexpected error: context is nil")
}
if fn, funcName := context.Func(), commonPrefix+"TestContext"; fn != funcName {
// Account for a case when the func full path is longer than commonPrefix but includes it.
if !strings.HasSuffix(fn, funcName) {
t.Errorf("expected context.Func == %s ; got %s", funcName, context.Func())
}
}
if context.ShortPath() != testShortPath {
t.Errorf("expected context.ShortPath == %s ; got %s", testShortPath, context.ShortPath())
}
if len(testFullPath) == 0 {
t.Fatal("working directory seems invalid")
}
if context.FullPath() != testFullPath {
t.Errorf("expected context.FullPath == %s ; got %s", testFullPath, context.FullPath())
}
}
func innerContext() (context LogContextInterface, err error) {
return currentContext(nil)
}
func TestInnerContext(t *testing.T) {
context, err := innerContext()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if context == nil {
t.Fatalf("unexpected error: context is nil")
}
if fn, funcName := context.Func(), commonPrefix+"innerContext"; fn != funcName {
// Account for a case when the func full path is longer than commonPrefix but includes it.
if !strings.HasSuffix(fn, funcName) {
t.Errorf("expected context.Func == %s ; got %s", funcName, context.Func())
}
}
if context.ShortPath() != testShortPath {
t.Errorf("expected context.ShortPath == %s ; got %s", testShortPath, context.ShortPath())
}
if len(testFullPath) == 0 {
t.Fatal("working directory seems invalid")
}
if context.FullPath() != testFullPath {
t.Errorf("expected context.FullPath == %s ; got %s", testFullPath, context.FullPath())
}
}
type testContext struct {
field string
}
func TestCustomContext(t *testing.T) {
expected := "testStr"
context, err := currentContext(&testContext{expected})
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if st, _ := context.CustomContext().(*testContext); st.field != expected {
t.Errorf("expected context.CustomContext == %s ; got %s", expected, st.field)
}
}

View File

@ -0,0 +1,98 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
type exceptionTestCase struct {
funcPattern string
filePattern string
funcName string
fileName string
match bool
}
var exceptionTestCases = []exceptionTestCase{
{"*", "*", "func", "file", true},
{"func*", "*", "func", "file", true},
{"*func", "*", "func", "file", true},
{"*func", "*", "1func", "file", true},
{"func*", "*", "func1", "file", true},
{"fu*nc", "*", "func", "file", true},
{"fu*nc", "*", "fu1nc", "file", true},
{"fu*nc", "*", "func1nc", "file", true},
{"*fu*nc*", "*", "somefuntonc", "file", true},
{"fu*nc", "*", "f1nc", "file", false},
{"func*", "*", "fun", "file", false},
{"fu*nc", "*", "func1n", "file", false},
{"**f**u**n**c**", "*", "func1n", "file", true},
}
func TestMatchingCorrectness(t *testing.T) {
constraints, err := NewListConstraints([]LogLevel{TraceLvl})
if err != nil {
t.Error(err)
return
}
for _, testCase := range exceptionTestCases {
rule, ruleError := NewLogLevelException(testCase.funcPattern, testCase.filePattern, constraints)
if ruleError != nil {
t.Fatalf("Unexpected error on rule creation: [ %v, %v ]. %v",
testCase.funcPattern, testCase.filePattern, ruleError)
}
match := rule.match(testCase.funcName, testCase.fileName)
if match != testCase.match {
t.Errorf("incorrect matching for [ %v, %v ] [ %v, %v ] Expected: %t. Got: %t",
testCase.funcPattern, testCase.filePattern, testCase.funcName, testCase.fileName, testCase.match, match)
}
}
}
func TestAsterisksReducing(t *testing.T) {
constraints, err := NewListConstraints([]LogLevel{TraceLvl})
if err != nil {
t.Error(err)
return
}
rule, err := NewLogLevelException("***func**", "fi*****le", constraints)
if err != nil {
t.Error(err)
return
}
expectFunc := "*func*"
if rule.FuncPattern() != expectFunc {
t.Errorf("asterisks must be reduced. Expect:%v, Got:%v", expectFunc, rule.FuncPattern())
}
expectFile := "fi*le"
if rule.FilePattern() != expectFile {
t.Errorf("asterisks must be reduced. Expect:%v, Got:%v", expectFile, rule.FilePattern())
}
}

View File

@ -0,0 +1,177 @@
// Copyright (c) 2013 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
type testCustomDispatcherMessageReceiver struct {
customTestReceiver
}
func TestCustomDispatcher_Message(t *testing.T) {
recName := "TestCustomDispatcher_Message"
RegisterReceiver(recName, &testCustomDispatcherMessageReceiver{})
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
XmlCustomAttrs: map[string]string{
"test": "testdata",
},
})
if err != nil {
t.Error(err)
return
}
context, err := currentContext(nil)
if err != nil {
t.Error(err)
return
}
bytes := []byte("Hello")
customDispatcher.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
cout := customDispatcher.innerReceiver.(*testCustomDispatcherMessageReceiver).customTestReceiver.co
if cout.initCalled != true {
t.Error("Init not called")
return
}
if cout.dataPassed != "testdata" {
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
return
}
if cout.messageOutput != string(bytes) {
t.Errorf("wrong message output: '%s'", cout.messageOutput)
return
}
if cout.levelOutput != TraceLvl {
t.Errorf("wrong log level: '%s'", cout.levelOutput)
return
}
if cout.flushed {
t.Error("Flush was not expected")
return
}
if cout.closed {
t.Error("Closing was not expected")
return
}
}
type testCustomDispatcherFlushReceiver struct {
customTestReceiver
}
func TestCustomDispatcher_Flush(t *testing.T) {
recName := "TestCustomDispatcher_Flush"
RegisterReceiver(recName, &testCustomDispatcherFlushReceiver{})
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
XmlCustomAttrs: map[string]string{
"test": "testdata",
},
})
if err != nil {
t.Error(err)
return
}
customDispatcher.Flush()
cout := customDispatcher.innerReceiver.(*testCustomDispatcherFlushReceiver).customTestReceiver.co
if cout.initCalled != true {
t.Error("Init not called")
return
}
if cout.dataPassed != "testdata" {
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
return
}
if cout.messageOutput != "" {
t.Errorf("wrong message output: '%s'", cout.messageOutput)
return
}
if cout.levelOutput != TraceLvl {
t.Errorf("wrong log level: '%s'", cout.levelOutput)
return
}
if !cout.flushed {
t.Error("Flush was expected")
return
}
if cout.closed {
t.Error("Closing was not expected")
return
}
}
type testCustomDispatcherCloseReceiver struct {
customTestReceiver
}
func TestCustomDispatcher_Close(t *testing.T) {
recName := "TestCustomDispatcher_Close"
RegisterReceiver(recName, &testCustomDispatcherCloseReceiver{})
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
XmlCustomAttrs: map[string]string{
"test": "testdata",
},
})
if err != nil {
t.Error(err)
return
}
customDispatcher.Close()
cout := customDispatcher.innerReceiver.(*testCustomDispatcherCloseReceiver).customTestReceiver.co
if cout.initCalled != true {
t.Error("Init not called")
return
}
if cout.dataPassed != "testdata" {
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
return
}
if cout.messageOutput != "" {
t.Errorf("wrong message output: '%s'", cout.messageOutput)
return
}
if cout.levelOutput != TraceLvl {
t.Errorf("wrong log level: '%s'", cout.levelOutput)
return
}
if !cout.flushed {
t.Error("Flush was expected")
return
}
if !cout.closed {
t.Error("Closing was expected")
return
}
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
func TestfilterDispatcher_Pass(t *testing.T) {
writer, _ := newBytesVerifier(t)
filter, err := NewFilterDispatcher(onlyMessageFormatForTest, []interface{}{writer}, TraceLvl)
if err != nil {
t.Error(err)
return
}
context, err := currentContext(nil)
if err != nil {
t.Error(err)
return
}
bytes := []byte("Hello")
writer.ExpectBytes(bytes)
filter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
writer.MustNotExpect()
}
func TestfilterDispatcher_Deny(t *testing.T) {
writer, _ := newBytesVerifier(t)
filter, err := NewFilterDispatcher(DefaultFormatter, []interface{}{writer})
if err != nil {
t.Error(err)
return
}
context, err := currentContext(nil)
if err != nil {
t.Error(err)
return
}
bytes := []byte("Hello")
filter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
}

View File

@ -0,0 +1,64 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"fmt"
"testing"
)
var onlyMessageFormatForTest *formatter
func init() {
var err error
onlyMessageFormatForTest, err = NewFormatter("%Msg")
if err != nil {
fmt.Println("Can not create only message format: " + err.Error())
}
}
func TestsplitDispatcher(t *testing.T) {
writer1, _ := newBytesVerifier(t)
writer2, _ := newBytesVerifier(t)
spliter, err := NewSplitDispatcher(onlyMessageFormatForTest, []interface{}{writer1, writer2})
if err != nil {
t.Error(err)
return
}
context, err := currentContext(nil)
if err != nil {
t.Error(err)
return
}
bytes := []byte("Hello")
writer1.ExpectBytes(bytes)
writer2.ExpectBytes(bytes)
spliter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
writer1.MustNotExpect()
writer2.MustNotExpect()
}

236
vendor/github.com/cihub/seelog/format_test.go generated vendored Normal file
View File

@ -0,0 +1,236 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"fmt"
"strings"
"testing"
"time"
)
const (
TestFuncName = "TestFormats"
)
type formatTest struct {
formatString string
input string
inputLogLevel LogLevel
expectedOutput string
errorExpected bool
}
var formatTests = []formatTest{
{"test", "abcdef", TraceLvl, "test", false},
{"", "abcdef", TraceLvl, "", false},
{"%Level", "", TraceLvl, "Trace", false},
{"%Level", "", DebugLvl, "Debug", false},
{"%Level", "", InfoLvl, "Info", false},
{"%Level", "", WarnLvl, "Warn", false},
{"%Level", "", ErrorLvl, "Error", false},
{"%Level", "", CriticalLvl, "Critical", false},
{"[%Level]", "", TraceLvl, "[Trace]", false},
{"[%Level]", "abc", DebugLvl, "[Debug]", false},
{"%LevelLevel", "", InfoLvl, "InfoLevel", false},
{"[%Level][%Level]", "", WarnLvl, "[Warn][Warn]", false},
{"[%Level]X[%Level]", "", ErrorLvl, "[Error]X[Error]", false},
{"%Levelll", "", CriticalLvl, "Criticalll", false},
{"%Lvl", "", TraceLvl, "", true},
{"%%Level", "", DebugLvl, "%Level", false},
{"%Level%", "", InfoLvl, "", true},
{"%sevel", "", WarnLvl, "", true},
{"Level", "", ErrorLvl, "Level", false},
{"%LevelLevel", "", CriticalLvl, "CriticalLevel", false},
{"%Lev", "", TraceLvl, "Trc", false},
{"%Lev", "", DebugLvl, "Dbg", false},
{"%Lev", "", InfoLvl, "Inf", false},
{"%Lev", "", WarnLvl, "Wrn", false},
{"%Lev", "", ErrorLvl, "Err", false},
{"%Lev", "", CriticalLvl, "Crt", false},
{"[%Lev]", "", TraceLvl, "[Trc]", false},
{"[%Lev]", "abc", DebugLvl, "[Dbg]", false},
{"%LevLevel", "", InfoLvl, "InfLevel", false},
{"[%Level][%Lev]", "", WarnLvl, "[Warn][Wrn]", false},
{"[%Lev]X[%Lev]", "", ErrorLvl, "[Err]X[Err]", false},
{"%Levll", "", CriticalLvl, "Crtll", false},
{"%LEVEL", "", TraceLvl, "TRACE", false},
{"%LEVEL", "", DebugLvl, "DEBUG", false},
{"%LEVEL", "", InfoLvl, "INFO", false},
{"%LEVEL", "", WarnLvl, "WARN", false},
{"%LEVEL", "", ErrorLvl, "ERROR", false},
{"%LEVEL", "", CriticalLvl, "CRITICAL", false},
{"[%LEVEL]", "", TraceLvl, "[TRACE]", false},
{"[%LEVEL]", "abc", DebugLvl, "[DEBUG]", false},
{"%LEVELLEVEL", "", InfoLvl, "INFOLEVEL", false},
{"[%LEVEL][%LEVEL]", "", WarnLvl, "[WARN][WARN]", false},
{"[%LEVEL]X[%Level]", "", ErrorLvl, "[ERROR]X[Error]", false},
{"%LEVELLL", "", CriticalLvl, "CRITICALLL", false},
{"%LEV", "", TraceLvl, "TRC", false},
{"%LEV", "", DebugLvl, "DBG", false},
{"%LEV", "", InfoLvl, "INF", false},
{"%LEV", "", WarnLvl, "WRN", false},
{"%LEV", "", ErrorLvl, "ERR", false},
{"%LEV", "", CriticalLvl, "CRT", false},
{"[%LEV]", "", TraceLvl, "[TRC]", false},
{"[%LEV]", "abc", DebugLvl, "[DBG]", false},
{"%LEVLEVEL", "", InfoLvl, "INFLEVEL", false},
{"[%LEVEL][%LEV]", "", WarnLvl, "[WARN][WRN]", false},
{"[%LEV]X[%LEV]", "", ErrorLvl, "[ERR]X[ERR]", false},
{"%LEVLL", "", CriticalLvl, "CRTLL", false},
{"%l", "", TraceLvl, "t", false},
{"%l", "", DebugLvl, "d", false},
{"%l", "", InfoLvl, "i", false},
{"%l", "", WarnLvl, "w", false},
{"%l", "", ErrorLvl, "e", false},
{"%l", "", CriticalLvl, "c", false},
{"[%l]", "", TraceLvl, "[t]", false},
{"[%l]", "abc", DebugLvl, "[d]", false},
{"%Level%Msg", "", TraceLvl, "Trace", false},
{"%Level%Msg", "A", DebugLvl, "DebugA", false},
{"%Level%Msg", "", InfoLvl, "Info", false},
{"%Level%Msg", "test", WarnLvl, "Warntest", false},
{"%Level%Msg", " ", ErrorLvl, "Error ", false},
{"%Level%Msg", "", CriticalLvl, "Critical", false},
{"[%Level]", "", TraceLvl, "[Trace]", false},
{"[%Level]", "abc", DebugLvl, "[Debug]", false},
{"%Level%MsgLevel", "A", InfoLvl, "InfoALevel", false},
{"[%Level]%Msg[%Level]", "test", WarnLvl, "[Warn]test[Warn]", false},
{"[%Level]%MsgX[%Level]", "test", ErrorLvl, "[Error]testX[Error]", false},
{"%Levell%Msgl", "Test", CriticalLvl, "CriticallTestl", false},
{"%Lev%Msg%LEVEL%LEV%l%Msg", "Test", InfoLvl, "InfTestINFOINFiTest", false},
{"%n", "", CriticalLvl, "\n", false},
{"%t", "", CriticalLvl, "\t", false},
}
func TestFormats(t *testing.T) {
context, conErr := currentContext(nil)
if conErr != nil {
t.Fatal("Cannot get current context:" + conErr.Error())
return
}
for _, test := range formatTests {
form, err := NewFormatter(test.formatString)
if (err != nil) != test.errorExpected {
t.Errorf("input: %s \nInput LL: %s\n* Expected error:%t Got error: %t\n",
test.input, test.inputLogLevel, test.errorExpected, (err != nil))
if err != nil {
t.Logf("%s\n", err.Error())
}
continue
} else if err != nil {
continue
}
msg := form.Format(test.input, test.inputLogLevel, context)
if err == nil && msg != test.expectedOutput {
t.Errorf("format: %s \nInput: %s \nInput LL: %s\n* Expected: %s \n* Got: %s\n",
test.formatString, test.input, test.inputLogLevel, test.expectedOutput, msg)
}
}
}
func TestDateFormat(t *testing.T) {
_, err := NewFormatter("%Date")
if err != nil {
t.Error("Unexpected error: " + err.Error())
}
}
func TestDateParameterizedFormat(t *testing.T) {
testFormat := "Mon Jan 02 2006 15:04:05"
preciseForamt := "Mon Jan 02 2006 15:04:05.000"
context, conErr := currentContext(nil)
if conErr != nil {
t.Fatal("Cannot get current context:" + conErr.Error())
return
}
form, err := NewFormatter("%Date(" + preciseForamt + ")")
if err != nil {
t.Error("Unexpected error: " + err.Error())
}
dateBefore := time.Now().Format(testFormat)
msg := form.Format("", TraceLvl, context)
dateAfter := time.Now().Format(testFormat)
if !strings.HasPrefix(msg, dateBefore) && !strings.HasPrefix(msg, dateAfter) {
t.Errorf("incorrect message: %v. Expected %v or %v", msg, dateBefore, dateAfter)
}
_, err = NewFormatter("%Date(" + preciseForamt)
if err == nil {
t.Error("Expected error for invalid format")
}
}
func createTestFormatter(format string) FormatterFunc {
return func(message string, level LogLevel, context LogContextInterface) interface{} {
return "TEST " + context.Func() + " TEST"
}
}
func TestCustomFormatterRegistration(t *testing.T) {
err := RegisterCustomFormatter("Level", createTestFormatter)
if err == nil {
t.Errorf("expected an error when trying to register a custom formatter with a reserved alias")
}
err = RegisterCustomFormatter("EscM", createTestFormatter)
if err == nil {
t.Errorf("expected an error when trying to register a custom formatter with a reserved parameterized alias")
}
err = RegisterCustomFormatter("TEST", createTestFormatter)
if err != nil {
t.Fatalf("Registering custom formatter: unexpected error: %s", err)
}
err = RegisterCustomFormatter("TEST", createTestFormatter)
if err == nil {
t.Errorf("expected an error when trying to register a custom formatter with duplicate name")
}
context, conErr := currentContext(nil)
if conErr != nil {
t.Fatal("Cannot get current context:" + conErr.Error())
return
}
form, err := NewFormatter("%Msg %TEST 123")
if err != nil {
t.Fatalf("%s\n", err.Error())
}
expected := fmt.Sprintf("test TEST %sTestCustomFormatterRegistration TEST 123", commonPrefix)
msg := form.Format("test", DebugLvl, context)
if msg != expected {
t.Fatalf("Custom formatter: invalid output. Expected: '%s'. Got: '%s'", expected, msg)
}
}

View File

@ -0,0 +1,118 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"errors"
"strconv"
"testing"
)
// bytesVerifier is a byte receiver which is used for correct input testing.
// It allows to compare expected result and actual result in context of received bytes.
type bytesVerifier struct {
expectedBytes []byte // bytes that are expected to be written in next Write call
waitingForInput bool // true if verifier is waiting for a Write call
writtenData []byte // real bytes that actually were received during the last Write call
testEnv *testing.T
}
func newBytesVerifier(t *testing.T) (*bytesVerifier, error) {
if t == nil {
return nil, errors.New("testing environment param is nil")
}
verifier := new(bytesVerifier)
verifier.testEnv = t
return verifier, nil
}
// Write is used to check whether verifier was waiting for input and whether bytes are the same as expectedBytes.
// After Write call, waitingForInput is set to false.
func (verifier *bytesVerifier) Write(bytes []byte) (n int, err error) {
if !verifier.waitingForInput {
verifier.testEnv.Errorf("unexpected input: %v", string(bytes))
return
}
verifier.waitingForInput = false
verifier.writtenData = bytes
if verifier.expectedBytes != nil {
if bytes == nil {
verifier.testEnv.Errorf("incoming 'bytes' is nil")
} else {
if len(bytes) != len(verifier.expectedBytes) {
verifier.testEnv.Errorf("'Bytes' has unexpected len. Expected: %d. Got: %d. . Expected string: %q. Got: %q",
len(verifier.expectedBytes), len(bytes), string(verifier.expectedBytes), string(bytes))
} else {
for i := 0; i < len(bytes); i++ {
if verifier.expectedBytes[i] != bytes[i] {
verifier.testEnv.Errorf("incorrect data on position %d. Expected: %d. Got: %d. Expected string: %q. Got: %q",
i, verifier.expectedBytes[i], bytes[i], string(verifier.expectedBytes), string(bytes))
break
}
}
}
}
}
return len(bytes), nil
}
func (verifier *bytesVerifier) ExpectBytes(bytes []byte) {
verifier.waitingForInput = true
verifier.expectedBytes = bytes
}
func (verifier *bytesVerifier) MustNotExpect() {
if verifier.waitingForInput {
errorText := "Unexpected input: "
if verifier.expectedBytes != nil {
errorText += "len = " + strconv.Itoa(len(verifier.expectedBytes))
errorText += ". text = " + string(verifier.expectedBytes)
}
verifier.testEnv.Errorf(errorText)
}
}
func (verifier *bytesVerifier) Close() error {
return nil
}
// nullWriter implements io.Writer inteface and does nothing, always returning a successful write result
type nullWriter struct {
}
func (writer *nullWriter) Write(bytes []byte) (n int, err error) {
return len(bytes), nil
}
func (writer *nullWriter) Close() error {
return nil
}

View File

@ -0,0 +1,196 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"strings"
"testing"
//"fmt"
"reflect"
)
var testEnv *testing.T
/*func TestWrapper(t *testing.T) {
testEnv = t
s := "<a d='a'><g m='a'></g><g h='t' j='kk'></g></a>"
reader := strings.NewReader(s)
config, err := unmarshalConfig(reader)
if err != nil {
testEnv.Error(err)
return
}
printXML(config, 0)
}
func printXML(node *xmlNode, level int) {
indent := strings.Repeat("\t", level)
fmt.Print(indent + node.name)
for key, value := range node.attributes {
fmt.Print(" " + key + "/" + value)
}
fmt.Println()
for _, child := range node.children {
printXML(child, level+1)
}
}*/
var xmlNodeTests []xmlNodeTest
type xmlNodeTest struct {
testName string
inputXML string
expected interface{}
errorExpected bool
}
func getXMLTests() []xmlNodeTest {
if xmlNodeTests == nil {
xmlNodeTests = make([]xmlNodeTest, 0)
testName := "Simple test"
testXML := `<a></a>`
testExpected := newNode()
testExpected.name = "a"
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Multiline test"
testXML =
`
<a>
</a>
`
testExpected = newNode()
testExpected.name = "a"
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Multiline test #2"
testXML =
`
<a>
</a>
`
testExpected = newNode()
testExpected.name = "a"
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Incorrect names"
testXML = `< a >< /a >`
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
testName = "Comments"
testXML =
`<!-- <abcdef/> -->
<a> <!-- <!--12345-->
</a>
`
testExpected = newNode()
testExpected.name = "a"
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Multiple roots"
testXML = `<a></a><b></b>`
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
testName = "Multiple roots + incorrect xml"
testXML = `<a></a><b>`
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
testName = "Some unicode and data"
testXML = `<俄语>данные</俄语>`
testExpected = newNode()
testExpected.name = "俄语"
testExpected.value = "данные"
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Values and children"
testXML = `<俄语>данные<and_a_child></and_a_child></俄语>`
testExpected = newNode()
testExpected.name = "俄语"
testExpected.value = "данные"
child := newNode()
child.name = "and_a_child"
testExpected.children = append(testExpected.children, child)
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Just children"
testXML = `<俄语><and_a_child></and_a_child></俄语>`
testExpected = newNode()
testExpected.name = "俄语"
child = newNode()
child.name = "and_a_child"
testExpected.children = append(testExpected.children, child)
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
testName = "Mixed test"
testXML = `<俄语 a="1" b="2.13" c="abc"><child abc="bca"/><child abc="def"></child></俄语>`
testExpected = newNode()
testExpected.name = "俄语"
testExpected.attributes["a"] = "1"
testExpected.attributes["b"] = "2.13"
testExpected.attributes["c"] = "abc"
child = newNode()
child.name = "child"
child.attributes["abc"] = "bca"
testExpected.children = append(testExpected.children, child)
child = newNode()
child.name = "child"
child.attributes["abc"] = "def"
testExpected.children = append(testExpected.children, child)
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
}
return xmlNodeTests
}
func TestXmlNode(t *testing.T) {
for _, test := range getXMLTests() {
reader := strings.NewReader(test.inputXML)
parsedXML, err := unmarshalConfig(reader)
if (err != nil) != test.errorExpected {
t.Errorf("\n%s:\nXML input: %s\nExpected error:%t. Got error: %t\n", test.testName,
test.inputXML, test.errorExpected, (err != nil))
if err != nil {
t.Logf("%s\n", err.Error())
}
continue
}
if err == nil && !reflect.DeepEqual(parsedXML, test.expected) {
t.Errorf("\n%s:\nXML input: %s\nExpected: %s. \nGot: %s\n", test.testName,
test.inputXML, test.expected, parsedXML)
}
}
}

View File

@ -0,0 +1,78 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
func TestChunkWriteOnFilling(t *testing.T) {
writer, _ := newBytesVerifier(t)
bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
if err != nil {
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
}
bytes := make([]byte, 1000)
bufferedWriter.Write(bytes)
writer.ExpectBytes(bytes)
bufferedWriter.Write(bytes)
}
func TestFlushByTimePeriod(t *testing.T) {
writer, _ := newBytesVerifier(t)
bufferedWriter, err := NewBufferedWriter(writer, 1024, 10)
if err != nil {
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
}
bytes := []byte("Hello")
for i := 0; i < 2; i++ {
writer.ExpectBytes(bytes)
bufferedWriter.Write(bytes)
}
}
func TestBigMessageMustPassMemoryBuffer(t *testing.T) {
writer, _ := newBytesVerifier(t)
bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
if err != nil {
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
}
bytes := make([]byte, 5000)
for i := 0; i < len(bytes); i++ {
bytes[i] = uint8(i % 255)
}
writer.ExpectBytes(bytes)
bufferedWriter.Write(bytes)
}

View File

@ -0,0 +1,254 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"
)
const (
messageLen = 10
)
var bytesFileTest = []byte(strings.Repeat("A", messageLen))
func TestSimpleFileWriter(t *testing.T) {
t.Logf("Starting file writer tests")
NewFileWriterTester(simplefileWriterTests, simplefileWriterGetter, t).test()
}
//===============================================================
func simplefileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, error) {
return NewFileWriter(testCase.fileName)
}
//===============================================================
type fileWriterTestCase struct {
files []string
fileName string
rollingType rollingType
fileSize int64
maxRolls int
datePattern string
writeCount int
resFiles []string
nameMode rollingNameMode
}
func createSimplefileWriterTestCase(fileName string, writeCount int) *fileWriterTestCase {
return &fileWriterTestCase{[]string{}, fileName, rollingTypeSize, 0, 0, "", writeCount, []string{fileName}, 0}
}
var simplefileWriterTests = []*fileWriterTestCase{
createSimplefileWriterTestCase("log.testlog", 1),
createSimplefileWriterTestCase("log.testlog", 50),
createSimplefileWriterTestCase(filepath.Join("dir", "log.testlog"), 50),
}
//===============================================================
type fileWriterTester struct {
testCases []*fileWriterTestCase
writerGetter func(*fileWriterTestCase) (io.WriteCloser, error)
t *testing.T
}
func NewFileWriterTester(
testCases []*fileWriterTestCase,
writerGetter func(*fileWriterTestCase) (io.WriteCloser, error),
t *testing.T) *fileWriterTester {
return &fileWriterTester{testCases, writerGetter, t}
}
func isWriterTestFile(fn string) bool {
return strings.Contains(fn, ".testlog")
}
func cleanupWriterTest(t *testing.T) {
toDel, err := getDirFilePaths(".", isWriterTestFile, true)
if nil != err {
t.Fatal("Cannot list files in test directory!")
}
for _, p := range toDel {
if err = tryRemoveFile(p); nil != err {
t.Errorf("cannot remove file %s in test directory: %s", p, err.Error())
}
}
if err = os.RemoveAll("dir"); nil != err {
t.Errorf("cannot remove temp test directory: %s", err.Error())
}
}
func getWriterTestResultFiles() ([]string, error) {
var p []string
visit := func(path string, f os.FileInfo, err error) error {
if !f.IsDir() && isWriterTestFile(path) {
abs, err := filepath.Abs(path)
if err != nil {
return fmt.Errorf("filepath.Abs failed for %s", path)
}
p = append(p, abs)
}
return nil
}
err := filepath.Walk(".", visit)
if nil != err {
return nil, err
}
return p, nil
}
func (tester *fileWriterTester) testCase(testCase *fileWriterTestCase, testNum int) {
defer cleanupWriterTest(tester.t)
tester.t.Logf("Start test [%v]\n", testNum)
for _, filePath := range testCase.files {
dir, _ := filepath.Split(filePath)
var err error
if 0 != len(dir) {
err = os.MkdirAll(dir, defaultDirectoryPermissions)
if err != nil {
tester.t.Error(err)
return
}
}
fi, err := os.Create(filePath)
if err != nil {
tester.t.Error(err)
return
}
err = fi.Close()
if err != nil {
tester.t.Error(err)
return
}
}
fwc, err := tester.writerGetter(testCase)
if err != nil {
tester.t.Error(err)
return
}
defer fwc.Close()
tester.performWrite(fwc, testCase.writeCount)
files, err := getWriterTestResultFiles()
if err != nil {
tester.t.Error(err)
return
}
tester.checkRequiredFilesExist(testCase, files)
tester.checkJustRequiredFilesExist(testCase, files)
}
func (tester *fileWriterTester) test() {
for i, tc := range tester.testCases {
cleanupWriterTest(tester.t)
tester.testCase(tc, i)
}
}
func (tester *fileWriterTester) performWrite(fileWriter io.Writer, count int) {
for i := 0; i < count; i++ {
_, err := fileWriter.Write(bytesFileTest)
if err != nil {
tester.t.Error(err)
return
}
}
}
func (tester *fileWriterTester) checkRequiredFilesExist(testCase *fileWriterTestCase, files []string) {
var found bool
for _, expected := range testCase.resFiles {
found = false
exAbs, err := filepath.Abs(expected)
if err != nil {
tester.t.Errorf("filepath.Abs failed for %s", expected)
continue
}
for _, f := range files {
if af, e := filepath.Abs(f); e == nil {
tester.t.Log(af)
if exAbs == af {
found = true
break
}
} else {
tester.t.Errorf("filepath.Abs failed for %s", f)
}
}
if !found {
tester.t.Errorf("expected file: %s doesn't exist. Got %v\n", exAbs, files)
}
}
}
func (tester *fileWriterTester) checkJustRequiredFilesExist(testCase *fileWriterTestCase, files []string) {
for _, f := range files {
found := false
for _, expected := range testCase.resFiles {
exAbs, err := filepath.Abs(expected)
if err != nil {
tester.t.Errorf("filepath.Abs failed for %s", expected)
} else {
if exAbs == f {
found = true
break
}
}
}
if !found {
tester.t.Errorf("unexpected file: %v", f)
}
}
}

View File

@ -0,0 +1,65 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"testing"
)
func TestformattedWriter(t *testing.T) {
formatStr := "%Level %LEVEL %Msg"
message := "message"
var logLevel = LogLevel(TraceLvl)
bytesVerifier, err := newBytesVerifier(t)
if err != nil {
t.Error(err)
return
}
formatter, err := NewFormatter(formatStr)
if err != nil {
t.Error(err)
return
}
writer, err := NewFormattedWriter(bytesVerifier, formatter)
if err != nil {
t.Error(err)
return
}
context, err := currentContext(nil)
if err != nil {
t.Error(err)
return
}
logMessage := formatter.Format(message, logLevel, context)
bytesVerifier.ExpectBytes([]byte(logMessage))
writer.Write(message, logLevel, context)
bytesVerifier.MustNotExpect()
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"fmt"
"io"
"testing"
)
// fileWriterTestCase is declared in writers_filewriter_test.go
func createRollingSizeFileWriterTestCase(
files []string,
fileName string,
fileSize int64,
maxRolls int,
writeCount int,
resFiles []string,
nameMode rollingNameMode) *fileWriterTestCase {
return &fileWriterTestCase{files, fileName, rollingTypeSize, fileSize, maxRolls, "", writeCount, resFiles, nameMode}
}
func createRollingDatefileWriterTestCase(
files []string,
fileName string,
datePattern string,
writeCount int,
resFiles []string,
nameMode rollingNameMode) *fileWriterTestCase {
return &fileWriterTestCase{files, fileName, rollingTypeTime, 0, 0, datePattern, writeCount, resFiles, nameMode}
}
func TestRollingFileWriter(t *testing.T) {
t.Logf("Starting rolling file writer tests")
NewFileWriterTester(rollingfileWriterTests, rollingFileWriterGetter, t).test()
}
//===============================================================
func rollingFileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, error) {
if testCase.rollingType == rollingTypeSize {
return NewRollingFileWriterSize(testCase.fileName, rollingArchiveNone, "", testCase.fileSize, testCase.maxRolls, testCase.nameMode)
} else if testCase.rollingType == rollingTypeTime {
return NewRollingFileWriterTime(testCase.fileName, rollingArchiveNone, "", -1, testCase.datePattern, rollingIntervalDaily, testCase.nameMode)
}
return nil, fmt.Errorf("incorrect rollingType")
}
//===============================================================
var rollingfileWriterTests = []*fileWriterTestCase{
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 1, []string{"log.testlog"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{"1.log.testlog"}, "log.testlog", 10, 10, 2, []string{"log.testlog", "1.log.testlog", "2.log.testlog"}, rollingNameModePrefix),
createRollingSizeFileWriterTestCase([]string{"log.testlog.1"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.2"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{"log.testlog.9"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.10"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{"log.testlog.a", "log.testlog.1b"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.1", "log.testlog.a", "log.testlog.1b"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 10, 2, []string{`dir/log.testlog`, `dir/1.log.testlog`}, rollingNameModePrefix),
createRollingSizeFileWriterTestCase([]string{`dir/dir/log.testlog.1`}, `dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, `dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{`dir/dir/dir/log.testlog.1`}, `dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, `dir/dir/dir/log.testlog.2`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `./log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, `log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{"dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, []string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", "dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 10, 10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 10, 10, 2, []string{`dir/log.testlog`, `dir/log.testlog.1`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{`././dir/dir/log.testlog.1`}, `dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, `dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{`././dir/dir/dir/log.testlog.1`}, `dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, `dir/dir/dir/log.testlog.2`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{}, `././log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, `log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, rollingNameModePostfix),
createRollingSizeFileWriterTestCase([]string{"././dir/dir/log.testlog.a", "././dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, []string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", "dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix),
// ====================
}

22
vendor/github.com/davecgh/go-spew/.gitignore generated vendored Normal file
View File

@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

14
vendor/github.com/davecgh/go-spew/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- 1.5.4
- 1.6.3
- 1.7
install:
- go get -v golang.org/x/tools/cmd/cover
script:
- go test -v -tags=safe ./spew
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
after_success:
- go get -v github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin
- goveralls -coverprofile=profile.cov -service=travis-ci

15
vendor/github.com/davecgh/go-spew/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

205
vendor/github.com/davecgh/go-spew/README.md generated vendored Normal file
View File

@ -0,0 +1,205 @@
go-spew
=======
[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)]
(https://travis-ci.org/davecgh/go-spew) [![ISC License]
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
(https://coveralls.io/r/davecgh/go-spew?branch=master)
Go-spew implements a deep pretty printer for Go data structures to aid in
debugging. A comprehensive suite of tests with 100% test coverage is provided
to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
report. Go-spew is licensed under the liberal ISC license, so it may be used in
open source or commercial projects.
If you're interested in reading about how this package came to life and some
of the challenges involved in providing a deep pretty printer, there is a blog
post about it
[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
## Documentation
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
(http://godoc.org/github.com/davecgh/go-spew/spew)
Full `go doc` style documentation for the project can be viewed online without
installing this package by using the excellent GoDoc site here:
http://godoc.org/github.com/davecgh/go-spew/spew
You can also view the documentation locally once the package is installed with
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
## Installation
```bash
$ go get -u github.com/davecgh/go-spew/spew
```
## Quick Start
Add this import line to the file you're working in:
```Go
import "github.com/davecgh/go-spew/spew"
```
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
```Go
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
```
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
and pointer addresses):
```Go
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
```
## Debugging a Web Application Example
Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
```Go
package main
import (
"fmt"
"html"
"net/http"
"github.com/davecgh/go-spew/spew"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
fmt.Fprintf(w, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
```
## Sample Dump Output
```
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) {
(string) "one": (bool) true
}
}
([]uint8) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
```
## Sample Formatter Output
Double pointer to a uint8:
```
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
```
Pointer to circular struct with a uint8 field and a pointer to itself:
```
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
```
## Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available via the
spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
```
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables. This option
relies on access to the unsafe package, so it will not have any effect when
running in environments without access to the unsafe package such as Google
App Engine or with the "safe" build tag specified.
Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of capacities
for arrays, slices, maps and channels. This is useful when diffing data
structures in tests.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are supported,
with other types sorted according to the reflect.Value.String() output
which guarantees display stability. Natural map order is used by
default.
* SpewKeys
SpewKeys specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only considered
if SortKeys is true.
```
## Unsafe Package Dependency
This package relies on the unsafe package to perform some of the more advanced
features, however it also supports a "limited" mode which allows it to work in
environments where the unsafe package is not available. By default, it will
operate in this mode on Google App Engine and when compiled with GopherJS. The
"safe" build tag may also be specified to force the package to build without
using the unsafe package.
## License
Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.

22
vendor/github.com/davecgh/go-spew/cov_report.sh generated vendored Normal file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# This script uses gocov to generate a test coverage report.
# The gocov tool my be obtained with the following command:
# go get github.com/axw/gocov/gocov
#
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
# Check for gocov.
if ! type gocov >/dev/null 2>&1; then
echo >&2 "This script requires the gocov tool."
echo >&2 "You may obtain it with the following command:"
echo >&2 "go get github.com/axw/gocov/gocov"
exit 1
fi
# Only run the cgo tests if gcc is installed.
if type gcc >/dev/null 2>&1; then
(cd spew && gocov test -tags testcgo | gocov report)
else
(cd spew && gocov test | gocov report)
fi

152
vendor/github.com/davecgh/go-spew/spew/bypass.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
}
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe
package spew
import "reflect"
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = true
)
// unsafeReflectValue typically converts the passed reflect.Value into a one
// that bypasses the typical safety restrictions preventing access to
// unaddressable and unexported data. However, doing this relies on access to
// the unsafe package. This is a stub version which simply returns the passed
// reflect.Value when the unsafe package is not available.
func unsafeReflectValue(v reflect.Value) reflect.Value {
return v
}

341
vendor/github.com/davecgh/go-spew/spew/common.go generated vendored Normal file
View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"reflect"
"sort"
"strconv"
)
// Some constants in the form of bytes to avoid string overhead. This mirrors
// the technique used in the fmt package.
var (
panicBytes = []byte("(PANIC=")
plusBytes = []byte("+")
iBytes = []byte("i")
trueBytes = []byte("true")
falseBytes = []byte("false")
interfaceBytes = []byte("(interface {})")
commaNewlineBytes = []byte(",\n")
newlineBytes = []byte("\n")
openBraceBytes = []byte("{")
openBraceNewlineBytes = []byte("{\n")
closeBraceBytes = []byte("}")
asteriskBytes = []byte("*")
colonBytes = []byte(":")
colonSpaceBytes = []byte(": ")
openParenBytes = []byte("(")
closeParenBytes = []byte(")")
spaceBytes = []byte(" ")
pointerChainBytes = []byte("->")
nilAngleBytes = []byte("<nil>")
maxNewlineBytes = []byte("<max depth reached>\n")
maxShortBytes = []byte("<max>")
circularBytes = []byte("<already shown>")
circularShortBytes = []byte("<shown>")
invalidAngleBytes = []byte("<invalid>")
openBracketBytes = []byte("[")
closeBracketBytes = []byte("]")
percentBytes = []byte("%")
precisionBytes = []byte(".")
openAngleBytes = []byte("<")
closeAngleBytes = []byte(">")
openMapBytes = []byte("map[")
closeMapBytes = []byte("]")
lenEqualsBytes = []byte("len=")
capEqualsBytes = []byte("cap=")
)
// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"
// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
if err := recover(); err != nil {
w.Write(panicBytes)
fmt.Fprintf(w, "%v", err)
w.Write(closeParenBytes)
}
}
// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
// We need an interface to check if the type implements the error or
// Stringer interface. However, the reflect package won't give us an
// interface on certain things like unexported struct fields in order
// to enforce visibility rules. We use unsafe, when it's available,
// to bypass these restrictions since this package does not mutate the
// values.
if !v.CanInterface() {
if UnsafeDisabled {
return false
}
v = unsafeReflectValue(v)
}
// Choose whether or not to do error and Stringer interface lookups against
// the base type or a pointer to the base type depending on settings.
// Technically calling one of these methods with a pointer receiver can
// mutate the value, however, types which choose to satisify an error or
// Stringer interface with a pointer receiver should not be mutating their
// state inside these interface methods.
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
v = unsafeReflectValue(v)
}
if v.CanAddr() {
v = v.Addr()
}
// Is it an error or Stringer?
switch iface := v.Interface().(type) {
case error:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.Error()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.Error()))
return true
case fmt.Stringer:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.String()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.String()))
return true
}
return false
}
// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
if val {
w.Write(trueBytes)
} else {
w.Write(falseBytes)
}
}
// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
w.Write([]byte(strconv.FormatInt(val, base)))
}
// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
w.Write([]byte(strconv.FormatUint(val, base)))
}
// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}
// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
r := real(c)
w.Write(openParenBytes)
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
i := imag(c)
if i >= 0 {
w.Write(plusBytes)
}
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
w.Write(iBytes)
w.Write(closeParenBytes)
}
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
num := uint64(p)
if num == 0 {
w.Write(nilAngleBytes)
return
}
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
buf := make([]byte, 18)
// It's simpler to construct the hex string right to left.
base := uint64(16)
i := len(buf) - 1
for num >= base {
buf[i] = hexDigits[num%base]
num /= base
i--
}
buf[i] = hexDigits[num]
// Add '0x' prefix.
i--
buf[i] = 'x'
i--
buf[i] = '0'
// Strip unused leading bytes.
buf = buf[i:]
w.Write(buf)
}
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
values []reflect.Value
strings []string // either nil or same len and values
cs *ConfigState
}
// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted. It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
vs := &valuesSorter{values: values, cs: cs}
if canSortSimply(vs.values[0].Kind()) {
return vs
}
if !cs.DisableMethods {
vs.strings = make([]string, len(values))
for i := range vs.values {
b := bytes.Buffer{}
if !handleMethods(cs, &b, vs.values[i]) {
vs.strings = nil
break
}
vs.strings[i] = b.String()
}
}
if vs.strings == nil && cs.SpewKeys {
vs.strings = make([]string, len(values))
for i := range vs.values {
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
}
}
return vs
}
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
// This switch parallels valueSortLess, except for the default case.
switch kind {
case reflect.Bool:
return true
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Uintptr:
return true
case reflect.Array:
return true
}
return false
}
// Len returns the number of values in the slice. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
return len(s.values)
}
// Swap swaps the values at the passed indices. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
s.values[i], s.values[j] = s.values[j], s.values[i]
if s.strings != nil {
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
}
}
// valueSortLess returns whether the first value should sort before the second
// value. It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Bool:
return !a.Bool() && b.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return a.Int() < b.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return a.Uint() < b.Uint()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.String:
return a.String() < b.String()
case reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Array:
// Compare the contents of both arrays.
l := a.Len()
for i := 0; i < l; i++ {
av := a.Index(i)
bv := b.Index(i)
if av.Interface() == bv.Interface() {
continue
}
return valueSortLess(av, bv)
}
}
return a.String() < b.String()
}
// Less returns whether the value at index i should sort before the
// value at index j. It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
if s.strings == nil {
return valueSortLess(s.values[i], s.values[j])
}
return s.strings[i] < s.strings[j]
}
// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer. Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
if len(values) == 0 {
return
}
sort.Sort(newValuesSorter(values, cs))
}

298
vendor/github.com/davecgh/go-spew/spew/common_test.go generated vendored Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// custom type to test Stinger interface on non-pointer receiver.
type stringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with non-pointer receivers.
func (s stringer) String() string {
return "stringer " + string(s)
}
// custom type to test Stinger interface on pointer receiver.
type pstringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with only pointer receivers.
func (s *pstringer) String() string {
return "stringer " + string(*s)
}
// xref1 and xref2 are cross referencing structs for testing circular reference
// detection.
type xref1 struct {
ps2 *xref2
}
type xref2 struct {
ps1 *xref1
}
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
// reference for testing detection.
type indirCir1 struct {
ps2 *indirCir2
}
type indirCir2 struct {
ps3 *indirCir3
}
type indirCir3 struct {
ps1 *indirCir1
}
// embed is used to test embedded structures.
type embed struct {
a string
}
// embedwrap is used to test embedded structures.
type embedwrap struct {
*embed
e *embed
}
// panicer is used to intentionally cause a panic for testing spew properly
// handles them
type panicer int
func (p panicer) String() string {
panic("test panic")
}
// customError is used to test custom error interface invocation.
type customError int
func (e customError) Error() string {
return fmt.Sprintf("error: %d", int(e))
}
// stringizeWants converts a slice of wanted test output into a format suitable
// for a test error message.
func stringizeWants(wants []string) string {
s := ""
for i, want := range wants {
if i > 0 {
s += fmt.Sprintf("want%d: %s", i+1, want)
} else {
s += "want: " + want
}
}
return s
}
// testFailed returns whether or not a test failed by checking if the result
// of the test is in the slice of wanted strings.
func testFailed(result string, wants []string) bool {
for _, want := range wants {
if result == want {
return false
}
}
return true
}
type sortableStruct struct {
x int
}
func (ss sortableStruct) String() string {
return fmt.Sprintf("ss.%d", ss.x)
}
type unsortableStruct struct {
x int
}
type sortTestCase struct {
input []reflect.Value
expected []reflect.Value
}
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
getInterfaces := func(values []reflect.Value) []interface{} {
interfaces := []interface{}{}
for _, v := range values {
interfaces = append(interfaces, v.Interface())
}
return interfaces
}
for _, test := range tests {
spew.SortValues(test.input, cs)
// reflect.DeepEqual cannot really make sense of reflect.Value,
// probably because of all the pointer tricks. For instance,
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
// instead.
input := getInterfaces(test.input)
expected := getInterfaces(test.expected)
if !reflect.DeepEqual(input, expected) {
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
}
}
}
// TestSortValues ensures the sort functionality for relect.Value based sorting
// works as intended.
func TestSortValues(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
embedA := v(embed{"a"})
embedB := v(embed{"b"})
embedC := v(embed{"c"})
tests := []sortTestCase{
// No values.
{
[]reflect.Value{},
[]reflect.Value{},
},
// Bools.
{
[]reflect.Value{v(false), v(true), v(false)},
[]reflect.Value{v(false), v(false), v(true)},
},
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Uints.
{
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
},
// Floats.
{
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// Array
{
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
},
// Uintptrs.
{
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
},
// SortableStructs.
{
// Note: not sorted - DisableMethods is set.
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
// Invalid.
{
[]reflect.Value{embedB, embedA, embedC},
[]reflect.Value{embedB, embedA, embedC},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
// based sorting works as intended when using string methods.
func TestSortValuesWithMethods(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
// based sorting works as intended when using spew to stringify keys.
func TestSortValuesWithSpew(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
helpTestSortValues(tests, &cs, t)
}

306
vendor/github.com/davecgh/go-spew/spew/config.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"os"
)
// ConfigState houses the configuration options used by spew to format and
// display values. There is a global instance, Config, that is used to control
// all top-level Formatter and Dump functionality. Each ConfigState instance
// provides methods equivalent to the top-level functions.
//
// The zero value for ConfigState provides no indentation. You would typically
// want to set it to a space or a tab.
//
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
// with default settings. See the documentation of NewDefaultConfig for default
// values.
type ConfigState struct {
// Indent specifies the string to use for each indentation level. The
// global config instance that all top-level functions use set this to a
// single space by default. If you would like more indentation, you might
// set this to a tab with "\t" or perhaps two spaces with " ".
Indent string
// MaxDepth controls the maximum number of levels to descend into nested
// data structures. The default, 0, means there is no limit.
//
// NOTE: Circular data structures are properly detected, so it is not
// necessary to set this value unless you specifically want to limit deeply
// nested data structures.
MaxDepth int
// DisableMethods specifies whether or not error and Stringer interfaces are
// invoked for types that implement them.
DisableMethods bool
// DisablePointerMethods specifies whether or not to check for and invoke
// error and Stringer interfaces on types which only accept a pointer
// receiver when the current type is not a pointer.
//
// NOTE: This might be an unsafe action since calling one of these methods
// with a pointer receiver could technically mutate the value, however,
// in practice, types which choose to satisify an error or Stringer
// interface with a pointer receiver should not be mutating their state
// inside these interface methods. As a result, this option relies on
// access to the unsafe package, so it will not have any effect when
// running in environments without access to the unsafe package such as
// Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool
// DisablePointerAddresses specifies whether to disable the printing of
// pointer addresses. This is useful when diffing data structures in tests.
DisablePointerAddresses bool
// DisableCapacities specifies whether to disable the printing of capacities
// for arrays, slices, maps and channels. This is useful when diffing
// data structures in tests.
DisableCapacities bool
// ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer
// interface and return immediately instead of continuing to recurse into
// the internals of the data type.
//
// NOTE: This flag does not have any effect if method invocation is disabled
// via the DisableMethods or DisablePointerMethods options.
ContinueOnMethod bool
// SortKeys specifies map keys should be sorted before being printed. Use
// this to have a more deterministic, diffable output. Note that only
// native types (bool, int, uint, floats, uintptr and string) and types
// that support the error or Stringer interfaces (if methods are
// enabled) are supported, with other types sorted according to the
// reflect.Value.String() output which guarantees display stability.
SortKeys bool
// SpewKeys specifies that, as a last resort attempt, map keys should
// be spewed to strings and sorted by those strings. This is only
// considered if SortKeys is true.
SpewKeys bool
}
// Config is the active configuration of the top-level functions.
// The configuration can be changed by modifying the contents of spew.Config.
var Config = ConfigState{Indent: " "}
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the formatted string as a value that satisfies error. See NewFormatter
// for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, c.convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, c.convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, c.convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a Formatter interface returned by c.NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, c.convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
return fmt.Print(c.convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, c.convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
return fmt.Println(c.convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprint(a ...interface{}) string {
return fmt.Sprint(c.convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, c.convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a Formatter interface returned by c.NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintln(a ...interface{}) string {
return fmt.Sprintln(c.convertArgs(a)...)
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
c.Printf, c.Println, or c.Printf.
*/
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(c, v)
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
fdump(c, w, a...)
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by modifying the public members
of c. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func (c *ConfigState) Dump(a ...interface{}) {
fdump(c, os.Stdout, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func (c *ConfigState) Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(c, &buf, a...)
return buf.String()
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a spew Formatter interface using
// the ConfigState associated with s.
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = newFormatter(c, arg)
}
return formatters
}
// NewDefaultConfig returns a ConfigState with the following default settings.
//
// Indent: " "
// MaxDepth: 0
// DisableMethods: false
// DisablePointerMethods: false
// ContinueOnMethod: false
// SortKeys: false
func NewDefaultConfig() *ConfigState {
return &ConfigState{Indent: " "}
}

211
vendor/github.com/davecgh/go-spew/spew/doc.go generated vendored Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Package spew implements a deep pretty printer for Go data structures to aid in
debugging.
A quick overview of the additional features spew provides over the built-in
printing facilities for Go data types are as follows:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output (only when using
Dump style)
There are two different approaches spew allows for dumping Go data structures:
* Dump style which prints with newlines, customizable indentation,
and additional debug information such as types and all pointer addresses
used to indirect to the final value
* A custom Formatter interface that integrates cleanly with the standard fmt
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
similar to the default %v while providing the additional functionality
outlined above and passing unsupported format verbs such as %x and %q
along to fmt
Quick Start
This section demonstrates how to quickly get started with spew. See the
sections below for further details on formatting and configuration options.
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
%#+v (adds types and pointer addresses):
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available
via the spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
The following configuration options are available:
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of
capacities for arrays, slices, maps and channels. This is useful when
diffing data structures in tests.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are
supported with other types sorted according to the
reflect.Value.String() output which guarantees display
stability. Natural map order is used by default.
* SpewKeys
Specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only
considered if SortKeys is true.
Dump Usage
Simply call spew.Dump with a list of variables you want to dump:
spew.Dump(myVar1, myVar2, ...)
You may also call spew.Fdump if you would prefer to output to an arbitrary
io.Writer. For example, to dump to standard error:
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
A third option is to call spew.Sdump to get the formatted output as a string:
str := spew.Sdump(myVar1, myVar2, ...)
Sample Dump Output
See the Dump example for details on the setup of the types and variables being
shown here.
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) (len=1) {
(string) (len=3) "one": (bool) true
}
}
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
command as shown.
([]uint8) (len=32 cap=32) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
Custom Formatter
Spew provides a custom formatter that implements the fmt.Formatter interface
so that it integrates cleanly with standard fmt package printing functions. The
formatter is useful for inline printing of smaller data types similar to the
standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Custom Formatter Usage
The simplest way to make use of the spew custom formatter is to call one of the
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
functions have syntax you are most likely already familiar with:
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Println(myVar, myVar2)
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
See the Index for the full list convenience functions.
Sample Formatter Output
Double pointer to a uint8:
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
Pointer to circular struct with a uint8 field and a pointer to itself:
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
See the Printf example for details on the setup of variables being shown
here.
Errors
Since it is possible for custom Stringer/error interfaces to panic, spew
detects them and handles them internally by printing the panic information
inline with the output. Since spew is intended to provide deep pretty printing
capabilities on structures, it intentionally does not return any errors.
*/
package spew

509
vendor/github.com/davecgh/go-spew/spew/dump.go generated vendored Normal file
View File

@ -0,0 +1,509 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"reflect"
"regexp"
"strconv"
"strings"
)
var (
// uint8Type is a reflect.Type representing a uint8. It is used to
// convert cgo types to uint8 slices for hexdumping.
uint8Type = reflect.TypeOf(uint8(0))
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
)
// dumpState contains information about the state of a dump operation.
type dumpState struct {
w io.Writer
depth int
pointers map[uintptr]int
ignoreNextType bool
ignoreNextIndent bool
cs *ConfigState
}
// indent performs indentation according to the depth level and cs.Indent
// option.
func (d *dumpState) indent() {
if d.ignoreNextIndent {
d.ignoreNextIndent = false
return
}
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
}
// unpackValue returns values inside of non-nil interfaces when possible.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface && !v.IsNil() {
v = v.Elem()
}
return v
}
// dumpPtr handles formatting of pointers by indirecting them as necessary.
func (d *dumpState) dumpPtr(v reflect.Value) {
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range d.pointers {
if depth >= d.depth {
delete(d.pointers, k)
}
}
// Keep list of all dereferenced pointers to show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by dereferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
cycleFound = true
indirects--
break
}
d.pointers[addr] = d.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type information.
d.w.Write(openParenBytes)
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
d.w.Write([]byte(ve.Type().String()))
d.w.Write(closeParenBytes)
// Display pointer information.
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
d.w.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
d.w.Write(pointerChainBytes)
}
printHexPtr(d.w, addr)
}
d.w.Write(closeParenBytes)
}
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound == true:
d.w.Write(nilAngleBytes)
case cycleFound == true:
d.w.Write(circularBytes)
default:
d.ignoreNextType = true
d.dump(ve)
}
d.w.Write(closeParenBytes)
}
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
// reflection) arrays and slices are dumped in hexdump -C fashion.
func (d *dumpState) dumpSlice(v reflect.Value) {
// Determine whether this type should be hex dumped or not. Also,
// for types which should be hexdumped, try to use the underlying data
// first, then fall back to trying to convert them to a uint8 slice.
var buf []uint8
doConvert := false
doHexDump := false
numEntries := v.Len()
if numEntries > 0 {
vt := v.Index(0).Type()
vts := vt.String()
switch {
// C types that need to be converted.
case cCharRE.MatchString(vts):
fallthrough
case cUnsignedCharRE.MatchString(vts):
fallthrough
case cUint8tCharRE.MatchString(vts):
doConvert = true
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
// We need an addressable interface to convert the type
// to a byte slice. However, the reflect package won't
// give us an interface on certain things like
// unexported struct fields in order to enforce
// visibility rules. We use unsafe, when available, to
// bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
if !UnsafeDisabled {
vs = vs.Slice(0, numEntries)
// Use the existing uint8 slice if it can be
// type asserted.
iface := vs.Interface()
if slice, ok := iface.([]uint8); ok {
buf = slice
doHexDump = true
break
}
}
// The underlying data needs to be converted if it can't
// be type asserted to a uint8 slice.
doConvert = true
}
// Copy and convert the underlying type if needed.
if doConvert && vt.ConvertibleTo(uint8Type) {
// Convert and copy each element into a uint8 byte
// slice.
buf = make([]uint8, numEntries)
for i := 0; i < numEntries; i++ {
vv := v.Index(i)
buf[i] = uint8(vv.Convert(uint8Type).Uint())
}
doHexDump = true
}
}
// Hexdump the entire slice as needed.
if doHexDump {
indent := strings.Repeat(d.cs.Indent, d.depth)
str := indent + hex.Dump(buf)
str = strings.Replace(str, "\n", "\n"+indent, -1)
str = strings.TrimRight(str, d.cs.Indent)
d.w.Write([]byte(str))
return
}
// Recursively call dump for each item.
for i := 0; i < numEntries; i++ {
d.dump(d.unpackValue(v.Index(i)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
// dump is the main workhorse for dumping a value. It uses the passed reflect
// value to figure out what kind of object we are dealing with and formats it
// appropriately. It is a recursive function, however circular data structures
// are detected and handled properly.
func (d *dumpState) dump(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
d.w.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
d.indent()
d.dumpPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !d.ignoreNextType {
d.indent()
d.w.Write(openParenBytes)
d.w.Write([]byte(v.Type().String()))
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
d.ignoreNextType = false
// Display length and capacity if the built-in len and cap functions
// work with the value's kind and the len/cap itself is non-zero.
valueLen, valueCap := 0, 0
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Chan:
valueLen, valueCap = v.Len(), v.Cap()
case reflect.Map, reflect.String:
valueLen = v.Len()
}
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
if !d.cs.DisableCapacities && valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
d.w.Write(capEqualsBytes)
printInt(d.w, int64(valueCap), 10)
}
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
// Call Stringer/error interfaces if they exist and the handle methods flag
// is enabled
if !d.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(d.cs, d.w, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(d.w, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(d.w, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(d.w, v.Uint(), 10)
case reflect.Float32:
printFloat(d.w, v.Float(), 32)
case reflect.Float64:
printFloat(d.w, v.Float(), 64)
case reflect.Complex64:
printComplex(d.w, v.Complex(), 32)
case reflect.Complex128:
printComplex(d.w, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
d.dumpSlice(v)
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.String:
d.w.Write([]byte(strconv.Quote(v.String())))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
d.w.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
numEntries := v.Len()
keys := v.MapKeys()
if d.cs.SortKeys {
sortValues(keys, d.cs)
}
for i, key := range keys {
d.dump(d.unpackValue(key))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.MapIndex(key)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Struct:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
d.indent()
vtf := vt.Field(i)
d.w.Write([]byte(vtf.Name))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.Field(i)))
if i < (numFields - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(d.w, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(d.w, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it in case any new
// types are added.
default:
if v.CanInterface() {
fmt.Fprintf(d.w, "%v", v.Interface())
} else {
fmt.Fprintf(d.w, "%v", v.String())
}
}
}
// fdump is a helper function to consolidate the logic from the various public
// methods which take varying writers and config states.
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
w.Write(spaceBytes)
w.Write(nilAngleBytes)
w.Write(newlineBytes)
continue
}
d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
d.w.Write(newlineBytes)
}
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func Fdump(w io.Writer, a ...interface{}) {
fdump(&Config, w, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(&Config, &buf, a...)
return buf.String()
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by an exported package global,
spew.Config. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func Dump(a ...interface{}) {
fdump(&Config, os.Stdout, a...)
}

1042
vendor/github.com/davecgh/go-spew/spew/dump_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

99
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This means the cgo tests are only added (and hence run) when
// specifially requested. This configuration is used because spew itself
// does not require cgo to run even though it does handle certain cgo types
// specially. Rather than forcing all clients to require cgo and an external
// C compiler just to run the tests, this scheme makes them optional.
// +build cgo,testcgo
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew/testdata"
)
func addCgoDumpTests() {
// C char pointer.
v := testdata.GetCgoCharPointer()
nv := testdata.GetCgoNullCharPointer()
pv := &v
vcAddr := fmt.Sprintf("%p", v)
vAddr := fmt.Sprintf("%p", pv)
pvAddr := fmt.Sprintf("%p", &pv)
vt := "*testdata._Ctype_char"
vs := "116"
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(nv, "("+vt+")(<nil>)\n")
// C char array.
v2, v2l, v2c := testdata.GetCgoCharArray()
v2Len := fmt.Sprintf("%d", v2l)
v2Cap := fmt.Sprintf("%d", v2c)
v2t := "[6]testdata._Ctype_char"
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
"{\n 00000000 74 65 73 74 32 00 " +
" |test2.|\n}"
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
// C unsigned char array.
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
v3Len := fmt.Sprintf("%d", v3l)
v3Cap := fmt.Sprintf("%d", v3c)
v3t := "[6]testdata._Ctype_unsignedchar"
v3t2 := "[6]testdata._Ctype_uchar"
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
"{\n 00000000 74 65 73 74 33 00 " +
" |test3.|\n}"
addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
// C signed char array.
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
v4Len := fmt.Sprintf("%d", v4l)
v4Cap := fmt.Sprintf("%d", v4c)
v4t := "[6]testdata._Ctype_schar"
v4t2 := "testdata._Ctype_schar"
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
") 0\n}"
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
// C uint8_t array.
v5, v5l, v5c := testdata.GetCgoUint8tArray()
v5Len := fmt.Sprintf("%d", v5l)
v5Cap := fmt.Sprintf("%d", v5c)
v5t := "[6]testdata._Ctype_uint8_t"
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
"{\n 00000000 74 65 73 74 35 00 " +
" |test5.|\n}"
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
// C typedefed unsigned char array.
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
v6Len := fmt.Sprintf("%d", v6l)
v6Cap := fmt.Sprintf("%d", v6c)
v6t := "[6]testdata._Ctype_custom_uchar_t"
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
"{\n 00000000 74 65 73 74 36 00 " +
" |test6.|\n}"
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when either cgo is not supported or "-tags testcgo" is not added to the go
// test command line. This file intentionally does not setup any cgo tests in
// this scenario.
// +build !cgo !testcgo
package spew_test
func addCgoDumpTests() {
// Don't add any tests for cgo since this file is only compiled when
// there should not be any cgo tests.
}

226
vendor/github.com/davecgh/go-spew/spew/example_test.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew"
)
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
// This example demonstrates how to use Dump to dump variables to stdout.
func ExampleDump() {
// The following package level declarations are assumed for this example:
/*
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
*/
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
f := Flag(5)
b := []byte{
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32,
}
// Dump!
spew.Dump(s1, f, b)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Flag) Unknown flag (5)
// ([]uint8) (len=34 cap=34) {
// 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
// 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
// 00000020 31 32 |12|
// }
//
}
// This example demonstrates how to use Printf to display a variable with a
// format string and inline formatting.
func ExamplePrintf() {
// Create a double pointer to a uint 8.
ui8 := uint8(5)
pui8 := &ui8
ppui8 := &pui8
// Create a circular data type.
type circular struct {
ui8 uint8
c *circular
}
c := circular{ui8: 1}
c.c = &c
// Print!
spew.Printf("ppui8: %v\n", ppui8)
spew.Printf("circular: %v\n", c)
// Output:
// ppui8: <**>5
// circular: {1 <*>{1 <*><shown>}}
}
// This example demonstrates how to use a ConfigState.
func ExampleConfigState() {
// Modify the indent level of the ConfigState only. The global
// configuration is not modified.
scs := spew.ConfigState{Indent: "\t"}
// Output using the ConfigState instance.
v := map[string]int{"one": 1}
scs.Printf("v: %v\n", v)
scs.Dump(v)
// Output:
// v: map[one:1]
// (map[string]int) (len=1) {
// (string) (len=3) "one": (int) 1
// }
}
// This example demonstrates how to use ConfigState.Dump to dump variables to
// stdout
func ExampleConfigState_Dump() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances with different indentation.
scs := spew.ConfigState{Indent: "\t"}
scs2 := spew.ConfigState{Indent: " "}
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
// Dump using the ConfigState instances.
scs.Dump(s1)
scs2.Dump(s1)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
//
}
// This example demonstrates how to use ConfigState.Printf to display a variable
// with a format string and inline formatting.
func ExampleConfigState_Printf() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances and modify the method handling of the
// first ConfigState only.
scs := spew.NewDefaultConfig()
scs2 := spew.NewDefaultConfig()
scs.DisableMethods = true
// Alternatively
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
// scs2 := spew.ConfigState{Indent: " "}
// This is of type Flag which implements a Stringer and has raw value 1.
f := flagTwo
// Dump using the ConfigState instances.
scs.Printf("f: %v\n", f)
scs2.Printf("f: %v\n", f)
// Output:
// f: 1
// f: flagTwo
}

419
vendor/github.com/davecgh/go-spew/spew/format.go generated vendored Normal file
View File

@ -0,0 +1,419 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// supportedFlags is a list of all the character flags supported by fmt package.
const supportedFlags = "0-+# "
// formatState implements the fmt.Formatter interface and contains information
// about the state of a formatting operation. The NewFormatter function can
// be used to get a new Formatter which can be used directly as arguments
// in standard fmt package printing calls.
type formatState struct {
value interface{}
fs fmt.State
depth int
pointers map[uintptr]int
ignoreNextType bool
cs *ConfigState
}
// buildDefaultFormat recreates the original format string without precision
// and width information to pass in to fmt.Sprintf in the case of an
// unrecognized type. Unless new types are added to the language, this
// function won't ever be called.
func (f *formatState) buildDefaultFormat() (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
buf.WriteRune('v')
format = buf.String()
return format
}
// constructOrigFormat recreates the original format string including precision
// and width information to pass along to the standard fmt package. This allows
// automatic deferral of all format strings this package doesn't support.
func (f *formatState) constructOrigFormat(verb rune) (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
if width, ok := f.fs.Width(); ok {
buf.WriteString(strconv.Itoa(width))
}
if precision, ok := f.fs.Precision(); ok {
buf.Write(precisionBytes)
buf.WriteString(strconv.Itoa(precision))
}
buf.WriteRune(verb)
format = buf.String()
return format
}
// unpackValue returns values inside of non-nil interfaces when possible and
// ensures that types for values which have been unpacked from an interface
// are displayed when the show types flag is also set.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
f.ignoreNextType = false
if !v.IsNil() {
v = v.Elem()
}
}
return v
}
// formatPtr handles formatting of pointers by indirecting them as necessary.
func (f *formatState) formatPtr(v reflect.Value) {
// Display nil if top level pointer is nil.
showTypes := f.fs.Flag('#')
if v.IsNil() && (!showTypes || f.ignoreNextType) {
f.fs.Write(nilAngleBytes)
return
}
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range f.pointers {
if depth >= f.depth {
delete(f.pointers, k)
}
}
// Keep list of all dereferenced pointers to possibly show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by derferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
cycleFound = true
indirects--
break
}
f.pointers[addr] = f.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type or indirection level depending on flags.
if showTypes && !f.ignoreNextType {
f.fs.Write(openParenBytes)
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
f.fs.Write([]byte(ve.Type().String()))
f.fs.Write(closeParenBytes)
} else {
if nilFound || cycleFound {
indirects += strings.Count(ve.Type().String(), "*")
}
f.fs.Write(openAngleBytes)
f.fs.Write([]byte(strings.Repeat("*", indirects)))
f.fs.Write(closeAngleBytes)
}
// Display pointer information depending on flags.
if f.fs.Flag('+') && (len(pointerChain) > 0) {
f.fs.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
f.fs.Write(pointerChainBytes)
}
printHexPtr(f.fs, addr)
}
f.fs.Write(closeParenBytes)
}
// Display dereferenced value.
switch {
case nilFound == true:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
f.fs.Write(circularShortBytes)
default:
f.ignoreNextType = true
f.format(ve)
}
}
// format is the main workhorse for providing the Formatter interface. It
// uses the passed reflect value to figure out what kind of object we are
// dealing with and formats it appropriately. It is a recursive function,
// however circular data structures are detected and handled properly.
func (f *formatState) format(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
f.fs.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
f.formatPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !f.ignoreNextType && f.fs.Flag('#') {
f.fs.Write(openParenBytes)
f.fs.Write([]byte(v.Type().String()))
f.fs.Write(closeParenBytes)
}
f.ignoreNextType = false
// Call Stringer/error interfaces if they exist and the handle methods
// flag is enabled.
if !f.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(f.cs, f.fs, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(f.fs, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(f.fs, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(f.fs, v.Uint(), 10)
case reflect.Float32:
printFloat(f.fs, v.Float(), 32)
case reflect.Float64:
printFloat(f.fs, v.Float(), 64)
case reflect.Complex64:
printComplex(f.fs, v.Complex(), 32)
case reflect.Complex128:
printComplex(f.fs, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
f.fs.Write(openBracketBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
numEntries := v.Len()
for i := 0; i < numEntries; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(v.Index(i)))
}
}
f.depth--
f.fs.Write(closeBracketBytes)
case reflect.String:
f.fs.Write([]byte(v.String()))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
f.fs.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
f.fs.Write(openMapBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
keys := v.MapKeys()
if f.cs.SortKeys {
sortValues(keys, f.cs)
}
for i, key := range keys {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(key))
f.fs.Write(colonBytes)
f.ignoreNextType = true
f.format(f.unpackValue(v.MapIndex(key)))
}
}
f.depth--
f.fs.Write(closeMapBytes)
case reflect.Struct:
numFields := v.NumField()
f.fs.Write(openBraceBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
vt := v.Type()
for i := 0; i < numFields; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
vtf := vt.Field(i)
if f.fs.Flag('+') || f.fs.Flag('#') {
f.fs.Write([]byte(vtf.Name))
f.fs.Write(colonBytes)
}
f.format(f.unpackValue(v.Field(i)))
}
}
f.depth--
f.fs.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(f.fs, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(f.fs, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it if any get added.
default:
format := f.buildDefaultFormat()
if v.CanInterface() {
fmt.Fprintf(f.fs, format, v.Interface())
} else {
fmt.Fprintf(f.fs, format, v.String())
}
}
}
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
// details.
func (f *formatState) Format(fs fmt.State, verb rune) {
f.fs = fs
// Use standard formatting for verbs that are not v.
if verb != 'v' {
format := f.constructOrigFormat(verb)
fmt.Fprintf(fs, format, f.value)
return
}
if f.value == nil {
if fs.Flag('#') {
fs.Write(interfaceBytes)
}
fs.Write(nilAngleBytes)
return
}
f.format(reflect.ValueOf(f.value))
}
// newFormatter is a helper function to consolidate the logic from the various
// public methods which take varying config states.
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
fs := &formatState{value: v, cs: cs}
fs.pointers = make(map[uintptr]int)
return fs
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
Printf, Println, or Fprintf.
*/
func NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(&Config, v)
}

1558
vendor/github.com/davecgh/go-spew/spew/format_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
)
// dummyFmtState implements a fake fmt.State to use for testing invalid
// reflect.Value handling. This is necessary because the fmt package catches
// invalid values before invoking the formatter on them.
type dummyFmtState struct {
bytes.Buffer
}
func (dfs *dummyFmtState) Flag(f int) bool {
if f == int('+') {
return true
}
return false
}
func (dfs *dummyFmtState) Precision() (int, bool) {
return 0, false
}
func (dfs *dummyFmtState) Width() (int, bool) {
return 0, false
}
// TestInvalidReflectValue ensures the dump and formatter code handles an
// invalid reflect value properly. This needs access to internal state since it
// should never happen in real code and therefore can't be tested via the public
// API.
func TestInvalidReflectValue(t *testing.T) {
i := 1
// Dump invalid reflect value.
v := new(reflect.Value)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(*v)
s := buf.String()
want := "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter invalid reflect value.
buf2 := new(dummyFmtState)
f := formatState{value: *v, cs: &Config, fs: buf2}
f.format(*v)
s = buf2.String()
want = "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
}
}
// SortValues makes the internal sortValues function available to the test
// package.
func SortValues(values []reflect.Value, cs *ConfigState) {
sortValues(values, cs)
}

View File

@ -0,0 +1,102 @@
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
"unsafe"
)
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
// the maximum kind value which does not exist. This is needed to test the
// fallback code which punts to the standard fmt library for new types that
// might get added to the language.
func changeKind(v *reflect.Value, readOnly bool) {
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
if readOnly {
*rvf |= flagRO
} else {
*rvf &= ^uintptr(flagRO)
}
}
// TestAddedReflectValue tests functionaly of the dump and formatter code which
// falls back to the standard fmt library for new types that might get added to
// the language.
func TestAddedReflectValue(t *testing.T) {
i := 1
// Dump using a reflect.Value that is exported.
v := reflect.ValueOf(int8(5))
changeKind(&v, false)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(v)
s := buf.String()
want := "(int8) 5"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Dump using a reflect.Value that is not exported.
changeKind(&v, true)
buf.Reset()
d.dump(v)
s = buf.String()
want = "(int8) <int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is exported.
changeKind(&v, false)
buf2 := new(dummyFmtState)
f := formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "5"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is not exported.
changeKind(&v, true)
buf2.Reset()
f = formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "<int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
}

148
vendor/github.com/davecgh/go-spew/spew/spew.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"fmt"
"io"
)
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the formatted string as a value that satisfies error. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a default Formatter interface returned by NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
func Print(a ...interface{}) (n int, err error) {
return fmt.Print(convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
func Println(a ...interface{}) (n int, err error) {
return fmt.Println(convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprint(a ...interface{}) string {
return fmt.Sprint(convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintln(a ...interface{}) string {
return fmt.Sprintln(convertArgs(a)...)
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a default spew Formatter interface.
func convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = NewFormatter(arg)
}
return formatters
}

320
vendor/github.com/davecgh/go-spew/spew/spew_test.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/davecgh/go-spew/spew"
)
// spewFunc is used to identify which public function of the spew package or
// ConfigState a test applies to.
type spewFunc int
const (
fCSFdump spewFunc = iota
fCSFprint
fCSFprintf
fCSFprintln
fCSPrint
fCSPrintln
fCSSdump
fCSSprint
fCSSprintf
fCSSprintln
fCSErrorf
fCSNewFormatter
fErrorf
fFprint
fFprintln
fPrint
fPrintln
fSdump
fSprint
fSprintf
fSprintln
)
// Map of spewFunc values to names for pretty printing.
var spewFuncStrings = map[spewFunc]string{
fCSFdump: "ConfigState.Fdump",
fCSFprint: "ConfigState.Fprint",
fCSFprintf: "ConfigState.Fprintf",
fCSFprintln: "ConfigState.Fprintln",
fCSSdump: "ConfigState.Sdump",
fCSPrint: "ConfigState.Print",
fCSPrintln: "ConfigState.Println",
fCSSprint: "ConfigState.Sprint",
fCSSprintf: "ConfigState.Sprintf",
fCSSprintln: "ConfigState.Sprintln",
fCSErrorf: "ConfigState.Errorf",
fCSNewFormatter: "ConfigState.NewFormatter",
fErrorf: "spew.Errorf",
fFprint: "spew.Fprint",
fFprintln: "spew.Fprintln",
fPrint: "spew.Print",
fPrintln: "spew.Println",
fSdump: "spew.Sdump",
fSprint: "spew.Sprint",
fSprintf: "spew.Sprintf",
fSprintln: "spew.Sprintln",
}
func (f spewFunc) String() string {
if s, ok := spewFuncStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
}
// spewTest is used to describe a test to be performed against the public
// functions of the spew package or ConfigState.
type spewTest struct {
cs *spew.ConfigState
f spewFunc
format string
in interface{}
want string
}
// spewTests houses the tests to be performed against the public functions of
// the spew package and ConfigState.
//
// These tests are only intended to ensure the public functions are exercised
// and are intentionally not exhaustive of types. The exhaustive type
// tests are handled in the dump and format tests.
var spewTests []spewTest
// redirStdout is a helper function to return the standard output from f as a
// byte slice.
func redirStdout(f func()) ([]byte, error) {
tempFile, err := ioutil.TempFile("", "ss-test")
if err != nil {
return nil, err
}
fileName := tempFile.Name()
defer os.Remove(fileName) // Ignore error
origStdout := os.Stdout
os.Stdout = tempFile
f()
os.Stdout = origStdout
tempFile.Close()
return ioutil.ReadFile(fileName)
}
func initSpewTests() {
// Config states with various settings.
scsDefault := spew.NewDefaultConfig()
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
scsNoCap := &spew.ConfigState{DisableCapacities: true}
// Variables for tests on types which implement Stringer interface with and
// without a pointer receiver.
ts := stringer("test")
tps := pstringer("test")
type ptrTester struct {
s *struct{}
}
tptr := &ptrTester{s: &struct{}{}}
// depthTester is used to test max depth handling for structs, array, slices
// and maps.
type depthTester struct {
ic indirCir1
arr [1]string
slice []string
m map[string]int
}
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
map[string]int{"one": 1}}
// Variable for tests on types which implement error interface.
te := customError(10)
spewTests = []spewTest{
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
{scsDefault, fCSFprint, "", int16(32767), "32767"},
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
{scsDefault, fFprint, "", float32(3.14), "3.14"},
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
{scsDefault, fPrint, "", true, "true"},
{scsDefault, fPrintln, "", false, "false\n"},
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
{scsNoMethods, fCSFprint, "", ts, "test"},
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
{scsNoMethods, fCSFprint, "", tps, "test"},
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
{scsNoPmethods, fCSFprint, "", tps, "test"},
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
"(len=4) (stringer test) \"test\"\n"},
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
"(error: 10) 10\n"},
{scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
{scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
{scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
{scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
}
}
// TestSpew executes all of the tests described by spewTests.
func TestSpew(t *testing.T) {
initSpewTests()
t.Logf("Running %d tests", len(spewTests))
for i, test := range spewTests {
buf := new(bytes.Buffer)
switch test.f {
case fCSFdump:
test.cs.Fdump(buf, test.in)
case fCSFprint:
test.cs.Fprint(buf, test.in)
case fCSFprintf:
test.cs.Fprintf(buf, test.format, test.in)
case fCSFprintln:
test.cs.Fprintln(buf, test.in)
case fCSPrint:
b, err := redirStdout(func() { test.cs.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSPrintln:
b, err := redirStdout(func() { test.cs.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSSdump:
str := test.cs.Sdump(test.in)
buf.WriteString(str)
case fCSSprint:
str := test.cs.Sprint(test.in)
buf.WriteString(str)
case fCSSprintf:
str := test.cs.Sprintf(test.format, test.in)
buf.WriteString(str)
case fCSSprintln:
str := test.cs.Sprintln(test.in)
buf.WriteString(str)
case fCSErrorf:
err := test.cs.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fCSNewFormatter:
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
case fErrorf:
err := spew.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fFprint:
spew.Fprint(buf, test.in)
case fFprintln:
spew.Fprintln(buf, test.in)
case fPrint:
b, err := redirStdout(func() { spew.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fPrintln:
b, err := redirStdout(func() { spew.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fSdump:
str := spew.Sdump(test.in)
buf.WriteString(str)
case fSprint:
str := spew.Sprint(test.in)
buf.WriteString(str)
case fSprintf:
str := spew.Sprintf(test.format, test.in)
buf.WriteString(str)
case fSprintln:
str := spew.Sprintln(test.in)
buf.WriteString(str)
default:
t.Errorf("%v #%d unrecognized function", test.f, i)
continue
}
s := buf.String()
if test.want != s {
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
continue
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This code should really only be in the dumpcgo_test.go file,
// but unfortunately Go will not allow cgo in test files, so this is a
// workaround to allow cgo types to be tested. This configuration is used
// because spew itself does not require cgo to run even though it does handle
// certain cgo types specially. Rather than forcing all clients to require cgo
// and an external C compiler just to run the tests, this scheme makes them
// optional.
// +build cgo,testcgo
package testdata
/*
#include <stdint.h>
typedef unsigned char custom_uchar_t;
char *ncp = 0;
char *cp = "test";
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
*/
import "C"
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
// used for tests.
func GetCgoNullCharPointer() interface{} {
return C.ncp
}
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
// tests.
func GetCgoCharPointer() interface{} {
return C.cp
}
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
// This is only used for tests.
func GetCgoCharArray() (interface{}, int, int) {
return C.ca, len(C.ca), cap(C.ca)
}
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
// array's len and cap. This is only used for tests.
func GetCgoUnsignedCharArray() (interface{}, int, int) {
return C.uca, len(C.uca), cap(C.uca)
}
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
// and cap. This is only used for tests.
func GetCgoSignedCharArray() (interface{}, int, int) {
return C.sca, len(C.sca), cap(C.sca)
}
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
// cap. This is only used for tests.
func GetCgoUint8tArray() (interface{}, int, int) {
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
}
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
// cgo and the array's len and cap. This is only used for tests.
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
return C.tuca, len(C.tuca), cap(C.tuca)
}

61
vendor/github.com/davecgh/go-spew/test_coverage.txt generated vendored Normal file
View File

@ -0,0 +1,61 @@
github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88)
github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82)
github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52)
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44)
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39)
github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30)
github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18)
github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13)
github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12)
github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11)
github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11)
github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10)
github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8)
github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7)
github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5)
github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4)
github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4)
github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4)
github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4)
github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3)
github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3)
github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3)
github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3)
github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3)
github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1)
github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1)
github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1)
github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1)
github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1)
github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1)
github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1)
github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505)

220
vendor/github.com/dustin/go-humanize/bigbytes_test.go generated vendored Normal file
View File

@ -0,0 +1,220 @@
package humanize
import (
"math/big"
"testing"
)
func TestBigByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
{"1,005.03 MB", 1005030000},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBigBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
} else {
if got.Uint64() != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
}
func TestBigByteErrors(t *testing.T) {
got, err := ParseBigBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBigBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
}
func bbyte(in uint64) string {
return BigBytes((&big.Int{}).SetUint64(in))
}
func bibyte(in uint64) string {
return BigIBytes((&big.Int{}).SetUint64(in))
}
func TestBigBytes(t *testing.T) {
testList{
{"bytes(0)", bbyte(0), "0 B"},
{"bytes(1)", bbyte(1), "1 B"},
{"bytes(803)", bbyte(803), "803 B"},
{"bytes(999)", bbyte(999), "999 B"},
{"bytes(1024)", bbyte(1024), "1.0 kB"},
{"bytes(1MB - 1)", bbyte(MByte - Byte), "1000 kB"},
{"bytes(1MB)", bbyte(1024 * 1024), "1.0 MB"},
{"bytes(1GB - 1K)", bbyte(GByte - KByte), "1000 MB"},
{"bytes(1GB)", bbyte(GByte), "1.0 GB"},
{"bytes(1TB - 1M)", bbyte(TByte - MByte), "1000 GB"},
{"bytes(1TB)", bbyte(TByte), "1.0 TB"},
{"bytes(1PB - 1T)", bbyte(PByte - TByte), "999 TB"},
{"bytes(1PB)", bbyte(PByte), "1.0 PB"},
{"bytes(1PB - 1T)", bbyte(EByte - PByte), "999 PB"},
{"bytes(1EB)", bbyte(EByte), "1.0 EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", bibyte(0), "0 B"},
{"bytes(1)", bibyte(1), "1 B"},
{"bytes(803)", bibyte(803), "803 B"},
{"bytes(1023)", bibyte(1023), "1023 B"},
{"bytes(1024)", bibyte(1024), "1.0 KiB"},
{"bytes(1MB - 1)", bibyte(MiByte - IByte), "1024 KiB"},
{"bytes(1MB)", bibyte(1024 * 1024), "1.0 MiB"},
{"bytes(1GB - 1K)", bibyte(GiByte - KiByte), "1024 MiB"},
{"bytes(1GB)", bibyte(GiByte), "1.0 GiB"},
{"bytes(1TB - 1M)", bibyte(TiByte - MiByte), "1024 GiB"},
{"bytes(1TB)", bibyte(TiByte), "1.0 TiB"},
{"bytes(1PB - 1T)", bibyte(PiByte - TiByte), "1023 TiB"},
{"bytes(1PB)", bibyte(PiByte), "1.0 PiB"},
{"bytes(1PB - 1T)", bibyte(EiByte - PiByte), "1023 PiB"},
{"bytes(1EiB)", bibyte(EiByte), "1.0 EiB"},
// Overflows.
// {"bytes(1EB - 1P)", bibyte((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", bibyte(5.5 * GiByte), "5.5 GiB"},
{"bytes(5.5GB)", bbyte(5.5 * GByte), "5.5 GB"},
}.validate(t)
}
func TestVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("15347691069326346944512", 10)
s := BigBytes(b)
if s != "15 ZB" {
t.Errorf("Expected 15 ZB, got %v", s)
}
s = BigIBytes(b)
if s != "13 ZiB" {
t.Errorf("Expected 13 ZiB, got %v", s)
}
b, _ = (&big.Int{}).SetString("15716035654990179271180288", 10)
s = BigBytes(b)
if s != "16 YB" {
t.Errorf("Expected 16 YB, got %v", s)
}
s = BigIBytes(b)
if s != "13 YiB" {
t.Errorf("Expected 13 YiB, got %v", s)
}
}
func TestVeryVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("16093220510709943573688614912", 10)
s := BigBytes(b)
if s != "16093 YB" {
t.Errorf("Expected 16093 YB, got %v", s)
}
s = BigIBytes(b)
if s != "13312 YiB" {
t.Errorf("Expected 13312 YiB, got %v", s)
}
}
func TestParseVeryBig(t *testing.T) {
tests := []struct {
in string
out string
}{
{"16 ZB", "16000000000000000000000"},
{"16 ZiB", "18889465931478580854784"},
{"16.5 ZB", "16500000000000000000000"},
{"16.5 ZiB", "19479761741837286506496"},
{"16 Z", "16000000000000000000000"},
{"16 Zi", "18889465931478580854784"},
{"16.5 Z", "16500000000000000000000"},
{"16.5 Zi", "19479761741837286506496"},
{"16 YB", "16000000000000000000000000"},
{"16 YiB", "19342813113834066795298816"},
{"16.5 YB", "16500000000000000000000000"},
{"16.5 YiB", "19947276023641381382651904"},
{"16 Y", "16000000000000000000000000"},
{"16 Yi", "19342813113834066795298816"},
{"16.5 Y", "16500000000000000000000000"},
{"16.5 Yi", "19947276023641381382651904"},
}
for _, test := range tests {
x, err := ParseBigBytes(test.in)
if err != nil {
t.Errorf("Error parsing %q: %v", test.in, err)
continue
}
if x.String() != test.out {
t.Errorf("Expected %q for %q, got %v", test.out, test.in, x)
}
}
}
func BenchmarkParseBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBigBytes("16.5 Z")
}
}
func BenchmarkBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
bibyte(16.5 * GByte)
}
}

146
vendor/github.com/dustin/go-humanize/bytes_test.go generated vendored Normal file
View File

@ -0,0 +1,146 @@
package humanize
import (
"testing"
)
func TestByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
// Bug #42
{"1,005.03 MB", 1005030000},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
}
if got != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
func TestByteErrors(t *testing.T) {
got, err := ParseBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
got, err = ParseBytes("16 EiB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
}
func TestBytes(t *testing.T) {
testList{
{"bytes(0)", Bytes(0), "0 B"},
{"bytes(1)", Bytes(1), "1 B"},
{"bytes(803)", Bytes(803), "803 B"},
{"bytes(999)", Bytes(999), "999 B"},
{"bytes(1024)", Bytes(1024), "1.0 kB"},
{"bytes(9999)", Bytes(9999), "10 kB"},
{"bytes(1MB - 1)", Bytes(MByte - Byte), "1000 kB"},
{"bytes(1MB)", Bytes(1024 * 1024), "1.0 MB"},
{"bytes(1GB - 1K)", Bytes(GByte - KByte), "1000 MB"},
{"bytes(1GB)", Bytes(GByte), "1.0 GB"},
{"bytes(1TB - 1M)", Bytes(TByte - MByte), "1000 GB"},
{"bytes(10MB)", Bytes(9999 * 1000), "10 MB"},
{"bytes(1TB)", Bytes(TByte), "1.0 TB"},
{"bytes(1PB - 1T)", Bytes(PByte - TByte), "999 TB"},
{"bytes(1PB)", Bytes(PByte), "1.0 PB"},
{"bytes(1PB - 1T)", Bytes(EByte - PByte), "999 PB"},
{"bytes(1EB)", Bytes(EByte), "1.0 EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", IBytes(0), "0 B"},
{"bytes(1)", IBytes(1), "1 B"},
{"bytes(803)", IBytes(803), "803 B"},
{"bytes(1023)", IBytes(1023), "1023 B"},
{"bytes(1024)", IBytes(1024), "1.0 KiB"},
{"bytes(1MB - 1)", IBytes(MiByte - IByte), "1024 KiB"},
{"bytes(1MB)", IBytes(1024 * 1024), "1.0 MiB"},
{"bytes(1GB - 1K)", IBytes(GiByte - KiByte), "1024 MiB"},
{"bytes(1GB)", IBytes(GiByte), "1.0 GiB"},
{"bytes(1TB - 1M)", IBytes(TiByte - MiByte), "1024 GiB"},
{"bytes(1TB)", IBytes(TiByte), "1.0 TiB"},
{"bytes(1PB - 1T)", IBytes(PiByte - TiByte), "1023 TiB"},
{"bytes(1PB)", IBytes(PiByte), "1.0 PiB"},
{"bytes(1PB - 1T)", IBytes(EiByte - PiByte), "1023 PiB"},
{"bytes(1EiB)", IBytes(EiByte), "1.0 EiB"},
// Overflows.
// {"bytes(1EB - 1P)", IBytes((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", IBytes(5.5 * GiByte), "5.5 GiB"},
{"bytes(5.5GB)", Bytes(5.5 * GByte), "5.5 GB"},
}.validate(t)
}
func BenchmarkParseBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBytes("16.5 GB")
}
}
func BenchmarkBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
Bytes(16.5 * GByte)
}
}

145
vendor/github.com/dustin/go-humanize/comma_test.go generated vendored Normal file
View File

@ -0,0 +1,145 @@
package humanize
import (
"math"
"math/big"
"testing"
)
func TestCommas(t *testing.T) {
testList{
{"0", Comma(0), "0"},
{"10", Comma(10), "10"},
{"100", Comma(100), "100"},
{"1,000", Comma(1000), "1,000"},
{"10,000", Comma(10000), "10,000"},
{"100,000", Comma(100000), "100,000"},
{"10,000,000", Comma(10000000), "10,000,000"},
{"10,100,000", Comma(10100000), "10,100,000"},
{"10,010,000", Comma(10010000), "10,010,000"},
{"10,001,000", Comma(10001000), "10,001,000"},
{"123,456,789", Comma(123456789), "123,456,789"},
{"maxint", Comma(9.223372e+18), "9,223,372,000,000,000,000"},
{"math.maxint", Comma(math.MaxInt64), "9,223,372,036,854,775,807"},
{"math.minint", Comma(math.MinInt64), "-9,223,372,036,854,775,808"},
{"minint", Comma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", Comma(-123456789), "-123,456,789"},
{"-10,100,000", Comma(-10100000), "-10,100,000"},
{"-10,010,000", Comma(-10010000), "-10,010,000"},
{"-10,001,000", Comma(-10001000), "-10,001,000"},
{"-10,000,000", Comma(-10000000), "-10,000,000"},
{"-100,000", Comma(-100000), "-100,000"},
{"-10,000", Comma(-10000), "-10,000"},
{"-1,000", Comma(-1000), "-1,000"},
{"-100", Comma(-100), "-100"},
{"-10", Comma(-10), "-10"},
}.validate(t)
}
func TestCommafWithDigits(t *testing.T) {
testList{
{"1.23, 0", CommafWithDigits(1.23, 0), "1"},
{"1.23, 1", CommafWithDigits(1.23, 1), "1.2"},
{"1.23, 2", CommafWithDigits(1.23, 2), "1.23"},
{"1.23, 3", CommafWithDigits(1.23, 3), "1.23"},
}.validate(t)
}
func TestCommafs(t *testing.T) {
testList{
{"0", Commaf(0), "0"},
{"10.11", Commaf(10.11), "10.11"},
{"100", Commaf(100), "100"},
{"1,000", Commaf(1000), "1,000"},
{"10,000", Commaf(10000), "10,000"},
{"100,000", Commaf(100000), "100,000"},
{"834,142.32", Commaf(834142.32), "834,142.32"},
{"10,000,000", Commaf(10000000), "10,000,000"},
{"10,100,000", Commaf(10100000), "10,100,000"},
{"10,010,000", Commaf(10010000), "10,010,000"},
{"10,001,000", Commaf(10001000), "10,001,000"},
{"123,456,789", Commaf(123456789), "123,456,789"},
{"maxf64", Commaf(math.MaxFloat64), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
{"minf64", Commaf(math.SmallestNonzeroFloat64), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"},
{"-123,456,789", Commaf(-123456789), "-123,456,789"},
{"-10,100,000", Commaf(-10100000), "-10,100,000"},
{"-10,010,000", Commaf(-10010000), "-10,010,000"},
{"-10,001,000", Commaf(-10001000), "-10,001,000"},
{"-10,000,000", Commaf(-10000000), "-10,000,000"},
{"-100,000", Commaf(-100000), "-100,000"},
{"-10,000", Commaf(-10000), "-10,000"},
{"-1,000", Commaf(-1000), "-1,000"},
{"-100.11", Commaf(-100.11), "-100.11"},
{"-10", Commaf(-10), "-10"},
}.validate(t)
}
func BenchmarkCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
Comma(1234567890)
}
}
func BenchmarkCommaf(b *testing.B) {
for i := 0; i < b.N; i++ {
Commaf(1234567890.83584)
}
}
func BenchmarkBigCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
BigComma(big.NewInt(1234567890))
}
}
func bigComma(i int64) string {
return BigComma(big.NewInt(i))
}
func TestBigCommas(t *testing.T) {
testList{
{"0", bigComma(0), "0"},
{"10", bigComma(10), "10"},
{"100", bigComma(100), "100"},
{"1,000", bigComma(1000), "1,000"},
{"10,000", bigComma(10000), "10,000"},
{"100,000", bigComma(100000), "100,000"},
{"10,000,000", bigComma(10000000), "10,000,000"},
{"10,100,000", bigComma(10100000), "10,100,000"},
{"10,010,000", bigComma(10010000), "10,010,000"},
{"10,001,000", bigComma(10001000), "10,001,000"},
{"123,456,789", bigComma(123456789), "123,456,789"},
{"maxint", bigComma(9.223372e+18), "9,223,372,000,000,000,000"},
{"minint", bigComma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", bigComma(-123456789), "-123,456,789"},
{"-10,100,000", bigComma(-10100000), "-10,100,000"},
{"-10,010,000", bigComma(-10010000), "-10,010,000"},
{"-10,001,000", bigComma(-10001000), "-10,001,000"},
{"-10,000,000", bigComma(-10000000), "-10,000,000"},
{"-100,000", bigComma(-100000), "-100,000"},
{"-10,000", bigComma(-10000), "-10,000"},
{"-1,000", bigComma(-1000), "-1,000"},
{"-100", bigComma(-100), "-100"},
{"-10", bigComma(-10), "-10"},
}.validate(t)
}
func TestVeryBigCommas(t *testing.T) {
tests := []struct{ in, exp string }{
{
"84889279597249724975972597249849757294578485",
"84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
{
"-84889279597249724975972597249849757294578485",
"-84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
}
for _, test := range tests {
n, _ := (&big.Int{}).SetString(test.in, 10)
got := BigComma(n)
if test.exp != got {
t.Errorf("Expected %q, got %q", test.exp, got)
}
}
}

44
vendor/github.com/dustin/go-humanize/commaf_test.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// +build go1.6
package humanize
import (
"math"
"math/big"
"testing"
)
func BenchmarkBigCommaf(b *testing.B) {
for i := 0; i < b.N; i++ {
Commaf(1234567890.83584)
}
}
func TestBigCommafs(t *testing.T) {
testList{
{"0", BigCommaf(big.NewFloat(0)), "0"},
{"10.11", BigCommaf(big.NewFloat(10.11)), "10.11"},
{"100", BigCommaf(big.NewFloat(100)), "100"},
{"1,000", BigCommaf(big.NewFloat(1000)), "1,000"},
{"10,000", BigCommaf(big.NewFloat(10000)), "10,000"},
{"100,000", BigCommaf(big.NewFloat(100000)), "100,000"},
{"834,142.32", BigCommaf(big.NewFloat(834142.32)), "834,142.32"},
{"10,000,000", BigCommaf(big.NewFloat(10000000)), "10,000,000"},
{"10,100,000", BigCommaf(big.NewFloat(10100000)), "10,100,000"},
{"10,010,000", BigCommaf(big.NewFloat(10010000)), "10,010,000"},
{"10,001,000", BigCommaf(big.NewFloat(10001000)), "10,001,000"},
{"123,456,789", BigCommaf(big.NewFloat(123456789)), "123,456,789"},
{"maxf64", BigCommaf(big.NewFloat(math.MaxFloat64)), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
{"minf64", BigCommaf(big.NewFloat(math.SmallestNonzeroFloat64)), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465"},
{"-123,456,789", BigCommaf(big.NewFloat(-123456789)), "-123,456,789"},
{"-10,100,000", BigCommaf(big.NewFloat(-10100000)), "-10,100,000"},
{"-10,010,000", BigCommaf(big.NewFloat(-10010000)), "-10,010,000"},
{"-10,001,000", BigCommaf(big.NewFloat(-10001000)), "-10,001,000"},
{"-10,000,000", BigCommaf(big.NewFloat(-10000000)), "-10,000,000"},
{"-100,000", BigCommaf(big.NewFloat(-100000)), "-100,000"},
{"-10,000", BigCommaf(big.NewFloat(-10000)), "-10,000"},
{"-1,000", BigCommaf(big.NewFloat(-1000)), "-1,000"},
{"-100.11", BigCommaf(big.NewFloat(-100.11)), "-100.11"},
{"-10", BigCommaf(big.NewFloat(-10)), "-10"},
}.validate(t)
}

18
vendor/github.com/dustin/go-humanize/common_test.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package humanize
import (
"testing"
)
type testList []struct {
name, got, exp string
}
func (tl testList) validate(t *testing.T) {
for _, test := range tl {
if test.got != test.exp {
t.Errorf("On %v, expected '%v', but got '%v'",
test.name, test.exp, test.got)
}
}
}

96
vendor/github.com/dustin/go-humanize/english/words.go generated vendored Normal file
View File

@ -0,0 +1,96 @@
// Package english provides utilities to generate more user-friendly English output.
package english
import (
"fmt"
"strings"
)
// These are included because they are common technical terms.
var specialPlurals = map[string]string{
"index": "indices",
"matrix": "matrices",
"vertex": "vertices",
}
var sibilantEndings = []string{"s", "sh", "tch", "x"}
var isVowel = map[byte]bool{
'A': true, 'E': true, 'I': true, 'O': true, 'U': true,
'a': true, 'e': true, 'i': true, 'o': true, 'u': true,
}
// PluralWord builds the plural form of an English word.
// The simple English rules of regular pluralization will be used
// if the plural form is an empty string (i.e. not explicitly given).
// The special cases are not guaranteed to work for strings outside ASCII.
func PluralWord(quantity int, singular, plural string) string {
if quantity == 1 {
return singular
}
if plural != "" {
return plural
}
if plural = specialPlurals[singular]; plural != "" {
return plural
}
// We need to guess what the English plural might be. Keep this
// function simple! It doesn't need to know about every possiblity;
// only regular rules and the most common special cases.
//
// Reference: http://en.wikipedia.org/wiki/English_plural
for _, ending := range sibilantEndings {
if strings.HasSuffix(singular, ending) {
return singular + "es"
}
}
l := len(singular)
if l >= 2 && singular[l-1] == 'o' && !isVowel[singular[l-2]] {
return singular + "es"
}
if l >= 2 && singular[l-1] == 'y' && !isVowel[singular[l-2]] {
return singular[:l-1] + "ies"
}
return singular + "s"
}
// Plural formats an integer and a string into a single pluralized string.
// The simple English rules of regular pluralization will be used
// if the plural form is an empty string (i.e. not explicitly given).
func Plural(quantity int, singular, plural string) string {
return fmt.Sprintf("%d %s", quantity, PluralWord(quantity, singular, plural))
}
// WordSeries converts a list of words into a word series in English.
// It returns a string containing all the given words separated by commas,
// the coordinating conjunction, and a serial comma, as appropriate.
func WordSeries(words []string, conjunction string) string {
switch len(words) {
case 0:
return ""
case 1:
return words[0]
default:
return fmt.Sprintf("%s %s %s", strings.Join(words[:len(words)-1], ", "), conjunction, words[len(words)-1])
}
}
// OxfordWordSeries converts a list of words into a word series in English,
// using an Oxford comma (https://en.wikipedia.org/wiki/Serial_comma). It
// returns a string containing all the given words separated by commas, the
// coordinating conjunction, and a serial comma, as appropriate.
func OxfordWordSeries(words []string, conjunction string) string {
switch len(words) {
case 0:
return ""
case 1:
return words[0]
case 2:
return strings.Join(words, fmt.Sprintf(" %s ", conjunction))
default:
return fmt.Sprintf("%s, %s %s", strings.Join(words[:len(words)-1], ", "), conjunction, words[len(words)-1])
}
}

View File

@ -0,0 +1,94 @@
package english
import (
"testing"
)
func TestPluralWord(t *testing.T) {
tests := []struct {
n int
singular, plural string
want string
}{
{0, "object", "", "objects"},
{1, "object", "", "object"},
{-1, "object", "", "objects"},
{42, "object", "", "objects"},
{2, "vax", "vaxen", "vaxen"},
// special cases
{2, "index", "", "indices"},
// ending in a sibilant sound
{2, "bus", "", "buses"},
{2, "bush", "", "bushes"},
{2, "watch", "", "watches"},
{2, "box", "", "boxes"},
// ending with 'o' preceded by a consonant
{2, "hero", "", "heroes"},
// ending with 'y' preceded by a consonant
{2, "lady", "", "ladies"},
{2, "day", "", "days"},
}
for _, tt := range tests {
if got := PluralWord(tt.n, tt.singular, tt.plural); got != tt.want {
t.Errorf("PluralWord(%d, %q, %q)=%q; want: %q", tt.n, tt.singular, tt.plural, got, tt.want)
}
}
}
func TestPlural(t *testing.T) {
tests := []struct {
n int
singular, plural string
want string
}{
{1, "object", "", "1 object"},
{42, "object", "", "42 objects"},
}
for _, tt := range tests {
if got := Plural(tt.n, tt.singular, tt.plural); got != tt.want {
t.Errorf("Plural(%d, %q, %q)=%q; want: %q", tt.n, tt.singular, tt.plural, got, tt.want)
}
}
}
func TestWordSeries(t *testing.T) {
tests := []struct {
words []string
conjunction string
want string
}{
{[]string{}, "and", ""},
{[]string{"foo"}, "and", "foo"},
{[]string{"foo", "bar"}, "and", "foo and bar"},
{[]string{"foo", "bar", "baz"}, "and", "foo, bar and baz"},
{[]string{"foo", "bar", "baz"}, "or", "foo, bar or baz"},
}
for _, tt := range tests {
if got := WordSeries(tt.words, tt.conjunction); got != tt.want {
t.Errorf("WordSeries(%q, %q)=%q; want: %q", tt.words, tt.conjunction, got, tt.want)
}
}
}
func TestOxfordWordSeries(t *testing.T) {
tests := []struct {
words []string
conjunction string
want string
}{
{[]string{}, "and", ""},
{[]string{"foo"}, "and", "foo"},
{[]string{"foo", "bar"}, "and", "foo and bar"},
{[]string{"foo", "bar", "baz"}, "and", "foo, bar, and baz"},
{[]string{"foo", "bar", "baz"}, "or", "foo, bar, or baz"},
}
for _, tt := range tests {
if got := OxfordWordSeries(tt.words, tt.conjunction); got != tt.want {
t.Errorf("OxfordWordSeries(%q, %q)=%q; want: %q", tt.words, tt.conjunction, got, tt.want)
}
}
}

123
vendor/github.com/dustin/go-humanize/ftoa_test.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
package humanize
import (
"fmt"
"math/rand"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"testing/quick"
)
func TestFtoa(t *testing.T) {
testList{
{"200", Ftoa(200), "200"},
{"2", Ftoa(2), "2"},
{"2.2", Ftoa(2.2), "2.2"},
{"2.02", Ftoa(2.02), "2.02"},
{"200.02", Ftoa(200.02), "200.02"},
}.validate(t)
}
func TestFtoaWithDigits(t *testing.T) {
testList{
{"1.23, 0", FtoaWithDigits(1.23, 0), "1"},
{"1.23, 1", FtoaWithDigits(1.23, 1), "1.2"},
{"1.23, 2", FtoaWithDigits(1.23, 2), "1.23"},
{"1.23, 3", FtoaWithDigits(1.23, 3), "1.23"},
}.validate(t)
}
func TestStripTrailingDigits(t *testing.T) {
err := quick.Check(func(s string, digits int) bool {
stripped := stripTrailingDigits(s, digits)
// A stripped string will always be a prefix of its original string
if !strings.HasPrefix(s, stripped) {
return false
}
if strings.ContainsRune(s, '.') {
// If there is a dot, the part on the left of the dot will never change
a := strings.Split(s, ".")
b := strings.Split(stripped, ".")
if a[0] != b[0] {
return false
}
} else {
// If there's no dot in the input, the output will always be the same as the input.
if stripped != s {
return false
}
}
return true
}, &quick.Config{
MaxCount: 10000,
Values: func(v []reflect.Value, r *rand.Rand) {
rdigs := func(n int) string {
digs := []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
var rv []rune
for i := 0; i < n; i++ {
rv = append(rv, digs[r.Intn(len(digs))])
}
return string(rv)
}
ls := r.Intn(20)
rs := r.Intn(20)
jc := "."
if rs == 0 {
jc = ""
}
s := rdigs(ls) + jc + rdigs(rs)
digits := r.Intn(len(s) + 1)
v[0] = reflect.ValueOf(s)
v[1] = reflect.ValueOf(digits)
},
})
if err != nil {
t.Error(err)
}
}
func BenchmarkFtoaRegexTrailing(b *testing.B) {
trailingZerosRegex := regexp.MustCompile(`\.?0+$`)
b.ResetTimer()
for i := 0; i < b.N; i++ {
trailingZerosRegex.ReplaceAllString("2.00000", "")
trailingZerosRegex.ReplaceAllString("2.0000", "")
trailingZerosRegex.ReplaceAllString("2.000", "")
trailingZerosRegex.ReplaceAllString("2.00", "")
trailingZerosRegex.ReplaceAllString("2.0", "")
trailingZerosRegex.ReplaceAllString("2", "")
}
}
func BenchmarkFtoaFunc(b *testing.B) {
for i := 0; i < b.N; i++ {
stripTrailingZeros("2.00000")
stripTrailingZeros("2.0000")
stripTrailingZeros("2.000")
stripTrailingZeros("2.00")
stripTrailingZeros("2.0")
stripTrailingZeros("2")
}
}
func BenchmarkFmtF(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%f", 2.03584)
}
}
func BenchmarkStrconvF(b *testing.B) {
for i := 0; i < b.N; i++ {
strconv.FormatFloat(2.03584, 'f', 6, 64)
}
}

79
vendor/github.com/dustin/go-humanize/number_test.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package humanize
import (
"math"
"testing"
)
type TestStruct struct {
name string
format string
num float64
formatted string
}
func TestFormatFloat(t *testing.T) {
tests := []TestStruct{
{"default", "", 12345.6789, "12,345.68"},
{"#", "#", 12345.6789, "12345.678900000"},
{"#.", "#.", 12345.6789, "12346"},
{"#,#", "#,#", 12345.6789, "12345,7"},
{"#,##", "#,##", 12345.6789, "12345,68"},
{"#,###", "#,###", 12345.6789, "12345,679"},
{"#,###.", "#,###.", 12345.6789, "12,346"},
{"#,###.##", "#,###.##", 12345.6789, "12,345.68"},
{"#,###.###", "#,###.###", 12345.6789, "12,345.679"},
{"#,###.####", "#,###.####", 12345.6789, "12,345.6789"},
{"#.###,######", "#.###,######", 12345.6789, "12.345,678900"},
{"bug46", "#,###.##", 52746220055.92342, "52,746,220,055.92"},
{"#\u202f###,##", "#\u202f###,##", 12345.6789, "12345,68"},
// special cases
{"NaN", "#", math.NaN(), "NaN"},
{"+Inf", "#", math.Inf(1), "Infinity"},
{"-Inf", "#", math.Inf(-1), "-Infinity"},
{"signStr <= -0.000000001", "", -0.000000002, "-0.00"},
{"signStr = 0", "", 0, "0.00"},
{"Format directive must start with +", "+000", 12345.6789, "+12345.678900000"},
}
for _, test := range tests {
got := FormatFloat(test.format, test.num)
if got != test.formatted {
t.Errorf("On %v (%v, %v), got %v, wanted %v",
test.name, test.format, test.num, got, test.formatted)
}
}
// Test a single integer
got := FormatInteger("#", 12345)
if got != "12345.000000000" {
t.Errorf("On %v (%v, %v), got %v, wanted %v",
"integerTest", "#", 12345, got, "12345.000000000")
}
// Test the things that could panic
panictests := []TestStruct{
{"RenderFloat(): invalid positive sign directive", "-", 12345.6789, "12,345.68"},
{"RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers", "0.01", 12345.6789, "12,345.68"},
}
for _, test := range panictests {
didPanic := false
var message interface{}
func() {
defer func() {
if message = recover(); message != nil {
didPanic = true
}
}()
// call the target function
_ = FormatFloat(test.format, test.num)
}()
if didPanic != true {
t.Errorf("On %v, should have panic and did not.",
test.name)
}
}
}

22
vendor/github.com/dustin/go-humanize/ordinals_test.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
package humanize
import (
"testing"
)
func TestOrdinals(t *testing.T) {
testList{
{"0", Ordinal(0), "0th"},
{"1", Ordinal(1), "1st"},
{"2", Ordinal(2), "2nd"},
{"3", Ordinal(3), "3rd"},
{"4", Ordinal(4), "4th"},
{"10", Ordinal(10), "10th"},
{"11", Ordinal(11), "11th"},
{"12", Ordinal(12), "12th"},
{"13", Ordinal(13), "13th"},
{"101", Ordinal(101), "101st"},
{"102", Ordinal(102), "102nd"},
{"103", Ordinal(103), "103rd"},
}.validate(t)
}

124
vendor/github.com/dustin/go-humanize/si_test.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package humanize
import (
"math"
"testing"
)
func TestSI(t *testing.T) {
tests := []struct {
name string
num float64
formatted string
}{
{"e-24", 1e-24, "1 yF"},
{"e-21", 1e-21, "1 zF"},
{"e-18", 1e-18, "1 aF"},
{"e-15", 1e-15, "1 fF"},
{"e-12", 1e-12, "1 pF"},
{"e-12", 2.2345e-12, "2.2345 pF"},
{"e-12", 2.23e-12, "2.23 pF"},
{"e-11", 2.23e-11, "22.3 pF"},
{"e-10", 2.2e-10, "220 pF"},
{"e-9", 2.2e-9, "2.2 nF"},
{"e-8", 2.2e-8, "22 nF"},
{"e-7", 2.2e-7, "220 nF"},
{"e-6", 2.2e-6, "2.2 µF"},
{"e-6", 1e-6, "1 µF"},
{"e-5", 2.2e-5, "22 µF"},
{"e-4", 2.2e-4, "220 µF"},
{"e-3", 2.2e-3, "2.2 mF"},
{"e-2", 2.2e-2, "22 mF"},
{"e-1", 2.2e-1, "220 mF"},
{"e+0", 2.2e-0, "2.2 F"},
{"e+0", 2.2, "2.2 F"},
{"e+1", 2.2e+1, "22 F"},
{"0", 0, "0 F"},
{"e+1", 22, "22 F"},
{"e+2", 2.2e+2, "220 F"},
{"e+2", 220, "220 F"},
{"e+3", 2.2e+3, "2.2 kF"},
{"e+3", 2200, "2.2 kF"},
{"e+4", 2.2e+4, "22 kF"},
{"e+4", 22000, "22 kF"},
{"e+5", 2.2e+5, "220 kF"},
{"e+6", 2.2e+6, "2.2 MF"},
{"e+6", 1e+6, "1 MF"},
{"e+7", 2.2e+7, "22 MF"},
{"e+8", 2.2e+8, "220 MF"},
{"e+9", 2.2e+9, "2.2 GF"},
{"e+10", 2.2e+10, "22 GF"},
{"e+11", 2.2e+11, "220 GF"},
{"e+12", 2.2e+12, "2.2 TF"},
{"e+15", 2.2e+15, "2.2 PF"},
{"e+18", 2.2e+18, "2.2 EF"},
{"e+21", 2.2e+21, "2.2 ZF"},
{"e+24", 2.2e+24, "2.2 YF"},
// special case
{"1F", 1000 * 1000, "1 MF"},
{"1F", 1e6, "1 MF"},
// negative number
{"-100 F", -100, "-100 F"},
}
for _, test := range tests {
got := SI(test.num, "F")
if got != test.formatted {
t.Errorf("On %v (%v), got %v, wanted %v",
test.name, test.num, got, test.formatted)
}
gotf, gotu, err := ParseSI(test.formatted)
if err != nil {
t.Errorf("Error parsing %v (%v): %v", test.name, test.formatted, err)
continue
}
if math.Abs(1-(gotf/test.num)) > 0.01 {
t.Errorf("On %v (%v), got %v, wanted %v (±%v)",
test.name, test.formatted, gotf, test.num,
math.Abs(1-(gotf/test.num)))
}
if gotu != "F" {
t.Errorf("On %v (%v), expected unit F, got %v",
test.name, test.formatted, gotu)
}
}
// Parse error
gotf, gotu, err := ParseSI("x1.21JW") // 1.21 jigga whats
if err == nil {
t.Errorf("Expected error on x1.21JW, got %v %v", gotf, gotu)
}
}
func TestSIWithDigits(t *testing.T) {
tests := []struct {
name string
num float64
digits int
formatted string
}{
{"e-12", 2.234e-12, 0, "2 pF"},
{"e-12", 2.234e-12, 1, "2.2 pF"},
{"e-12", 2.234e-12, 2, "2.23 pF"},
{"e-12", 2.234e-12, 3, "2.234 pF"},
{"e-12", 2.234e-12, 4, "2.234 pF"},
}
for _, test := range tests {
got := SIWithDigits(test.num, test.digits, "F")
if got != test.formatted {
t.Errorf("On %v (%v), got %v, wanted %v",
test.name, test.num, got, test.formatted)
}
}
}
func BenchmarkParseSI(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSI("2.2346ZB")
}
}

124
vendor/github.com/dustin/go-humanize/times_test.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package humanize
import (
"math"
"testing"
"time"
)
func TestPast(t *testing.T) {
now := time.Now()
testList{
{"now", Time(now), "now"},
{"1 second ago", Time(now.Add(-1 * time.Second)), "1 second ago"},
{"12 seconds ago", Time(now.Add(-12 * time.Second)), "12 seconds ago"},
{"30 seconds ago", Time(now.Add(-30 * time.Second)), "30 seconds ago"},
{"45 seconds ago", Time(now.Add(-45 * time.Second)), "45 seconds ago"},
{"1 minute ago", Time(now.Add(-63 * time.Second)), "1 minute ago"},
{"15 minutes ago", Time(now.Add(-15 * time.Minute)), "15 minutes ago"},
{"1 hour ago", Time(now.Add(-63 * time.Minute)), "1 hour ago"},
{"2 hours ago", Time(now.Add(-2 * time.Hour)), "2 hours ago"},
{"21 hours ago", Time(now.Add(-21 * time.Hour)), "21 hours ago"},
{"1 day ago", Time(now.Add(-26 * time.Hour)), "1 day ago"},
{"2 days ago", Time(now.Add(-49 * time.Hour)), "2 days ago"},
{"3 days ago", Time(now.Add(-3 * Day)), "3 days ago"},
{"1 week ago (1)", Time(now.Add(-7 * Day)), "1 week ago"},
{"1 week ago (2)", Time(now.Add(-12 * Day)), "1 week ago"},
{"2 weeks ago", Time(now.Add(-15 * Day)), "2 weeks ago"},
{"1 month ago", Time(now.Add(-39 * Day)), "1 month ago"},
{"3 months ago", Time(now.Add(-99 * Day)), "3 months ago"},
{"1 year ago (1)", Time(now.Add(-365 * Day)), "1 year ago"},
{"1 year ago (1)", Time(now.Add(-400 * Day)), "1 year ago"},
{"2 years ago (1)", Time(now.Add(-548 * Day)), "2 years ago"},
{"2 years ago (2)", Time(now.Add(-725 * Day)), "2 years ago"},
{"2 years ago (3)", Time(now.Add(-800 * Day)), "2 years ago"},
{"3 years ago", Time(now.Add(-3 * Year)), "3 years ago"},
{"long ago", Time(now.Add(-LongTime)), "a long while ago"},
}.validate(t)
}
func TestReltimeOffbyone(t *testing.T) {
testList{
{"1w-1", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, -1), "ago", ""), "6 days ago"},
{"1w±0", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, 0), "ago", ""), "1 week ago"},
{"1w+1", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, 1), "ago", ""), "1 week ago"},
{"2w-1", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, -1), "ago", ""), "1 week ago"},
{"2w±0", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, 0), "ago", ""), "2 weeks ago"},
{"2w+1", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, 1), "ago", ""), "2 weeks ago"},
}.validate(t)
}
func TestFuture(t *testing.T) {
// Add a little time so that these things properly line up in
// the future.
now := time.Now().Add(time.Millisecond * 250)
testList{
{"now", Time(now), "now"},
{"1 second from now", Time(now.Add(+1 * time.Second)), "1 second from now"},
{"12 seconds from now", Time(now.Add(+12 * time.Second)), "12 seconds from now"},
{"30 seconds from now", Time(now.Add(+30 * time.Second)), "30 seconds from now"},
{"45 seconds from now", Time(now.Add(+45 * time.Second)), "45 seconds from now"},
{"15 minutes from now", Time(now.Add(+15 * time.Minute)), "15 minutes from now"},
{"2 hours from now", Time(now.Add(+2 * time.Hour)), "2 hours from now"},
{"21 hours from now", Time(now.Add(+21 * time.Hour)), "21 hours from now"},
{"1 day from now", Time(now.Add(+26 * time.Hour)), "1 day from now"},
{"2 days from now", Time(now.Add(+49 * time.Hour)), "2 days from now"},
{"3 days from now", Time(now.Add(+3 * Day)), "3 days from now"},
{"1 week from now (1)", Time(now.Add(+7 * Day)), "1 week from now"},
{"1 week from now (2)", Time(now.Add(+12 * Day)), "1 week from now"},
{"2 weeks from now", Time(now.Add(+15 * Day)), "2 weeks from now"},
{"1 month from now", Time(now.Add(+30 * Day)), "1 month from now"},
{"1 year from now", Time(now.Add(+365 * Day)), "1 year from now"},
{"2 years from now", Time(now.Add(+2 * Year)), "2 years from now"},
{"a while from now", Time(now.Add(+LongTime)), "a long while from now"},
}.validate(t)
}
func TestRange(t *testing.T) {
start := time.Time{}
end := time.Unix(math.MaxInt64, math.MaxInt64)
x := RelTime(start, end, "ago", "from now")
if x != "a long while from now" {
t.Errorf("Expected a long while from now, got %q", x)
}
}
func TestCustomRelTime(t *testing.T) {
now := time.Now().Add(time.Millisecond * 250)
magnitudes := []RelTimeMagnitude{
{time.Second, "now", time.Second},
{2 * time.Second, "1 second %s", 1},
{time.Minute, "%d seconds %s", time.Second},
{Day - time.Second, "%d minutes %s", time.Minute},
{Day, "%d hours %s", time.Hour},
{2 * Day, "1 day %s", 1},
{Week, "%d days %s", Day},
{2 * Week, "1 week %s", 1},
{6 * Month, "%d weeks %s", Week},
{Year, "%d months %s", Month},
}
customRelTime := func(then time.Time) string {
return CustomRelTime(then, time.Now(), "ago", "from now", magnitudes)
}
testList{
{"now", customRelTime(now), "now"},
{"1 second from now", customRelTime(now.Add(+1 * time.Second)), "1 second from now"},
{"12 seconds from now", customRelTime(now.Add(+12 * time.Second)), "12 seconds from now"},
{"30 seconds from now", customRelTime(now.Add(+30 * time.Second)), "30 seconds from now"},
{"45 seconds from now", customRelTime(now.Add(+45 * time.Second)), "45 seconds from now"},
{"15 minutes from now", customRelTime(now.Add(+15 * time.Minute)), "15 minutes from now"},
{"2 hours from now", customRelTime(now.Add(+2 * time.Hour)), "120 minutes from now"},
{"21 hours from now", customRelTime(now.Add(+21 * time.Hour)), "1260 minutes from now"},
{"1 day from now", customRelTime(now.Add(+26 * time.Hour)), "1 day from now"},
{"2 days from now", customRelTime(now.Add(+49 * time.Hour)), "2 days from now"},
{"3 days from now", customRelTime(now.Add(+3 * Day)), "3 days from now"},
{"1 week from now (1)", customRelTime(now.Add(+7 * Day)), "1 week from now"},
{"1 week from now (2)", customRelTime(now.Add(+12 * Day)), "1 week from now"},
{"2 weeks from now", customRelTime(now.Add(+15 * Day)), "2 weeks from now"},
{"1 month from now", customRelTime(now.Add(+30 * Day)), "4 weeks from now"},
{"6 months from now", customRelTime(now.Add(+6*Month - time.Second)), "25 weeks from now"},
{"1 year from now", customRelTime(now.Add(+365 * Day)), "12 months from now"},
{"2 years from now", customRelTime(now.Add(+2 * Year)), "24 months from now"},
{"a while from now", customRelTime(now.Add(+LongTime)), "444 months from now"},
}.validate(t)
}

397
vendor/github.com/fatih/structs/field_test.go generated vendored Normal file
View File

@ -0,0 +1,397 @@
package structs
import (
"reflect"
"testing"
)
// A test struct that defines all cases
type Foo struct {
A string
B int `structs:"y"`
C bool `json:"c"`
d string // not exported
E *Baz
x string `xml:"x"` // not exported, with tag
Y []string
Z map[string]interface{}
*Bar // embedded
}
type Baz struct {
A string
B int
}
type Bar struct {
E string
F int
g []string
}
func newStruct() *Struct {
b := &Bar{
E: "example",
F: 2,
g: []string{"zeynep", "fatih"},
}
// B and x is not initialized for testing
f := &Foo{
A: "gopher",
C: true,
d: "small",
E: nil,
Y: []string{"example"},
Z: nil,
}
f.Bar = b
return New(f)
}
func TestField_Set(t *testing.T) {
s := newStruct()
f := s.Field("A")
err := f.Set("fatih")
if err != nil {
t.Error(err)
}
if f.Value().(string) != "fatih" {
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
}
f = s.Field("Y")
err = f.Set([]string{"override", "with", "this"})
if err != nil {
t.Error(err)
}
sliceLen := len(f.Value().([]string))
if sliceLen != 3 {
t.Errorf("Setted values slice length is wrong: %d, want: %d", sliceLen, 3)
}
f = s.Field("C")
err = f.Set(false)
if err != nil {
t.Error(err)
}
if f.Value().(bool) {
t.Errorf("Setted value is wrong: %t want: %t", f.Value().(bool), false)
}
// let's pass a different type
f = s.Field("A")
err = f.Set(123) // Field A is of type string, but we are going to pass an integer
if err == nil {
t.Error("Setting a field's value with a different type than the field's type should return an error")
}
// old value should be still there :)
if f.Value().(string) != "fatih" {
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
}
// let's access an unexported field, which should give an error
f = s.Field("d")
err = f.Set("large")
if err != errNotExported {
t.Error(err)
}
// let's set a pointer to struct
b := &Bar{
E: "gopher",
F: 2,
}
f = s.Field("Bar")
err = f.Set(b)
if err != nil {
t.Error(err)
}
baz := &Baz{
A: "helloWorld",
B: 42,
}
f = s.Field("E")
err = f.Set(baz)
if err != nil {
t.Error(err)
}
ba := s.Field("E").Value().(*Baz)
if ba.A != "helloWorld" {
t.Errorf("could not set baz. Got: %s Want: helloWorld", ba.A)
}
}
func TestField_NotSettable(t *testing.T) {
a := map[int]Baz{
4: Baz{
A: "value",
},
}
s := New(a[4])
if err := s.Field("A").Set("newValue"); err != errNotSettable {
t.Errorf("Trying to set non-settable field should error with %q. Got %q instead.", errNotSettable, err)
}
}
func TestField_Zero(t *testing.T) {
s := newStruct()
f := s.Field("A")
err := f.Zero()
if err != nil {
t.Error(err)
}
if f.Value().(string) != "" {
t.Errorf("Zeroed value is wrong: %s want: %s", f.Value().(string), "")
}
f = s.Field("Y")
err = f.Zero()
if err != nil {
t.Error(err)
}
sliceLen := len(f.Value().([]string))
if sliceLen != 0 {
t.Errorf("Zeroed values slice length is wrong: %d, want: %d", sliceLen, 0)
}
f = s.Field("C")
err = f.Zero()
if err != nil {
t.Error(err)
}
if f.Value().(bool) {
t.Errorf("Zeroed value is wrong: %t want: %t", f.Value().(bool), false)
}
// let's access an unexported field, which should give an error
f = s.Field("d")
err = f.Zero()
if err != errNotExported {
t.Error(err)
}
f = s.Field("Bar")
err = f.Zero()
if err != nil {
t.Error(err)
}
f = s.Field("E")
err = f.Zero()
if err != nil {
t.Error(err)
}
v := s.Field("E").value
if !v.IsNil() {
t.Errorf("could not set baz. Got: %s Want: <nil>", v.Interface())
}
}
func TestField(t *testing.T) {
s := newStruct()
defer func() {
err := recover()
if err == nil {
t.Error("Retrieveing a non existing field from the struct should panic")
}
}()
_ = s.Field("no-field")
}
func TestField_Kind(t *testing.T) {
s := newStruct()
f := s.Field("A")
if f.Kind() != reflect.String {
t.Errorf("Field A has wrong kind: %s want: %s", f.Kind(), reflect.String)
}
f = s.Field("B")
if f.Kind() != reflect.Int {
t.Errorf("Field B has wrong kind: %s want: %s", f.Kind(), reflect.Int)
}
// unexported
f = s.Field("d")
if f.Kind() != reflect.String {
t.Errorf("Field d has wrong kind: %s want: %s", f.Kind(), reflect.String)
}
}
func TestField_Tag(t *testing.T) {
s := newStruct()
v := s.Field("B").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a non existing tag should return empty, got: %s", v)
}
v = s.Field("C").Tag("json")
if v != "c" {
t.Errorf("Field's tag value of the existing field C should return 'c', got: %s", v)
}
v = s.Field("d").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a non exported field should return empty, got: %s", v)
}
v = s.Field("x").Tag("xml")
if v != "x" {
t.Errorf("Field's tag value of a non exported field with a tag should return 'x', got: %s", v)
}
v = s.Field("A").Tag("json")
if v != "" {
t.Errorf("Field's tag value of a existing field without a tag should return empty, got: %s", v)
}
}
func TestField_Value(t *testing.T) {
s := newStruct()
v := s.Field("A").Value()
val, ok := v.(string)
if !ok {
t.Errorf("Field's value of a A should be string")
}
if val != "gopher" {
t.Errorf("Field's value of a existing tag should return 'gopher', got: %s", val)
}
defer func() {
err := recover()
if err == nil {
t.Error("Value of a non exported field from the field should panic")
}
}()
// should panic
_ = s.Field("d").Value()
}
func TestField_IsEmbedded(t *testing.T) {
s := newStruct()
if !s.Field("Bar").IsEmbedded() {
t.Errorf("Fields 'Bar' field is an embedded field")
}
if s.Field("d").IsEmbedded() {
t.Errorf("Fields 'd' field is not an embedded field")
}
}
func TestField_IsExported(t *testing.T) {
s := newStruct()
if !s.Field("Bar").IsExported() {
t.Errorf("Fields 'Bar' field is an exported field")
}
if !s.Field("A").IsExported() {
t.Errorf("Fields 'A' field is an exported field")
}
if s.Field("d").IsExported() {
t.Errorf("Fields 'd' field is not an exported field")
}
}
func TestField_IsZero(t *testing.T) {
s := newStruct()
if s.Field("A").IsZero() {
t.Errorf("Fields 'A' field is an initialized field")
}
if !s.Field("B").IsZero() {
t.Errorf("Fields 'B' field is not an initialized field")
}
}
func TestField_Name(t *testing.T) {
s := newStruct()
if s.Field("A").Name() != "A" {
t.Errorf("Fields 'A' field should have the name 'A'")
}
}
func TestField_Field(t *testing.T) {
s := newStruct()
e := s.Field("Bar").Field("E")
val, ok := e.Value().(string)
if !ok {
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
}
if val != "example" {
t.Errorf("The value of 'e' should be 'example, got: %s", val)
}
defer func() {
err := recover()
if err == nil {
t.Error("Field of a non existing nested struct should panic")
}
}()
_ = s.Field("Bar").Field("e")
}
func TestField_Fields(t *testing.T) {
s := newStruct()
fields := s.Field("Bar").Fields()
if len(fields) != 3 {
t.Errorf("We expect 3 fields in embedded struct, was: %d", len(fields))
}
}
func TestField_FieldOk(t *testing.T) {
s := newStruct()
b, ok := s.FieldOk("Bar")
if !ok {
t.Error("The field 'Bar' should exists.")
}
e, ok := b.FieldOk("E")
if !ok {
t.Error("The field 'E' should exists.")
}
val, ok := e.Value().(string)
if !ok {
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
}
if val != "example" {
t.Errorf("The value of 'e' should be 'example, got: %s", val)
}
}

351
vendor/github.com/fatih/structs/structs_example_test.go generated vendored Normal file
View File

@ -0,0 +1,351 @@
package structs
import (
"fmt"
"time"
)
func ExampleNew() {
type Server struct {
Name string
ID int32
Enabled bool
}
server := &Server{
Name: "Arslan",
ID: 123456,
Enabled: true,
}
s := New(server)
fmt.Printf("Name : %v\n", s.Name())
fmt.Printf("Values : %v\n", s.Values())
fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
// Output:
// Name : Server
// Values : [Arslan 123456 true]
// Value of ID : 123456
}
func ExampleMap() {
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "Arslan",
ID: 123456,
Enabled: true,
}
m := Map(s)
fmt.Printf("%#v\n", m["Name"])
fmt.Printf("%#v\n", m["ID"])
fmt.Printf("%#v\n", m["Enabled"])
// Output:
// "Arslan"
// 123456
// true
}
func ExampleMap_tags() {
// Custom tags can change the map keys instead of using the fields name
type Server struct {
Name string `structs:"server_name"`
ID int32 `structs:"server_id"`
Enabled bool `structs:"enabled"`
}
s := &Server{
Name: "Zeynep",
ID: 789012,
}
m := Map(s)
// access them by the custom tags defined above
fmt.Printf("%#v\n", m["server_name"])
fmt.Printf("%#v\n", m["server_id"])
fmt.Printf("%#v\n", m["enabled"])
// Output:
// "Zeynep"
// 789012
// false
}
func ExampleMap_omitNested() {
// By default field with struct types are processed too. We can stop
// processing them via "omitnested" tag option.
type Server struct {
Name string `structs:"server_name"`
ID int32 `structs:"server_id"`
Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
}
const shortForm = "2006-Jan-02"
t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
s := &Server{
Name: "Zeynep",
ID: 789012,
Time: t,
}
m := Map(s)
// access them by the custom tags defined above
fmt.Printf("%v\n", m["server_name"])
fmt.Printf("%v\n", m["server_id"])
fmt.Printf("%v\n", m["time"].(time.Time))
// Output:
// Zeynep
// 789012
// 2013-02-03 00:00:00 +0000 UTC
}
func ExampleMap_omitEmpty() {
// By default field with struct types of zero values are processed too. We
// can stop processing them via "omitempty" tag option.
type Server struct {
Name string `structs:",omitempty"`
ID int32 `structs:"server_id,omitempty"`
Location string
}
// Only add location
s := &Server{
Location: "Tokyo",
}
m := Map(s)
// map contains only the Location field
fmt.Printf("%v\n", m)
// Output:
// map[Location:Tokyo]
}
func ExampleValues() {
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "Fatih",
ID: 135790,
Enabled: false,
}
m := Values(s)
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Fatih 135790 false]
}
func ExampleValues_omitEmpty() {
// By default field with struct types of zero values are processed too. We
// can stop processing them via "omitempty" tag option.
type Server struct {
Name string `structs:",omitempty"`
ID int32 `structs:"server_id,omitempty"`
Location string
}
// Only add location
s := &Server{
Location: "Ankara",
}
m := Values(s)
// values contains only the Location field
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Ankara]
}
func ExampleValues_tags() {
type Location struct {
City string
Country string
}
type Server struct {
Name string
ID int32
Enabled bool
Location Location `structs:"-"` // values from location are not included anymore
}
s := &Server{
Name: "Fatih",
ID: 135790,
Enabled: false,
Location: Location{City: "Ankara", Country: "Turkey"},
}
// Let get all values from the struct s. Note that we don't include values
// from the Location field
m := Values(s)
fmt.Printf("Values: %+v\n", m)
// Output:
// Values: [Fatih 135790 false]
}
func ExampleFields() {
type Access struct {
Name string
LastAccessed time.Time
Number int
}
s := &Access{
Name: "Fatih",
LastAccessed: time.Now(),
Number: 1234567,
}
fields := Fields(s)
for i, field := range fields {
fmt.Printf("[%d] %+v\n", i, field.Name())
}
// Output:
// [0] Name
// [1] LastAccessed
// [2] Number
}
func ExampleFields_nested() {
type Person struct {
Name string
Number int
}
type Access struct {
Person Person
HasPermission bool
LastAccessed time.Time
}
s := &Access{
Person: Person{Name: "fatih", Number: 1234567},
LastAccessed: time.Now(),
HasPermission: true,
}
// Let's get all fields from the struct s.
fields := Fields(s)
for _, field := range fields {
if field.Name() == "Person" {
fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
}
}
// Output:
// Access.Person.Name: fatih
}
func ExampleField() {
type Person struct {
Name string
Number int
}
type Access struct {
Person Person
HasPermission bool
LastAccessed time.Time
}
access := &Access{
Person: Person{Name: "fatih", Number: 1234567},
LastAccessed: time.Now(),
HasPermission: true,
}
// Create a new Struct type
s := New(access)
// Get the Field type for "Person" field
p := s.Field("Person")
// Get the underlying "Name field" and print the value of it
name := p.Field("Name")
fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())
// Output:
// Value of Person.Access.Name: fatih
}
func ExampleIsZero() {
type Server struct {
Name string
ID int32
Enabled bool
}
// Nothing is initalized
a := &Server{}
isZeroA := IsZero(a)
// Name and Enabled is initialized, but not ID
b := &Server{
Name: "Golang",
Enabled: true,
}
isZeroB := IsZero(b)
fmt.Printf("%#v\n", isZeroA)
fmt.Printf("%#v\n", isZeroB)
// Output:
// true
// false
}
func ExampleHasZero() {
// Let's define an Access struct. Note that the "Enabled" field is not
// going to be checked because we added the "structs" tag to the field.
type Access struct {
Name string
LastAccessed time.Time
Number int
Enabled bool `structs:"-"`
}
// Name and Number is not initialized.
a := &Access{
LastAccessed: time.Now(),
}
hasZeroA := HasZero(a)
// Name and Number is initialized.
b := &Access{
Name: "Fatih",
LastAccessed: time.Now(),
Number: 12345,
}
hasZeroB := HasZero(b)
fmt.Printf("%#v\n", hasZeroA)
fmt.Printf("%#v\n", hasZeroB)
// Output:
// true
// false
}

1453
vendor/github.com/fatih/structs/structs_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

46
vendor/github.com/fatih/structs/tags_test.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
package structs
import "testing"
func TestParseTag_Name(t *testing.T) {
tags := []struct {
tag string
has bool
}{
{"", false},
{"name", true},
{"name,opt", true},
{"name , opt, opt2", false}, // has a single whitespace
{", opt, opt2", false},
}
for _, tag := range tags {
name, _ := parseTag(tag.tag)
if (name != "name") && tag.has {
t.Errorf("Parse tag should return name: %#v", tag)
}
}
}
func TestParseTag_Opts(t *testing.T) {
tags := []struct {
opts string
has bool
}{
{"name", false},
{"name,opt", true},
{"name , opt, opt2", false}, // has a single whitespace
{",opt, opt2", true},
{", opt3, opt4", false},
}
// search for "opt"
for _, tag := range tags {
_, opts := parseTag(tag.opts)
if opts.Has("opt") != tag.has {
t.Errorf("Tag opts should have opt: %#v", tag)
}
}
}

94
vendor/github.com/hashicorp/errwrap/errwrap_test.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
package errwrap
import (
"fmt"
"testing"
)
func TestWrappedError_impl(t *testing.T) {
var _ error = new(wrappedError)
}
func TestGetAll(t *testing.T) {
cases := []struct {
Err error
Msg string
Len int
}{
{},
{
fmt.Errorf("foo"),
"foo",
1,
},
{
fmt.Errorf("bar"),
"foo",
0,
},
{
Wrapf("bar", fmt.Errorf("foo")),
"foo",
1,
},
{
Wrapf("{{err}}", fmt.Errorf("foo")),
"foo",
2,
},
{
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
"foo",
1,
},
}
for i, tc := range cases {
actual := GetAll(tc.Err, tc.Msg)
if len(actual) != tc.Len {
t.Fatalf("%d: bad: %#v", i, actual)
}
for _, v := range actual {
if v.Error() != tc.Msg {
t.Fatalf("%d: bad: %#v", i, actual)
}
}
}
}
func TestGetAllType(t *testing.T) {
cases := []struct {
Err error
Type interface{}
Len int
}{
{},
{
fmt.Errorf("foo"),
"foo",
0,
},
{
fmt.Errorf("bar"),
fmt.Errorf("foo"),
1,
},
{
Wrapf("bar", fmt.Errorf("foo")),
fmt.Errorf("baz"),
2,
},
{
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
Wrapf("", nil),
0,
},
}
for i, tc := range cases {
actual := GetAllType(tc.Err, tc.Type)
if len(actual) != tc.Len {
t.Fatalf("%d: bad: %#v", i, actual)
}
}
}

View File

@ -0,0 +1,82 @@
package multierror
import (
"errors"
"testing"
)
func TestAppend_Error(t *testing.T) {
original := &Error{
Errors: []error{errors.New("foo")},
}
result := Append(original, errors.New("bar"))
if len(result.Errors) != 2 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
original = &Error{}
result = Append(original, errors.New("bar"))
if len(result.Errors) != 1 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
// Test when a typed nil is passed
var e *Error
result = Append(e, errors.New("baz"))
if len(result.Errors) != 1 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
// Test flattening
original = &Error{
Errors: []error{errors.New("foo")},
}
result = Append(original, Append(nil, errors.New("foo"), errors.New("bar")))
if len(result.Errors) != 3 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}
func TestAppend_NilError(t *testing.T) {
var err error
result := Append(err, errors.New("bar"))
if len(result.Errors) != 1 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}
func TestAppend_NilErrorArg(t *testing.T) {
var err error
var nilErr *Error
result := Append(err, nilErr)
if len(result.Errors) != 0 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}
func TestAppend_NilErrorIfaceArg(t *testing.T) {
var err error
var nilErr error
result := Append(err, nilErr)
if len(result.Errors) != 0 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}
func TestAppend_NonError(t *testing.T) {
original := errors.New("foo")
result := Append(original, errors.New("bar"))
if len(result.Errors) != 2 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}
func TestAppend_NonError_Error(t *testing.T) {
original := errors.New("foo")
result := Append(original, Append(nil, errors.New("bar")))
if len(result.Errors) != 2 {
t.Fatalf("wrong len: %d", len(result.Errors))
}
}

View File

@ -0,0 +1,48 @@
package multierror
import (
"errors"
"fmt"
"reflect"
"strings"
"testing"
)
func TestFlatten(t *testing.T) {
original := &Error{
Errors: []error{
errors.New("one"),
&Error{
Errors: []error{
errors.New("two"),
&Error{
Errors: []error{
errors.New("three"),
},
},
},
},
},
}
expected := strings.TrimSpace(`
3 errors occurred:
* one
* two
* three
`)
actual := fmt.Sprintf("%s", Flatten(original))
if expected != actual {
t.Fatalf("expected: %s, got: %s", expected, actual)
}
}
func TestFlatten_nonError(t *testing.T) {
err := errors.New("foo")
actual := Flatten(err)
if !reflect.DeepEqual(actual, err) {
t.Fatalf("bad: %#v", actual)
}
}

View File

@ -0,0 +1,38 @@
package multierror
import (
"errors"
"testing"
)
func TestListFormatFuncSingle(t *testing.T) {
expected := `1 error occurred:
* foo`
errors := []error{
errors.New("foo"),
}
actual := ListFormatFunc(errors)
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}
func TestListFormatFuncMultiple(t *testing.T) {
expected := `2 errors occurred:
* foo
* bar`
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
actual := ListFormatFunc(errors)
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}

View File

@ -0,0 +1,70 @@
package multierror
import (
"errors"
"reflect"
"testing"
)
func TestError_Impl(t *testing.T) {
var _ error = new(Error)
}
func TestErrorError_custom(t *testing.T) {
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
fn := func(es []error) string {
return "foo"
}
multi := &Error{Errors: errors, ErrorFormat: fn}
if multi.Error() != "foo" {
t.Fatalf("bad: %s", multi.Error())
}
}
func TestErrorError_default(t *testing.T) {
expected := `2 errors occurred:
* foo
* bar`
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
multi := &Error{Errors: errors}
if multi.Error() != expected {
t.Fatalf("bad: %s", multi.Error())
}
}
func TestErrorErrorOrNil(t *testing.T) {
err := new(Error)
if err.ErrorOrNil() != nil {
t.Fatalf("bad: %#v", err.ErrorOrNil())
}
err.Errors = []error{errors.New("foo")}
if v := err.ErrorOrNil(); v == nil {
t.Fatal("should not be nil")
} else if !reflect.DeepEqual(v, err) {
t.Fatalf("bad: %#v", v)
}
}
func TestErrorWrappedErrors(t *testing.T) {
errors := []error{
errors.New("foo"),
errors.New("bar"),
}
multi := &Error{Errors: errors}
if !reflect.DeepEqual(multi.Errors, multi.WrappedErrors()) {
t.Fatalf("bad: %s", multi.WrappedErrors())
}
}

View File

@ -0,0 +1,33 @@
package multierror
import (
"errors"
"testing"
)
func TestPrefix_Error(t *testing.T) {
original := &Error{
Errors: []error{errors.New("foo")},
}
result := Prefix(original, "bar")
if result.(*Error).Errors[0].Error() != "bar foo" {
t.Fatalf("bad: %s", result)
}
}
func TestPrefix_NilError(t *testing.T) {
var err error
result := Prefix(err, "bar")
if result != nil {
t.Fatalf("bad: %#v", result)
}
}
func TestPrefix_NonError(t *testing.T) {
original := errors.New("foo")
result := Prefix(original, "bar")
if result.Error() != "bar foo" {
t.Fatalf("bad: %s", result)
}
}

54
vendor/github.com/hashicorp/go-multierror/scripts/deps.sh generated vendored Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env bash
#
# This script updates dependencies using a temporary directory. This is required
# to avoid any auxillary dependencies that sneak into GOPATH.
set -e
# Get the parent directory of where this script is.
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
# Change into that directory
cd "$DIR"
# Get the name from the directory
NAME=${NAME:-"$(basename $(pwd))"}
# Announce
echo "==> Updating dependencies..."
echo "--> Making tmpdir..."
tmpdir=$(mktemp -d)
function cleanup {
rm -rf "${tmpdir}"
}
trap cleanup EXIT
export GOPATH="${tmpdir}"
export PATH="${tmpdir}/bin:$PATH"
mkdir -p "${tmpdir}/src/github.com/hashicorp"
pushd "${tmpdir}/src/github.com/hashicorp" &>/dev/null
echo "--> Copying ${NAME}..."
cp -R "$DIR" "${tmpdir}/src/github.com/hashicorp/${NAME}"
pushd "${tmpdir}/src/github.com/hashicorp/${NAME}" &>/dev/null
rm -rf vendor/
echo "--> Installing dependency manager..."
go get -u github.com/kardianos/govendor
govendor init
echo "--> Installing all dependencies (may take some time)..."
govendor fetch -v +outside
echo "--> Vendoring..."
govendor add +external
echo "--> Moving into place..."
vpath="${tmpdir}/src/github.com/hashicorp/${NAME}/vendor"
popd &>/dev/null
popd &>/dev/null
rm -rf vendor/
cp -R "${vpath}" .

82
vendor/github.com/mars9/crypt/crypt_test.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package crypt
import (
"bytes"
"crypto/sha1"
"io/ioutil"
"os"
"testing"
)
var plain = [][]byte{
[]byte("Nö, ich trinke keinen Tee, ich bin Atheist. --- Helge Schneider"),
[]byte("I wish these damn scientists would leave intelligence to the experts. --- Gen. Richard Stillwell (CIA)"),
[]byte("I want to die peacefully in my sleep like my grandfather, not screaming in terror like his passengers. --- Charlie Hall"),
[]byte("NOTE 3: Each bit has the value either ZERO or ONE. --- ECMA-035 spec"),
[]byte("Writing about music is like dancing about architecture. --- Frank Zappa"),
[]byte("If you want to go somewhere, goto is the best way to get there. --- K Thompson"),
}
func TestEncryptDecrypt(t *testing.T) {
enc := bytes.NewBuffer(nil)
dec := bytes.NewBuffer(nil)
password := []byte("test password")
c := &Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: NewPbkdf2Key(password, 32),
}
defer c.Key.Reset()
for _, src := range plain {
enc.Reset()
dec.Reset()
err := c.Encrypt(enc, bytes.NewReader(src))
if err != nil {
t.Fatal(err)
}
err = c.Decrypt(dec, enc)
if err != nil {
t.Fatal(err)
}
if bytes.Compare(dec.Bytes(), src) != 0 {
t.Errorf("encrypt/decrypt error: want %q, got %q", string(src), string(dec.Bytes()))
}
}
}
func TestEncryptDecrypt1(t *testing.T) {
f, err := os.Open("crypt_test.go")
if err != nil {
t.Fatal(err)
}
defer f.Close()
encBuf := bytes.NewBuffer(nil)
password := []byte("test password")
c := &Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: NewPbkdf2Key(password, 32),
}
defer c.Key.Reset()
err = c.Encrypt(encBuf, f)
if err != nil {
t.Fatal(err)
}
decBuf := bytes.NewBuffer(nil)
err = c.Decrypt(decBuf, encBuf)
if err != nil {
t.Fatal(err)
}
src, err := ioutil.ReadFile("crypt_test.go")
if err != nil {
t.Fatal(err)
}
if bytes.Compare(decBuf.Bytes(), src) != 0 {
t.Errorf("encrypt/decrypt file error: crypt_test.go")
}
}

170
vendor/github.com/mars9/crypt/crypto/main.go generated vendored Normal file
View File

@ -0,0 +1,170 @@
package main
import (
"bytes"
"crypto/sha1"
"flag"
"fmt"
"os"
"runtime"
"github.com/mars9/crypt"
"github.com/mars9/keyring"
"github.com/mars9/passwd"
)
var (
prompt = flag.Bool("p", false, "prompt to enter a passphrase")
decrypt = flag.Bool("d", false, "decrypt infile to oufile")
service = flag.String("s", "go-crypto", "keyring service name")
username = flag.String("u", os.Getenv("USER"), "keyring username")
initKeyring = flag.Bool("i", false, "intialize keyring")
)
func passphrase() ([]byte, error) {
if *prompt {
password, err := passwd.Get("Enter passphrase: ")
if err != nil {
return nil, fmt.Errorf("get passphrase: %v\n", err)
}
if !*decrypt {
confirm, err := passwd.Get("Confirm passphrase: ")
if err != nil {
return nil, fmt.Errorf("get passphrase: %v\n", err)
}
if !bytes.Equal(password, confirm) {
return nil, fmt.Errorf("Passphrase mismatch, try again.")
}
}
return password, nil
}
ring, err := keyring.New()
if err != nil {
return nil, err
}
return ring.Get(*service, *username)
}
func initialize() error {
password, err := passwd.Get("Enter passphrase: ")
if err != nil {
return fmt.Errorf("get passphrase: %v\n", err)
}
confirm, err := passwd.Get("Confirm passphrase: ")
if err != nil {
return fmt.Errorf("get passphrase: %v\n", err)
}
if !bytes.Equal(password, confirm) {
return fmt.Errorf("Passphrase mismatch, try again.")
}
ring, err := keyring.New()
if err != nil {
return err
}
return ring.Set(*service, *username, password)
}
func main() {
flag.Usage = usage
flag.Parse()
narg := flag.NArg()
if narg > 2 {
usage()
}
if runtime.GOOS == "windows" && narg == 0 {
usage()
}
if *initKeyring {
if err := initialize(); err != nil {
fmt.Fprintf(os.Stderr, "initialize keyring: %v", err)
os.Exit(1)
}
os.Exit(0)
}
password, err := passphrase()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(3)
}
defer func() {
for i := range password {
password[i] = 0
}
}()
in := os.Stdin
out := os.Stdout
if narg > 0 {
in, err = os.Open(flag.Arg(0))
if err != nil {
fmt.Fprintf(os.Stderr, "open %s: %v\n", flag.Arg(0), err)
os.Exit(1)
}
defer in.Close()
if narg == 2 {
out, err = os.Create(flag.Arg(1))
if err != nil {
fmt.Fprintf(os.Stderr, "create %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
defer func() {
if err := out.Sync(); err != nil {
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
if err := out.Close(); err != nil {
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
}()
}
}
c := &crypt.Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: crypt.NewPbkdf2Key(password, 32),
}
if !*decrypt {
if err := c.Encrypt(out, in); err != nil {
fmt.Fprintf(os.Stderr, "encrypt: %v\n", err)
os.Exit(1)
}
} else {
if err := c.Decrypt(out, in); err != nil {
fmt.Fprintf(os.Stderr, "decrypt: %v\n", err)
os.Exit(1)
}
}
}
func usage() {
if runtime.GOOS == "windows" {
fmt.Fprintf(os.Stderr, "Usage: %s [options] infile [outfile]\n", os.Args[0])
} else {
fmt.Fprintf(os.Stderr, "Usage: %s [options] [infile] [[outfile]]\n", os.Args[0])
}
fmt.Fprint(os.Stderr, usageMsg)
fmt.Fprintf(os.Stderr, "\nOptions:\n")
flag.PrintDefaults()
os.Exit(2)
}
const usageMsg = `
Files are encrypted with AES (Rijndael) in cipher block counter mode
(CTR) and authenticate with HMAC-SHA. Encryption and HMAC keys are
derived from passphrase using PBKDF2.
If outfile is not specified, the de-/encrypted data is written to the
standard output and if infile is not specified, the de-/encrypted data
is read from standard input (reading standard input is not available
on windows).
`

View File

@ -0,0 +1,185 @@
package colorstring
import (
"os"
"testing"
)
func TestColor(t *testing.T) {
cases := []struct {
Input, Output string
}{
{
Input: "foo",
Output: "foo",
},
{
Input: "[blue]foo",
Output: "\033[34mfoo\033[0m",
},
{
Input: "foo[blue]foo",
Output: "foo\033[34mfoo\033[0m",
},
{
Input: "foo[what]foo",
Output: "foo[what]foo",
},
{
Input: "foo[_blue_]foo",
Output: "foo\033[44mfoo\033[0m",
},
{
Input: "foo[bold]foo",
Output: "foo\033[1mfoo\033[0m",
},
{
Input: "[blue]foo[bold]bar",
Output: "\033[34mfoo\033[1mbar\033[0m",
},
{
Input: "[underline]foo[reset]bar",
Output: "\033[4mfoo\033[0mbar\033[0m",
},
}
for _, tc := range cases {
actual := Color(tc.Input)
if actual != tc.Output {
t.Errorf(
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
tc.Input,
actual,
tc.Output)
}
}
}
func TestColorPrefix(t *testing.T) {
cases := []struct {
Input, Output string
}{
{
Input: "foo",
Output: "",
},
{
Input: "[blue]foo",
Output: "[blue]",
},
{
Input: "[bold][blue]foo",
Output: "[bold][blue]",
},
{
Input: " [bold][blue]foo",
Output: "[bold][blue]",
},
}
for _, tc := range cases {
actual := ColorPrefix(tc.Input)
if actual != tc.Output {
t.Errorf(
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
tc.Input,
actual,
tc.Output)
}
}
}
func TestColorizeColor_disable(t *testing.T) {
c := def
c.Disable = true
cases := []struct {
Input, Output string
}{
{
"[blue]foo",
"foo",
},
{
"[foo]bar",
"[foo]bar",
},
}
for _, tc := range cases {
actual := c.Color(tc.Input)
if actual != tc.Output {
t.Errorf(
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
tc.Input,
actual,
tc.Output)
}
}
}
func TestColorizeColor_noReset(t *testing.T) {
c := def
c.Reset = false
input := "[blue]foo"
output := "\033[34mfoo"
actual := c.Color(input)
if actual != output {
t.Errorf(
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
input,
actual,
output)
}
}
func TestConvenienceWrappers(t *testing.T) {
var length int
printInput := "[bold]Print:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
printlnInput := "[bold]Println:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y"
printfInput := "[bold]Printf:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
fprintInput := "[bold]Fprint:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
fprintlnInput := "[bold]Fprintln:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y"
fprintfInput := "[bold]Fprintf:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
// colorstring.Print
length, _ = Print(printInput)
assertOutputLength(t, printInput, 58, length)
// colorstring.Println
length, _ = Println(printlnInput)
assertOutputLength(t, printlnInput, 59, length)
// colorstring.Printf
length, _ = Printf(printfInput)
assertOutputLength(t, printfInput, 59, length)
// colorstring.Fprint
length, _ = Fprint(os.Stdout, fprintInput)
assertOutputLength(t, fprintInput, 59, length)
// colorstring.Fprintln
length, _ = Fprintln(os.Stdout, fprintlnInput)
assertOutputLength(t, fprintlnInput, 60, length)
// colorstring.Fprintf
length, _ = Fprintf(os.Stdout, fprintfInput)
assertOutputLength(t, fprintfInput, 59, length)
}
func assertOutputLength(t *testing.T, input string, expectedLength int, actualLength int) {
if actualLength != expectedLength {
t.Errorf("Input: %#v\n\n Output length: %d\n\n Expected: %d",
input,
actualLength,
expectedLength)
}
}

21
vendor/github.com/mitchellh/go-homedir/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Mitchell Hashimoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

14
vendor/github.com/mitchellh/go-homedir/README.md generated vendored Normal file
View File

@ -0,0 +1,14 @@
# go-homedir
This is a Go library for detecting the user's home directory without
the use of cgo, so the library can be used in cross-compilation environments.
Usage is incredibly simple, just call `homedir.Dir()` to get the home directory
for a user, and `homedir.Expand()` to expand the `~` in a path to the home
directory.
**Why not just use `os/user`?** The built-in `os/user` package requires
cgo on Darwin systems. This means that any Go code that uses that package
cannot cross compile. But 99% of the time the use for `os/user` is just to
retrieve the home directory, which we can do for the current user without
cgo. This library does that, enabling cross-compilation.

155
vendor/github.com/mitchellh/go-homedir/homedir.go generated vendored Normal file
View File

@ -0,0 +1,155 @@
package homedir
import (
"bytes"
"errors"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
)
// DisableCache will disable caching of the home directory. Caching is enabled
// by default.
var DisableCache bool
var homedirCache string
var cacheLock sync.RWMutex
// Dir returns the home directory for the executing user.
//
// This uses an OS-specific method for discovering the home directory.
// An error is returned if a home directory cannot be detected.
func Dir() (string, error) {
if !DisableCache {
cacheLock.RLock()
cached := homedirCache
cacheLock.RUnlock()
if cached != "" {
return cached, nil
}
}
cacheLock.Lock()
defer cacheLock.Unlock()
var result string
var err error
if runtime.GOOS == "windows" {
result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
result, err = dirUnix()
}
if err != nil {
return "", err
}
homedirCache = result
return result, nil
}
// Expand expands the path to include the home directory if the path
// is prefixed with `~`. If it isn't prefixed with `~`, the path is
// returned as-is.
func Expand(path string) (string, error) {
if len(path) == 0 {
return path, nil
}
if path[0] != '~' {
return path, nil
}
if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
return "", errors.New("cannot expand user-specific home dir")
}
dir, err := Dir()
if err != nil {
return "", err
}
return filepath.Join(dir, path[1:]), nil
}
func dirUnix() (string, error) {
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, env vars are lowercase.
homeEnv = "home"
}
// First prefer the HOME environmental variable
if home := os.Getenv(homeEnv); home != "" {
return home, nil
}
var stdout bytes.Buffer
// If that fails, try OS specific commands
if runtime.GOOS == "darwin" {
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result, nil
}
}
} else {
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
// If the error is ErrNotFound, we ignore it. Otherwise, return it.
if err != exec.ErrNotFound {
return "", err
}
} else {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5], nil
}
}
}
}
// If all else fails, try the shell
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}
return result, nil
}
func dirWindows() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
return home, nil
}
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
home = os.Getenv("USERPROFILE")
}
if home == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
}
return home, nil
}

129
vendor/github.com/mitchellh/go-homedir/homedir_test.go generated vendored Normal file
View File

@ -0,0 +1,129 @@
package homedir
import (
"os"
"os/user"
"path/filepath"
"testing"
)
func patchEnv(key, value string) func() {
bck := os.Getenv(key)
deferFunc := func() {
os.Setenv(key, bck)
}
if value != "" {
os.Setenv(key, value)
} else {
os.Unsetenv(key)
}
return deferFunc
}
func BenchmarkDir(b *testing.B) {
// We do this for any "warmups"
for i := 0; i < 10; i++ {
Dir()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
Dir()
}
}
func TestDir(t *testing.T) {
u, err := user.Current()
if err != nil {
t.Fatalf("err: %s", err)
}
dir, err := Dir()
if err != nil {
t.Fatalf("err: %s", err)
}
if u.HomeDir != dir {
t.Fatalf("%#v != %#v", u.HomeDir, dir)
}
DisableCache = true
defer func() { DisableCache = false }()
defer patchEnv("HOME", "")()
dir, err = Dir()
if err != nil {
t.Fatalf("err: %s", err)
}
if u.HomeDir != dir {
t.Fatalf("%#v != %#v", u.HomeDir, dir)
}
}
func TestExpand(t *testing.T) {
u, err := user.Current()
if err != nil {
t.Fatalf("err: %s", err)
}
cases := []struct {
Input string
Output string
Err bool
}{
{
"/foo",
"/foo",
false,
},
{
"~/foo",
filepath.Join(u.HomeDir, "foo"),
false,
},
{
"",
"",
false,
},
{
"~",
u.HomeDir,
false,
},
{
"~foo/foo",
"",
true,
},
}
for _, tc := range cases {
actual, err := Expand(tc.Input)
if (err != nil) != tc.Err {
t.Fatalf("Input: %#v\n\nErr: %s", tc.Input, err)
}
if actual != tc.Output {
t.Fatalf("Input: %#v\n\nOutput: %#v", tc.Input, actual)
}
}
DisableCache = true
defer func() { DisableCache = false }()
defer patchEnv("HOME", "/custom/path/")()
expected := filepath.Join("/", "custom", "path", "foo/bar")
actual, err := Expand("~/foo/bar")
if err != nil {
t.Errorf("No error is expected, got: %v", err)
} else if actual != expected {
t.Errorf("Expected: %v; actual: %v", expected, actual)
}
}

1
vendor/github.com/mr-tron/base58/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
.idea/

58
vendor/github.com/mr-tron/base58/README.md generated vendored Normal file
View File

@ -0,0 +1,58 @@
# base58 A Fast Implementation of Base58 encoding used in Bitcoin
[![GoDoc](https://godoc.org/github.com/mr-tron/base58/base58?status.svg)](https://godoc.org/github.com/mr-tron/base58/base58) [![Go Report Card](https://goreportcard.com/badge/github.com/mr-tron/base58)](https://goreportcard.com/report/github.com/mr-tron/base58)
Fast implementation of base58 encoding in Go (Golang).
Base algorithm is copied from https://github.com/trezor/trezor-crypto/blob/master/base58.c
To import library
```go
import (
"github.com/mr-tron/base58/base58"
)
```
# Example
```go
package main
import (
"fmt"
"os"
"github.com/mr-tron/base58/base58"
)
func main() {
exampleBase58Encoded := []string{
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
}
// If a base58 string is on the command line, then use that instead of the 4 exampels above.
if len(os.Args) > 1 {
exampleBase58Encoded = os.Args[1:]
}
for _, vv := range exampleBase58Encoded {
num, err := base58.Decode(vv)
if err != nil {
fmt.Printf("Demo %d, got error %s\n", err)
continue
}
chk := base58.Encode(num)
if vv == string(chk) {
fmt.Printf ( "Successfully decoded then re-encoded %s\n", vv )
} else {
fmt.Printf ( "Failed on %s\n", vv )
}
}
}
```

View File

@ -0,0 +1,26 @@
package base58
import "testing"
func TestBase58_test2(t *testing.T) {
testAddr := []string{
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
}
for ii, vv := range testAddr {
// num := Base58Decode([]byte(vv))
// chk := Base58Encode(num)
num, err := FastBase58Decoding(vv)
if err != nil {
t.Errorf("Test %d, expected success, got error %s\n", ii, err)
}
chk := FastBase58Encoding(num)
if vv != string(chk) {
t.Errorf("Test %d, expected=%s got=%s Address did base58 encode/decode correctly.", ii, vv, chk)
}
}
}

117
vendor/github.com/mr-tron/base58/base58/base58_test.go generated vendored Normal file
View File

@ -0,0 +1,117 @@
package base58
import (
"crypto/rand"
"encoding/hex"
"testing"
)
type testValues struct {
dec []byte
enc string
}
var n = 5000000
var testPairs = make([]testValues, 0, n)
func initTestPairs() {
if len(testPairs) > 0 {
return
}
// pre-make the test pairs, so it doesn't take up benchmark time...
data := make([]byte, 32)
for i := 0; i < n; i++ {
rand.Read(data)
testPairs = append(testPairs, testValues{dec: data, enc: FastBase58Encoding(data)})
}
}
func randAlphabet() *Alphabet {
// Permutes [0, 127] and returns the first 58 elements.
// Like (math/rand).Perm but using crypto/rand.
var randomness [128]byte
rand.Read(randomness[:])
var bts [128]byte
for i, r := range randomness {
j := int(r) % (i + 1)
bts[i] = bts[j]
bts[j] = byte(i)
}
return NewAlphabet(string(bts[:58]))
}
func TestFastEqTrivialEncodingAndDecoding(t *testing.T) {
for k := 0; k < 10; k++ {
testEncDecLoop(t, randAlphabet())
}
testEncDecLoop(t, BTCAlphabet)
testEncDecLoop(t, FlickrAlphabet)
}
func testEncDecLoop(t *testing.T, alph *Alphabet) {
for j := 1; j < 256; j++ {
var b = make([]byte, j)
for i := 0; i < 100; i++ {
rand.Read(b)
fe := FastBase58EncodingAlphabet(b, alph)
te := TrivialBase58EncodingAlphabet(b, alph)
if fe != te {
t.Errorf("encoding err: %#v", hex.EncodeToString(b))
}
fd, ferr := FastBase58DecodingAlphabet(fe, alph)
if ferr != nil {
t.Errorf("fast error: %v", ferr)
}
td, terr := TrivialBase58DecodingAlphabet(te, alph)
if terr != nil {
t.Errorf("trivial error: %v", terr)
}
if hex.EncodeToString(b) != hex.EncodeToString(td) {
t.Errorf("decoding err: %s != %s", hex.EncodeToString(b), hex.EncodeToString(td))
}
if hex.EncodeToString(b) != hex.EncodeToString(fd) {
t.Errorf("decoding err: %s != %s", hex.EncodeToString(b), hex.EncodeToString(fd))
}
}
}
}
func BenchmarkTrivialBase58Encoding(b *testing.B) {
initTestPairs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
TrivialBase58Encoding([]byte(testPairs[i].dec))
}
}
func BenchmarkFastBase58Encoding(b *testing.B) {
initTestPairs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
FastBase58Encoding(testPairs[i].dec)
}
}
func BenchmarkTrivialBase58Decoding(b *testing.B) {
initTestPairs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
TrivialBase58Decoding(testPairs[i].enc)
}
}
func BenchmarkFastBase58Decoding(b *testing.B) {
initTestPairs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
FastBase58Decoding(testPairs[i].enc)
}
}

View File

@ -0,0 +1 @@
cli

37
vendor/github.com/mr-tron/base58/example/cli/cli.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"fmt"
"os"
"github.com/mr-tron/base58/base58"
)
func main() {
exampleBase58Encoded := []string{
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
}
// If a base58 string is on the command line, then use that instead of the 4 exampels above.
if len(os.Args) > 1 {
exampleBase58Encoded = os.Args[1:]
}
for _, vv := range exampleBase58Encoded {
num, err := base58.Decode(vv)
if err != nil {
fmt.Printf("Demo %s, got error %s\n", vv, err)
continue
}
chk := base58.Encode(num)
if vv == string(chk) {
fmt.Printf("Successfully decoded then re-encoded %s\n", vv)
} else {
fmt.Printf("Failed on %s\n", vv)
}
}
}

112
vendor/github.com/mr-tron/base58/main.go generated vendored Normal file
View File

@ -0,0 +1,112 @@
package main
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/mr-tron/base58/base58"
)
func checkSum(b []byte) []byte {
sh1, sh2 := sha256.New(), sha256.New()
sh1.Write(b)
sh2.Write(sh1.Sum(nil))
return sh2.Sum(nil)
}
func main() {
var (
err error
bin []byte
help = flag.Bool("h", false, "display this message")
lnBreak = flag.Int("b", 76, "break encoded string into num character lines. Use 0 to disable line wrapping")
input = flag.String("i", "-", `input file (use: "-" for stdin)`)
output = flag.String("o", "-", `output file (use: "-" for stdout)`)
decode = flag.Bool("d", false, `decode input`)
check = flag.Bool("k", false, `use sha256 check`)
useError = flag.Bool("e", false, `write error to stderr`)
)
flag.Parse()
if *help {
flag.Usage()
os.Exit(0)
}
fin, fout := os.Stdin, os.Stdout
if *input != "-" {
if fin, err = os.Open(*input); err != nil {
fmt.Fprintf(os.Stderr, "input file err: %v\n", err)
os.Exit(1)
}
}
if *output != "-" {
if fout, err = os.Create(*output); err != nil {
fmt.Fprintf(os.Stderr, "output file err: %v\n", err)
os.Exit(1)
}
}
if bin, err = ioutil.ReadAll(fin); err != nil {
fmt.Fprintf(os.Stderr, "read input err: %v\n", err)
os.Exit(1)
}
if *decode {
decoded, err := base58.FastBase58Decoding(string(bin))
if err != nil {
fmt.Fprintf(os.Stderr, "decode input err: %v\n", err)
os.Exit(1)
}
var checkResult bool
if *check {
chk := len(decoded) - 4
decodedCk := decoded[chk:]
decoded = decoded[:chk]
sum := checkSum(decoded)
checkResult = hex.EncodeToString(sum[:4]) == hex.EncodeToString(decodedCk)
}
io.Copy(fout, bytes.NewReader(decoded))
if *check && !checkResult {
if *useError {
fmt.Fprintf(os.Stderr, "%t", false)
}
os.Exit(3)
}
os.Exit(0)
}
if *check {
sum := checkSum(bin)
bin = append(bin, sum[:4]...)
}
encoded := base58.FastBase58Encoding(bin)
if *lnBreak > 0 {
lines := (len(encoded) / *lnBreak) + 1
for i := 0; i < lines; i++ {
start := i * *lnBreak
end := start + *lnBreak
if i == lines-1 {
fmt.Fprintln(fout, encoded[start:])
return
}
fmt.Fprintln(fout, encoded[start:end])
}
}
fmt.Fprintln(fout, encoded)
}

59
vendor/github.com/pkg/errors/bench_test.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
// +build go1.7
package errors
import (
"fmt"
"testing"
stderrors "errors"
)
func noErrors(at, depth int) error {
if at >= depth {
return stderrors.New("no error")
}
return noErrors(at+1, depth)
}
func yesErrors(at, depth int) error {
if at >= depth {
return New("ye error")
}
return yesErrors(at+1, depth)
}
func BenchmarkErrors(b *testing.B) {
var toperr error
type run struct {
stack int
std bool
}
runs := []run{
{10, false},
{10, true},
{100, false},
{100, true},
{1000, false},
{1000, true},
}
for _, r := range runs {
part := "pkg/errors"
if r.std {
part = "errors"
}
name := fmt.Sprintf("%s-stack-%d", part, r.stack)
b.Run(name, func(b *testing.B) {
var err error
f := yesErrors
if r.std {
f = noErrors
}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
err = f(0, r.stack)
}
b.StopTimer()
toperr = err
})
}
}

226
vendor/github.com/pkg/errors/errors_test.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
package errors
import (
"errors"
"fmt"
"io"
"reflect"
"testing"
)
func TestNew(t *testing.T) {
tests := []struct {
err string
want error
}{
{"", fmt.Errorf("")},
{"foo", fmt.Errorf("foo")},
{"foo", New("foo")},
{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
}
for _, tt := range tests {
got := New(tt.err)
if got.Error() != tt.want.Error() {
t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
}
}
}
func TestWrapNil(t *testing.T) {
got := Wrap(nil, "no error")
if got != nil {
t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWrap(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
}
for _, tt := range tests {
got := Wrap(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
}
}
}
type nilError struct{}
func (nilError) Error() string { return "nil error" }
func TestCause(t *testing.T) {
x := New("error")
tests := []struct {
err error
want error
}{{
// nil error is nil
err: nil,
want: nil,
}, {
// explicit nil error is nil
err: (error)(nil),
want: nil,
}, {
// typed nil is nil
err: (*nilError)(nil),
want: (*nilError)(nil),
}, {
// uncaused error is unaffected
err: io.EOF,
want: io.EOF,
}, {
// caused error returns cause
err: Wrap(io.EOF, "ignored"),
want: io.EOF,
}, {
err: x, // return from errors.New
want: x,
}, {
WithMessage(nil, "whoops"),
nil,
}, {
WithMessage(io.EOF, "whoops"),
io.EOF,
}, {
WithStack(nil),
nil,
}, {
WithStack(io.EOF),
io.EOF,
}}
for i, tt := range tests {
got := Cause(tt.err)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
}
}
}
func TestWrapfNil(t *testing.T) {
got := Wrapf(nil, "no error")
if got != nil {
t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWrapf(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
}
for _, tt := range tests {
got := Wrapf(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
}
}
}
func TestErrorf(t *testing.T) {
tests := []struct {
err error
want string
}{
{Errorf("read error without format specifiers"), "read error without format specifiers"},
{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
}
for _, tt := range tests {
got := tt.err.Error()
if got != tt.want {
t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
}
}
}
func TestWithStackNil(t *testing.T) {
got := WithStack(nil)
if got != nil {
t.Errorf("WithStack(nil): got %#v, expected nil", got)
}
}
func TestWithStack(t *testing.T) {
tests := []struct {
err error
want string
}{
{io.EOF, "EOF"},
{WithStack(io.EOF), "EOF"},
}
for _, tt := range tests {
got := WithStack(tt.err).Error()
if got != tt.want {
t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
}
}
}
func TestWithMessageNil(t *testing.T) {
got := WithMessage(nil, "no error")
if got != nil {
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWithMessage(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
}
for _, tt := range tests {
got := WithMessage(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
}
}
}
// errors.New, etc values are not expected to be compared by value
// but the change in errors#27 made them incomparable. Assert that
// various kinds of errors have a functional equality operator, even
// if the result of that equality is always false.
func TestErrorEquality(t *testing.T) {
vals := []error{
nil,
io.EOF,
errors.New("EOF"),
New("EOF"),
Errorf("EOF"),
Wrap(io.EOF, "EOF"),
Wrapf(io.EOF, "EOF%d", 2),
WithMessage(nil, "whoops"),
WithMessage(io.EOF, "whoops"),
WithStack(io.EOF),
WithStack(nil),
}
for i := range vals {
for j := range vals {
_ = vals[i] == vals[j] // mustn't panic
}
}
}

205
vendor/github.com/pkg/errors/example_test.go generated vendored Normal file
View File

@ -0,0 +1,205 @@
package errors_test
import (
"fmt"
"github.com/pkg/errors"
)
func ExampleNew() {
err := errors.New("whoops")
fmt.Println(err)
// Output: whoops
}
func ExampleNew_printf() {
err := errors.New("whoops")
fmt.Printf("%+v", err)
// Example output:
// whoops
// github.com/pkg/errors_test.ExampleNew_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:17
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
}
func ExampleWithMessage() {
cause := errors.New("whoops")
err := errors.WithMessage(cause, "oh noes")
fmt.Println(err)
// Output: oh noes: whoops
}
func ExampleWithStack() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Println(err)
// Output: whoops
}
func ExampleWithStack_printf() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Printf("%+v", err)
// Example Output:
// whoops
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
// testing.runExample
// /usr/lib/go/src/testing/example.go:114
// testing.RunExamples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).Run
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /usr/lib/go/src/runtime/proc.go:183
// runtime.goexit
// /usr/lib/go/src/runtime/asm_amd64.s:2086
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
// testing.runExample
// /usr/lib/go/src/testing/example.go:114
// testing.RunExamples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).Run
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /usr/lib/go/src/runtime/proc.go:183
// runtime.goexit
// /usr/lib/go/src/runtime/asm_amd64.s:2086
}
func ExampleWrap() {
cause := errors.New("whoops")
err := errors.Wrap(cause, "oh noes")
fmt.Println(err)
// Output: oh noes: whoops
}
func fn() error {
e1 := errors.New("error")
e2 := errors.Wrap(e1, "inner")
e3 := errors.Wrap(e2, "middle")
return errors.Wrap(e3, "outer")
}
func ExampleCause() {
err := fn()
fmt.Println(err)
fmt.Println(errors.Cause(err))
// Output: outer: middle: inner: error
// error
}
func ExampleWrap_extended() {
err := fn()
fmt.Printf("%+v\n", err)
// Example output:
// error
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
// github.com/pkg/errors_test.ExampleCause_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:63
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:104
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
}
func ExampleWrapf() {
cause := errors.New("whoops")
err := errors.Wrapf(cause, "oh noes #%d", 2)
fmt.Println(err)
// Output: oh noes #2: whoops
}
func ExampleErrorf_extended() {
err := errors.Errorf("whoops: %s", "foo")
fmt.Printf("%+v", err)
// Example output:
// whoops: foo
// github.com/pkg/errors_test.ExampleErrorf
// /home/dfc/src/github.com/pkg/errors/example_test.go:101
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:102
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
}
func Example_stackTrace() {
type stackTracer interface {
StackTrace() errors.StackTrace
}
err, ok := errors.Cause(fn()).(stackTracer)
if !ok {
panic("oops, err does not implement stackTracer")
}
st := err.StackTrace()
fmt.Printf("%+v", st[0:2]) // top two frames
// Example output:
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
// github.com/pkg/errors_test.Example_stackTrace
// /home/dfc/src/github.com/pkg/errors/example_test.go:127
}
func ExampleCause_printf() {
err := errors.Wrap(func() error {
return func() error {
return errors.Errorf("hello %s", fmt.Sprintf("world"))
}()
}(), "failed")
fmt.Printf("%v", err)
// Output: failed: hello world
}

535
vendor/github.com/pkg/errors/format_test.go generated vendored Normal file
View File

@ -0,0 +1,535 @@
package errors
import (
"errors"
"fmt"
"io"
"regexp"
"strings"
"testing"
)
func TestFormatNew(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
New("error"),
"%s",
"error",
}, {
New("error"),
"%v",
"error",
}, {
New("error"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatNew\n" +
"\t.+/github.com/pkg/errors/format_test.go:26",
}, {
New("error"),
"%q",
`"error"`,
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatErrorf(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Errorf("%s", "error"),
"%s",
"error",
}, {
Errorf("%s", "error"),
"%v",
"error",
}, {
Errorf("%s", "error"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatErrorf\n" +
"\t.+/github.com/pkg/errors/format_test.go:56",
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWrap(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Wrap(New("error"), "error2"),
"%s",
"error2: error",
}, {
Wrap(New("error"), "error2"),
"%v",
"error2: error",
}, {
Wrap(New("error"), "error2"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:82",
}, {
Wrap(io.EOF, "error"),
"%s",
"error: EOF",
}, {
Wrap(io.EOF, "error"),
"%v",
"error: EOF",
}, {
Wrap(io.EOF, "error"),
"%+v",
"EOF\n" +
"error\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:96",
}, {
Wrap(Wrap(io.EOF, "error1"), "error2"),
"%+v",
"EOF\n" +
"error1\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:103\n",
}, {
Wrap(New("error with space"), "context"),
"%q",
`"context: error with space"`,
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWrapf(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Wrapf(io.EOF, "error%d", 2),
"%s",
"error2: EOF",
}, {
Wrapf(io.EOF, "error%d", 2),
"%v",
"error2: EOF",
}, {
Wrapf(io.EOF, "error%d", 2),
"%+v",
"EOF\n" +
"error2\n" +
"github.com/pkg/errors.TestFormatWrapf\n" +
"\t.+/github.com/pkg/errors/format_test.go:134",
}, {
Wrapf(New("error"), "error%d", 2),
"%s",
"error2: error",
}, {
Wrapf(New("error"), "error%d", 2),
"%v",
"error2: error",
}, {
Wrapf(New("error"), "error%d", 2),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatWrapf\n" +
"\t.+/github.com/pkg/errors/format_test.go:149",
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWithStack(t *testing.T) {
tests := []struct {
error
format string
want []string
}{{
WithStack(io.EOF),
"%s",
[]string{"EOF"},
}, {
WithStack(io.EOF),
"%v",
[]string{"EOF"},
}, {
WithStack(io.EOF),
"%+v",
[]string{"EOF",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:175"},
}, {
WithStack(New("error")),
"%s",
[]string{"error"},
}, {
WithStack(New("error")),
"%v",
[]string{"error"},
}, {
WithStack(New("error")),
"%+v",
[]string{"error",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:189",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:189"},
}, {
WithStack(WithStack(io.EOF)),
"%+v",
[]string{"EOF",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:197",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:197"},
}, {
WithStack(WithStack(Wrapf(io.EOF, "message"))),
"%+v",
[]string{"EOF",
"message",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205"},
}, {
WithStack(Errorf("error%d", 1)),
"%+v",
[]string{"error1",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:216",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:216"},
}}
for i, tt := range tests {
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
}
}
func TestFormatWithMessage(t *testing.T) {
tests := []struct {
error
format string
want []string
}{{
WithMessage(New("error"), "error2"),
"%s",
[]string{"error2: error"},
}, {
WithMessage(New("error"), "error2"),
"%v",
[]string{"error2: error"},
}, {
WithMessage(New("error"), "error2"),
"%+v",
[]string{
"error",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:244",
"error2"},
}, {
WithMessage(io.EOF, "addition1"),
"%s",
[]string{"addition1: EOF"},
}, {
WithMessage(io.EOF, "addition1"),
"%v",
[]string{"addition1: EOF"},
}, {
WithMessage(io.EOF, "addition1"),
"%+v",
[]string{"EOF", "addition1"},
}, {
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
"%v",
[]string{"addition2: addition1: EOF"},
}, {
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
"%+v",
[]string{"EOF", "addition1", "addition2"},
}, {
Wrap(WithMessage(io.EOF, "error1"), "error2"),
"%+v",
[]string{"EOF", "error1", "error2",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:272"},
}, {
WithMessage(Errorf("error%d", 1), "error2"),
"%+v",
[]string{"error1",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:278",
"error2"},
}, {
WithMessage(WithStack(io.EOF), "error"),
"%+v",
[]string{
"EOF",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:285",
"error"},
}, {
WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"),
"%+v",
[]string{
"EOF",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:293",
"inside-error",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:293",
"outside-error"},
}}
for i, tt := range tests {
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
}
}
func TestFormatGeneric(t *testing.T) {
starts := []struct {
err error
want []string
}{
{New("new-error"), []string{
"new-error",
"github.com/pkg/errors.TestFormatGeneric\n" +
"\t.+/github.com/pkg/errors/format_test.go:315"},
}, {Errorf("errorf-error"), []string{
"errorf-error",
"github.com/pkg/errors.TestFormatGeneric\n" +
"\t.+/github.com/pkg/errors/format_test.go:319"},
}, {errors.New("errors-new-error"), []string{
"errors-new-error"},
},
}
wrappers := []wrapper{
{
func(err error) error { return WithMessage(err, "with-message") },
[]string{"with-message"},
}, {
func(err error) error { return WithStack(err) },
[]string{
"github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" +
".+/github.com/pkg/errors/format_test.go:333",
},
}, {
func(err error) error { return Wrap(err, "wrap-error") },
[]string{
"wrap-error",
"github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" +
".+/github.com/pkg/errors/format_test.go:339",
},
}, {
func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
[]string{
"wrapf-error1",
"github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" +
".+/github.com/pkg/errors/format_test.go:346",
},
},
}
for s := range starts {
err := starts[s].err
want := starts[s].want
testFormatCompleteCompare(t, s, err, "%+v", want, false)
testGenericRecursive(t, err, want, wrappers, 3)
}
}
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
got := fmt.Sprintf(format, arg)
gotLines := strings.SplitN(got, "\n", -1)
wantLines := strings.SplitN(want, "\n", -1)
if len(wantLines) > len(gotLines) {
t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want)
return
}
for i, w := range wantLines {
match, err := regexp.MatchString(w, gotLines[i])
if err != nil {
t.Fatal(err)
}
if !match {
t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want)
}
}
}
var stackLineR = regexp.MustCompile(`\.`)
// parseBlocks parses input into a slice, where:
// - incase entry contains a newline, its a stacktrace
// - incase entry contains no newline, its a solo line.
//
// Detecting stack boundaries only works incase the WithStack-calls are
// to be found on the same line, thats why it is optionally here.
//
// Example use:
//
// for _, e := range blocks {
// if strings.ContainsAny(e, "\n") {
// // Match as stack
// } else {
// // Match as line
// }
// }
//
func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
var blocks []string
stack := ""
wasStack := false
lines := map[string]bool{} // already found lines
for _, l := range strings.Split(input, "\n") {
isStackLine := stackLineR.MatchString(l)
switch {
case !isStackLine && wasStack:
blocks = append(blocks, stack, l)
stack = ""
lines = map[string]bool{}
case isStackLine:
if wasStack {
// Detecting two stacks after another, possible cause lines match in
// our tests due to WithStack(WithStack(io.EOF)) on same line.
if detectStackboundaries {
if lines[l] {
if len(stack) == 0 {
return nil, errors.New("len of block must not be zero here")
}
blocks = append(blocks, stack)
stack = l
lines = map[string]bool{l: true}
continue
}
}
stack = stack + "\n" + l
} else {
stack = l
}
lines[l] = true
case !isStackLine && !wasStack:
blocks = append(blocks, l)
default:
return nil, errors.New("must not happen")
}
wasStack = isStackLine
}
// Use up stack
if stack != "" {
blocks = append(blocks, stack)
}
return blocks, nil
}
func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
gotStr := fmt.Sprintf(format, arg)
got, err := parseBlocks(gotStr, detectStackBoundaries)
if err != nil {
t.Fatal(err)
}
if len(got) != len(want) {
t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q",
n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr)
}
for i := range got {
if strings.ContainsAny(want[i], "\n") {
// Match as stack
match, err := regexp.MatchString(want[i], got[i])
if err != nil {
t.Fatal(err)
}
if !match {
t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n",
n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want))
}
} else {
// Match as message
if got[i] != want[i] {
t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i])
}
}
}
}
type wrapper struct {
wrap func(err error) error
want []string
}
func prettyBlocks(blocks []string, prefix ...string) string {
var out []string
for _, b := range blocks {
out = append(out, fmt.Sprintf("%v", b))
}
return " " + strings.Join(out, "\n ")
}
func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) {
if len(beforeWant) == 0 {
panic("beforeWant must not be empty")
}
for _, w := range list {
if len(w.want) == 0 {
panic("want must not be empty")
}
err := w.wrap(beforeErr)
// Copy required cause append(beforeWant, ..) modified beforeWant subtly.
beforeCopy := make([]string, len(beforeWant))
copy(beforeCopy, beforeWant)
beforeWant := beforeCopy
last := len(beforeWant) - 1
var want []string
// Merge two stacks behind each other.
if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") {
want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...)
} else {
want = append(beforeWant, w.want...)
}
testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false)
if maxDepth > 0 {
testGenericRecursive(t, err, want, list, maxDepth-1)
}
}
}

292
vendor/github.com/pkg/errors/stack_test.go generated vendored Normal file
View File

@ -0,0 +1,292 @@
package errors
import (
"fmt"
"runtime"
"testing"
)
var initpc, _, _, _ = runtime.Caller(0)
func TestFrameLine(t *testing.T) {
var tests = []struct {
Frame
want int
}{{
Frame(initpc),
9,
}, {
func() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}(),
20,
}, {
func() Frame {
var pc, _, _, _ = runtime.Caller(1)
return Frame(pc)
}(),
28,
}, {
Frame(0), // invalid PC
0,
}}
for _, tt := range tests {
got := tt.Frame.line()
want := tt.want
if want != got {
t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
}
}
}
type X struct{}
func (x X) val() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}
func (x *X) ptr() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}
func TestFrameFormat(t *testing.T) {
var tests = []struct {
Frame
format string
want string
}{{
Frame(initpc),
"%s",
"stack_test.go",
}, {
Frame(initpc),
"%+s",
"github.com/pkg/errors.init\n" +
"\t.+/github.com/pkg/errors/stack_test.go",
}, {
Frame(0),
"%s",
"unknown",
}, {
Frame(0),
"%+s",
"unknown",
}, {
Frame(initpc),
"%d",
"9",
}, {
Frame(0),
"%d",
"0",
}, {
Frame(initpc),
"%n",
"init",
}, {
func() Frame {
var x X
return x.ptr()
}(),
"%n",
`\(\*X\).ptr`,
}, {
func() Frame {
var x X
return x.val()
}(),
"%n",
"X.val",
}, {
Frame(0),
"%n",
"",
}, {
Frame(initpc),
"%v",
"stack_test.go:9",
}, {
Frame(initpc),
"%+v",
"github.com/pkg/errors.init\n" +
"\t.+/github.com/pkg/errors/stack_test.go:9",
}, {
Frame(0),
"%v",
"unknown:0",
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.Frame, tt.format, tt.want)
}
}
func TestFuncname(t *testing.T) {
tests := []struct {
name, want string
}{
{"", ""},
{"runtime.main", "main"},
{"github.com/pkg/errors.funcname", "funcname"},
{"funcname", "funcname"},
{"io.copyBuffer", "copyBuffer"},
{"main.(*R).Write", "(*R).Write"},
}
for _, tt := range tests {
got := funcname(tt.name)
want := tt.want
if got != want {
t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got)
}
}
}
func TestTrimGOPATH(t *testing.T) {
var tests = []struct {
Frame
want string
}{{
Frame(initpc),
"github.com/pkg/errors/stack_test.go",
}}
for i, tt := range tests {
pc := tt.Frame.pc()
fn := runtime.FuncForPC(pc)
file, _ := fn.FileLine(pc)
got := trimGOPATH(fn.Name(), file)
testFormatRegexp(t, i, got, "%s", tt.want)
}
}
func TestStackTrace(t *testing.T) {
tests := []struct {
err error
want []string
}{{
New("ooh"), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:172",
},
}, {
Wrap(New("ooh"), "ahh"), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:177", // this is the stack of Wrap, not New
},
}, {
Cause(Wrap(New("ooh"), "ahh")), []string{
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:182", // this is the stack of New
},
}, {
func() error { return New("ooh") }(), []string{
`github.com/pkg/errors.(func·009|TestStackTrace.func1)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New's caller
},
}, {
Cause(func() error {
return func() error {
return Errorf("hello %s", fmt.Sprintf("world"))
}()
}()), []string{
`github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf
`github.com/pkg/errors.(func·011|TestStackTrace.func2)` +
"\n\t.+/github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller
"github.com/pkg/errors.TestStackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
},
}}
for i, tt := range tests {
x, ok := tt.err.(interface {
StackTrace() StackTrace
})
if !ok {
t.Errorf("expected %#v to implement StackTrace() StackTrace", tt.err)
continue
}
st := x.StackTrace()
for j, want := range tt.want {
testFormatRegexp(t, i, st[j], "%+v", want)
}
}
}
func stackTrace() StackTrace {
const depth = 8
var pcs [depth]uintptr
n := runtime.Callers(1, pcs[:])
var st stack = pcs[0:n]
return st.StackTrace()
}
func TestStackTraceFormat(t *testing.T) {
tests := []struct {
StackTrace
format string
want string
}{{
nil,
"%s",
`\[\]`,
}, {
nil,
"%v",
`\[\]`,
}, {
nil,
"%+v",
"",
}, {
nil,
"%#v",
`\[\]errors.Frame\(nil\)`,
}, {
make(StackTrace, 0),
"%s",
`\[\]`,
}, {
make(StackTrace, 0),
"%v",
`\[\]`,
}, {
make(StackTrace, 0),
"%+v",
"",
}, {
make(StackTrace, 0),
"%#v",
`\[\]errors.Frame{}`,
}, {
stackTrace()[:2],
"%s",
`\[stack_test.go stack_test.go\]`,
}, {
stackTrace()[:2],
"%v",
`\[stack_test.go:225 stack_test.go:272\]`,
}, {
stackTrace()[:2],
"%+v",
"\n" +
"github.com/pkg/errors.stackTrace\n" +
"\t.+/github.com/pkg/errors/stack_test.go:225\n" +
"github.com/pkg/errors.TestStackTraceFormat\n" +
"\t.+/github.com/pkg/errors/stack_test.go:276",
}, {
stackTrace()[:2],
"%#v",
`\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`,
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
}
}

5
vendor/github.com/pmezard/go-difflib/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: go
go:
- 1.5
- tip

27
vendor/github.com/pmezard/go-difflib/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2013, Patrick Mezard
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

50
vendor/github.com/pmezard/go-difflib/README.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
go-difflib
==========
[![Build Status](https://travis-ci.org/pmezard/go-difflib.png?branch=master)](https://travis-ci.org/pmezard/go-difflib)
[![GoDoc](https://godoc.org/github.com/pmezard/go-difflib/difflib?status.svg)](https://godoc.org/github.com/pmezard/go-difflib/difflib)
Go-difflib is a partial port of python 3 difflib package. Its main goal
was to make unified and context diff available in pure Go, mostly for
testing purposes.
The following class and functions (and related tests) have be ported:
* `SequenceMatcher`
* `unified_diff()`
* `context_diff()`
## Installation
```bash
$ go get github.com/pmezard/go-difflib/difflib
```
### Quick Start
Diffs are configured with Unified (or ContextDiff) structures, and can
be output to an io.Writer or returned as a string.
```Go
diff := UnifiedDiff{
A: difflib.SplitLines("foo\nbar\n"),
B: difflib.SplitLines("foo\nbaz\n"),
FromFile: "Original",
ToFile: "Current",
Context: 3,
}
text, _ := GetUnifiedDiffString(diff)
fmt.Printf(text)
```
would output:
```
--- Original
+++ Current
@@ -1,3 +1,3 @@
foo
-bar
+baz
```

772
vendor/github.com/pmezard/go-difflib/difflib/difflib.go generated vendored Normal file
View File

@ -0,0 +1,772 @@
// Package difflib is a partial port of Python difflib module.
//
// It provides tools to compare sequences of strings and generate textual diffs.
//
// The following class and functions have been ported:
//
// - SequenceMatcher
//
// - unified_diff
//
// - context_diff
//
// Getting unified diffs was the main goal of the port. Keep in mind this code
// is mostly suitable to output text differences in a human friendly way, there
// are no guarantees generated diffs are consumable by patch(1).
package difflib
import (
"bufio"
"bytes"
"fmt"
"io"
"strings"
)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func calculateRatio(matches, length int) float64 {
if length > 0 {
return 2.0 * float64(matches) / float64(length)
}
return 1.0
}
type Match struct {
A int
B int
Size int
}
type OpCode struct {
Tag byte
I1 int
I2 int
J1 int
J2 int
}
// SequenceMatcher compares sequence of strings. The basic
// algorithm predates, and is a little fancier than, an algorithm
// published in the late 1980's by Ratcliff and Obershelp under the
// hyperbolic name "gestalt pattern matching". The basic idea is to find
// the longest contiguous matching subsequence that contains no "junk"
// elements (R-O doesn't address junk). The same idea is then applied
// recursively to the pieces of the sequences to the left and to the right
// of the matching subsequence. This does not yield minimal edit
// sequences, but does tend to yield matches that "look right" to people.
//
// SequenceMatcher tries to compute a "human-friendly diff" between two
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
// longest *contiguous* & junk-free matching subsequence. That's what
// catches peoples' eyes. The Windows(tm) windiff has another interesting
// notion, pairing up elements that appear uniquely in each sequence.
// That, and the method here, appear to yield more intuitive difference
// reports than does diff. This method appears to be the least vulnerable
// to synching up on blocks of "junk lines", though (like blank lines in
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
// because this is the only method of the 3 that has a *concept* of
// "junk" <wink>.
//
// Timing: Basic R-O is cubic time worst case and quadratic time expected
// case. SequenceMatcher is quadratic time for the worst case and has
// expected-case behavior dependent in a complicated way on how many
// elements the sequences have in common; best case time is linear.
type SequenceMatcher struct {
a []string
b []string
b2j map[string][]int
IsJunk func(string) bool
autoJunk bool
bJunk map[string]struct{}
matchingBlocks []Match
fullBCount map[string]int
bPopular map[string]struct{}
opCodes []OpCode
}
func NewMatcher(a, b []string) *SequenceMatcher {
m := SequenceMatcher{autoJunk: true}
m.SetSeqs(a, b)
return &m
}
func NewMatcherWithJunk(a, b []string, autoJunk bool,
isJunk func(string) bool) *SequenceMatcher {
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
m.SetSeqs(a, b)
return &m
}
// Set two sequences to be compared.
func (m *SequenceMatcher) SetSeqs(a, b []string) {
m.SetSeq1(a)
m.SetSeq2(b)
}
// Set the first sequence to be compared. The second sequence to be compared is
// not changed.
//
// SequenceMatcher computes and caches detailed information about the second
// sequence, so if you want to compare one sequence S against many sequences,
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
// sequences.
//
// See also SetSeqs() and SetSeq2().
func (m *SequenceMatcher) SetSeq1(a []string) {
if &a == &m.a {
return
}
m.a = a
m.matchingBlocks = nil
m.opCodes = nil
}
// Set the second sequence to be compared. The first sequence to be compared is
// not changed.
func (m *SequenceMatcher) SetSeq2(b []string) {
if &b == &m.b {
return
}
m.b = b
m.matchingBlocks = nil
m.opCodes = nil
m.fullBCount = nil
m.chainB()
}
func (m *SequenceMatcher) chainB() {
// Populate line -> index mapping
b2j := map[string][]int{}
for i, s := range m.b {
indices := b2j[s]
indices = append(indices, i)
b2j[s] = indices
}
// Purge junk elements
m.bJunk = map[string]struct{}{}
if m.IsJunk != nil {
junk := m.bJunk
for s, _ := range b2j {
if m.IsJunk(s) {
junk[s] = struct{}{}
}
}
for s, _ := range junk {
delete(b2j, s)
}
}
// Purge remaining popular elements
popular := map[string]struct{}{}
n := len(m.b)
if m.autoJunk && n >= 200 {
ntest := n/100 + 1
for s, indices := range b2j {
if len(indices) > ntest {
popular[s] = struct{}{}
}
}
for s, _ := range popular {
delete(b2j, s)
}
}
m.bPopular = popular
m.b2j = b2j
}
func (m *SequenceMatcher) isBJunk(s string) bool {
_, ok := m.bJunk[s]
return ok
}
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
//
// If IsJunk is not defined:
//
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
// alo <= i <= i+k <= ahi
// blo <= j <= j+k <= bhi
// and for all (i',j',k') meeting those conditions,
// k >= k'
// i <= i'
// and if i == i', j <= j'
//
// In other words, of all maximal matching blocks, return one that
// starts earliest in a, and of all those maximal matching blocks that
// start earliest in a, return the one that starts earliest in b.
//
// If IsJunk is defined, first the longest matching block is
// determined as above, but with the additional restriction that no
// junk element appears in the block. Then that block is extended as
// far as possible by matching (only) junk elements on both sides. So
// the resulting block never matches on junk except as identical junk
// happens to be adjacent to an "interesting" match.
//
// If no blocks match, return (alo, blo, 0).
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
// CAUTION: stripping common prefix or suffix would be incorrect.
// E.g.,
// ab
// acab
// Longest matching block is "ab", but if common prefix is
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
// strip, so ends up claiming that ab is changed to acab by
// inserting "ca" in the middle. That's minimal but unintuitive:
// "it's obvious" that someone inserted "ac" at the front.
// Windiff ends up at the same place as diff, but by pairing up
// the unique 'b's and then matching the first two 'a's.
besti, bestj, bestsize := alo, blo, 0
// find longest junk-free match
// during an iteration of the loop, j2len[j] = length of longest
// junk-free match ending with a[i-1] and b[j]
j2len := map[int]int{}
for i := alo; i != ahi; i++ {
// look at all instances of a[i] in b; note that because
// b2j has no junk keys, the loop is skipped if a[i] is junk
newj2len := map[int]int{}
for _, j := range m.b2j[m.a[i]] {
// a[i] matches b[j]
if j < blo {
continue
}
if j >= bhi {
break
}
k := j2len[j-1] + 1
newj2len[j] = k
if k > bestsize {
besti, bestj, bestsize = i-k+1, j-k+1, k
}
}
j2len = newj2len
}
// Extend the best by non-junk elements on each end. In particular,
// "popular" non-junk elements aren't in b2j, which greatly speeds
// the inner loop above, but also means "the best" match so far
// doesn't contain any junk *or* popular non-junk elements.
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
!m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
// Now that we have a wholly interesting match (albeit possibly
// empty!), we may as well suck up the matching junk on each
// side of it too. Can't think of a good reason not to, and it
// saves post-processing the (possibly considerable) expense of
// figuring out what to do with it. In the case of an empty
// interesting match, this is clearly the right thing to do,
// because no other kind of match is possible in the regions.
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
return Match{A: besti, B: bestj, Size: bestsize}
}
// Return list of triples describing matching subsequences.
//
// Each triple is of the form (i, j, n), and means that
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
// adjacent triples in the list, and the second is not the last triple in the
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
// adjacent equal blocks.
//
// The last triple is a dummy, (len(a), len(b), 0), and is the only
// triple with n==0.
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
if m.matchingBlocks != nil {
return m.matchingBlocks
}
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
match := m.findLongestMatch(alo, ahi, blo, bhi)
i, j, k := match.A, match.B, match.Size
if match.Size > 0 {
if alo < i && blo < j {
matched = matchBlocks(alo, i, blo, j, matched)
}
matched = append(matched, match)
if i+k < ahi && j+k < bhi {
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
}
}
return matched
}
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
// It's possible that we have adjacent equal blocks in the
// matching_blocks list now.
nonAdjacent := []Match{}
i1, j1, k1 := 0, 0, 0
for _, b := range matched {
// Is this block adjacent to i1, j1, k1?
i2, j2, k2 := b.A, b.B, b.Size
if i1+k1 == i2 && j1+k1 == j2 {
// Yes, so collapse them -- this just increases the length of
// the first block by the length of the second, and the first
// block so lengthened remains the block to compare against.
k1 += k2
} else {
// Not adjacent. Remember the first block (k1==0 means it's
// the dummy we started with), and make the second block the
// new block to compare against.
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
i1, j1, k1 = i2, j2, k2
}
}
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
m.matchingBlocks = nonAdjacent
return m.matchingBlocks
}
// Return list of 5-tuples describing how to turn a into b.
//
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
// tuple preceding it, and likewise for j1 == the previous j2.
//
// The tags are characters, with these meanings:
//
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
//
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
//
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
//
// 'e' (equal): a[i1:i2] == b[j1:j2]
func (m *SequenceMatcher) GetOpCodes() []OpCode {
if m.opCodes != nil {
return m.opCodes
}
i, j := 0, 0
matching := m.GetMatchingBlocks()
opCodes := make([]OpCode, 0, len(matching))
for _, m := range matching {
// invariant: we've pumped out correct diffs to change
// a[:i] into b[:j], and the next matching block is
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
// out a diff to change a[i:ai] into b[j:bj], pump out
// the matching block, and move (i,j) beyond the match
ai, bj, size := m.A, m.B, m.Size
tag := byte(0)
if i < ai && j < bj {
tag = 'r'
} else if i < ai {
tag = 'd'
} else if j < bj {
tag = 'i'
}
if tag > 0 {
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
}
i, j = ai+size, bj+size
// the list of matching blocks is terminated by a
// sentinel with size 0
if size > 0 {
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
}
}
m.opCodes = opCodes
return m.opCodes
}
// Isolate change clusters by eliminating ranges with no changes.
//
// Return a generator of groups with up to n lines of context.
// Each group is in the same format as returned by GetOpCodes().
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
if n < 0 {
n = 3
}
codes := m.GetOpCodes()
if len(codes) == 0 {
codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
}
// Fixup leading and trailing groups if they show no changes.
if codes[0].Tag == 'e' {
c := codes[0]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
}
if codes[len(codes)-1].Tag == 'e' {
c := codes[len(codes)-1]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
}
nn := n + n
groups := [][]OpCode{}
group := []OpCode{}
for _, c := range codes {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
// End the current group and start a new one whenever
// there is a large range with no changes.
if c.Tag == 'e' && i2-i1 > nn {
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
j1, min(j2, j1+n)})
groups = append(groups, group)
group = []OpCode{}
i1, j1 = max(i1, i2-n), max(j1, j2-n)
}
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
}
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
groups = append(groups, group)
}
return groups
}
// Return a measure of the sequences' similarity (float in [0,1]).
//
// Where T is the total number of elements in both sequences, and
// M is the number of matches, this is 2.0*M / T.
// Note that this is 1 if the sequences are identical, and 0 if
// they have nothing in common.
//
// .Ratio() is expensive to compute if you haven't already computed
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
// want to try .QuickRatio() or .RealQuickRation() first to get an
// upper bound.
func (m *SequenceMatcher) Ratio() float64 {
matches := 0
for _, m := range m.GetMatchingBlocks() {
matches += m.Size
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() relatively quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute.
func (m *SequenceMatcher) QuickRatio() float64 {
// viewing a and b as multisets, set matches to the cardinality
// of their intersection; this counts the number of matches
// without regard to order, so is clearly an upper bound
if m.fullBCount == nil {
m.fullBCount = map[string]int{}
for _, s := range m.b {
m.fullBCount[s] = m.fullBCount[s] + 1
}
}
// avail[x] is the number of times x appears in 'b' less the
// number of times we've seen it in 'a' so far ... kinda
avail := map[string]int{}
matches := 0
for _, s := range m.a {
n, ok := avail[s]
if !ok {
n = m.fullBCount[s]
}
avail[s] = n - 1
if n > 0 {
matches += 1
}
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() very quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute than either .Ratio() or .QuickRatio().
func (m *SequenceMatcher) RealQuickRatio() float64 {
la, lb := len(m.a), len(m.b)
return calculateRatio(min(la, lb), la+lb)
}
// Convert range to the "ed" format
func formatRangeUnified(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 1 {
return fmt.Sprintf("%d", beginning)
}
if length == 0 {
beginning -= 1 // empty ranges begin at line just before the range
}
return fmt.Sprintf("%d,%d", beginning, length)
}
// Unified diff parameters
type UnifiedDiff struct {
A []string // First sequence lines
FromFile string // First file name
FromDate string // First file time
B []string // Second sequence lines
ToFile string // Second file name
ToDate string // Second file time
Eol string // Headers end of line, defaults to LF
Context int // Number of context lines
}
// Compare two sequences of lines; generate the delta as a unified diff.
//
// Unified diffs are a compact way of showing line changes and a few
// lines of context. The number of context lines is set by 'n' which
// defaults to three.
//
// By default, the diff control lines (those with ---, +++, or @@) are
// created with a trailing newline. This is helpful so that inputs
// created from file.readlines() result in diffs that are suitable for
// file.writelines() since both the inputs and outputs have trailing
// newlines.
//
// For inputs that do not have trailing newlines, set the lineterm
// argument to "" so that the output will be uniformly newline free.
//
// The unidiff format normally has a header for filenames and modification
// times. Any or all of these may be specified using strings for
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
// The modification times are normally expressed in the ISO 8601 format.
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
wf := func(format string, args ...interface{}) error {
_, err := buf.WriteString(fmt.Sprintf(format, args...))
return err
}
ws := func(s string) error {
_, err := buf.WriteString(s)
return err
}
if len(diff.Eol) == 0 {
diff.Eol = "\n"
}
started := false
m := NewMatcher(diff.A, diff.B)
for _, g := range m.GetGroupedOpCodes(diff.Context) {
if !started {
started = true
fromDate := ""
if len(diff.FromDate) > 0 {
fromDate = "\t" + diff.FromDate
}
toDate := ""
if len(diff.ToDate) > 0 {
toDate = "\t" + diff.ToDate
}
if diff.FromFile != "" || diff.ToFile != "" {
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
if err != nil {
return err
}
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
if err != nil {
return err
}
}
}
first, last := g[0], g[len(g)-1]
range1 := formatRangeUnified(first.I1, last.I2)
range2 := formatRangeUnified(first.J1, last.J2)
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
return err
}
for _, c := range g {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
if c.Tag == 'e' {
for _, line := range diff.A[i1:i2] {
if err := ws(" " + line); err != nil {
return err
}
}
continue
}
if c.Tag == 'r' || c.Tag == 'd' {
for _, line := range diff.A[i1:i2] {
if err := ws("-" + line); err != nil {
return err
}
}
}
if c.Tag == 'r' || c.Tag == 'i' {
for _, line := range diff.B[j1:j2] {
if err := ws("+" + line); err != nil {
return err
}
}
}
}
}
return nil
}
// Like WriteUnifiedDiff but returns the diff a string.
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
w := &bytes.Buffer{}
err := WriteUnifiedDiff(w, diff)
return string(w.Bytes()), err
}
// Convert range to the "ed" format.
func formatRangeContext(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 0 {
beginning -= 1 // empty ranges begin at line just before the range
}
if length <= 1 {
return fmt.Sprintf("%d", beginning)
}
return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
}
type ContextDiff UnifiedDiff
// Compare two sequences of lines; generate the delta as a context diff.
//
// Context diffs are a compact way of showing line changes and a few
// lines of context. The number of context lines is set by diff.Context
// which defaults to three.
//
// By default, the diff control lines (those with *** or ---) are
// created with a trailing newline.
//
// For inputs that do not have trailing newlines, set the diff.Eol
// argument to "" so that the output will be uniformly newline free.
//
// The context diff format normally has a header for filenames and
// modification times. Any or all of these may be specified using
// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
// The modification times are normally expressed in the ISO 8601 format.
// If not specified, the strings default to blanks.
func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
var diffErr error
wf := func(format string, args ...interface{}) {
_, err := buf.WriteString(fmt.Sprintf(format, args...))
if diffErr == nil && err != nil {
diffErr = err
}
}
ws := func(s string) {
_, err := buf.WriteString(s)
if diffErr == nil && err != nil {
diffErr = err
}
}
if len(diff.Eol) == 0 {
diff.Eol = "\n"
}
prefix := map[byte]string{
'i': "+ ",
'd': "- ",
'r': "! ",
'e': " ",
}
started := false
m := NewMatcher(diff.A, diff.B)
for _, g := range m.GetGroupedOpCodes(diff.Context) {
if !started {
started = true
fromDate := ""
if len(diff.FromDate) > 0 {
fromDate = "\t" + diff.FromDate
}
toDate := ""
if len(diff.ToDate) > 0 {
toDate = "\t" + diff.ToDate
}
if diff.FromFile != "" || diff.ToFile != "" {
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
}
}
first, last := g[0], g[len(g)-1]
ws("***************" + diff.Eol)
range1 := formatRangeContext(first.I1, last.I2)
wf("*** %s ****%s", range1, diff.Eol)
for _, c := range g {
if c.Tag == 'r' || c.Tag == 'd' {
for _, cc := range g {
if cc.Tag == 'i' {
continue
}
for _, line := range diff.A[cc.I1:cc.I2] {
ws(prefix[cc.Tag] + line)
}
}
break
}
}
range2 := formatRangeContext(first.J1, last.J2)
wf("--- %s ----%s", range2, diff.Eol)
for _, c := range g {
if c.Tag == 'r' || c.Tag == 'i' {
for _, cc := range g {
if cc.Tag == 'd' {
continue
}
for _, line := range diff.B[cc.J1:cc.J2] {
ws(prefix[cc.Tag] + line)
}
}
break
}
}
}
return diffErr
}
// Like WriteContextDiff but returns the diff a string.
func GetContextDiffString(diff ContextDiff) (string, error) {
w := &bytes.Buffer{}
err := WriteContextDiff(w, diff)
return string(w.Bytes()), err
}
// Split a string on "\n" while preserving them. The output can be used
// as input for UnifiedDiff and ContextDiff structures.
func SplitLines(s string) []string {
lines := strings.SplitAfter(s, "\n")
lines[len(lines)-1] += "\n"
return lines
}

View File

@ -0,0 +1,426 @@
package difflib
import (
"bytes"
"fmt"
"math"
"reflect"
"strings"
"testing"
)
func assertAlmostEqual(t *testing.T, a, b float64, places int) {
if math.Abs(a-b) > math.Pow10(-places) {
t.Errorf("%.7f != %.7f", a, b)
}
}
func assertEqual(t *testing.T, a, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("%v != %v", a, b)
}
}
func splitChars(s string) []string {
chars := make([]string, 0, len(s))
// Assume ASCII inputs
for i := 0; i != len(s); i++ {
chars = append(chars, string(s[i]))
}
return chars
}
func TestSequenceMatcherRatio(t *testing.T) {
s := NewMatcher(splitChars("abcd"), splitChars("bcde"))
assertEqual(t, s.Ratio(), 0.75)
assertEqual(t, s.QuickRatio(), 0.75)
assertEqual(t, s.RealQuickRatio(), 1.0)
}
func TestGetOptCodes(t *testing.T) {
a := "qabxcd"
b := "abycdf"
s := NewMatcher(splitChars(a), splitChars(b))
w := &bytes.Buffer{}
for _, op := range s.GetOpCodes() {
fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag),
op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2])
}
result := string(w.Bytes())
expected := `d a[0:1], (q) b[0:0] ()
e a[1:3], (ab) b[0:2] (ab)
r a[3:4], (x) b[2:3] (y)
e a[4:6], (cd) b[3:5] (cd)
i a[6:6], () b[5:6] (f)
`
if expected != result {
t.Errorf("unexpected op codes: \n%s", result)
}
}
func TestGroupedOpCodes(t *testing.T) {
a := []string{}
for i := 0; i != 39; i++ {
a = append(a, fmt.Sprintf("%02d", i))
}
b := []string{}
b = append(b, a[:8]...)
b = append(b, " i")
b = append(b, a[8:19]...)
b = append(b, " x")
b = append(b, a[20:22]...)
b = append(b, a[27:34]...)
b = append(b, " y")
b = append(b, a[35:]...)
s := NewMatcher(a, b)
w := &bytes.Buffer{}
for _, g := range s.GetGroupedOpCodes(-1) {
fmt.Fprintf(w, "group\n")
for _, op := range g {
fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag),
op.I1, op.I2, op.J1, op.J2)
}
}
result := string(w.Bytes())
expected := `group
e, 5, 8, 5, 8
i, 8, 8, 8, 9
e, 8, 11, 9, 12
group
e, 16, 19, 17, 20
r, 19, 20, 20, 21
e, 20, 22, 21, 23
d, 22, 27, 23, 23
e, 27, 30, 23, 26
group
e, 31, 34, 27, 30
r, 34, 35, 30, 31
e, 35, 38, 31, 34
`
if expected != result {
t.Errorf("unexpected op codes: \n%s", result)
}
}
func ExampleGetUnifiedDiffCode() {
a := `one
two
three
four
fmt.Printf("%s,%T",a,b)`
b := `zero
one
three
four`
diff := UnifiedDiff{
A: SplitLines(a),
B: SplitLines(b),
FromFile: "Original",
FromDate: "2005-01-26 23:30:50",
ToFile: "Current",
ToDate: "2010-04-02 10:20:52",
Context: 3,
}
result, _ := GetUnifiedDiffString(diff)
fmt.Println(strings.Replace(result, "\t", " ", -1))
// Output:
// --- Original 2005-01-26 23:30:50
// +++ Current 2010-04-02 10:20:52
// @@ -1,5 +1,4 @@
// +zero
// one
// -two
// three
// four
// -fmt.Printf("%s,%T",a,b)
}
func ExampleGetContextDiffCode() {
a := `one
two
three
four
fmt.Printf("%s,%T",a,b)`
b := `zero
one
tree
four`
diff := ContextDiff{
A: SplitLines(a),
B: SplitLines(b),
FromFile: "Original",
ToFile: "Current",
Context: 3,
Eol: "\n",
}
result, _ := GetContextDiffString(diff)
fmt.Print(strings.Replace(result, "\t", " ", -1))
// Output:
// *** Original
// --- Current
// ***************
// *** 1,5 ****
// one
// ! two
// ! three
// four
// - fmt.Printf("%s,%T",a,b)
// --- 1,4 ----
// + zero
// one
// ! tree
// four
}
func ExampleGetContextDiffString() {
a := `one
two
three
four`
b := `zero
one
tree
four`
diff := ContextDiff{
A: SplitLines(a),
B: SplitLines(b),
FromFile: "Original",
ToFile: "Current",
Context: 3,
Eol: "\n",
}
result, _ := GetContextDiffString(diff)
fmt.Printf(strings.Replace(result, "\t", " ", -1))
// Output:
// *** Original
// --- Current
// ***************
// *** 1,4 ****
// one
// ! two
// ! three
// four
// --- 1,4 ----
// + zero
// one
// ! tree
// four
}
func rep(s string, count int) string {
return strings.Repeat(s, count)
}
func TestWithAsciiOneInsert(t *testing.T) {
sm := NewMatcher(splitChars(rep("b", 100)),
splitChars("a"+rep("b", 100)))
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
assertEqual(t, sm.GetOpCodes(),
[]OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}})
assertEqual(t, len(sm.bPopular), 0)
sm = NewMatcher(splitChars(rep("b", 100)),
splitChars(rep("b", 50)+"a"+rep("b", 50)))
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
assertEqual(t, sm.GetOpCodes(),
[]OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}})
assertEqual(t, len(sm.bPopular), 0)
}
func TestWithAsciiOnDelete(t *testing.T) {
sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)),
splitChars(rep("a", 40)+rep("b", 40)))
assertAlmostEqual(t, sm.Ratio(), 0.994, 3)
assertEqual(t, sm.GetOpCodes(),
[]OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}})
}
func TestWithAsciiBJunk(t *testing.T) {
isJunk := func(s string) bool {
return s == " "
}
sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
splitChars(rep("a", 44)+rep("b", 40)), true, isJunk)
assertEqual(t, sm.bJunk, map[string]struct{}{})
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}})
isJunk = func(s string) bool {
return s == " " || s == "b"
}
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}})
}
func TestSFBugsRatioForNullSeqn(t *testing.T) {
sm := NewMatcher(nil, nil)
assertEqual(t, sm.Ratio(), 1.0)
assertEqual(t, sm.QuickRatio(), 1.0)
assertEqual(t, sm.RealQuickRatio(), 1.0)
}
func TestSFBugsComparingEmptyLists(t *testing.T) {
groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1)
assertEqual(t, len(groups), 0)
diff := UnifiedDiff{
FromFile: "Original",
ToFile: "Current",
Context: 3,
}
result, err := GetUnifiedDiffString(diff)
assertEqual(t, err, nil)
assertEqual(t, result, "")
}
func TestOutputFormatRangeFormatUnified(t *testing.T) {
// Per the diff spec at http://www.unix.org/single_unix_specification/
//
// Each <range> field shall be of the form:
// %1d", <beginning line number> if the range contains exactly one line,
// and:
// "%1d,%1d", <beginning line number>, <number of lines> otherwise.
// If a range is empty, its beginning line number shall be the number of
// the line just before the range, or 0 if the empty range starts the file.
fm := formatRangeUnified
assertEqual(t, fm(3, 3), "3,0")
assertEqual(t, fm(3, 4), "4")
assertEqual(t, fm(3, 5), "4,2")
assertEqual(t, fm(3, 6), "4,3")
assertEqual(t, fm(0, 0), "0,0")
}
func TestOutputFormatRangeFormatContext(t *testing.T) {
// Per the diff spec at http://www.unix.org/single_unix_specification/
//
// The range of lines in file1 shall be written in the following format
// if the range contains two or more lines:
// "*** %d,%d ****\n", <beginning line number>, <ending line number>
// and the following format otherwise:
// "*** %d ****\n", <ending line number>
// The ending line number of an empty range shall be the number of the preceding line,
// or 0 if the range is at the start of the file.
//
// Next, the range of lines in file2 shall be written in the following format
// if the range contains two or more lines:
// "--- %d,%d ----\n", <beginning line number>, <ending line number>
// and the following format otherwise:
// "--- %d ----\n", <ending line number>
fm := formatRangeContext
assertEqual(t, fm(3, 3), "3")
assertEqual(t, fm(3, 4), "4")
assertEqual(t, fm(3, 5), "4,5")
assertEqual(t, fm(3, 6), "4,6")
assertEqual(t, fm(0, 0), "0")
}
func TestOutputFormatTabDelimiter(t *testing.T) {
diff := UnifiedDiff{
A: splitChars("one"),
B: splitChars("two"),
FromFile: "Original",
FromDate: "2005-01-26 23:30:50",
ToFile: "Current",
ToDate: "2010-04-12 10:20:52",
Eol: "\n",
}
ud, err := GetUnifiedDiffString(diff)
assertEqual(t, err, nil)
assertEqual(t, SplitLines(ud)[:2], []string{
"--- Original\t2005-01-26 23:30:50\n",
"+++ Current\t2010-04-12 10:20:52\n",
})
cd, err := GetContextDiffString(ContextDiff(diff))
assertEqual(t, err, nil)
assertEqual(t, SplitLines(cd)[:2], []string{
"*** Original\t2005-01-26 23:30:50\n",
"--- Current\t2010-04-12 10:20:52\n",
})
}
func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
diff := UnifiedDiff{
A: splitChars("one"),
B: splitChars("two"),
FromFile: "Original",
ToFile: "Current",
Eol: "\n",
}
ud, err := GetUnifiedDiffString(diff)
assertEqual(t, err, nil)
assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"})
cd, err := GetContextDiffString(ContextDiff(diff))
assertEqual(t, err, nil)
assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"})
}
func TestOmitFilenames(t *testing.T) {
diff := UnifiedDiff{
A: SplitLines("o\nn\ne\n"),
B: SplitLines("t\nw\no\n"),
Eol: "\n",
}
ud, err := GetUnifiedDiffString(diff)
assertEqual(t, err, nil)
assertEqual(t, SplitLines(ud), []string{
"@@ -0,0 +1,2 @@\n",
"+t\n",
"+w\n",
"@@ -2,2 +3,0 @@\n",
"-n\n",
"-e\n",
"\n",
})
cd, err := GetContextDiffString(ContextDiff(diff))
assertEqual(t, err, nil)
assertEqual(t, SplitLines(cd), []string{
"***************\n",
"*** 0 ****\n",
"--- 1,2 ----\n",
"+ t\n",
"+ w\n",
"***************\n",
"*** 2,3 ****\n",
"- n\n",
"- e\n",
"--- 3 ----\n",
"\n",
})
}
func TestSplitLines(t *testing.T) {
allTests := []struct {
input string
want []string
}{
{"foo", []string{"foo\n"}},
{"foo\nbar", []string{"foo\n", "bar\n"}},
{"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}},
}
for _, test := range allTests {
assertEqual(t, SplitLines(test.input), test.want)
}
}
func benchmarkSplitLines(b *testing.B, count int) {
str := strings.Repeat("foo\n", count)
b.ResetTimer()
n := 0
for i := 0; i < b.N; i++ {
n += len(SplitLines(str))
}
}
func BenchmarkSplitLines100(b *testing.B) {
benchmarkSplitLines(b, 100)
}
func BenchmarkSplitLines10000(b *testing.B) {
benchmarkSplitLines(b, 10000)
}

View File

@ -1,191 +0,0 @@
package keypair
import (
"bytes"
crypto_rand "crypto/rand"
"encoding/json"
"errors"
"hash/fnv"
"io"
math_rand "math/rand"
base65536 "github.com/Nightbug/go-base65536"
"github.com/mr-tron/base58/base58"
"golang.org/x/crypto/nacl/box"
)
var baseType = "base58"
func SetBase(s string) (err error) {
if s == "base58" {
baseType = s
} else if s == "base65536" {
baseType = s
} else {
err = errors.New("no such base")
}
return
}
type KeyPair struct {
Public string `json:"public"`
Private string `json:"private,omitempty"`
private *[32]byte
public *[32]byte
}
func (kp KeyPair) String() string {
b, _ := json.Marshal(kp)
return string(b)
}
// New will generate a new key pair, or reload a keypair
// from a public key or a public-private key pair.
func New(kpLoad ...KeyPair) (kp KeyPair, err error) {
kp = KeyPair{}
if len(kpLoad) > 0 {
kp.Public = kpLoad[0].Public
kp.Private = kpLoad[0].Private
} else {
kp.Public, kp.Private, err = generateKeyPair()
if err != nil {
return
}
}
kp.public, err = keyToBytes(kp.Public)
if err != nil {
return
}
if len(kp.Private) > 0 {
kp.private, err = keyToBytes(kp.Private)
if err != nil {
return
}
}
return
}
func generateKeyPair() (publicKey, privateKey string, err error) {
publicKeyBytes, privateKeyBytes, err := box.GenerateKey(crypto_rand.Reader)
if err != nil {
return
}
if baseType == "base58" {
publicKey = base58.FastBase58Encoding(publicKeyBytes[:])
privateKey = base58.FastBase58Encoding(privateKeyBytes[:])
} else if baseType == "base65536" {
publicKey = base65536.Marshal(publicKeyBytes[:])
privateKey = base65536.Marshal(privateKeyBytes[:])
}
return
}
func generateDeterministicKey(seedBytes []byte) (publicKey, privateKey string) {
h := fnv.New32a()
h.Write(seedBytes)
math_rand.Seed(int64(h.Sum32()))
b := make([]byte, 512)
math_rand.Read(b)
reader := bytes.NewReader(b)
publicKeyBytes, privateKeyBytes, err := box.GenerateKey(reader)
if err != nil {
panic(err)
}
if baseType == "base58" {
publicKey = base58.FastBase58Encoding(publicKeyBytes[:])
privateKey = base58.FastBase58Encoding(privateKeyBytes[:])
} else if baseType == "base65536" {
publicKey = base65536.Marshal(publicKeyBytes[:])
privateKey = base65536.Marshal(privateKeyBytes[:])
}
return
}
// NewDeterministic will return a deterministic key
func NewDeterministic(passphrase string) (kp KeyPair, err error) {
pub, priv := generateDeterministicKey([]byte(passphrase))
kp, err = New(KeyPair{Public: pub, Private: priv})
return
}
func keyToBytes(s string) (key *[32]byte, err error) {
var keyBytes []byte
if baseType == "base58" {
keyBytes, err = base58.FastBase58Decoding(s)
} else if baseType == "base65536" {
err = base65536.Unmarshal([]byte(s), &keyBytes)
}
if err != nil {
return
}
key = new([32]byte)
copy(key[:], keyBytes[:32])
return
}
// Encrypt a message for a recipient
func (kp KeyPair) Encrypt(msg []byte, recipientPublicKey string) (encrypted []byte, err error) {
recipient, err := New(KeyPair{Public: recipientPublicKey})
if err != nil {
return
}
encrypted, err = encryptWithKeyPair(msg, kp.private, recipient.public)
return
}
// Decrypt a message
func (kp KeyPair) Decrypt(encrypted []byte, senderPublicKey string) (msg []byte, err error) {
sender, err := New(KeyPair{Public: senderPublicKey})
if err != nil {
return
}
msg, err = decryptWithKeyPair(encrypted, sender.public, kp.private)
return
}
func encryptWithKeyPair(msg []byte, senderPrivateKey, recipientPublicKey *[32]byte) (encrypted []byte, err error) {
// You must use a different nonce for each message you encrypt with the
// same key. Since the nonce here is 192 bits long, a random value
// provides a sufficiently small probability of repeats.
var nonce [24]byte
if _, err = io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {
return
}
// This encrypts msg and appends the result to the nonce.
encrypted = box.Seal(nonce[:], msg, &nonce, recipientPublicKey, senderPrivateKey)
return
}
func decryptWithKeyPair(enc []byte, senderPublicKey, recipientPrivateKey *[32]byte) (decrypted []byte, err error) {
// The recipient can decrypt the message using their private key and the
// sender's public key. When you decrypt, you must use the same nonce you
// used to encrypt the message. One way to achieve this is to store the
// nonce alongside the encrypted message. Above, we stored the nonce in the
// first 24 bytes of the encrypted text.
var decryptNonce [24]byte
copy(decryptNonce[:], enc[:24])
var ok bool
decrypted, ok = box.Open(nil, enc[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
if !ok {
err = errors.New("keypair decryption failed")
}
return
}
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}

View File

@ -0,0 +1,38 @@
package main
import (
"encoding/hex"
"io"
)
const bufsize = 256
type hexdump struct {
w io.Writer
buf [bufsize]byte
}
func hexoutput(w io.Writer) io.WriteCloser {
return &hexdump{w: w}
}
func (h *hexdump) Write(data []byte) (n int, err error) {
for n < len(data) {
amt := len(data) - n
if hex.EncodedLen(amt) > bufsize {
amt = hex.DecodedLen(bufsize)
}
nn := hex.Encode(h.buf[:], data[n:n+amt])
_, err := h.w.Write(h.buf[:nn])
n += amt
if err != nil {
return n, err
}
}
return n, nil
}
func (h *hexdump) Close() error {
_, err := h.w.Write([]byte{'\n'})
return err
}

View File

@ -0,0 +1,51 @@
package main
import (
"flag"
"io"
"log"
"os"
"path"
"bitbucket.org/dchapes/mnemonicode"
)
func main() {
log.SetFlags(0)
log.SetPrefix(path.Base(os.Args[0]) + ": ")
hexFlag := flag.Bool("x", false, "hex output")
verboseFlag := flag.Bool("v", false, "verbose")
flag.Parse()
if flag.NArg() > 0 {
flag.Usage()
os.Exit(2)
}
output := io.WriteCloser(os.Stdout)
if *hexFlag {
output = hexoutput(output)
}
var n int64
var err error
if true {
dec := mnemonicode.NewDecoder(os.Stdin)
n, err = io.Copy(output, dec)
} else {
w := mnemonicode.NewDecodeWriter(output)
n, err = io.Copy(w, os.Stdin)
if err != nil {
log.Fatal(err)
}
err = w.Close()
}
if err != nil {
log.Fatal(err)
}
if *verboseFlag {
log.Println("bytes decoded:", n)
}
if err = output.Close(); err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,66 @@
package main
import (
"encoding/hex"
"unicode"
"unicode/utf8"
"golang.org/x/text/transform"
)
type hexinput bool
func (h *hexinput) Reset() {
*h = false
}
func (h *hexinput) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
if r = rune(src[0]); r < utf8.RuneSelf {
sz = 1
} else {
r, sz = utf8.DecodeRune(src)
if sz == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src) {
err = transform.ErrShortSrc
break
}
// Just ignore it
nSrc++
continue
}
}
if unicode.IsSpace(r) {
nSrc += sz
continue
}
if sz > 1 {
err = hex.InvalidByteError(src[0]) // XXX
break
}
if len(src) < 2 {
err = transform.ErrShortSrc
break
}
if nDst+1 > len(dst) {
err = transform.ErrShortDst
break
}
sz = 2
nSrc += 2
if !*h {
*h = true
if r == '0' && (src[1] == 'x' || src[1] == 'X') {
continue
}
}
if _, err = hex.Decode(dst[nDst:], src[:2]); err != nil {
break
}
nDst++
}
return
}

Some files were not shown because too many files have changed in this diff Show More