--- /dev/null
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains simple golden tests for various examples.
+// Besides validating the results when the implementation changes,
+// it provides a way to look at the generated code without having
+// to execute the print statements in one's head.
+
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/internal/testenv"
+)
+
+// Golden represents a test case.
+type Golden struct {
+ name string
+ trimPrefix string
+ lineComment bool
+ input string // input; the package clause is provided when running the test.
+ output string // expected output.
+}
+
+var golden = []Golden{
+ {"day", "", false, day_in, day_out},
+ {"offset", "", false, offset_in, offset_out},
+ {"gap", "", false, gap_in, gap_out},
+ {"num", "", false, num_in, num_out},
+ {"unum", "", false, unum_in, unum_out},
+ {"unumpos", "", false, unumpos_in, unumpos_out},
+ {"prime", "", false, prime_in, prime_out},
+ {"prefix", "Type", false, prefix_in, prefix_out},
+ {"tokens", "", true, tokens_in, tokens_out},
+}
+
+// Each example starts with "type XXX [u]int", with a single space separating them.
+
+// Simple test: enumeration of type int starting at 0.
+const day_in = `type Day int
+const (
+ Monday Day = iota
+ Tuesday
+ Wednesday
+ Thursday
+ Friday
+ Saturday
+ Sunday
+)
+`
+
+const day_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[Monday-0]
+ _ = x[Tuesday-1]
+ _ = x[Wednesday-2]
+ _ = x[Thursday-3]
+ _ = x[Friday-4]
+ _ = x[Saturday-5]
+ _ = x[Sunday-6]
+}
+
+const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
+
+var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
+
+func (i Day) String() string {
+ if i < 0 || i >= Day(len(_Day_index)-1) {
+ return "Day(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Day_name[_Day_index[i]:_Day_index[i+1]]
+}
+`
+
+// Enumeration with an offset.
+// Also includes a duplicate.
+const offset_in = `type Number int
+const (
+ _ Number = iota
+ One
+ Two
+ Three
+ AnotherOne = One // Duplicate; note that AnotherOne doesn't appear below.
+)
+`
+
+const offset_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[One-1]
+ _ = x[Two-2]
+ _ = x[Three-3]
+}
+
+const _Number_name = "OneTwoThree"
+
+var _Number_index = [...]uint8{0, 3, 6, 11}
+
+func (i Number) String() string {
+ i -= 1
+ if i < 0 || i >= Number(len(_Number_index)-1) {
+ return "Number(" + strconv.FormatInt(int64(i+1), 10) + ")"
+ }
+ return _Number_name[_Number_index[i]:_Number_index[i+1]]
+}
+`
+
+// Gaps and an offset.
+const gap_in = `type Gap int
+const (
+ Two Gap = 2
+ Three Gap = 3
+ Five Gap = 5
+ Six Gap = 6
+ Seven Gap = 7
+ Eight Gap = 8
+ Nine Gap = 9
+ Eleven Gap = 11
+)
+`
+
+const gap_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[Two-2]
+ _ = x[Three-3]
+ _ = x[Five-5]
+ _ = x[Six-6]
+ _ = x[Seven-7]
+ _ = x[Eight-8]
+ _ = x[Nine-9]
+ _ = x[Eleven-11]
+}
+
+const (
+ _Gap_name_0 = "TwoThree"
+ _Gap_name_1 = "FiveSixSevenEightNine"
+ _Gap_name_2 = "Eleven"
+)
+
+var (
+ _Gap_index_0 = [...]uint8{0, 3, 8}
+ _Gap_index_1 = [...]uint8{0, 4, 7, 12, 17, 21}
+)
+
+func (i Gap) String() string {
+ switch {
+ case 2 <= i && i <= 3:
+ i -= 2
+ return _Gap_name_0[_Gap_index_0[i]:_Gap_index_0[i+1]]
+ case 5 <= i && i <= 9:
+ i -= 5
+ return _Gap_name_1[_Gap_index_1[i]:_Gap_index_1[i+1]]
+ case i == 11:
+ return _Gap_name_2
+ default:
+ return "Gap(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+`
+
+// Signed integers spanning zero.
+const num_in = `type Num int
+const (
+ m_2 Num = -2 + iota
+ m_1
+ m0
+ m1
+ m2
+)
+`
+
+const num_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[m_2 - -2]
+ _ = x[m_1 - -1]
+ _ = x[m0-0]
+ _ = x[m1-1]
+ _ = x[m2-2]
+}
+
+const _Num_name = "m_2m_1m0m1m2"
+
+var _Num_index = [...]uint8{0, 3, 6, 8, 10, 12}
+
+func (i Num) String() string {
+ i -= -2
+ if i < 0 || i >= Num(len(_Num_index)-1) {
+ return "Num(" + strconv.FormatInt(int64(i+-2), 10) + ")"
+ }
+ return _Num_name[_Num_index[i]:_Num_index[i+1]]
+}
+`
+
+// Unsigned integers spanning zero.
+const unum_in = `type Unum uint
+const (
+ m_2 Unum = iota + 253
+ m_1
+)
+
+const (
+ m0 Unum = iota
+ m1
+ m2
+)
+`
+
+const unum_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[m_2-253]
+ _ = x[m_1-254]
+ _ = x[m0-0]
+ _ = x[m1-1]
+ _ = x[m2-2]
+}
+
+const (
+ _Unum_name_0 = "m0m1m2"
+ _Unum_name_1 = "m_2m_1"
+)
+
+var (
+ _Unum_index_0 = [...]uint8{0, 2, 4, 6}
+ _Unum_index_1 = [...]uint8{0, 3, 6}
+)
+
+func (i Unum) String() string {
+ switch {
+ case i <= 2:
+ return _Unum_name_0[_Unum_index_0[i]:_Unum_index_0[i+1]]
+ case 253 <= i && i <= 254:
+ i -= 253
+ return _Unum_name_1[_Unum_index_1[i]:_Unum_index_1[i+1]]
+ default:
+ return "Unum(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+`
+
+// Unsigned positive integers.
+const unumpos_in = `type Unumpos uint
+const (
+ m253 Unumpos = iota + 253
+ m254
+)
+
+const (
+ m1 Unumpos = iota + 1
+ m2
+ m3
+)
+`
+
+const unumpos_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[m253-253]
+ _ = x[m254-254]
+ _ = x[m1-1]
+ _ = x[m2-2]
+ _ = x[m3-3]
+}
+
+const (
+ _Unumpos_name_0 = "m1m2m3"
+ _Unumpos_name_1 = "m253m254"
+)
+
+var (
+ _Unumpos_index_0 = [...]uint8{0, 2, 4, 6}
+ _Unumpos_index_1 = [...]uint8{0, 4, 8}
+)
+
+func (i Unumpos) String() string {
+ switch {
+ case 1 <= i && i <= 3:
+ i -= 1
+ return _Unumpos_name_0[_Unumpos_index_0[i]:_Unumpos_index_0[i+1]]
+ case 253 <= i && i <= 254:
+ i -= 253
+ return _Unumpos_name_1[_Unumpos_index_1[i]:_Unumpos_index_1[i+1]]
+ default:
+ return "Unumpos(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+`
+
+// Enough gaps to trigger a map implementation of the method.
+// Also includes a duplicate to test that it doesn't cause problems
+const prime_in = `type Prime int
+const (
+ p2 Prime = 2
+ p3 Prime = 3
+ p5 Prime = 5
+ p7 Prime = 7
+ p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
+ p11 Prime = 11
+ p13 Prime = 13
+ p17 Prime = 17
+ p19 Prime = 19
+ p23 Prime = 23
+ p29 Prime = 29
+ p37 Prime = 31
+ p41 Prime = 41
+ p43 Prime = 43
+)
+`
+
+const prime_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[p2-2]
+ _ = x[p3-3]
+ _ = x[p5-5]
+ _ = x[p7-7]
+ _ = x[p77-7]
+ _ = x[p11-11]
+ _ = x[p13-13]
+ _ = x[p17-17]
+ _ = x[p19-19]
+ _ = x[p23-23]
+ _ = x[p29-29]
+ _ = x[p37-31]
+ _ = x[p41-41]
+ _ = x[p43-43]
+}
+
+const _Prime_name = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
+
+var _Prime_map = map[Prime]string{
+ 2: _Prime_name[0:2],
+ 3: _Prime_name[2:4],
+ 5: _Prime_name[4:6],
+ 7: _Prime_name[6:8],
+ 11: _Prime_name[8:11],
+ 13: _Prime_name[11:14],
+ 17: _Prime_name[14:17],
+ 19: _Prime_name[17:20],
+ 23: _Prime_name[20:23],
+ 29: _Prime_name[23:26],
+ 31: _Prime_name[26:29],
+ 41: _Prime_name[29:32],
+ 43: _Prime_name[32:35],
+}
+
+func (i Prime) String() string {
+ if str, ok := _Prime_map[i]; ok {
+ return str
+ }
+ return "Prime(" + strconv.FormatInt(int64(i), 10) + ")"
+}
+`
+
+const prefix_in = `type Type int
+const (
+ TypeInt Type = iota
+ TypeString
+ TypeFloat
+ TypeRune
+ TypeByte
+ TypeStruct
+ TypeSlice
+)
+`
+
+const prefix_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[TypeInt-0]
+ _ = x[TypeString-1]
+ _ = x[TypeFloat-2]
+ _ = x[TypeRune-3]
+ _ = x[TypeByte-4]
+ _ = x[TypeStruct-5]
+ _ = x[TypeSlice-6]
+}
+
+const _Type_name = "IntStringFloatRuneByteStructSlice"
+
+var _Type_index = [...]uint8{0, 3, 9, 14, 18, 22, 28, 33}
+
+func (i Type) String() string {
+ if i < 0 || i >= Type(len(_Type_index)-1) {
+ return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Type_name[_Type_index[i]:_Type_index[i+1]]
+}
+`
+
+const tokens_in = `type Token int
+const (
+ And Token = iota // &
+ Or // |
+ Add // +
+ Sub // -
+ Ident
+ Period // .
+
+ // not to be used
+ SingleBefore
+ // not to be used
+ BeforeAndInline // inline
+ InlineGeneral /* inline general */
+)
+`
+
+const tokens_out = `func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[And-0]
+ _ = x[Or-1]
+ _ = x[Add-2]
+ _ = x[Sub-3]
+ _ = x[Ident-4]
+ _ = x[Period-5]
+ _ = x[SingleBefore-6]
+ _ = x[BeforeAndInline-7]
+ _ = x[InlineGeneral-8]
+}
+
+const _Token_name = "&|+-Ident.SingleBeforeinlineinline general"
+
+var _Token_index = [...]uint8{0, 1, 2, 3, 4, 9, 10, 22, 28, 42}
+
+func (i Token) String() string {
+ if i < 0 || i >= Token(len(_Token_index)-1) {
+ return "Token(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Token_name[_Token_index[i]:_Token_index[i+1]]
+}
+`
+
+func TestGolden(t *testing.T) {
+ testenv.NeedsTool(t, "go")
+
+ dir, err := ioutil.TempDir("", "stringer")
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.RemoveAll(dir)
+
+ for _, test := range golden {
+ g := Generator{
+ trimPrefix: test.trimPrefix,
+ lineComment: test.lineComment,
+ }
+ input := "package test\n" + test.input
+ file := test.name + ".go"
+ absFile := filepath.Join(dir, file)
+ err := ioutil.WriteFile(absFile, []byte(input), 0644)
+ if err != nil {
+ t.Error(err)
+ }
+
+ g.parsePackage([]string{absFile}, nil)
+ // Extract the name and type of the constant from the first line.
+ tokens := strings.SplitN(test.input, " ", 3)
+ if len(tokens) != 3 {
+ t.Fatalf("%s: need type declaration on first line", test.name)
+ }
+ g.generate(tokens[1])
+ got := string(g.format())
+ if got != test.output {
+ t.Errorf("%s: got(%d)\n====\n%q====\nexpected(%d)\n====%q", test.name, len(got), got, len(test.output), test.output)
+ }
+ }
+}