spew_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. package spew_test
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io/ioutil"
  21. "os"
  22. "testing"
  23. "github.com/davecgh/go-spew/spew"
  24. )
  25. // spewFunc is used to identify which public function of the spew package or
  26. // ConfigState a test applies to.
  27. type spewFunc int
  28. const (
  29. fCSFdump spewFunc = iota
  30. fCSFprint
  31. fCSFprintf
  32. fCSFprintln
  33. fCSPrint
  34. fCSPrintln
  35. fCSSdump
  36. fCSSprint
  37. fCSSprintf
  38. fCSSprintln
  39. fCSErrorf
  40. fCSNewFormatter
  41. fErrorf
  42. fFprint
  43. fFprintln
  44. fPrint
  45. fPrintln
  46. fSdump
  47. fSprint
  48. fSprintf
  49. fSprintln
  50. )
  51. // Map of spewFunc values to names for pretty printing.
  52. var spewFuncStrings = map[spewFunc]string{
  53. fCSFdump: "ConfigState.Fdump",
  54. fCSFprint: "ConfigState.Fprint",
  55. fCSFprintf: "ConfigState.Fprintf",
  56. fCSFprintln: "ConfigState.Fprintln",
  57. fCSSdump: "ConfigState.Sdump",
  58. fCSPrint: "ConfigState.Print",
  59. fCSPrintln: "ConfigState.Println",
  60. fCSSprint: "ConfigState.Sprint",
  61. fCSSprintf: "ConfigState.Sprintf",
  62. fCSSprintln: "ConfigState.Sprintln",
  63. fCSErrorf: "ConfigState.Errorf",
  64. fCSNewFormatter: "ConfigState.NewFormatter",
  65. fErrorf: "spew.Errorf",
  66. fFprint: "spew.Fprint",
  67. fFprintln: "spew.Fprintln",
  68. fPrint: "spew.Print",
  69. fPrintln: "spew.Println",
  70. fSdump: "spew.Sdump",
  71. fSprint: "spew.Sprint",
  72. fSprintf: "spew.Sprintf",
  73. fSprintln: "spew.Sprintln",
  74. }
  75. func (f spewFunc) String() string {
  76. if s, ok := spewFuncStrings[f]; ok {
  77. return s
  78. }
  79. return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
  80. }
  81. // spewTest is used to describe a test to be performed against the public
  82. // functions of the spew package or ConfigState.
  83. type spewTest struct {
  84. cs *spew.ConfigState
  85. f spewFunc
  86. format string
  87. in interface{}
  88. want string
  89. }
  90. // spewTests houses the tests to be performed against the public functions of
  91. // the spew package and ConfigState.
  92. //
  93. // These tests are only intended to ensure the public functions are exercised
  94. // and are intentionally not exhaustive of types. The exhaustive type
  95. // tests are handled in the dump and format tests.
  96. var spewTests []spewTest
  97. // redirStdout is a helper function to return the standard output from f as a
  98. // byte slice.
  99. func redirStdout(f func()) ([]byte, error) {
  100. tempFile, err := ioutil.TempFile("", "ss-test")
  101. if err != nil {
  102. return nil, err
  103. }
  104. fileName := tempFile.Name()
  105. defer os.Remove(fileName) // Ignore error
  106. origStdout := os.Stdout
  107. os.Stdout = tempFile
  108. f()
  109. os.Stdout = origStdout
  110. tempFile.Close()
  111. return ioutil.ReadFile(fileName)
  112. }
  113. func initSpewTests() {
  114. // Config states with various settings.
  115. scsDefault := spew.NewDefaultConfig()
  116. scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
  117. scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
  118. scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
  119. scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
  120. scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
  121. scsNoCap := &spew.ConfigState{DisableCapacities: true}
  122. // Variables for tests on types which implement Stringer interface with and
  123. // without a pointer receiver.
  124. ts := stringer("test")
  125. tps := pstringer("test")
  126. type ptrTester struct {
  127. s *struct{}
  128. }
  129. tptr := &ptrTester{s: &struct{}{}}
  130. // depthTester is used to test max depth handling for structs, array, slices
  131. // and maps.
  132. type depthTester struct {
  133. ic indirCir1
  134. arr [1]string
  135. slice []string
  136. m map[string]int
  137. }
  138. dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
  139. map[string]int{"one": 1}}
  140. // Variable for tests on types which implement error interface.
  141. te := customError(10)
  142. spewTests = []spewTest{
  143. {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
  144. {scsDefault, fCSFprint, "", int16(32767), "32767"},
  145. {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
  146. {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
  147. {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
  148. {scsDefault, fCSPrintln, "", uint8(255), "255\n"},
  149. {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
  150. {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
  151. {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
  152. {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
  153. {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
  154. {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
  155. {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
  156. {scsDefault, fFprint, "", float32(3.14), "3.14"},
  157. {scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
  158. {scsDefault, fPrint, "", true, "true"},
  159. {scsDefault, fPrintln, "", false, "false\n"},
  160. {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
  161. {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
  162. {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
  163. {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
  164. {scsNoMethods, fCSFprint, "", ts, "test"},
  165. {scsNoMethods, fCSFprint, "", &ts, "<*>test"},
  166. {scsNoMethods, fCSFprint, "", tps, "test"},
  167. {scsNoMethods, fCSFprint, "", &tps, "<*>test"},
  168. {scsNoPmethods, fCSFprint, "", ts, "stringer test"},
  169. {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
  170. {scsNoPmethods, fCSFprint, "", tps, "test"},
  171. {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
  172. {scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
  173. {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
  174. " ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
  175. " arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
  176. " slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
  177. " m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
  178. {scsContinue, fCSFprint, "", ts, "(stringer test) test"},
  179. {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
  180. "(len=4) (stringer test) \"test\"\n"},
  181. {scsContinue, fCSFprint, "", te, "(error: 10) 10"},
  182. {scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
  183. "(error: 10) 10\n"},
  184. {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
  185. {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
  186. {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
  187. {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
  188. }
  189. }
  190. // TestSpew executes all of the tests described by spewTests.
  191. func TestSpew(t *testing.T) {
  192. initSpewTests()
  193. t.Logf("Running %d tests", len(spewTests))
  194. for i, test := range spewTests {
  195. buf := new(bytes.Buffer)
  196. switch test.f {
  197. case fCSFdump:
  198. test.cs.Fdump(buf, test.in)
  199. case fCSFprint:
  200. test.cs.Fprint(buf, test.in)
  201. case fCSFprintf:
  202. test.cs.Fprintf(buf, test.format, test.in)
  203. case fCSFprintln:
  204. test.cs.Fprintln(buf, test.in)
  205. case fCSPrint:
  206. b, err := redirStdout(func() { test.cs.Print(test.in) })
  207. if err != nil {
  208. t.Errorf("%v #%d %v", test.f, i, err)
  209. continue
  210. }
  211. buf.Write(b)
  212. case fCSPrintln:
  213. b, err := redirStdout(func() { test.cs.Println(test.in) })
  214. if err != nil {
  215. t.Errorf("%v #%d %v", test.f, i, err)
  216. continue
  217. }
  218. buf.Write(b)
  219. case fCSSdump:
  220. str := test.cs.Sdump(test.in)
  221. buf.WriteString(str)
  222. case fCSSprint:
  223. str := test.cs.Sprint(test.in)
  224. buf.WriteString(str)
  225. case fCSSprintf:
  226. str := test.cs.Sprintf(test.format, test.in)
  227. buf.WriteString(str)
  228. case fCSSprintln:
  229. str := test.cs.Sprintln(test.in)
  230. buf.WriteString(str)
  231. case fCSErrorf:
  232. err := test.cs.Errorf(test.format, test.in)
  233. buf.WriteString(err.Error())
  234. case fCSNewFormatter:
  235. fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
  236. case fErrorf:
  237. err := spew.Errorf(test.format, test.in)
  238. buf.WriteString(err.Error())
  239. case fFprint:
  240. spew.Fprint(buf, test.in)
  241. case fFprintln:
  242. spew.Fprintln(buf, test.in)
  243. case fPrint:
  244. b, err := redirStdout(func() { spew.Print(test.in) })
  245. if err != nil {
  246. t.Errorf("%v #%d %v", test.f, i, err)
  247. continue
  248. }
  249. buf.Write(b)
  250. case fPrintln:
  251. b, err := redirStdout(func() { spew.Println(test.in) })
  252. if err != nil {
  253. t.Errorf("%v #%d %v", test.f, i, err)
  254. continue
  255. }
  256. buf.Write(b)
  257. case fSdump:
  258. str := spew.Sdump(test.in)
  259. buf.WriteString(str)
  260. case fSprint:
  261. str := spew.Sprint(test.in)
  262. buf.WriteString(str)
  263. case fSprintf:
  264. str := spew.Sprintf(test.format, test.in)
  265. buf.WriteString(str)
  266. case fSprintln:
  267. str := spew.Sprintln(test.in)
  268. buf.WriteString(str)
  269. default:
  270. t.Errorf("%v #%d unrecognized function", test.f, i)
  271. continue
  272. }
  273. s := buf.String()
  274. if test.want != s {
  275. t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
  276. continue
  277. }
  278. }
  279. }