1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file contains simple golden tests for various examples.
6 // Besides validating the results when the implementation changes,
7 // it provides a way to look at the generated code without having
8 // to execute the print statements in one's head.
19 "golang.org/x/tools/internal/testenv"
22 // Golden represents a test case.
27 input string // input; the package clause is provided when running the test.
28 output string // expected output.
31 var golden = []Golden{
32 {"day", "", false, day_in, day_out},
33 {"offset", "", false, offset_in, offset_out},
34 {"gap", "", false, gap_in, gap_out},
35 {"num", "", false, num_in, num_out},
36 {"unum", "", false, unum_in, unum_out},
37 {"unumpos", "", false, unumpos_in, unumpos_out},
38 {"prime", "", false, prime_in, prime_out},
39 {"prefix", "Type", false, prefix_in, prefix_out},
40 {"tokens", "", true, tokens_in, tokens_out},
43 // Each example starts with "type XXX [u]int", with a single space separating them.
45 // Simple test: enumeration of type int starting at 0.
46 const day_in = `type Day int
58 const day_out = `func _() {
59 // An "invalid array index" compiler error signifies that the constant values have changed.
60 // Re-run the stringer command to generate them again.
71 const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
73 var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
75 func (i Day) String() string {
76 if i < 0 || i >= Day(len(_Day_index)-1) {
77 return "Day(" + strconv.FormatInt(int64(i), 10) + ")"
79 return _Day_name[_Day_index[i]:_Day_index[i+1]]
83 // Enumeration with an offset.
84 // Also includes a duplicate.
85 const offset_in = `type Number int
91 AnotherOne = One // Duplicate; note that AnotherOne doesn't appear below.
95 const offset_out = `func _() {
96 // An "invalid array index" compiler error signifies that the constant values have changed.
97 // Re-run the stringer command to generate them again.
104 const _Number_name = "OneTwoThree"
106 var _Number_index = [...]uint8{0, 3, 6, 11}
108 func (i Number) String() string {
110 if i < 0 || i >= Number(len(_Number_index)-1) {
111 return "Number(" + strconv.FormatInt(int64(i+1), 10) + ")"
113 return _Number_name[_Number_index[i]:_Number_index[i+1]]
117 // Gaps and an offset.
118 const gap_in = `type Gap int
131 const gap_out = `func _() {
132 // An "invalid array index" compiler error signifies that the constant values have changed.
133 // Re-run the stringer command to generate them again.
146 _Gap_name_0 = "TwoThree"
147 _Gap_name_1 = "FiveSixSevenEightNine"
148 _Gap_name_2 = "Eleven"
152 _Gap_index_0 = [...]uint8{0, 3, 8}
153 _Gap_index_1 = [...]uint8{0, 4, 7, 12, 17, 21}
156 func (i Gap) String() string {
158 case 2 <= i && i <= 3:
160 return _Gap_name_0[_Gap_index_0[i]:_Gap_index_0[i+1]]
161 case 5 <= i && i <= 9:
163 return _Gap_name_1[_Gap_index_1[i]:_Gap_index_1[i+1]]
167 return "Gap(" + strconv.FormatInt(int64(i), 10) + ")"
172 // Signed integers spanning zero.
173 const num_in = `type Num int
183 const num_out = `func _() {
184 // An "invalid array index" compiler error signifies that the constant values have changed.
185 // Re-run the stringer command to generate them again.
194 const _Num_name = "m_2m_1m0m1m2"
196 var _Num_index = [...]uint8{0, 3, 6, 8, 10, 12}
198 func (i Num) String() string {
200 if i < 0 || i >= Num(len(_Num_index)-1) {
201 return "Num(" + strconv.FormatInt(int64(i+-2), 10) + ")"
203 return _Num_name[_Num_index[i]:_Num_index[i+1]]
207 // Unsigned integers spanning zero.
208 const unum_in = `type Unum uint
210 m_2 Unum = iota + 253
221 const unum_out = `func _() {
222 // An "invalid array index" compiler error signifies that the constant values have changed.
223 // Re-run the stringer command to generate them again.
233 _Unum_name_0 = "m0m1m2"
234 _Unum_name_1 = "m_2m_1"
238 _Unum_index_0 = [...]uint8{0, 2, 4, 6}
239 _Unum_index_1 = [...]uint8{0, 3, 6}
242 func (i Unum) String() string {
245 return _Unum_name_0[_Unum_index_0[i]:_Unum_index_0[i+1]]
246 case 253 <= i && i <= 254:
248 return _Unum_name_1[_Unum_index_1[i]:_Unum_index_1[i+1]]
250 return "Unum(" + strconv.FormatInt(int64(i), 10) + ")"
255 // Unsigned positive integers.
256 const unumpos_in = `type Unumpos uint
258 m253 Unumpos = iota + 253
263 m1 Unumpos = iota + 1
269 const unumpos_out = `func _() {
270 // An "invalid array index" compiler error signifies that the constant values have changed.
271 // Re-run the stringer command to generate them again.
281 _Unumpos_name_0 = "m1m2m3"
282 _Unumpos_name_1 = "m253m254"
286 _Unumpos_index_0 = [...]uint8{0, 2, 4, 6}
287 _Unumpos_index_1 = [...]uint8{0, 4, 8}
290 func (i Unumpos) String() string {
292 case 1 <= i && i <= 3:
294 return _Unumpos_name_0[_Unumpos_index_0[i]:_Unumpos_index_0[i+1]]
295 case 253 <= i && i <= 254:
297 return _Unumpos_name_1[_Unumpos_index_1[i]:_Unumpos_index_1[i+1]]
299 return "Unumpos(" + strconv.FormatInt(int64(i), 10) + ")"
304 // Enough gaps to trigger a map implementation of the method.
305 // Also includes a duplicate to test that it doesn't cause problems
306 const prime_in = `type Prime int
312 p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
325 const prime_out = `func _() {
326 // An "invalid array index" compiler error signifies that the constant values have changed.
327 // Re-run the stringer command to generate them again.
345 const _Prime_name = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
347 var _Prime_map = map[Prime]string{
352 11: _Prime_name[8:11],
353 13: _Prime_name[11:14],
354 17: _Prime_name[14:17],
355 19: _Prime_name[17:20],
356 23: _Prime_name[20:23],
357 29: _Prime_name[23:26],
358 31: _Prime_name[26:29],
359 41: _Prime_name[29:32],
360 43: _Prime_name[32:35],
363 func (i Prime) String() string {
364 if str, ok := _Prime_map[i]; ok {
367 return "Prime(" + strconv.FormatInt(int64(i), 10) + ")"
371 const prefix_in = `type Type int
383 const prefix_out = `func _() {
384 // An "invalid array index" compiler error signifies that the constant values have changed.
385 // Re-run the stringer command to generate them again.
396 const _Type_name = "IntStringFloatRuneByteStructSlice"
398 var _Type_index = [...]uint8{0, 3, 9, 14, 18, 22, 28, 33}
400 func (i Type) String() string {
401 if i < 0 || i >= Type(len(_Type_index)-1) {
402 return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
404 return _Type_name[_Type_index[i]:_Type_index[i+1]]
408 const tokens_in = `type Token int
410 And Token = iota // &
420 BeforeAndInline // inline
421 InlineGeneral /* inline general */
425 const tokens_out = `func _() {
426 // An "invalid array index" compiler error signifies that the constant values have changed.
427 // Re-run the stringer command to generate them again.
435 _ = x[SingleBefore-6]
436 _ = x[BeforeAndInline-7]
437 _ = x[InlineGeneral-8]
440 const _Token_name = "&|+-Ident.SingleBeforeinlineinline general"
442 var _Token_index = [...]uint8{0, 1, 2, 3, 4, 9, 10, 22, 28, 42}
444 func (i Token) String() string {
445 if i < 0 || i >= Token(len(_Token_index)-1) {
446 return "Token(" + strconv.FormatInt(int64(i), 10) + ")"
448 return _Token_name[_Token_index[i]:_Token_index[i+1]]
452 func TestGolden(t *testing.T) {
453 testenv.NeedsTool(t, "go")
455 dir, err := ioutil.TempDir("", "stringer")
459 defer os.RemoveAll(dir)
461 for _, test := range golden {
463 trimPrefix: test.trimPrefix,
464 lineComment: test.lineComment,
466 input := "package test\n" + test.input
467 file := test.name + ".go"
468 absFile := filepath.Join(dir, file)
469 err := ioutil.WriteFile(absFile, []byte(input), 0644)
474 g.parsePackage([]string{absFile}, nil)
475 // Extract the name and type of the constant from the first line.
476 tokens := strings.SplitN(test.input, " ", 3)
477 if len(tokens) != 3 {
478 t.Fatalf("%s: need type declaration on first line", test.name)
480 g.generate(tokens[1])
481 got := string(g.format())
482 if got != test.output {
483 t.Errorf("%s: got(%d)\n====\n%q====\nexpected(%d)\n====%q", test.name, len(got), got, len(test.output), test.output)