github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/stringer/golden_test.go (about) 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 10 package main 11 12 import ( 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. 22 type 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 30 var golden = []Golden{ 31 {"day", "", false, day_in, day_out}, 32 {"offset", "", false, offset_in, offset_out}, 33 {"gap", "", false, gap_in, gap_out}, 34 {"num", "", false, num_in, num_out}, 35 {"unum", "", false, unum_in, unum_out}, 36 {"unumpos", "", false, unumpos_in, unumpos_out}, 37 {"prime", "", false, prime_in, prime_out}, 38 {"prefix", "Type", false, prefix_in, prefix_out}, 39 {"tokens", "", true, tokens_in, tokens_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. 45 const day_in = `type Day int 46 const ( 47 Monday Day = iota 48 Tuesday 49 Wednesday 50 Thursday 51 Friday 52 Saturday 53 Sunday 54 ) 55 ` 56 57 const 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 70 const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" 71 72 var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50} 73 74 func (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. 84 const offset_in = `type Number int 85 const ( 86 _ Number = iota 87 One 88 Two 89 Three 90 AnotherOne = One // Duplicate; note that AnotherOne doesn't appear below. 91 ) 92 ` 93 94 const 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 103 const _Number_name = "OneTwoThree" 104 105 var _Number_index = [...]uint8{0, 3, 6, 11} 106 107 func (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. 117 const gap_in = `type Gap int 118 const ( 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 130 const 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 144 const ( 145 _Gap_name_0 = "TwoThree" 146 _Gap_name_1 = "FiveSixSevenEightNine" 147 _Gap_name_2 = "Eleven" 148 ) 149 150 var ( 151 _Gap_index_0 = [...]uint8{0, 3, 8} 152 _Gap_index_1 = [...]uint8{0, 4, 7, 12, 17, 21} 153 ) 154 155 func (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. 172 const num_in = `type Num int 173 const ( 174 m_2 Num = -2 + iota 175 m_1 176 m0 177 m1 178 m2 179 ) 180 ` 181 182 const 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 193 const _Num_name = "m_2m_1m0m1m2" 194 195 var _Num_index = [...]uint8{0, 3, 6, 8, 10, 12} 196 197 func (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. 207 const unum_in = `type Unum uint 208 const ( 209 m_2 Unum = iota + 253 210 m_1 211 ) 212 213 const ( 214 m0 Unum = iota 215 m1 216 m2 217 ) 218 ` 219 220 const 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 231 const ( 232 _Unum_name_0 = "m0m1m2" 233 _Unum_name_1 = "m_2m_1" 234 ) 235 236 var ( 237 _Unum_index_0 = [...]uint8{0, 2, 4, 6} 238 _Unum_index_1 = [...]uint8{0, 3, 6} 239 ) 240 241 func (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. 255 const unumpos_in = `type Unumpos uint 256 const ( 257 m253 Unumpos = iota + 253 258 m254 259 ) 260 261 const ( 262 m1 Unumpos = iota + 1 263 m2 264 m3 265 ) 266 ` 267 268 const 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 279 const ( 280 _Unumpos_name_0 = "m1m2m3" 281 _Unumpos_name_1 = "m253m254" 282 ) 283 284 var ( 285 _Unumpos_index_0 = [...]uint8{0, 2, 4, 6} 286 _Unumpos_index_1 = [...]uint8{0, 4, 8} 287 ) 288 289 func (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 305 const prime_in = `type Prime int 306 const ( 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 324 const 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 344 const _Prime_name = "p2p3p5p7p11p13p17p19p23p29p37p41p43" 345 346 var _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 362 func (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 370 const prefix_in = `type Type int 371 const ( 372 TypeInt Type = iota 373 TypeString 374 TypeFloat 375 TypeRune 376 TypeByte 377 TypeStruct 378 TypeSlice 379 ) 380 ` 381 382 const 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 395 const _Type_name = "IntStringFloatRuneByteStructSlice" 396 397 var _Type_index = [...]uint8{0, 3, 9, 14, 18, 22, 28, 33} 398 399 func (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 407 const tokens_in = `type Token int 408 const ( 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 424 const 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 439 const _Token_name = "&|+-Ident.SingleBeforeinlineinline general" 440 441 var _Token_index = [...]uint8{0, 1, 2, 3, 4, 9, 10, 22, 28, 42} 442 443 func (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 451 func TestGolden(t *testing.T) { 452 testenv.NeedsTool(t, "go") 453 454 dir := t.TempDir() 455 for _, test := range golden { 456 g := Generator{ 457 trimPrefix: test.trimPrefix, 458 lineComment: test.lineComment, 459 } 460 input := "package test\n" + test.input 461 file := test.name + ".go" 462 absFile := filepath.Join(dir, file) 463 err := os.WriteFile(absFile, []byte(input), 0644) 464 if err != nil { 465 t.Error(err) 466 } 467 468 g.parsePackage([]string{absFile}, nil) 469 // Extract the name and type of the constant from the first line. 470 tokens := strings.SplitN(test.input, " ", 3) 471 if len(tokens) != 3 { 472 t.Fatalf("%s: need type declaration on first line", test.name) 473 } 474 g.generate(tokens[1]) 475 got := string(g.format()) 476 if got != test.output { 477 t.Errorf("%s: got(%d)\n====\n%q====\nexpected(%d)\n====%q", test.name, len(got), got, len(test.output), test.output) 478 } 479 } 480 }