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