spew_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright (c) 2013 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. "github.com/davecgh/go-spew/spew"
  21. "io/ioutil"
  22. "os"
  23. "testing"
  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. fCSSprint
  36. fCSSprintf
  37. fCSSprintln
  38. fCSErrorf
  39. fCSNewFormatter
  40. fErrorf
  41. fFprint
  42. fFprintln
  43. fPrint
  44. fPrintln
  45. fSprint
  46. fSprintf
  47. fSprintln
  48. )
  49. // Map of spewFunc values to names for pretty printing.
  50. var spewFuncStrings = map[spewFunc]string{
  51. fCSFdump: "ConfigState.Fdump",
  52. fCSFprint: "ConfigState.Fprint",
  53. fCSFprintf: "ConfigState.Fprintf",
  54. fCSFprintln: "ConfigState.Fprintln",
  55. fCSPrint: "ConfigState.Print",
  56. fCSPrintln: "ConfigState.Println",
  57. fCSSprint: "ConfigState.Sprint",
  58. fCSSprintf: "ConfigState.Sprintf",
  59. fCSSprintln: "ConfigState.Sprintln",
  60. fCSErrorf: "ConfigState.Errorf",
  61. fCSNewFormatter: "ConfigState.NewFormatter",
  62. fErrorf: "spew.Errorf",
  63. fFprint: "spew.Fprint",
  64. fFprintln: "spew.Fprintln",
  65. fPrint: "spew.Print",
  66. fPrintln: "spew.Println",
  67. fSprint: "spew.Sprint",
  68. fSprintf: "spew.Sprintf",
  69. fSprintln: "spew.Sprintln",
  70. }
  71. func (f spewFunc) String() string {
  72. if s, ok := spewFuncStrings[f]; ok {
  73. return s
  74. }
  75. return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
  76. }
  77. // spewTest is used to describe a test to be performed against the public
  78. // functions of the spew package or ConfigState.
  79. type spewTest struct {
  80. cs *spew.ConfigState
  81. f spewFunc
  82. format string
  83. in interface{}
  84. want string
  85. }
  86. // spewTests houses the tests to be performed against the public functions of
  87. // the spew package and ConfigState.
  88. //
  89. // These tests are only intended to ensure the public functions are exercised
  90. // and are intentionally not exhaustive of types. The exhaustive type
  91. // tests are handled in the dump and format tests.
  92. var spewTests []spewTest
  93. // redirStdout is a helper function to return the standard output from f as a
  94. // byte slice.
  95. func redirStdout(f func()) ([]byte, error) {
  96. tempFile, err := ioutil.TempFile("", "ss-test")
  97. if err != nil {
  98. return nil, err
  99. }
  100. fileName := tempFile.Name()
  101. defer os.Remove(fileName) // Ignore error
  102. origStdout := os.Stdout
  103. os.Stdout = tempFile
  104. f()
  105. os.Stdout = origStdout
  106. tempFile.Close()
  107. return ioutil.ReadFile(fileName)
  108. }
  109. func initSpewTests() {
  110. // Config states with various settings.
  111. scsDefault := spew.NewDefaultConfig()
  112. scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
  113. scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
  114. scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
  115. scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
  116. // Variables for tests on types which implement Stringer interface with and
  117. // without a pointer receiver.
  118. ts := stringer("test")
  119. tps := pstringer("test")
  120. // depthTester is used to test max depth handling for structs, array, slices
  121. // and maps.
  122. type depthTester struct {
  123. ic indirCir1
  124. arr [1]string
  125. slice []string
  126. m map[string]int
  127. }
  128. dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
  129. map[string]int{"one": 1}}
  130. // Variable for tests on types which implement error interface.
  131. te := customError(10)
  132. spewTests = []spewTest{
  133. {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
  134. {scsDefault, fCSFprint, "", int16(32767), "32767"},
  135. {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
  136. {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
  137. {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
  138. {scsDefault, fCSPrintln, "", uint8(255), "255\n"},
  139. {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
  140. {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
  141. {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
  142. {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
  143. {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
  144. {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
  145. {scsDefault, fFprint, "", float32(3.14), "3.14"},
  146. {scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
  147. {scsDefault, fPrint, "", true, "true"},
  148. {scsDefault, fPrintln, "", false, "false\n"},
  149. {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
  150. {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
  151. {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
  152. {scsNoMethods, fCSFprint, "", ts, "test"},
  153. {scsNoMethods, fCSFprint, "", &ts, "<*>test"},
  154. {scsNoMethods, fCSFprint, "", tps, "test"},
  155. {scsNoMethods, fCSFprint, "", &tps, "<*>test"},
  156. {scsNoPmethods, fCSFprint, "", ts, "stringer test"},
  157. {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
  158. {scsNoPmethods, fCSFprint, "", tps, "test"},
  159. {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
  160. {scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
  161. {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
  162. " ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
  163. " arr: ([1]string) {\n <max depth reached>\n },\n" +
  164. " slice: ([]string) {\n <max depth reached>\n },\n" +
  165. " m: (map[string]int) {\n <max depth reached>\n }\n}\n"},
  166. {scsContinue, fCSFprint, "", ts, "(stringer test) test"},
  167. {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
  168. "(stringer test) \"test\"\n"},
  169. {scsContinue, fCSFprint, "", te, "(error: 10) 10"},
  170. {scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
  171. "(error: 10) 10\n"},
  172. }
  173. }
  174. // TestSpew executes all of the tests described by spewTests.
  175. func TestSpew(t *testing.T) {
  176. initSpewTests()
  177. t.Logf("Running %d tests", len(spewTests))
  178. for i, test := range spewTests {
  179. buf := new(bytes.Buffer)
  180. switch test.f {
  181. case fCSFdump:
  182. test.cs.Fdump(buf, test.in)
  183. case fCSFprint:
  184. test.cs.Fprint(buf, test.in)
  185. case fCSFprintf:
  186. test.cs.Fprintf(buf, test.format, test.in)
  187. case fCSFprintln:
  188. test.cs.Fprintln(buf, test.in)
  189. case fCSPrint:
  190. b, err := redirStdout(func() { test.cs.Print(test.in) })
  191. if err != nil {
  192. t.Errorf("%v #%d %v", test.f, i, err)
  193. continue
  194. }
  195. buf.Write(b)
  196. case fCSPrintln:
  197. b, err := redirStdout(func() { test.cs.Println(test.in) })
  198. if err != nil {
  199. t.Errorf("%v #%d %v", test.f, i, err)
  200. continue
  201. }
  202. buf.Write(b)
  203. case fCSSprint:
  204. str := test.cs.Sprint(test.in)
  205. buf.WriteString(str)
  206. case fCSSprintf:
  207. str := test.cs.Sprintf(test.format, test.in)
  208. buf.WriteString(str)
  209. case fCSSprintln:
  210. str := test.cs.Sprintln(test.in)
  211. buf.WriteString(str)
  212. case fCSErrorf:
  213. err := test.cs.Errorf(test.format, test.in)
  214. buf.WriteString(err.Error())
  215. case fCSNewFormatter:
  216. fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
  217. case fErrorf:
  218. err := spew.Errorf(test.format, test.in)
  219. buf.WriteString(err.Error())
  220. case fFprint:
  221. spew.Fprint(buf, test.in)
  222. case fFprintln:
  223. spew.Fprintln(buf, test.in)
  224. case fPrint:
  225. b, err := redirStdout(func() { spew.Print(test.in) })
  226. if err != nil {
  227. t.Errorf("%v #%d %v", test.f, i, err)
  228. continue
  229. }
  230. buf.Write(b)
  231. case fPrintln:
  232. b, err := redirStdout(func() { spew.Println(test.in) })
  233. if err != nil {
  234. t.Errorf("%v #%d %v", test.f, i, err)
  235. continue
  236. }
  237. buf.Write(b)
  238. case fSprint:
  239. str := spew.Sprint(test.in)
  240. buf.WriteString(str)
  241. case fSprintf:
  242. str := spew.Sprintf(test.format, test.in)
  243. buf.WriteString(str)
  244. case fSprintln:
  245. str := spew.Sprintln(test.in)
  246. buf.WriteString(str)
  247. default:
  248. t.Errorf("%v #%d unrecognized function", test.f, i)
  249. continue
  250. }
  251. s := buf.String()
  252. if test.want != s {
  253. t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
  254. continue
  255. }
  256. }
  257. }