diff --git a/Gopkg.lock b/Gopkg.lock
index 56667e8..29d2624 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -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
diff --git a/Gopkg.toml b/Gopkg.toml
index 5cfff59..eca74be 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -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"
diff --git a/vendor/github.com/Nightbug/go-base65536/README.md b/vendor/github.com/Nightbug/go-base65536/README.md
deleted file mode 100644
index 9f954ba..0000000
--- a/vendor/github.com/Nightbug/go-base65536/README.md
+++ /dev/null
@@ -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
diff --git a/vendor/github.com/Nightbug/go-base65536/base65536.go b/vendor/github.com/Nightbug/go-base65536/base65536.go
deleted file mode 100644
index 0862832..0000000
--- a/vendor/github.com/Nightbug/go-base65536/base65536.go
+++ /dev/null
@@ -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
-}
diff --git a/vendor/github.com/Nightbug/go-base65536/get_b2.go b/vendor/github.com/Nightbug/go-base65536/get_b2.go
deleted file mode 100644
index 673999f..0000000
--- a/vendor/github.com/Nightbug/go-base65536/get_b2.go
+++ /dev/null
@@ -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,
-}
diff --git a/vendor/github.com/Nightbug/go-base65536/get_block_start.go b/vendor/github.com/Nightbug/go-base65536/get_block_start.go
deleted file mode 100644
index 2bce461..0000000
--- a/vendor/github.com/Nightbug/go-base65536/get_block_start.go
+++ /dev/null
@@ -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,
-}
diff --git a/vendor/github.com/cihub/seelog/behavior_adaptive_test.go b/vendor/github.com/cihub/seelog/behavior_adaptive_test.go
new file mode 100644
index 0000000..e991949
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/behavior_adaptive_test.go
@@ -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 := `
+
+
+
+
+
+
+
+`
+
+ 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()
+}
diff --git a/vendor/github.com/cihub/seelog/behavior_asyncloop_test.go b/vendor/github.com/cihub/seelog/behavior_asyncloop_test.go
new file mode 100644
index 0000000..142c4fc
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/behavior_asyncloop_test.go
@@ -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 := `
+
+
+
+
+
+
+
+`
+
+ 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 := `
+
+
+
+
+
+
+
+`
+
+ 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()
+}
diff --git a/vendor/github.com/cihub/seelog/behavior_asynctimer_test.go b/vendor/github.com/cihub/seelog/behavior_asynctimer_test.go
new file mode 100644
index 0000000..37bfa6a
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/behavior_asynctimer_test.go
@@ -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 := `
+
+
+
+
+
+
+
+`
+
+ 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()
+}
diff --git a/vendor/github.com/cihub/seelog/behavior_synclogger_test.go b/vendor/github.com/cihub/seelog/behavior_synclogger_test.go
new file mode 100644
index 0000000..ddcbbb6
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/behavior_synclogger_test.go
@@ -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 := `
+
+
+
+
+
+
+
+`
+
+ 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()
+}
diff --git a/vendor/github.com/cihub/seelog/cfg_logconfig_test.go b/vendor/github.com/cihub/seelog/cfg_logconfig_test.go
new file mode 100644
index 0000000..af64a6c
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/cfg_logconfig_test.go
@@ -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 :=
+ `
+
+
+
+
+
+
+`
+
+ 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)
+}
diff --git a/vendor/github.com/cihub/seelog/cfg_parser_test.go b/vendor/github.com/cihub/seelog/cfg_parser_test.go
new file mode 100644
index 0000000..9c6f9b8
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/cfg_parser_test.go
@@ -0,0 +1,1089 @@
+// 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"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+type customTestReceiverOutput struct {
+ initCalled bool
+ dataPassed string
+ messageOutput string
+ levelOutput LogLevel
+ closed bool
+ flushed bool
+}
+type customTestReceiver struct{ co *customTestReceiverOutput }
+
+func (cr *customTestReceiver) ReceiveMessage(message string, level LogLevel, context LogContextInterface) error {
+ cr.co.messageOutput = message
+ cr.co.levelOutput = level
+ return nil
+}
+
+func (cr *customTestReceiver) String() string {
+ return fmt.Sprintf("custom data='%s'", cr.co.dataPassed)
+}
+
+func (cr *customTestReceiver) AfterParse(initArgs CustomReceiverInitArgs) error {
+ cr.co = new(customTestReceiverOutput)
+ cr.co.initCalled = true
+ cr.co.dataPassed = initArgs.XmlCustomAttrs["test"]
+ return nil
+}
+
+func (cr *customTestReceiver) Flush() {
+ cr.co.flushed = true
+}
+
+func (cr *customTestReceiver) Close() error {
+ cr.co.closed = true
+ return nil
+}
+
+var re = regexp.MustCompile(`[^a-zA-Z0-9]+`)
+
+func getTestFileName(testName, postfix string) string {
+ if len(postfix) != 0 {
+ return strings.ToLower(re.ReplaceAllString(testName, "_")) + "_" + postfix + "_test.log"
+ }
+ return strings.ToLower(re.ReplaceAllString(testName, "_")) + "_test.log"
+}
+
+var parserTests []parserTest
+
+type parserTest struct {
+ testName string
+ config string
+ expected *configForParsing //interface{}
+ errorExpected bool
+ parserConfig *CfgParseParams
+}
+
+func getParserTests() []parserTest {
+ if parserTests == nil {
+ parserTests = make([]parserTest, 0)
+
+ testName := "Simple file output"
+ testLogFileName := getTestFileName(testName, "")
+ testConfig := `
+
+
+
+
+
+ `
+ testExpected := new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ := NewFileWriter(testLogFileName)
+ testHeadSplitter, _ := NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Filter dispatcher"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFilter, _ := NewFilterDispatcher(DefaultFormatter, []interface{}{testfileWriter}, DebugLvl, InfoLvl, CriticalLvl)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testFilter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Console writer"
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ := NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "SMTP writer"
+ testConfig = `
+
+
+
+
+
+
+
+
+
+
+
+ `
+
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testSMTPWriter := NewSMTPWriter(
+ "sa",
+ "sn",
+ []string{"ra1", "ra2", "ra3"},
+ "hn",
+ "123",
+ "un",
+ "up",
+ []string{"cacdp1", "cacdp2"},
+ DefaultSubjectPhrase,
+ nil,
+ )
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testSMTPWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "SMTP writer custom header and subject configuration"
+ testConfig = `
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testSMTPWriter = NewSMTPWriter(
+ "sa",
+ "sn",
+ []string{"ra1"},
+ "hn",
+ "123",
+ "un",
+ "up",
+ []string{"cacdp1"},
+ "ohlala",
+ []string{"Priority: Urgent", "Importance: high", "Sensitivity: Company-Confidential", "Auto-Submitted: auto-generated"},
+ )
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testSMTPWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Default output"
+ testConfig = `
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Asyncloop behavior"
+ testConfig = `
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Asynctimer behavior"
+ testConfig = `
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncTimerloggerTypeFromString
+ testExpected.LoggerData = asyncTimerLoggerData{101}
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer size"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ := NewRollingFileWriterSize(testLogFileName, rollingArchiveNone, "", 100, 5, rollingNameModePostfix)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "log.zip", 100, 5, rollingNameModePostfix)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip with specified path"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "test.zip", 100, 5, rollingNameModePrefix)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive none"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveNone, "", 100, 5, rollingNameModePostfix)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer date"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ := NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingIntervalAny, rollingNameModePostfix)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriterTime})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Buffered writer"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ = NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingIntervalDaily, rollingNameModePostfix)
+ testbufferedWriter, _ := NewBufferedWriter(testrollingFileWriterTime, 100500, 100)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testbufferedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Inner splitter output"
+ testLogFileName1 := getTestFileName(testName, "1")
+ testLogFileName2 := getTestFileName(testName, "2")
+ testLogFileName3 := getTestFileName(testName, "3")
+ testConfig = `
+
+
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter1, _ := NewFileWriter(testLogFileName2)
+ testfileWriter2, _ := NewFileWriter(testLogFileName3)
+ testInnerSplitter, _ := NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter1, testfileWriter2})
+ testfileWriter, _ = NewFileWriter(testLogFileName1)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter, testInnerSplitter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ RegisterReceiver("custom-name-1", &customTestReceiver{})
+
+ testName = "Custom receiver 1"
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testCustomReceiver, _ := NewCustomReceiverDispatcher(DefaultFormatter, "custom-name-1", CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set",
+ },
+ })
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Custom receiver 2"
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ crec := &customTestReceiver{}
+ cargs := CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set2",
+ },
+ }
+ crec.AfterParse(cargs)
+ testCustomReceiver2, _ := NewCustomReceiverDispatcherByValue(DefaultFormatter, crec, "custom-name-2", cargs)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver2})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ fnc := func(initArgs CustomReceiverInitArgs) (CustomReceiver, error) {
+ return &customTestReceiver{}, nil
+ }
+ cfg := CfgParseParams{
+ CustomReceiverProducers: map[string]CustomReceiverProducer{
+ "custom-name-2": CustomReceiverProducer(fnc),
+ },
+ }
+ testExpected.Params = &cfg
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, &cfg})
+
+ RegisterReceiver("-", &customTestReceiver{})
+ testName = "Custom receiver 3"
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ creccustom := &customTestReceiver{}
+ cargs3 := CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set3",
+ },
+ }
+ creccustom.AfterParse(cargs3)
+ testCustomReceiver, _ = NewCustomReceiverDispatcherByValue(DefaultFormatter, creccustom, "-", cargs3)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Custom receivers with formats"
+ testConfig = `
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testCustomReceivers := make([]*customReceiverDispatcher, 3)
+ for i := 0; i < 3; i++ {
+ testCustomReceivers[i], _ = NewCustomReceiverDispatcher(DefaultFormatter, "custom-name-1", CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": fmt.Sprintf("set%d", i+1),
+ },
+ })
+ }
+
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceivers[0], testCustomReceivers[1], testCustomReceivers[2]})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Format"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFormat, _ := NewFormatter("%Level %Msg %File")
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testfileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Format2"
+ testLogFileName = getTestFileName(testName, "")
+ testLogFileName1 = getTestFileName(testName, "1")
+ testConfig = `
+
+
+
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testfileWriter1, _ = NewFileWriter(testLogFileName1)
+ testFormat1, _ := NewFormatter("%Level %Msg %File")
+ testFormat2, _ := NewFormatter("%l %Msg")
+ formattedWriter, _ := NewFormattedWriter(testfileWriter1, testFormat2)
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat1, []interface{}{testfileWriter, formattedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Minlevel = warn"
+ testConfig = ``
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(WarnLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Maxlevel = trace"
+ testConfig = ``
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, TraceLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Level between info and error"
+ testConfig = ``
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(InfoLvl, ErrorLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Off with minlevel"
+ testConfig = ``
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewOffConstraints()
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Off with levels"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Levels list"
+ testConfig = ``
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewListConstraints([]LogLevel{
+ DebugLvl, InfoLvl, CriticalLvl})
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Errors #1"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #2"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #3"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #4"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #5"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #6"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #7"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #8"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #9"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #10"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #11"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #12"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #13"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #14"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #15"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #16"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #17"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #18"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #19"
+ testConfig = ``
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Exceptions: restricting"
+ testConfig =
+ `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ listConstraint, _ := NewOffConstraints()
+ exception, _ := NewLogLevelException("Test*", "someFile.go", listConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Exceptions: allowing #1"
+ testConfig =
+ `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewListConstraints([]LogLevel{ErrorLvl})
+ minMaxConstraint, _ := NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ exception, _ = NewLogLevelException("*", "testfile.go", minMaxConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Exceptions: allowing #2"
+ testConfig = `
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewOffConstraints()
+ minMaxConstraint, _ = NewMinMaxConstraints(WarnLvl, CriticalLvl)
+ exception, _ = NewLogLevelException("*", "testfile.go", minMaxConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Predefined formats"
+ formatID := predefinedPrefix + "xml-debug-short"
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testFormat, _ = predefinedFormats[formatID]
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Predefined formats redefine"
+ testLogFileName = getTestFileName(testName, "")
+ formatID = predefinedPrefix + "xml-debug-short"
+ testConfig = `
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFormat, _ = NewFormatter("%Level %Msg %File")
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testfileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Conn writer 1"
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testConnWriter := NewConnWriter("tcp", ":8888", false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testConnWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Conn writer 2"
+ testConfig = `
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testConnWriter = NewConnWriter("tcp", ":8888", true)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testConnWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Errors #11"
+ testConfig = `
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #12"
+ testConfig = `
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #13"
+ testConfig = `
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #14"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #15"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #16"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #17"
+ testConfig = `
+
+
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #18"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #19"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #20"
+ testConfig = `
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #21"
+ testConfig = `
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #22"
+ testConfig = `
+
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #23"
+ testConfig = `
+
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #24"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #25"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #26"
+ testConfig = `
+
+
+
+
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Buffered writer same formatid override"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+
+
+
+
+
+
+
+
+
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ = NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingIntervalDaily, rollingNameModePrefix)
+ testbufferedWriter, _ = NewBufferedWriter(testrollingFileWriterTime, 100500, 100)
+ testFormat, _ = NewFormatter("%Level %Msg %File 123")
+ formattedWriter, _ = NewFormattedWriter(testbufferedWriter, testFormat)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{formattedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ }
+
+ return parserTests
+}
+
+// Temporary solution: compare by string identity. Not the best solution in
+// terms of performance, but a valid one in terms of comparison, because
+// every seelog dispatcher/receiver must have a valid String() func
+// that fully represents its internal parameters.
+func configsAreEqual(conf1 *configForParsing, conf2 interface{}) bool {
+ if conf1 == nil {
+ return conf2 == nil
+ }
+ if conf2 == nil {
+ return conf1 == nil
+ }
+
+ // configForParsing, ok := conf2 //.(*configForParsing)
+ // if !ok {
+ // return false
+ // }
+
+ return fmt.Sprintf("%v", conf1) == fmt.Sprintf("%v", conf2) //configForParsing)
+}
+
+func testLogFileFilter(fn string) bool {
+ return ".log" == filepath.Ext(fn)
+}
+
+func cleanupAfterCfgTest(t *testing.T) {
+ toDel, err := getDirFilePaths(".", testLogFileFilter, true)
+ if nil != err {
+ t.Fatal("Cannot list files in test directory!")
+ }
+
+ for _, p := range toDel {
+ err = tryRemoveFile(p)
+ if nil != err {
+ t.Errorf("cannot remove file %s in test directory: %s", p, err.Error())
+ }
+ }
+}
+
+func parseTest(test parserTest, t *testing.T) {
+ conf, err := configFromReaderWithConfig(strings.NewReader(test.config), test.parserConfig)
+ if /*err != nil &&*/ conf != nil && conf.RootDispatcher != nil {
+ defer func() {
+ if err = conf.RootDispatcher.Close(); err != nil {
+ t.Errorf("\n----ERROR while closing root dispatcher in %s test: %s", test.testName, err)
+ }
+ }()
+ }
+
+ if (err != nil) != test.errorExpected {
+ t.Errorf("\n----ERROR in %s:\nConfig: %s\n* Expected error:%t. Got error: %t\n",
+ test.testName, test.config, test.errorExpected, (err != nil))
+ if err != nil {
+ t.Logf("%s\n", err.Error())
+ }
+ return
+ }
+
+ if err == nil && !configsAreEqual(conf, test.expected) {
+ t.Errorf("\n----ERROR in %s:\nConfig: %s\n* Expected: %v. \n* Got: %v\n",
+ test.testName, test.config, test.expected, conf)
+ }
+}
+
+func TestParser(t *testing.T) {
+ defer cleanupAfterCfgTest(t)
+
+ for _, test := range getParserTests() {
+ parseTest(test, t)
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/common_constraints_test.go b/vendor/github.com/cihub/seelog/common_constraints_test.go
new file mode 100644
index 0000000..bb9918e
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/common_constraints_test.go
@@ -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
+ }
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/common_context_test.go b/vendor/github.com/cihub/seelog/common_context_test.go
new file mode 100644
index 0000000..bd1e47a
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/common_context_test.go
@@ -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)
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/common_exception_test.go b/vendor/github.com/cihub/seelog/common_exception_test.go
new file mode 100644
index 0000000..d98c280
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/common_exception_test.go
@@ -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())
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/dispatch_customdispatcher_test.go b/vendor/github.com/cihub/seelog/dispatch_customdispatcher_test.go
new file mode 100644
index 0000000..23f631a
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/dispatch_customdispatcher_test.go
@@ -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
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/dispatch_filterdispatcher_test.go b/vendor/github.com/cihub/seelog/dispatch_filterdispatcher_test.go
new file mode 100644
index 0000000..c1894a7
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/dispatch_filterdispatcher_test.go
@@ -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) {})
+}
diff --git a/vendor/github.com/cihub/seelog/dispatch_splitdispatcher_test.go b/vendor/github.com/cihub/seelog/dispatch_splitdispatcher_test.go
new file mode 100644
index 0000000..fc4651c
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/dispatch_splitdispatcher_test.go
@@ -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()
+}
diff --git a/vendor/github.com/cihub/seelog/format_test.go b/vendor/github.com/cihub/seelog/format_test.go
new file mode 100644
index 0000000..dd61bdf
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/format_test.go
@@ -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)
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/internals_byteverifiers_test.go b/vendor/github.com/cihub/seelog/internals_byteverifiers_test.go
new file mode 100644
index 0000000..0ab6ebc
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/internals_byteverifiers_test.go
@@ -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
+}
diff --git a/vendor/github.com/cihub/seelog/internals_xmlnode_test.go b/vendor/github.com/cihub/seelog/internals_xmlnode_test.go
new file mode 100644
index 0000000..3a4487c
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/internals_xmlnode_test.go
@@ -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 := ""
+ 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 := ``
+ testExpected := newNode()
+ testExpected.name = "a"
+ xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
+
+ testName = "Multiline test"
+ testXML =
+ `
+
+
+`
+ testExpected = newNode()
+ testExpected.name = "a"
+ xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
+
+ testName = "Multiline test #2"
+ testXML =
+ `
+
+
+
+
+
+
+`
+ 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 =
+ `
+
+
+`
+ testExpected = newNode()
+ testExpected.name = "a"
+ xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
+
+ testName = "Multiple roots"
+ testXML = ``
+ xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
+
+ testName = "Multiple roots + incorrect xml"
+ testXML = ``
+ 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 = `<俄语>данные俄语>`
+ 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 = `<俄语>俄语>`
+ 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">俄语>`
+ 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)
+ }
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go b/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go
new file mode 100644
index 0000000..03f74f7
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go
@@ -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)
+}
diff --git a/vendor/github.com/cihub/seelog/writers_filewriter_test.go b/vendor/github.com/cihub/seelog/writers_filewriter_test.go
new file mode 100644
index 0000000..1893be8
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/writers_filewriter_test.go
@@ -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)
+ }
+ }
+}
diff --git a/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go b/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go
new file mode 100644
index 0000000..351ac4e
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go
@@ -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()
+}
diff --git a/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go b/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
new file mode 100644
index 0000000..9ca91ae
--- /dev/null
+++ b/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
@@ -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),
+ // ====================
+}
diff --git a/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/davecgh/go-spew/.gitignore
new file mode 100644
index 0000000..0026861
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/.gitignore
@@ -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
diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml
new file mode 100644
index 0000000..984e073
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/.travis.yml
@@ -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
diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644
index 0000000..c836416
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2012-2016 Dave Collins
+
+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.
diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md
new file mode 100644
index 0000000..2624304
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/README.md
@@ -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, "")
+}
+
+func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":8080", nil)
+}
+```
+
+## Sample Dump Output
+
+```
+(main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+ flag: (main.Flag) flagTwo,
+ data: (uintptr)
+ }),
+ 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 <*>}
+ %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
+ %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
+ %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
+```
+
+## 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.
diff --git a/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/davecgh/go-spew/cov_report.sh
new file mode 100644
index 0000000..9579497
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/cov_report.sh
@@ -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
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644
index 0000000..8a4a658
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go
@@ -0,0 +1,152 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// 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<>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
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644
index 0000000..1fe3cf3
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// 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
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644
index 0000000..7c519ff
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/common.go
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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("")
+ maxNewlineBytes = []byte("\n")
+ maxShortBytes = []byte("")
+ circularBytes = []byte("")
+ circularShortBytes = []byte("")
+ invalidAngleBytes = []byte("")
+ 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))
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go
new file mode 100644
index 0000000..0f5ce47
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/common_test.go
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644
index 0000000..2e3d22f
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/config.go
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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: " "}
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644
index 0000000..aacaac6
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/doc.go
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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)
+ }),
+ 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 <*>}
+ %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
+ %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
+ %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
+
+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
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644
index 0000000..df1d582
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dump.go
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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...)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go
new file mode 100644
index 0000000..5aad9c7
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dump_test.go
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Array containing bytes
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Slice containing bytes
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+ exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+*/
+
+package spew_test
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unsafe"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+// dumpTest is used to describe a test to be performed against the Dump method.
+type dumpTest struct {
+ in interface{}
+ wants []string
+}
+
+// dumpTests houses all of the tests to be performed against the Dump method.
+var dumpTests = make([]dumpTest, 0)
+
+// addDumpTest is a helper method to append the passed input and desired result
+// to dumpTests
+func addDumpTest(in interface{}, wants ...string) {
+ test := dumpTest{in, wants}
+ dumpTests = append(dumpTests, test)
+}
+
+func addIntDumpTests() {
+ // Max int8.
+ v := int8(127)
+ nv := (*int8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int8"
+ vs := "127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Max int16.
+ v2 := int16(32767)
+ nv2 := (*int16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "int16"
+ v2s := "32767"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Max int32.
+ v3 := int32(2147483647)
+ nv3 := (*int32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "int32"
+ v3s := "2147483647"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Max int64.
+ v4 := int64(9223372036854775807)
+ nv4 := (*int64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "int64"
+ v4s := "9223372036854775807"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Max int.
+ v5 := int(2147483647)
+ nv5 := (*int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "int"
+ v5s := "2147483647"
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addUintDumpTests() {
+ // Max uint8.
+ v := uint8(255)
+ nv := (*uint8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uint8"
+ vs := "255"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Max uint16.
+ v2 := uint16(65535)
+ nv2 := (*uint16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Max uint32.
+ v3 := uint32(4294967295)
+ nv3 := (*uint32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "uint32"
+ v3s := "4294967295"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Max uint64.
+ v4 := uint64(18446744073709551615)
+ nv4 := (*uint64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "uint64"
+ v4s := "18446744073709551615"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Max uint.
+ v5 := uint(4294967295)
+ nv5 := (*uint)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "uint"
+ v5s := "4294967295"
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addBoolDumpTests() {
+ // Boolean true.
+ v := bool(true)
+ nv := (*bool)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "bool"
+ vs := "true"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Boolean false.
+ v2 := bool(false)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "bool"
+ v2s := "false"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFloatDumpTests() {
+ // Standard float32.
+ v := float32(3.1415)
+ nv := (*float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "3.1415"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Standard float64.
+ v2 := float64(3.1415926)
+ nv2 := (*float64)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "float64"
+ v2s := "3.1415926"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addComplexDumpTests() {
+ // Standard complex64.
+ v := complex(float32(6), -2)
+ nv := (*complex64)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "complex64"
+ vs := "(6-2i)"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Standard complex128.
+ v2 := complex(float64(-6), 2)
+ nv2 := (*complex128)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "complex128"
+ v2s := "(-6+2i)"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addArrayDumpTests() {
+ // Array containing standard ints.
+ v := [3]int{1, 2, 3}
+ vLen := fmt.Sprintf("%d", len(v))
+ vCap := fmt.Sprintf("%d", cap(v))
+ nv := (*[3]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int"
+ vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
+ vt + ") 2,\n (" + vt + ") 3\n}"
+ addDumpTest(v, "([3]"+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*[3]"+vt+")()\n")
+
+ // Array containing type with custom formatter on pointer receiver only.
+ v2i0 := pstringer("1")
+ v2i1 := pstringer("2")
+ v2i2 := pstringer("3")
+ v2 := [3]pstringer{v2i0, v2i1, v2i2}
+ v2i0Len := fmt.Sprintf("%d", len(v2i0))
+ v2i1Len := fmt.Sprintf("%d", len(v2i1))
+ v2i2Len := fmt.Sprintf("%d", len(v2i2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ v2Cap := fmt.Sprintf("%d", cap(v2))
+ nv2 := (*[3]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.pstringer"
+ v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+ ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t +
+ ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t +
+ ") (len=" + v2i2Len + ") " + "stringer 3\n}"
+ v2s := v2sp
+ if spew.UnsafeDisabled {
+ v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+ ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" +
+ v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len +
+ ") " + "\"3\"\n}"
+ }
+ addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n")
+ addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n")
+ addDumpTest(nv2, "(*[3]"+v2t+")()\n")
+
+ // Array containing interfaces.
+ v3i0 := "one"
+ v3 := [3]interface{}{v3i0, int(2), uint(3)}
+ v3i0Len := fmt.Sprintf("%d", len(v3i0))
+ v3Len := fmt.Sprintf("%d", len(v3))
+ v3Cap := fmt.Sprintf("%d", cap(v3))
+ nv3 := (*[3]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[3]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+ "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+ v3t4 + ") 3\n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Array containing bytes.
+ v4 := [34]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,
+ }
+ v4Len := fmt.Sprintf("%d", len(v4))
+ v4Cap := fmt.Sprintf("%d", cap(v4))
+ nv4 := (*[34]byte)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[34]uint8"
+ v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+ "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
+ " |............... |\n" +
+ " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
+ " |!\"#$%&'()*+,-./0|\n" +
+ " 00000020 31 32 " +
+ " |12|\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+}
+
+func addSliceDumpTests() {
+ // Slice containing standard float32 values.
+ v := []float32{3.14, 6.28, 12.56}
+ vLen := fmt.Sprintf("%d", len(v))
+ vCap := fmt.Sprintf("%d", cap(v))
+ nv := (*[]float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
+ vt + ") 6.28,\n (" + vt + ") 12.56\n}"
+ addDumpTest(v, "([]"+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*[]"+vt+")()\n")
+
+ // Slice containing type with custom formatter on pointer receiver only.
+ v2i0 := pstringer("1")
+ v2i1 := pstringer("2")
+ v2i2 := pstringer("3")
+ v2 := []pstringer{v2i0, v2i1, v2i2}
+ v2i0Len := fmt.Sprintf("%d", len(v2i0))
+ v2i1Len := fmt.Sprintf("%d", len(v2i1))
+ v2i2Len := fmt.Sprintf("%d", len(v2i2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ v2Cap := fmt.Sprintf("%d", cap(v2))
+ nv2 := (*[]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.pstringer"
+ v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+ v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+ ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+ "stringer 3\n}"
+ addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*[]"+v2t+")()\n")
+
+ // Slice containing interfaces.
+ v3i0 := "one"
+ v3 := []interface{}{v3i0, int(2), uint(3), nil}
+ v3i0Len := fmt.Sprintf("%d", len(v3i0))
+ v3Len := fmt.Sprintf("%d", len(v3))
+ v3Cap := fmt.Sprintf("%d", cap(v3))
+ nv3 := (*[]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3t5 := "interface {}"
+ v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+ "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+ v3t4 + ") 3,\n (" + v3t5 + ") \n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Slice containing bytes.
+ v4 := []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,
+ }
+ v4Len := fmt.Sprintf("%d", len(v4))
+ v4Cap := fmt.Sprintf("%d", cap(v4))
+ nv4 := (*[]byte)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[]uint8"
+ v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+ "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
+ " |............... |\n" +
+ " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
+ " |!\"#$%&'()*+,-./0|\n" +
+ " 00000020 31 32 " +
+ " |12|\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Nil slice.
+ v5 := []int(nil)
+ nv5 := (*[]int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "[]int"
+ v5s := ""
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addStringDumpTests() {
+ // Standard string.
+ v := "test"
+ vLen := fmt.Sprintf("%d", len(v))
+ nv := (*string)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "string"
+ vs := "(len=" + vLen + ") \"test\""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addInterfaceDumpTests() {
+ // Nil interface.
+ var v interface{}
+ nv := (*interface{})(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "interface {}"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Sub-interface.
+ v2 := interface{}(uint16(65535))
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addMapDumpTests() {
+ // Map with string keys and int vals.
+ k := "one"
+ kk := "two"
+ m := map[string]int{k: 1, kk: 2}
+ klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
+ kkLen := fmt.Sprintf("%d", len(kk))
+ mLen := fmt.Sprintf("%d", len(m))
+ nilMap := map[string]int(nil)
+ nm := (*map[string]int)(nil)
+ pm := &m
+ mAddr := fmt.Sprintf("%p", pm)
+ pmAddr := fmt.Sprintf("%p", &pm)
+ mt := "map[string]int"
+ mt1 := "string"
+ mt2 := "int"
+ ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
+ "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
+ ") \"two\": (" + mt2 + ") 2\n}"
+ ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
+ "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
+ ") \"one\": (" + mt2 + ") 1\n}"
+ addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
+ addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
+ "(*"+mt+")("+mAddr+")("+ms2+")\n")
+ addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
+ "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
+ addDumpTest(nm, "(*"+mt+")()\n")
+ addDumpTest(nilMap, "("+mt+") \n")
+
+ // Map with custom formatter type on pointer receiver only keys and vals.
+ k2 := pstringer("one")
+ v2 := pstringer("1")
+ m2 := map[pstringer]pstringer{k2: v2}
+ k2Len := fmt.Sprintf("%d", len(k2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ m2Len := fmt.Sprintf("%d", len(m2))
+ nilMap2 := map[pstringer]pstringer(nil)
+ nm2 := (*map[pstringer]pstringer)(nil)
+ pm2 := &m2
+ m2Addr := fmt.Sprintf("%p", pm2)
+ pm2Addr := fmt.Sprintf("%p", &pm2)
+ m2t := "map[spew_test.pstringer]spew_test.pstringer"
+ m2t1 := "spew_test.pstringer"
+ m2t2 := "spew_test.pstringer"
+ m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
+ "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
+ if spew.UnsafeDisabled {
+ m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len +
+ ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len +
+ ") \"1\"\n}"
+ }
+ addDumpTest(m2, "("+m2t+") "+m2s+"\n")
+ addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
+ addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
+ addDumpTest(nm2, "(*"+m2t+")()\n")
+ addDumpTest(nilMap2, "("+m2t+") \n")
+
+ // Map with interface keys and values.
+ k3 := "one"
+ k3Len := fmt.Sprintf("%d", len(k3))
+ m3 := map[interface{}]interface{}{k3: 1}
+ m3Len := fmt.Sprintf("%d", len(m3))
+ nilMap3 := map[interface{}]interface{}(nil)
+ nm3 := (*map[interface{}]interface{})(nil)
+ pm3 := &m3
+ m3Addr := fmt.Sprintf("%p", pm3)
+ pm3Addr := fmt.Sprintf("%p", &pm3)
+ m3t := "map[interface {}]interface {}"
+ m3t1 := "string"
+ m3t2 := "int"
+ m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
+ "\"one\": (" + m3t2 + ") 1\n}"
+ addDumpTest(m3, "("+m3t+") "+m3s+"\n")
+ addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
+ addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
+ addDumpTest(nm3, "(*"+m3t+")()\n")
+ addDumpTest(nilMap3, "("+m3t+") \n")
+
+ // Map with nil interface value.
+ k4 := "nil"
+ k4Len := fmt.Sprintf("%d", len(k4))
+ m4 := map[string]interface{}{k4: nil}
+ m4Len := fmt.Sprintf("%d", len(m4))
+ nilMap4 := map[string]interface{}(nil)
+ nm4 := (*map[string]interface{})(nil)
+ pm4 := &m4
+ m4Addr := fmt.Sprintf("%p", pm4)
+ pm4Addr := fmt.Sprintf("%p", &pm4)
+ m4t := "map[string]interface {}"
+ m4t1 := "string"
+ m4t2 := "interface {}"
+ m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
+ " \"nil\": (" + m4t2 + ") \n}"
+ addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+ addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+ addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+ addDumpTest(nm4, "(*"+m4t+")()\n")
+ addDumpTest(nilMap4, "("+m4t+") \n")
+}
+
+func addStructDumpTests() {
+ // Struct with primitives.
+ type s1 struct {
+ a int8
+ b uint8
+ }
+ v := s1{127, 255}
+ nv := (*s1)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.s1"
+ vt2 := "int8"
+ vt3 := "uint8"
+ vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Struct that contains another struct.
+ type s2 struct {
+ s1 s1
+ b bool
+ }
+ v2 := s2{s1{127, 255}, true}
+ nv2 := (*s2)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.s2"
+ v2t2 := "spew_test.s1"
+ v2t3 := "int8"
+ v2t4 := "uint8"
+ v2t5 := "bool"
+ v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" +
+ v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Struct that contains custom type with Stringer pointer interface via both
+ // exported and unexported fields.
+ type s3 struct {
+ s pstringer
+ S pstringer
+ }
+ v3 := s3{"test", "test2"}
+ nv3 := (*s3)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "spew_test.s3"
+ v3t2 := "spew_test.pstringer"
+ v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
+ ") (len=5) stringer test2\n}"
+ v3sp := v3s
+ if spew.UnsafeDisabled {
+ v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+ v3t2 + ") (len=5) \"test2\"\n}"
+ v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+ v3t2 + ") (len=5) stringer test2\n}"
+ }
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Struct that contains embedded struct and field to same struct.
+ e := embed{"embedstr"}
+ eLen := fmt.Sprintf("%d", len("embedstr"))
+ v4 := embedwrap{embed: &e, e: &e}
+ nv4 := (*embedwrap)(nil)
+ pv4 := &v4
+ eAddr := fmt.Sprintf("%p", &e)
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "spew_test.embedwrap"
+ v4t2 := "spew_test.embed"
+ v4t3 := "string"
+ v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 +
+ ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
+ ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" +
+ " \"embedstr\"\n })\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+}
+
+func addUintptrDumpTests() {
+ // Null pointer.
+ v := uintptr(0)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uintptr"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+
+ // Address of real variable.
+ i := 1
+ v2 := uintptr(unsafe.Pointer(&i))
+ nv2 := (*uintptr)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uintptr"
+ v2s := fmt.Sprintf("%p", &i)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addUnsafePointerDumpTests() {
+ // Null pointer.
+ v := unsafe.Pointer(uintptr(0))
+ nv := (*unsafe.Pointer)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "unsafe.Pointer"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Address of real variable.
+ i := 1
+ v2 := unsafe.Pointer(&i)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "unsafe.Pointer"
+ v2s := fmt.Sprintf("%p", &i)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addChanDumpTests() {
+ // Nil channel.
+ var v chan int
+ pv := &v
+ nv := (*chan int)(nil)
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "chan int"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Real channel.
+ v2 := make(chan int)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "chan int"
+ v2s := fmt.Sprintf("%p", v2)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFuncDumpTests() {
+ // Function with no params and no returns.
+ v := addIntDumpTests
+ nv := (*func())(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "func()"
+ vs := fmt.Sprintf("%p", v)
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Function with param and no returns.
+ v2 := TestDump
+ nv2 := (*func(*testing.T))(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "func(*testing.T)"
+ v2s := fmt.Sprintf("%p", v2)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Function with multiple params and multiple returns.
+ var v3 = func(i int, s string) (b bool, err error) {
+ return true, nil
+ }
+ nv3 := (*func(int, string) (bool, error))(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "func(int, string) (bool, error)"
+ v3s := fmt.Sprintf("%p", v3)
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+}
+
+func addCircularDumpTests() {
+ // Struct that is circular through self referencing.
+ type circular struct {
+ c *circular
+ }
+ v := circular{nil}
+ v.c = &v
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.circular"
+ vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" +
+ vAddr + ")()\n })\n}"
+ vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
+
+ // Structs that are circular through cross referencing.
+ v2 := xref1{nil}
+ ts2 := xref2{&v2}
+ v2.ps2 = &ts2
+ pv2 := &v2
+ ts2Addr := fmt.Sprintf("%p", &ts2)
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.xref1"
+ v2t2 := "spew_test.xref2"
+ v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
+ ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr +
+ ")()\n })\n })\n}"
+ v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
+ ")(" + v2Addr + ")()\n })\n}"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
+
+ // Structs that are indirectly circular.
+ v3 := indirCir1{nil}
+ tic2 := indirCir2{nil}
+ tic3 := indirCir3{&v3}
+ tic2.ps3 = &tic3
+ v3.ps2 = &tic2
+ pv3 := &v3
+ tic2Addr := fmt.Sprintf("%p", &tic2)
+ tic3Addr := fmt.Sprintf("%p", &tic3)
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "spew_test.indirCir1"
+ v3t2 := "spew_test.indirCir2"
+ v3t3 := "spew_test.indirCir3"
+ v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
+ ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
+ ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr +
+ ")()\n })\n })\n })\n}"
+ v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
+ ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
+ ")()\n })\n })\n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
+}
+
+func addPanicDumpTests() {
+ // Type that panics in its Stringer interface.
+ v := panicer(127)
+ nv := (*panicer)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.panicer"
+ vs := "(PANIC=test panic)127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addErrorDumpTests() {
+ // Type that has a custom Error interface.
+ v := customError(127)
+ nv := (*customError)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.customError"
+ vs := "error: 127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+// TestDump executes all of the tests described by dumpTests.
+func TestDump(t *testing.T) {
+ // Setup tests.
+ addIntDumpTests()
+ addUintDumpTests()
+ addBoolDumpTests()
+ addFloatDumpTests()
+ addComplexDumpTests()
+ addArrayDumpTests()
+ addSliceDumpTests()
+ addStringDumpTests()
+ addInterfaceDumpTests()
+ addMapDumpTests()
+ addStructDumpTests()
+ addUintptrDumpTests()
+ addUnsafePointerDumpTests()
+ addChanDumpTests()
+ addFuncDumpTests()
+ addCircularDumpTests()
+ addPanicDumpTests()
+ addErrorDumpTests()
+ addCgoDumpTests()
+
+ t.Logf("Running %d tests", len(dumpTests))
+ for i, test := range dumpTests {
+ buf := new(bytes.Buffer)
+ spew.Fdump(buf, test.in)
+ s := buf.String()
+ if testFailed(s, test.wants) {
+ t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
+ continue
+ }
+ }
+}
+
+func TestDumpSortedKeys(t *testing.T) {
+ cfg := spew.ConfigState{SortKeys: true}
+ s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
+ expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " +
+ "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " +
+ "(len=1) \"3\"\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
+ expected = "(map[spew_test.stringer]int) (len=3) {\n" +
+ "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" +
+ "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" +
+ "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+ expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+ "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" +
+ "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" +
+ "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" +
+ "}\n"
+ if spew.UnsafeDisabled {
+ expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+ "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" +
+ "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" +
+ "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" +
+ "}\n"
+ }
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+ expected = "(map[spew_test.customError]int) (len=3) {\n" +
+ "(spew_test.customError) error: 1: (int) 1,\n" +
+ "(spew_test.customError) error: 2: (int) 2,\n" +
+ "(spew_test.customError) error: 3: (int) 3\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
new file mode 100644
index 0000000..6ab1808
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
@@ -0,0 +1,99 @@
+// Copyright (c) 2013-2016 Dave Collins
+//
+// 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+")()\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")
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
new file mode 100644
index 0000000..52a0971
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 Dave Collins
+//
+// 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.
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go
new file mode 100644
index 0000000..c6ec8c6
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/example_test.go
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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)
+ // },
+ // 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 <*>}}
+}
+
+// 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)
+ // },
+ // ExportedField: (map[interface {}]interface {}) (len=1) {
+ // (string) (len=3) "one": (bool) true
+ // }
+ // }
+ // (spew_test.Foo) {
+ // unexportedField: (spew_test.Bar) {
+ // data: (uintptr)
+ // },
+ // 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
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644
index 0000000..c49875b
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/format.go
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go
new file mode 100644
index 0000000..f9b93ab
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/format_test.go
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * 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.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+ exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+- Type that has a custom Error interface
+- %x passthrough with uint
+- %#x passthrough with uint
+- %f passthrough with precision
+- %f passthrough with width and precision
+- %d passthrough with width
+- %q passthrough with string
+*/
+
+package spew_test
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unsafe"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+// formatterTest is used to describe a test to be performed against NewFormatter.
+type formatterTest struct {
+ format string
+ in interface{}
+ wants []string
+}
+
+// formatterTests houses all of the tests to be performed against NewFormatter.
+var formatterTests = make([]formatterTest, 0)
+
+// addFormatterTest is a helper method to append the passed input and desired
+// result to formatterTests.
+func addFormatterTest(format string, in interface{}, wants ...string) {
+ test := formatterTest{format, in, wants}
+ formatterTests = append(formatterTests, test)
+}
+
+func addIntFormatterTests() {
+ // Max int8.
+ v := int8(127)
+ nv := (*int8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int8"
+ vs := "127"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Max int16.
+ v2 := int16(32767)
+ nv2 := (*int16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "int16"
+ v2s := "32767"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Max int32.
+ v3 := int32(2147483647)
+ nv3 := (*int32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "int32"
+ v3s := "2147483647"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+
+ // Max int64.
+ v4 := int64(9223372036854775807)
+ nv4 := (*int64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "int64"
+ v4s := "9223372036854775807"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+
+ // Max int.
+ v5 := int(2147483647)
+ nv5 := (*int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "int"
+ v5s := "2147483647"
+ addFormatterTest("%v", v5, v5s)
+ addFormatterTest("%v", pv5, "<*>"+v5s)
+ addFormatterTest("%v", &pv5, "<**>"+v5s)
+ addFormatterTest("%v", nv5, "")
+ addFormatterTest("%+v", v5, v5s)
+ addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+ addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%+v", nv5, "")
+ addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+ addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+ addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"")
+}
+
+func addUintFormatterTests() {
+ // Max uint8.
+ v := uint8(255)
+ nv := (*uint8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uint8"
+ vs := "255"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Max uint16.
+ v2 := uint16(65535)
+ nv2 := (*uint16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Max uint32.
+ v3 := uint32(4294967295)
+ nv3 := (*uint32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "uint32"
+ v3s := "4294967295"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+
+ // Max uint64.
+ v4 := uint64(18446744073709551615)
+ nv4 := (*uint64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "uint64"
+ v4s := "18446744073709551615"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+
+ // Max uint.
+ v5 := uint(4294967295)
+ nv5 := (*uint)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "uint"
+ v5s := "4294967295"
+ addFormatterTest("%v", v5, v5s)
+ addFormatterTest("%v", pv5, "<*>"+v5s)
+ addFormatterTest("%v", &pv5, "<**>"+v5s)
+ addFormatterTest("%v", nv5, "")
+ addFormatterTest("%+v", v5, v5s)
+ addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+ addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%+v", nv5, "")
+ addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+ addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+ addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+}
+
+func addBoolFormatterTests() {
+ // Boolean true.
+ v := bool(true)
+ nv := (*bool)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "bool"
+ vs := "true"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Boolean false.
+ v2 := bool(false)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "bool"
+ v2s := "false"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFloatFormatterTests() {
+ // Standard float32.
+ v := float32(3.1415)
+ nv := (*float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "3.1415"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Standard float64.
+ v2 := float64(3.1415926)
+ nv2 := (*float64)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "float64"
+ v2s := "3.1415926"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+}
+
+func addComplexFormatterTests() {
+ // Standard complex64.
+ v := complex(float32(6), -2)
+ nv := (*complex64)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "complex64"
+ vs := "(6-2i)"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Standard complex128.
+ v2 := complex(float64(-6), 2)
+ nv2 := (*complex128)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "complex128"
+ v2s := "(-6+2i)"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+}
+
+func addArrayFormatterTests() {
+ // Array containing standard ints.
+ v := [3]int{1, 2, 3}
+ nv := (*[3]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "[3]int"
+ vs := "[1 2 3]"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Array containing type with custom formatter on pointer receiver only.
+ v2 := [3]pstringer{"1", "2", "3"}
+ nv2 := (*[3]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "[3]spew_test.pstringer"
+ v2sp := "[stringer 1 stringer 2 stringer 3]"
+ v2s := v2sp
+ if spew.UnsafeDisabled {
+ v2s = "[1 2 3]"
+ }
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2sp)
+ addFormatterTest("%v", &pv2, "<**>"+v2sp)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Array containing interfaces.
+ v3 := [3]interface{}{"one", int(2), uint(3)}
+ nv3 := (*[3]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[3]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3s := "[one 2 3]"
+ v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+}
+
+func addSliceFormatterTests() {
+ // Slice containing standard float32 values.
+ v := []float32{3.14, 6.28, 12.56}
+ nv := (*[]float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "[]float32"
+ vs := "[3.14 6.28 12.56]"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Slice containing type with custom formatter on pointer receiver only.
+ v2 := []pstringer{"1", "2", "3"}
+ nv2 := (*[]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "[]spew_test.pstringer"
+ v2s := "[stringer 1 stringer 2 stringer 3]"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Slice containing interfaces.
+ v3 := []interface{}{"one", int(2), uint(3), nil}
+ nv3 := (*[]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3t5 := "interface {}"
+ v3s := "[one 2 3 ]"
+ v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
+ ")]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+
+ // Nil slice.
+ var v4 []int
+ nv4 := (*[]int)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[]int"
+ v4s := ""
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+}
+
+func addStringFormatterTests() {
+ // Standard string.
+ v := "test"
+ nv := (*string)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "string"
+ vs := "test"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+}
+
+func addInterfaceFormatterTests() {
+ // Nil interface.
+ var v interface{}
+ nv := (*interface{})(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "interface {}"
+ vs := ""
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Sub-interface.
+ v2 := interface{}(uint16(65535))
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addMapFormatterTests() {
+ // Map with string keys and int vals.
+ v := map[string]int{"one": 1, "two": 2}
+ nilMap := map[string]int(nil)
+ nv := (*map[string]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "map[string]int"
+ vs := "map[one:1 two:2]"
+ vs2 := "map[two:2 one:1]"
+ addFormatterTest("%v", v, vs, vs2)
+ addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
+ addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
+ addFormatterTest("%+v", nilMap, "")
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs, vs2)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
+ "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+ addFormatterTest("%+v", nilMap, "")
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
+ addFormatterTest("%#v", nilMap, "("+vt+")"+"")
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
+ "(*"+vt+")("+vAddr+")"+vs2)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
+ "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
+ addFormatterTest("%#+v", nilMap, "("+vt+")"+"")
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Map with custom formatter type on pointer receiver only keys and vals.
+ v2 := map[pstringer]pstringer{"one": "1"}
+ nv2 := (*map[pstringer]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "map[spew_test.pstringer]spew_test.pstringer"
+ v2s := "map[stringer one:stringer 1]"
+ if spew.UnsafeDisabled {
+ v2s = "map[one:1]"
+ }
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Map with interface keys and values.
+ v3 := map[interface{}]interface{}{"one": 1}
+ nv3 := (*map[interface{}]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "map[interface {}]interface {}"
+ v3t1 := "string"
+ v3t2 := "int"
+ v3s := "map[one:1]"
+ v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+
+ // Map with nil interface value
+ v4 := map[string]interface{}{"nil": nil}
+ nv4 := (*map[string]interface{})(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "map[string]interface {}"
+ v4t1 := "interface {}"
+ v4s := "map[nil:]"
+ v4s2 := "map[nil:(" + v4t1 + ")]"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+}
+
+func addStructFormatterTests() {
+ // Struct with primitives.
+ type s1 struct {
+ a int8
+ b uint8
+ }
+ v := s1{127, 255}
+ nv := (*s1)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.s1"
+ vt2 := "int8"
+ vt3 := "uint8"
+ vs := "{127 255}"
+ vs2 := "{a:127 b:255}"
+ vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs2)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs3)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs3)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Struct that contains another struct.
+ type s2 struct {
+ s1 s1
+ b bool
+ }
+ v2 := s2{s1{127, 255}, true}
+ nv2 := (*s2)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.s2"
+ v2t2 := "spew_test.s1"
+ v2t3 := "int8"
+ v2t4 := "uint8"
+ v2t5 := "bool"
+ v2s := "{{127 255} true}"
+ v2s2 := "{s1:{a:127 b:255} b:true}"
+ v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" +
+ v2t5 + ")true}"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s2)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Struct that contains custom type with Stringer pointer interface via both
+ // exported and unexported fields.
+ type s3 struct {
+ s pstringer
+ S pstringer
+ }
+ v3 := s3{"test", "test2"}
+ nv3 := (*s3)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "spew_test.s3"
+ v3t2 := "spew_test.pstringer"
+ v3s := "{stringer test stringer test2}"
+ v3sp := v3s
+ v3s2 := "{s:stringer test S:stringer test2}"
+ v3s2p := v3s2
+ v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}"
+ v3s3p := v3s3
+ if spew.UnsafeDisabled {
+ v3s = "{test test2}"
+ v3sp = "{test stringer test2}"
+ v3s2 = "{s:test S:test2}"
+ v3s2p = "{s:test S:stringer test2}"
+ v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}"
+ v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}"
+ }
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3sp)
+ addFormatterTest("%v", &pv3, "<**>"+v3sp)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s2)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+
+ // Struct that contains embedded struct and field to same struct.
+ e := embed{"embedstr"}
+ v4 := embedwrap{embed: &e, e: &e}
+ nv4 := (*embedwrap)(nil)
+ pv4 := &v4
+ eAddr := fmt.Sprintf("%p", &e)
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "spew_test.embedwrap"
+ v4t2 := "spew_test.embed"
+ v4t3 := "string"
+ v4s := "{<*>{embedstr} <*>{embedstr}}"
+ v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr +
+ "){a:embedstr}}"
+ v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 +
+ "){a:(" + v4t3 + ")embedstr}}"
+ v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 +
+ ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%+v", v4, v4s2)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+}
+
+func addUintptrFormatterTests() {
+ // Null pointer.
+ v := uintptr(0)
+ nv := (*uintptr)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uintptr"
+ vs := ""
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Address of real variable.
+ i := 1
+ v2 := uintptr(unsafe.Pointer(&i))
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uintptr"
+ v2s := fmt.Sprintf("%p", &i)
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addUnsafePointerFormatterTests() {
+ // Null pointer.
+ v := unsafe.Pointer(uintptr(0))
+ nv := (*unsafe.Pointer)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "unsafe.Pointer"
+ vs := ""
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Address of real variable.
+ i := 1
+ v2 := unsafe.Pointer(&i)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "unsafe.Pointer"
+ v2s := fmt.Sprintf("%p", &i)
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addChanFormatterTests() {
+ // Nil channel.
+ var v chan int
+ pv := &v
+ nv := (*chan int)(nil)
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "chan int"
+ vs := ""
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Real channel.
+ v2 := make(chan int)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "chan int"
+ v2s := fmt.Sprintf("%p", v2)
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFuncFormatterTests() {
+ // Function with no params and no returns.
+ v := addIntFormatterTests
+ nv := (*func())(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "func()"
+ vs := fmt.Sprintf("%p", v)
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Function with param and no returns.
+ v2 := TestFormatter
+ nv2 := (*func(*testing.T))(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "func(*testing.T)"
+ v2s := fmt.Sprintf("%p", v2)
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "