GoPLS Viewer

Home|gopls/cmd/stringer/golden_test.go
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.
4
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.
9
10package main
11
12import (
13    "os"
14    "path/filepath"
15    "strings"
16    "testing"
17
18    "golang.org/x/tools/internal/testenv"
19)
20
21// Golden represents a test case.
22type Golden struct {
23    name        string
24    trimPrefix  string
25    lineComment bool
26    input       string // input; the package clause is provided when running the test.
27    output      string // expected output.
28}
29
30var golden = []Golden{
31    {"day"""falseday_inday_out},
32    {"offset"""falseoffset_inoffset_out},
33    {"gap"""falsegap_ingap_out},
34    {"num"""falsenum_innum_out},
35    {"unum"""falseunum_inunum_out},
36    {"unumpos"""falseunumpos_inunumpos_out},
37    {"prime"""falseprime_inprime_out},
38    {"prefix""Type"falseprefix_inprefix_out},
39    {"tokens"""truetokens_intokens_out},
40}
41
42// Each example starts with "type XXX [u]int", with a single space separating them.
43
44// Simple test: enumeration of type int starting at 0.
45const day_in = `type Day int
46const (
47    Monday Day = iota
48    Tuesday
49    Wednesday
50    Thursday
51    Friday
52    Saturday
53    Sunday
54)
55`
56
57const day_out = `func _() {
58    // An "invalid array index" compiler error signifies that the constant values have changed.
59    // Re-run the stringer command to generate them again.
60    var x [1]struct{}
61    _ = x[Monday-0]
62    _ = x[Tuesday-1]
63    _ = x[Wednesday-2]
64    _ = x[Thursday-3]
65    _ = x[Friday-4]
66    _ = x[Saturday-5]
67    _ = x[Sunday-6]
68}
69
70const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
71
72var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
73
74func (i Day) String() string {
75    if i < 0 || i >= Day(len(_Day_index)-1) {
76        return "Day(" + strconv.FormatInt(int64(i), 10) + ")"
77    }
78    return _Day_name[_Day_index[i]:_Day_index[i+1]]
79}
80`
81
82// Enumeration with an offset.
83// Also includes a duplicate.
84const offset_in = `type Number int
85const (
86    _ Number = iota
87    One
88    Two
89    Three
90    AnotherOne = One  // Duplicate; note that AnotherOne doesn't appear below.
91)
92`
93
94const offset_out = `func _() {
95    // An "invalid array index" compiler error signifies that the constant values have changed.
96    // Re-run the stringer command to generate them again.
97    var x [1]struct{}
98    _ = x[One-1]
99    _ = x[Two-2]
100    _ = x[Three-3]
101}
102
103const _Number_name = "OneTwoThree"
104
105var _Number_index = [...]uint8{0, 3, 6, 11}
106
107func (i Number) String() string {
108    i -= 1
109    if i < 0 || i >= Number(len(_Number_index)-1) {
110        return "Number(" + strconv.FormatInt(int64(i+1), 10) + ")"
111    }
112    return _Number_name[_Number_index[i]:_Number_index[i+1]]
113}
114`
115
116// Gaps and an offset.
117const gap_in = `type Gap int
118const (
119    Two Gap = 2
120    Three Gap = 3
121    Five Gap = 5
122    Six Gap = 6
123    Seven Gap = 7
124    Eight Gap = 8
125    Nine Gap = 9
126    Eleven Gap = 11
127)
128`
129
130const gap_out = `func _() {
131    // An "invalid array index" compiler error signifies that the constant values have changed.
132    // Re-run the stringer command to generate them again.
133    var x [1]struct{}
134    _ = x[Two-2]
135    _ = x[Three-3]
136    _ = x[Five-5]
137    _ = x[Six-6]
138    _ = x[Seven-7]
139    _ = x[Eight-8]
140    _ = x[Nine-9]
141    _ = x[Eleven-11]
142}
143
144const (
145    _Gap_name_0 = "TwoThree"
146    _Gap_name_1 = "FiveSixSevenEightNine"
147    _Gap_name_2 = "Eleven"
148)
149
150var (
151    _Gap_index_0 = [...]uint8{0, 3, 8}
152    _Gap_index_1 = [...]uint8{0, 4, 7, 12, 17, 21}
153)
154
155func (i Gap) String() string {
156    switch {
157    case 2 <= i && i <= 3:
158        i -= 2
159        return _Gap_name_0[_Gap_index_0[i]:_Gap_index_0[i+1]]
160    case 5 <= i && i <= 9:
161        i -= 5
162        return _Gap_name_1[_Gap_index_1[i]:_Gap_index_1[i+1]]
163    case i == 11:
164        return _Gap_name_2
165    default:
166        return "Gap(" + strconv.FormatInt(int64(i), 10) + ")"
167    }
168}
169`
170
171// Signed integers spanning zero.
172const num_in = `type Num int
173const (
174    m_2 Num = -2 + iota
175    m_1
176    m0
177    m1
178    m2
179)
180`
181
182const num_out = `func _() {
183    // An "invalid array index" compiler error signifies that the constant values have changed.
184    // Re-run the stringer command to generate them again.
185    var x [1]struct{}
186    _ = x[m_2 - -2]
187    _ = x[m_1 - -1]
188    _ = x[m0-0]
189    _ = x[m1-1]
190    _ = x[m2-2]
191}
192
193const _Num_name = "m_2m_1m0m1m2"
194
195var _Num_index = [...]uint8{0, 3, 6, 8, 10, 12}
196
197func (i Num) String() string {
198    i -= -2
199    if i < 0 || i >= Num(len(_Num_index)-1) {
200        return "Num(" + strconv.FormatInt(int64(i+-2), 10) + ")"
201    }
202    return _Num_name[_Num_index[i]:_Num_index[i+1]]
203}
204`
205
206// Unsigned integers spanning zero.
207const unum_in = `type Unum uint
208const (
209    m_2 Unum = iota + 253
210    m_1
211)
212
213const (
214    m0 Unum = iota
215    m1
216    m2
217)
218`
219
220const unum_out = `func _() {
221    // An "invalid array index" compiler error signifies that the constant values have changed.
222    // Re-run the stringer command to generate them again.
223    var x [1]struct{}
224    _ = x[m_2-253]
225    _ = x[m_1-254]
226    _ = x[m0-0]
227    _ = x[m1-1]
228    _ = x[m2-2]
229}
230
231const (
232    _Unum_name_0 = "m0m1m2"
233    _Unum_name_1 = "m_2m_1"
234)
235
236var (
237    _Unum_index_0 = [...]uint8{0, 2, 4, 6}
238    _Unum_index_1 = [...]uint8{0, 3, 6}
239)
240
241func (i Unum) String() string {
242    switch {
243    case i <= 2:
244        return _Unum_name_0[_Unum_index_0[i]:_Unum_index_0[i+1]]
245    case 253 <= i && i <= 254:
246        i -= 253
247        return _Unum_name_1[_Unum_index_1[i]:_Unum_index_1[i+1]]
248    default:
249        return "Unum(" + strconv.FormatInt(int64(i), 10) + ")"
250    }
251}
252`
253
254// Unsigned positive integers.
255const unumpos_in = `type Unumpos uint
256const (
257    m253 Unumpos = iota + 253
258    m254
259)
260
261const (
262    m1 Unumpos = iota + 1
263    m2
264    m3
265)
266`
267
268const unumpos_out = `func _() {
269    // An "invalid array index" compiler error signifies that the constant values have changed.
270    // Re-run the stringer command to generate them again.
271    var x [1]struct{}
272    _ = x[m253-253]
273    _ = x[m254-254]
274    _ = x[m1-1]
275    _ = x[m2-2]
276    _ = x[m3-3]
277}
278
279const (
280    _Unumpos_name_0 = "m1m2m3"
281    _Unumpos_name_1 = "m253m254"
282)
283
284var (
285    _Unumpos_index_0 = [...]uint8{0, 2, 4, 6}
286    _Unumpos_index_1 = [...]uint8{0, 4, 8}
287)
288
289func (i Unumpos) String() string {
290    switch {
291    case 1 <= i && i <= 3:
292        i -= 1
293        return _Unumpos_name_0[_Unumpos_index_0[i]:_Unumpos_index_0[i+1]]
294    case 253 <= i && i <= 254:
295        i -= 253
296        return _Unumpos_name_1[_Unumpos_index_1[i]:_Unumpos_index_1[i+1]]
297    default:
298        return "Unumpos(" + strconv.FormatInt(int64(i), 10) + ")"
299    }
300}
301`
302
303// Enough gaps to trigger a map implementation of the method.
304// Also includes a duplicate to test that it doesn't cause problems
305const prime_in = `type Prime int
306const (
307    p2 Prime = 2
308    p3 Prime = 3
309    p5 Prime = 5
310    p7 Prime = 7
311    p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
312    p11 Prime = 11
313    p13 Prime = 13
314    p17 Prime = 17
315    p19 Prime = 19
316    p23 Prime = 23
317    p29 Prime = 29
318    p37 Prime = 31
319    p41 Prime = 41
320    p43 Prime = 43
321)
322`
323
324const prime_out = `func _() {
325    // An "invalid array index" compiler error signifies that the constant values have changed.
326    // Re-run the stringer command to generate them again.
327    var x [1]struct{}
328    _ = x[p2-2]
329    _ = x[p3-3]
330    _ = x[p5-5]
331    _ = x[p7-7]
332    _ = x[p77-7]
333    _ = x[p11-11]
334    _ = x[p13-13]
335    _ = x[p17-17]
336    _ = x[p19-19]
337    _ = x[p23-23]
338    _ = x[p29-29]
339    _ = x[p37-31]
340    _ = x[p41-41]
341    _ = x[p43-43]
342}
343
344const _Prime_name = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
345
346var _Prime_map = map[Prime]string{
347    2:  _Prime_name[0:2],
348    3:  _Prime_name[2:4],
349    5:  _Prime_name[4:6],
350    7:  _Prime_name[6:8],
351    11: _Prime_name[8:11],
352    13: _Prime_name[11:14],
353    17: _Prime_name[14:17],
354    19: _Prime_name[17:20],
355    23: _Prime_name[20:23],
356    29: _Prime_name[23:26],
357    31: _Prime_name[26:29],
358    41: _Prime_name[29:32],
359    43: _Prime_name[32:35],
360}
361
362func (i Prime) String() string {
363    if str, ok := _Prime_map[i]; ok {
364        return str
365    }
366    return "Prime(" + strconv.FormatInt(int64(i), 10) + ")"
367}
368`
369
370const prefix_in = `type Type int
371const (
372    TypeInt Type = iota
373    TypeString
374    TypeFloat
375    TypeRune
376    TypeByte
377    TypeStruct
378    TypeSlice
379)
380`
381
382const prefix_out = `func _() {
383    // An "invalid array index" compiler error signifies that the constant values have changed.
384    // Re-run the stringer command to generate them again.
385    var x [1]struct{}
386    _ = x[TypeInt-0]
387    _ = x[TypeString-1]
388    _ = x[TypeFloat-2]
389    _ = x[TypeRune-3]
390    _ = x[TypeByte-4]
391    _ = x[TypeStruct-5]
392    _ = x[TypeSlice-6]
393}
394
395const _Type_name = "IntStringFloatRuneByteStructSlice"
396
397var _Type_index = [...]uint8{0, 3, 9, 14, 18, 22, 28, 33}
398
399func (i Type) String() string {
400    if i < 0 || i >= Type(len(_Type_index)-1) {
401        return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
402    }
403    return _Type_name[_Type_index[i]:_Type_index[i+1]]
404}
405`
406
407const tokens_in = `type Token int
408const (
409    And Token = iota // &
410    Or               // |
411    Add              // +
412    Sub              // -
413    Ident
414    Period // .
415
416    // not to be used
417    SingleBefore
418    // not to be used
419    BeforeAndInline // inline
420    InlineGeneral /* inline general */
421)
422`
423
424const tokens_out = `func _() {
425    // An "invalid array index" compiler error signifies that the constant values have changed.
426    // Re-run the stringer command to generate them again.
427    var x [1]struct{}
428    _ = x[And-0]
429    _ = x[Or-1]
430    _ = x[Add-2]
431    _ = x[Sub-3]
432    _ = x[Ident-4]
433    _ = x[Period-5]
434    _ = x[SingleBefore-6]
435    _ = x[BeforeAndInline-7]
436    _ = x[InlineGeneral-8]
437}
438
439const _Token_name = "&|+-Ident.SingleBeforeinlineinline general"
440
441var _Token_index = [...]uint8{0, 1, 2, 3, 4, 9, 10, 22, 28, 42}
442
443func (i Token) String() string {
444    if i < 0 || i >= Token(len(_Token_index)-1) {
445        return "Token(" + strconv.FormatInt(int64(i), 10) + ")"
446    }
447    return _Token_name[_Token_index[i]:_Token_index[i+1]]
448}
449`
450
451func TestGolden(t *testing.T) {
452    testenv.NeedsTool(t"go")
453
454    direrr := os.MkdirTemp("""stringer")
455    if err != nil {
456        t.Error(err)
457    }
458    defer os.RemoveAll(dir)
459
460    for _test := range golden {
461        g := Generator{
462            trimPrefix:  test.trimPrefix,
463            lineCommenttest.lineComment,
464        }
465        input := "package test\n" + test.input
466        file := test.name + ".go"
467        absFile := filepath.Join(dirfile)
468        err := os.WriteFile(absFile, []byte(input), 0644)
469        if err != nil {
470            t.Error(err)
471        }
472
473        g.parsePackage([]string{absFile}, nil)
474        // Extract the name and type of the constant from the first line.
475        tokens := strings.SplitN(test.input" "3)
476        if len(tokens) != 3 {
477            t.Fatalf("%s: need type declaration on first line"test.name)
478        }
479        g.generate(tokens[1])
480        got := string(g.format())
481        if got != test.output {
482            t.Errorf("%s: got(%d)\n====\n%q====\nexpected(%d)\n====%q"test.namelen(got), gotlen(test.output), test.output)
483        }
484    }
485}
486
MembersX
offset_in
num_out
unumpos_in
prime_in
tokens_in
TestGolden
Golden.output
day_out
TestGolden.t
TestGolden.RangeStmt_9632.BlockStmt.g
TestGolden.RangeStmt_9632.BlockStmt.got
Golden
gap_in
TestGolden.RangeStmt_9632.BlockStmt.tokens
TestGolden.dir
TestGolden.RangeStmt_9632.test
num_in
unum_out
unumpos_out
TestGolden.RangeStmt_9632.BlockStmt.err
Golden.input
gap_out
prefix_out
tokens_out
Golden.lineComment
unum_in
day_in
prime_out
prefix_in
TestGolden.err
TestGolden.RangeStmt_9632.BlockStmt.absFile
Golden.name
Golden.trimPrefix
offset_out
Members
X