github.com/nibnait/go-learn@v0.0.0-20220227013611-dfa47ea6d2da/src/pkg/mod/golang.org/x/sys@v0.0.0-20210630005230-0f9fa26af87c/unix/mkmerge_test.go (about) 1 // Copyright 2020 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 //go:build ignore 6 // +build ignore 7 8 // Test cases for mkmerge.go. 9 // Usage: 10 // $ go test mkmerge.go mkmerge_test.go 11 package main 12 13 import ( 14 "bytes" 15 "fmt" 16 "go/parser" 17 "go/token" 18 "html/template" 19 "strings" 20 "testing" 21 ) 22 23 func TestImports(t *testing.T) { 24 t.Run("importName", func(t *testing.T) { 25 cases := []struct { 26 src string 27 ident string 28 }{ 29 {`"syscall"`, "syscall"}, 30 {`. "foobar"`, "."}, 31 {`"go/ast"`, "ast"}, 32 {`moo "go/format"`, "moo"}, 33 {`. "go/token"`, "."}, 34 {`"golang.org/x/sys/unix"`, "unix"}, 35 {`nix "golang.org/x/sys/unix"`, "nix"}, 36 {`_ "golang.org/x/sys/unix"`, "_"}, 37 } 38 39 for _, c := range cases { 40 pkgSrc := fmt.Sprintf("package main\nimport %s", c.src) 41 42 f, err := parser.ParseFile(token.NewFileSet(), "", pkgSrc, parser.ImportsOnly) 43 if err != nil { 44 t.Error(err) 45 continue 46 } 47 if len(f.Imports) != 1 { 48 t.Errorf("Got %d imports, expected 1", len(f.Imports)) 49 continue 50 } 51 52 got, err := importName(f.Imports[0]) 53 if err != nil { 54 t.Fatal(err) 55 } 56 if got != c.ident { 57 t.Errorf("Got %q, expected %q", got, c.ident) 58 } 59 } 60 }) 61 62 t.Run("filterImports", func(t *testing.T) { 63 cases := []struct{ before, after string }{ 64 {`package test 65 66 import ( 67 "foo" 68 "bar" 69 )`, 70 "package test\n"}, 71 {`package test 72 73 import ( 74 "foo" 75 "bar" 76 ) 77 78 func useFoo() { foo.Usage() }`, 79 `package test 80 81 import ( 82 "foo" 83 ) 84 85 func useFoo() { foo.Usage() } 86 `}, 87 } 88 for _, c := range cases { 89 got, err := filterImports([]byte(c.before)) 90 if err != nil { 91 t.Error(err) 92 } 93 94 if string(got) != c.after { 95 t.Errorf("Got:\n%s\nExpected:\n%s\n", got, c.after) 96 } 97 } 98 }) 99 } 100 101 func TestMerge(t *testing.T) { 102 // Input architecture files 103 inTmpl := template.Must(template.New("input").Parse(` 104 // Package comments 105 106 // build directives for arch{{.}} 107 108 // +build goos,arch{{.}} 109 110 package main 111 112 /* 113 #include <stdint.h> 114 #include <stddef.h> 115 int utimes(uintptr_t, uintptr_t); 116 int utimensat(int, uintptr_t, uintptr_t, int); 117 */ 118 import "C" 119 120 // The imports 121 import ( 122 "commonDep" 123 "uniqueDep{{.}}" 124 ) 125 126 // Vars 127 var ( 128 commonVar = commonDep.Use("common") 129 130 uniqueVar{{.}} = "unique{{.}}" 131 ) 132 133 // Common free standing comment 134 135 // Common comment 136 const COMMON_INDEPENDENT = 1234 137 const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}" 138 139 // Group comment 140 const ( 141 COMMON_GROUP = "COMMON_GROUP" 142 UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}" 143 ) 144 145 // Group2 comment 146 const ( 147 UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}" 148 UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}" 149 ) 150 151 // Group3 comment 152 const ( 153 sub1Common1 = 11 154 sub1Unique2{{.}} = 12 155 sub1Common3_LONG = 13 156 157 sub2Unique1{{.}} = 21 158 sub2Common2 = 22 159 sub2Common3 = 23 160 sub2Unique4{{.}} = 24 161 ) 162 163 type commonInt int 164 165 type uniqueInt{{.}} int 166 167 func commonF() string { 168 return commonDep.Use("common") 169 } 170 171 func uniqueF() string { 172 C.utimes(0, 0) 173 return uniqueDep{{.}}.Use("{{.}}") 174 } 175 176 // Group4 comment 177 const ( 178 sub3Common1 = 31 179 sub3Unique2{{.}} = 32 180 sub3Unique3{{.}} = 33 181 sub3Common4 = 34 182 183 sub4Common1, sub4Unique2{{.}} = 41, 42 184 sub4Unique3{{.}}, sub4Common4 = 43, 44 185 ) 186 `)) 187 188 // Filtered architecture files 189 outTmpl := template.Must(template.New("output").Parse(`// Package comments 190 191 // build directives for arch{{.}} 192 193 // +build goos,arch{{.}} 194 195 package main 196 197 /* 198 #include <stdint.h> 199 #include <stddef.h> 200 int utimes(uintptr_t, uintptr_t); 201 int utimensat(int, uintptr_t, uintptr_t, int); 202 */ 203 import "C" 204 205 // The imports 206 import ( 207 "commonDep" 208 "uniqueDep{{.}}" 209 ) 210 211 // Vars 212 var ( 213 commonVar = commonDep.Use("common") 214 215 uniqueVar{{.}} = "unique{{.}}" 216 ) 217 218 const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}" 219 220 // Group comment 221 const ( 222 UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}" 223 ) 224 225 // Group2 comment 226 const ( 227 UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}" 228 UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}" 229 ) 230 231 // Group3 comment 232 const ( 233 sub1Unique2{{.}} = 12 234 235 sub2Unique1{{.}} = 21 236 sub2Unique4{{.}} = 24 237 ) 238 239 type uniqueInt{{.}} int 240 241 func uniqueF() string { 242 C.utimes(0, 0) 243 return uniqueDep{{.}}.Use("{{.}}") 244 } 245 246 // Group4 comment 247 const ( 248 sub3Unique2{{.}} = 32 249 sub3Unique3{{.}} = 33 250 251 sub4Common1, sub4Unique2{{.}} = 41, 42 252 sub4Unique3{{.}}, sub4Common4 = 43, 44 253 ) 254 `)) 255 256 const mergedFile = `// Package comments 257 258 package main 259 260 // The imports 261 import ( 262 "commonDep" 263 ) 264 265 // Common free standing comment 266 267 // Common comment 268 const COMMON_INDEPENDENT = 1234 269 270 // Group comment 271 const ( 272 COMMON_GROUP = "COMMON_GROUP" 273 ) 274 275 // Group3 comment 276 const ( 277 sub1Common1 = 11 278 sub1Common3_LONG = 13 279 280 sub2Common2 = 22 281 sub2Common3 = 23 282 ) 283 284 type commonInt int 285 286 func commonF() string { 287 return commonDep.Use("common") 288 } 289 290 // Group4 comment 291 const ( 292 sub3Common1 = 31 293 sub3Common4 = 34 294 ) 295 ` 296 297 // Generate source code for different "architectures" 298 var inFiles, outFiles []srcFile 299 for _, arch := range strings.Fields("A B C D") { 300 buf := new(bytes.Buffer) 301 err := inTmpl.Execute(buf, arch) 302 if err != nil { 303 t.Fatal(err) 304 } 305 inFiles = append(inFiles, srcFile{"file" + arch, buf.Bytes()}) 306 307 buf = new(bytes.Buffer) 308 err = outTmpl.Execute(buf, arch) 309 if err != nil { 310 t.Fatal(err) 311 } 312 outFiles = append(outFiles, srcFile{"file" + arch, buf.Bytes()}) 313 } 314 315 t.Run("getCodeSet", func(t *testing.T) { 316 got, err := getCodeSet(inFiles[0].src) 317 if err != nil { 318 t.Fatal(err) 319 } 320 321 expectedElems := []codeElem{ 322 {token.COMMENT, "Package comments\n"}, 323 {token.COMMENT, "build directives for archA\n"}, 324 {token.COMMENT, "+build goos,archA\n"}, 325 {token.CONST, `COMMON_INDEPENDENT = 1234`}, 326 {token.CONST, `UNIQUE_INDEPENDENT_A = "UNIQUE_INDEPENDENT_A"`}, 327 {token.CONST, `COMMON_GROUP = "COMMON_GROUP"`}, 328 {token.CONST, `UNIQUE_GROUP_A = "UNIQUE_GROUP_A"`}, 329 {token.CONST, `UNIQUE_GROUP21_A = "UNIQUE_GROUP21_A"`}, 330 {token.CONST, `UNIQUE_GROUP22_A = "UNIQUE_GROUP22_A"`}, 331 {token.CONST, `sub1Common1 = 11`}, 332 {token.CONST, `sub1Unique2A = 12`}, 333 {token.CONST, `sub1Common3_LONG = 13`}, 334 {token.CONST, `sub2Unique1A = 21`}, 335 {token.CONST, `sub2Common2 = 22`}, 336 {token.CONST, `sub2Common3 = 23`}, 337 {token.CONST, `sub2Unique4A = 24`}, 338 {token.CONST, `sub3Common1 = 31`}, 339 {token.CONST, `sub3Unique2A = 32`}, 340 {token.CONST, `sub3Unique3A = 33`}, 341 {token.CONST, `sub3Common4 = 34`}, 342 {token.CONST, `sub4Common1, sub4Unique2A = 41, 42`}, 343 {token.CONST, `sub4Unique3A, sub4Common4 = 43, 44`}, 344 {token.TYPE, `commonInt int`}, 345 {token.TYPE, `uniqueIntA int`}, 346 {token.FUNC, `func commonF() string { 347 return commonDep.Use("common") 348 }`}, 349 {token.FUNC, `func uniqueF() string { 350 C.utimes(0, 0) 351 return uniqueDepA.Use("A") 352 }`}, 353 } 354 expected := newCodeSet() 355 for _, d := range expectedElems { 356 expected.add(d) 357 } 358 359 if len(got.set) != len(expected.set) { 360 t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set)) 361 } 362 for expElem := range expected.set { 363 if !got.has(expElem) { 364 t.Errorf("Didn't get expected codeElem %#v", expElem) 365 } 366 } 367 for gotElem := range got.set { 368 if !expected.has(gotElem) { 369 t.Errorf("Got unexpected codeElem %#v", gotElem) 370 } 371 } 372 }) 373 374 t.Run("getCommonSet", func(t *testing.T) { 375 got, err := getCommonSet(inFiles) 376 if err != nil { 377 t.Fatal(err) 378 } 379 380 expected := newCodeSet() 381 expected.add(codeElem{token.COMMENT, "Package comments\n"}) 382 expected.add(codeElem{token.CONST, `COMMON_INDEPENDENT = 1234`}) 383 expected.add(codeElem{token.CONST, `COMMON_GROUP = "COMMON_GROUP"`}) 384 expected.add(codeElem{token.CONST, `sub1Common1 = 11`}) 385 expected.add(codeElem{token.CONST, `sub1Common3_LONG = 13`}) 386 expected.add(codeElem{token.CONST, `sub2Common2 = 22`}) 387 expected.add(codeElem{token.CONST, `sub2Common3 = 23`}) 388 expected.add(codeElem{token.CONST, `sub3Common1 = 31`}) 389 expected.add(codeElem{token.CONST, `sub3Common4 = 34`}) 390 expected.add(codeElem{token.TYPE, `commonInt int`}) 391 expected.add(codeElem{token.FUNC, `func commonF() string { 392 return commonDep.Use("common") 393 }`}) 394 395 if len(got.set) != len(expected.set) { 396 t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set)) 397 } 398 for expElem := range expected.set { 399 if !got.has(expElem) { 400 t.Errorf("Didn't get expected codeElem %#v", expElem) 401 } 402 } 403 for gotElem := range got.set { 404 if !expected.has(gotElem) { 405 t.Errorf("Got unexpected codeElem %#v", gotElem) 406 } 407 } 408 }) 409 410 t.Run("filter(keepCommon)", func(t *testing.T) { 411 commonSet, err := getCommonSet(inFiles) 412 if err != nil { 413 t.Fatal(err) 414 } 415 416 got, err := filter(inFiles[0].src, commonSet.keepCommon) 417 expected := []byte(mergedFile) 418 419 if !bytes.Equal(got, expected) { 420 t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected)) 421 diffLines(t, got, expected) 422 } 423 }) 424 425 t.Run("filter(keepArchSpecific)", func(t *testing.T) { 426 commonSet, err := getCommonSet(inFiles) 427 if err != nil { 428 t.Fatal(err) 429 } 430 431 for i := range inFiles { 432 got, err := filter(inFiles[i].src, commonSet.keepArchSpecific) 433 if err != nil { 434 t.Fatal(err) 435 } 436 437 expected := outFiles[i].src 438 439 if !bytes.Equal(got, expected) { 440 t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected)) 441 diffLines(t, got, expected) 442 } 443 } 444 }) 445 } 446 447 func TestMergedName(t *testing.T) { 448 t.Run("getValidGOOS", func(t *testing.T) { 449 testcases := []struct { 450 filename, goos string 451 ok bool 452 }{ 453 {"zerrors_aix.go", "aix", true}, 454 {"zerrors_darwin.go", "darwin", true}, 455 {"zerrors_dragonfly.go", "dragonfly", true}, 456 {"zerrors_freebsd.go", "freebsd", true}, 457 {"zerrors_linux.go", "linux", true}, 458 {"zerrors_netbsd.go", "netbsd", true}, 459 {"zerrors_openbsd.go", "openbsd", true}, 460 {"zerrors_solaris.go", "solaris", true}, 461 {"zerrors_multics.go", "", false}, 462 } 463 for _, tc := range testcases { 464 goos, ok := getValidGOOS(tc.filename) 465 if goos != tc.goos { 466 t.Errorf("got GOOS %q, expected %q", goos, tc.goos) 467 } 468 if ok != tc.ok { 469 t.Errorf("got ok %v, expected %v", ok, tc.ok) 470 } 471 } 472 }) 473 } 474 475 // Helper functions to diff test sources 476 477 func diffLines(t *testing.T, got, expected []byte) { 478 t.Helper() 479 480 gotLines := bytes.Split(got, []byte{'\n'}) 481 expLines := bytes.Split(expected, []byte{'\n'}) 482 483 i := 0 484 for i < len(gotLines) && i < len(expLines) { 485 if !bytes.Equal(gotLines[i], expLines[i]) { 486 t.Errorf("Line %d: Got:\n%q\nExpected:\n%q", i+1, gotLines[i], expLines[i]) 487 return 488 } 489 i++ 490 } 491 492 if i < len(gotLines) && i >= len(expLines) { 493 t.Errorf("Line %d: got %q, expected EOF", i+1, gotLines[i]) 494 } 495 if i >= len(gotLines) && i < len(expLines) { 496 t.Errorf("Line %d: got EOF, expected %q", i+1, gotLines[i]) 497 } 498 } 499 500 func addLineNr(src []byte) []byte { 501 lines := bytes.Split(src, []byte("\n")) 502 for i, line := range lines { 503 lines[i] = []byte(fmt.Sprintf("%d: %s", i+1, line)) 504 } 505 return bytes.Join(lines, []byte("\n")) 506 }