2 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
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.
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.
26 "github.com/davecgh/go-spew/spew"
29 // spewFunc is used to identify which public function of the spew package or
30 // ConfigState a test applies to.
34 fCSFdump spewFunc = iota
57 // Map of spewFunc values to names for pretty printing.
58 var spewFuncStrings = map[spewFunc]string{
59 fCSFdump: "ConfigState.Fdump",
60 fCSFprint: "ConfigState.Fprint",
61 fCSFprintf: "ConfigState.Fprintf",
62 fCSFprintln: "ConfigState.Fprintln",
63 fCSSdump: "ConfigState.Sdump",
64 fCSPrint: "ConfigState.Print",
65 fCSPrintln: "ConfigState.Println",
66 fCSSprint: "ConfigState.Sprint",
67 fCSSprintf: "ConfigState.Sprintf",
68 fCSSprintln: "ConfigState.Sprintln",
69 fCSErrorf: "ConfigState.Errorf",
70 fCSNewFormatter: "ConfigState.NewFormatter",
71 fErrorf: "spew.Errorf",
72 fFprint: "spew.Fprint",
73 fFprintln: "spew.Fprintln",
75 fPrintln: "spew.Println",
77 fSprint: "spew.Sprint",
78 fSprintf: "spew.Sprintf",
79 fSprintln: "spew.Sprintln",
82 func (f spewFunc) String() string {
83 if s, ok := spewFuncStrings[f]; ok {
86 return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
89 // spewTest is used to describe a test to be performed against the public
90 // functions of the spew package or ConfigState.
91 type spewTest struct {
99 // spewTests houses the tests to be performed against the public functions of
100 // the spew package and ConfigState.
102 // These tests are only intended to ensure the public functions are exercised
103 // and are intentionally not exhaustive of types. The exhaustive type
104 // tests are handled in the dump and format tests.
105 var spewTests []spewTest
107 // redirStdout is a helper function to return the standard output from f as a
109 func redirStdout(f func()) ([]byte, error) {
110 tempFile, err := ioutil.TempFile("", "ss-test")
114 fileName := tempFile.Name()
115 defer os.Remove(fileName) // Ignore error
117 origStdout := os.Stdout
120 os.Stdout = origStdout
123 return ioutil.ReadFile(fileName)
126 func initSpewTests() {
127 // Config states with various settings.
128 scsDefault := spew.NewDefaultConfig()
129 scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
130 scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
131 scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
132 scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
133 scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
134 scsNoCap := &spew.ConfigState{DisableCapacities: true}
136 // Variables for tests on types which implement Stringer interface with and
137 // without a pointer receiver.
138 ts := stringer("test")
139 tps := pstringer("test")
141 type ptrTester struct {
144 tptr := &ptrTester{s: &struct{}{}}
146 // depthTester is used to test max depth handling for structs, array, slices
148 type depthTester struct {
154 dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
155 map[string]int{"one": 1}}
157 // Variable for tests on types which implement error interface.
158 te := customError(10)
160 spewTests = []spewTest{
161 {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
162 {scsDefault, fCSFprint, "", int16(32767), "32767"},
163 {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
164 {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
165 {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
166 {scsDefault, fCSPrintln, "", uint8(255), "255\n"},
167 {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
168 {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
169 {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
170 {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
171 {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
172 {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
173 {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
174 {scsDefault, fFprint, "", float32(3.14), "3.14"},
175 {scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
176 {scsDefault, fPrint, "", true, "true"},
177 {scsDefault, fPrintln, "", false, "false\n"},
178 {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
179 {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
180 {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
181 {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
182 {scsNoMethods, fCSFprint, "", ts, "test"},
183 {scsNoMethods, fCSFprint, "", &ts, "<*>test"},
184 {scsNoMethods, fCSFprint, "", tps, "test"},
185 {scsNoMethods, fCSFprint, "", &tps, "<*>test"},
186 {scsNoPmethods, fCSFprint, "", ts, "stringer test"},
187 {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
188 {scsNoPmethods, fCSFprint, "", tps, "test"},
189 {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
190 {scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
191 {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
192 " ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
193 " arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
194 " slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
195 " m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
196 {scsContinue, fCSFprint, "", ts, "(stringer test) test"},
197 {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
198 "(len=4) (stringer test) \"test\"\n"},
199 {scsContinue, fCSFprint, "", te, "(error: 10) 10"},
200 {scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
202 {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
203 {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
204 {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
205 {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
209 // TestSpew executes all of the tests described by spewTests.
210 func TestSpew(t *testing.T) {
213 t.Logf("Running %d tests", len(spewTests))
214 for i, test := range spewTests {
215 buf := new(bytes.Buffer)
218 test.cs.Fdump(buf, test.in)
221 test.cs.Fprint(buf, test.in)
224 test.cs.Fprintf(buf, test.format, test.in)
227 test.cs.Fprintln(buf, test.in)
230 b, err := redirStdout(func() { test.cs.Print(test.in) })
232 t.Errorf("%v #%d %v", test.f, i, err)
238 b, err := redirStdout(func() { test.cs.Println(test.in) })
240 t.Errorf("%v #%d %v", test.f, i, err)
246 str := test.cs.Sdump(test.in)
250 str := test.cs.Sprint(test.in)
254 str := test.cs.Sprintf(test.format, test.in)
258 str := test.cs.Sprintln(test.in)
262 err := test.cs.Errorf(test.format, test.in)
263 buf.WriteString(err.Error())
265 case fCSNewFormatter:
266 fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
269 err := spew.Errorf(test.format, test.in)
270 buf.WriteString(err.Error())
273 spew.Fprint(buf, test.in)
276 spew.Fprintln(buf, test.in)
279 b, err := redirStdout(func() { spew.Print(test.in) })
281 t.Errorf("%v #%d %v", test.f, i, err)
287 b, err := redirStdout(func() { spew.Println(test.in) })
289 t.Errorf("%v #%d %v", test.f, i, err)
295 str := spew.Sdump(test.in)
299 str := spew.Sprint(test.in)
303 str := spew.Sprintf(test.format, test.in)
307 str := spew.Sprintln(test.in)
311 t.Errorf("%v #%d unrecognized function", test.f, i)
316 t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)