|  | // 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) | 
|  | } | 
|  | } | 
|  | } |