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.
7 // Test cases for mkmerge.go.
9 // $ go test mkmerge.go mkmerge_test.go
22 func TestImports(t *testing.T) {
23 t.Run("importName", func(t *testing.T) {
28 {`"syscall"`, "syscall"},
31 {`moo "go/format"`, "moo"},
32 {`. "go/token"`, "."},
33 {`"golang.org/x/sys/unix"`, "unix"},
34 {`nix "golang.org/x/sys/unix"`, "nix"},
35 {`_ "golang.org/x/sys/unix"`, "_"},
38 for _, c := range cases {
39 pkgSrc := fmt.Sprintf("package main\nimport %s", c.src)
41 f, err := parser.ParseFile(token.NewFileSet(), "", pkgSrc, parser.ImportsOnly)
46 if len(f.Imports) != 1 {
47 t.Errorf("Got %d imports, expected 1", len(f.Imports))
51 got, err := importName(f.Imports[0])
56 t.Errorf("Got %q, expected %q", got, c.ident)
61 t.Run("filterImports", func(t *testing.T) {
62 cases := []struct{ before, after string }{
77 func useFoo() { foo.Usage() }`,
84 func useFoo() { foo.Usage() }
87 for _, c := range cases {
88 got, err := filterImports([]byte(c.before))
93 if string(got) != c.after {
94 t.Errorf("Got:\n%s\nExpected:\n%s\n", got, c.after)
100 func TestMerge(t *testing.T) {
101 // Input architecture files
102 inTmpl := template.Must(template.New("input").Parse(`
105 // build directives for arch{{.}}
107 // +build goos,arch{{.}}
114 int utimes(uintptr_t, uintptr_t);
115 int utimensat(int, uintptr_t, uintptr_t, int);
127 commonVar = commonDep.Use("common")
129 uniqueVar{{.}} = "unique{{.}}"
132 // Common free standing comment
135 const COMMON_INDEPENDENT = 1234
136 const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}"
140 COMMON_GROUP = "COMMON_GROUP"
141 UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}"
146 UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}"
147 UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}"
153 sub1Unique2{{.}} = 12
154 sub1Common3_LONG = 13
156 sub2Unique1{{.}} = 21
159 sub2Unique4{{.}} = 24
164 type uniqueInt{{.}} int
166 func commonF() string {
167 return commonDep.Use("common")
170 func uniqueF() string {
172 return uniqueDep{{.}}.Use("{{.}}")
178 sub3Unique2{{.}} = 32
179 sub3Unique3{{.}} = 33
182 sub4Common1, sub4Unique2{{.}} = 41, 42
183 sub4Unique3{{.}}, sub4Common4 = 43, 44
187 // Filtered architecture files
188 outTmpl := template.Must(template.New("output").Parse(`// Package comments
190 // build directives for arch{{.}}
192 // +build goos,arch{{.}}
199 int utimes(uintptr_t, uintptr_t);
200 int utimensat(int, uintptr_t, uintptr_t, int);
212 commonVar = commonDep.Use("common")
214 uniqueVar{{.}} = "unique{{.}}"
217 const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}"
221 UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}"
226 UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}"
227 UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}"
232 sub1Unique2{{.}} = 12
234 sub2Unique1{{.}} = 21
235 sub2Unique4{{.}} = 24
238 type uniqueInt{{.}} int
240 func uniqueF() string {
242 return uniqueDep{{.}}.Use("{{.}}")
247 sub3Unique2{{.}} = 32
248 sub3Unique3{{.}} = 33
250 sub4Common1, sub4Unique2{{.}} = 41, 42
251 sub4Unique3{{.}}, sub4Common4 = 43, 44
255 const mergedFile = `// Package comments
264 // Common free standing comment
267 const COMMON_INDEPENDENT = 1234
271 COMMON_GROUP = "COMMON_GROUP"
277 sub1Common3_LONG = 13
285 func commonF() string {
286 return commonDep.Use("common")
296 // Generate source code for different "architectures"
297 var inFiles, outFiles []srcFile
298 for _, arch := range strings.Fields("A B C D") {
299 buf := new(bytes.Buffer)
300 err := inTmpl.Execute(buf, arch)
304 inFiles = append(inFiles, srcFile{"file" + arch, buf.Bytes()})
306 buf = new(bytes.Buffer)
307 err = outTmpl.Execute(buf, arch)
311 outFiles = append(outFiles, srcFile{"file" + arch, buf.Bytes()})
314 t.Run("getCodeSet", func(t *testing.T) {
315 got, err := getCodeSet(inFiles[0].src)
320 expectedElems := []codeElem{
321 {token.COMMENT, "Package comments\n"},
322 {token.COMMENT, "build directives for archA\n"},
323 {token.COMMENT, "+build goos,archA\n"},
324 {token.CONST, `COMMON_INDEPENDENT = 1234`},
325 {token.CONST, `UNIQUE_INDEPENDENT_A = "UNIQUE_INDEPENDENT_A"`},
326 {token.CONST, `COMMON_GROUP = "COMMON_GROUP"`},
327 {token.CONST, `UNIQUE_GROUP_A = "UNIQUE_GROUP_A"`},
328 {token.CONST, `UNIQUE_GROUP21_A = "UNIQUE_GROUP21_A"`},
329 {token.CONST, `UNIQUE_GROUP22_A = "UNIQUE_GROUP22_A"`},
330 {token.CONST, `sub1Common1 = 11`},
331 {token.CONST, `sub1Unique2A = 12`},
332 {token.CONST, `sub1Common3_LONG = 13`},
333 {token.CONST, `sub2Unique1A = 21`},
334 {token.CONST, `sub2Common2 = 22`},
335 {token.CONST, `sub2Common3 = 23`},
336 {token.CONST, `sub2Unique4A = 24`},
337 {token.CONST, `sub3Common1 = 31`},
338 {token.CONST, `sub3Unique2A = 32`},
339 {token.CONST, `sub3Unique3A = 33`},
340 {token.CONST, `sub3Common4 = 34`},
341 {token.CONST, `sub4Common1, sub4Unique2A = 41, 42`},
342 {token.CONST, `sub4Unique3A, sub4Common4 = 43, 44`},
343 {token.TYPE, `commonInt int`},
344 {token.TYPE, `uniqueIntA int`},
345 {token.FUNC, `func commonF() string {
346 return commonDep.Use("common")
348 {token.FUNC, `func uniqueF() string {
350 return uniqueDepA.Use("A")
353 expected := newCodeSet()
354 for _, d := range expectedElems {
358 if len(got.set) != len(expected.set) {
359 t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set))
361 for expElem := range expected.set {
362 if !got.has(expElem) {
363 t.Errorf("Didn't get expected codeElem %#v", expElem)
366 for gotElem := range got.set {
367 if !expected.has(gotElem) {
368 t.Errorf("Got unexpected codeElem %#v", gotElem)
373 t.Run("getCommonSet", func(t *testing.T) {
374 got, err := getCommonSet(inFiles)
379 expected := newCodeSet()
380 expected.add(codeElem{token.COMMENT, "Package comments\n"})
381 expected.add(codeElem{token.CONST, `COMMON_INDEPENDENT = 1234`})
382 expected.add(codeElem{token.CONST, `COMMON_GROUP = "COMMON_GROUP"`})
383 expected.add(codeElem{token.CONST, `sub1Common1 = 11`})
384 expected.add(codeElem{token.CONST, `sub1Common3_LONG = 13`})
385 expected.add(codeElem{token.CONST, `sub2Common2 = 22`})
386 expected.add(codeElem{token.CONST, `sub2Common3 = 23`})
387 expected.add(codeElem{token.CONST, `sub3Common1 = 31`})
388 expected.add(codeElem{token.CONST, `sub3Common4 = 34`})
389 expected.add(codeElem{token.TYPE, `commonInt int`})
390 expected.add(codeElem{token.FUNC, `func commonF() string {
391 return commonDep.Use("common")
394 if len(got.set) != len(expected.set) {
395 t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set))
397 for expElem := range expected.set {
398 if !got.has(expElem) {
399 t.Errorf("Didn't get expected codeElem %#v", expElem)
402 for gotElem := range got.set {
403 if !expected.has(gotElem) {
404 t.Errorf("Got unexpected codeElem %#v", gotElem)
409 t.Run("filter(keepCommon)", func(t *testing.T) {
410 commonSet, err := getCommonSet(inFiles)
415 got, err := filter(inFiles[0].src, commonSet.keepCommon)
416 expected := []byte(mergedFile)
418 if !bytes.Equal(got, expected) {
419 t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected))
420 diffLines(t, got, expected)
424 t.Run("filter(keepArchSpecific)", func(t *testing.T) {
425 commonSet, err := getCommonSet(inFiles)
430 for i := range inFiles {
431 got, err := filter(inFiles[i].src, commonSet.keepArchSpecific)
436 expected := outFiles[i].src
438 if !bytes.Equal(got, expected) {
439 t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected))
440 diffLines(t, got, expected)
446 func TestMergedName(t *testing.T) {
447 t.Run("getValidGOOS", func(t *testing.T) {
448 testcases := []struct {
449 filename, goos string
452 {"zerrors_aix.go", "aix", true},
453 {"zerrors_darwin.go", "darwin", true},
454 {"zerrors_dragonfly.go", "dragonfly", true},
455 {"zerrors_freebsd.go", "freebsd", true},
456 {"zerrors_linux.go", "linux", true},
457 {"zerrors_netbsd.go", "netbsd", true},
458 {"zerrors_openbsd.go", "openbsd", true},
459 {"zerrors_solaris.go", "solaris", true},
460 {"zerrors_multics.go", "", false},
462 for _, tc := range testcases {
463 goos, ok := getValidGOOS(tc.filename)
465 t.Errorf("got GOOS %q, expected %q", goos, tc.goos)
468 t.Errorf("got ok %v, expected %v", ok, tc.ok)
474 // Helper functions to diff test sources
476 func diffLines(t *testing.T, got, expected []byte) {
479 gotLines := bytes.Split(got, []byte{'\n'})
480 expLines := bytes.Split(expected, []byte{'\n'})
483 for i < len(gotLines) && i < len(expLines) {
484 if !bytes.Equal(gotLines[i], expLines[i]) {
485 t.Errorf("Line %d: Got:\n%q\nExpected:\n%q", i+1, gotLines[i], expLines[i])
491 if i < len(gotLines) && i >= len(expLines) {
492 t.Errorf("Line %d: got %q, expected EOF", i+1, gotLines[i])
494 if i >= len(gotLines) && i < len(expLines) {
495 t.Errorf("Line %d: got EOF, expected %q", i+1, gotLines[i])
499 func addLineNr(src []byte) []byte {
500 lines := bytes.Split(src, []byte("\n"))
501 for i, line := range lines {
502 lines[i] = []byte(fmt.Sprintf("%d: %s", i+1, line))
504 return bytes.Join(lines, []byte("\n"))