Files
sys/unix/internal/mkmerge/mkmerge_test.go
T
Johan Jansson 7580c6e521 unix: factor out mkmerge into a proper package
Factor mkmerge.go and mkmerge_test.go into package internal/mkmerge.

Due to ignore constraints, mkmerge_test.go wasn't run by the Go
builders and failing tests were unnoticed.

Factoring mkmerge into its own package and removing ignore constraints
makes the tests run automatically by the Go builders.

Fixes golang/go#49484

Change-Id: I56a0b7220e40d1d7e5193490cb547cad4202f9ac
Reviewed-on: https://go-review.googlesource.com/c/sys/+/363334
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Trust: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
2021-11-12 16:43:55 +00:00

503 lines
11 KiB
Go

// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"go/parser"
"go/token"
"html/template"
"strings"
"testing"
)
func TestImports(t *testing.T) {
t.Run("importName", func(t *testing.T) {
cases := []struct {
src string
ident string
}{
{`"syscall"`, "syscall"},
{`. "foobar"`, "."},
{`"go/ast"`, "ast"},
{`moo "go/format"`, "moo"},
{`. "go/token"`, "."},
{`"golang.org/x/sys/unix"`, "unix"},
{`nix "golang.org/x/sys/unix"`, "nix"},
{`_ "golang.org/x/sys/unix"`, "_"},
}
for _, c := range cases {
pkgSrc := fmt.Sprintf("package main\nimport %s", c.src)
f, err := parser.ParseFile(token.NewFileSet(), "", pkgSrc, parser.ImportsOnly)
if err != nil {
t.Error(err)
continue
}
if len(f.Imports) != 1 {
t.Errorf("Got %d imports, expected 1", len(f.Imports))
continue
}
got, err := importName(f.Imports[0])
if err != nil {
t.Fatal(err)
}
if got != c.ident {
t.Errorf("Got %q, expected %q", got, c.ident)
}
}
})
t.Run("filterImports", func(t *testing.T) {
cases := []struct{ before, after string }{
{`package test
import (
"foo"
"bar"
)`,
"package test\n"},
{`package test
import (
"foo"
"bar"
)
func useFoo() { foo.Usage() }`,
`package test
import (
"foo"
)
func useFoo() { foo.Usage() }
`},
}
for _, c := range cases {
got, err := filterImports([]byte(c.before))
if err != nil {
t.Error(err)
}
if string(got) != c.after {
t.Errorf("Got:\n%s\nExpected:\n%s\n", got, c.after)
}
}
})
}
func TestMerge(t *testing.T) {
// Input architecture files
inTmpl := template.Must(template.New("input").Parse(`
// Package comments
// build directives for arch{{.}}
//go:build goos && arch{{.}}
// +build goos,arch{{.}}
package main
/*
#include <stdint.h>
#include <stddef.h>
int utimes(uintptr_t, uintptr_t);
int utimensat(int, uintptr_t, uintptr_t, int);
*/
import "C"
// The imports
import (
"commonDep"
"uniqueDep{{.}}"
)
// Vars
var (
commonVar = commonDep.Use("common")
uniqueVar{{.}} = "unique{{.}}"
)
// Common free standing comment
// Common comment
const COMMON_INDEPENDENT = 1234
const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}"
// Group comment
const (
COMMON_GROUP = "COMMON_GROUP"
UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}"
)
// Group2 comment
const (
UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}"
UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}"
)
// Group3 comment
const (
sub1Common1 = 11
sub1Unique2{{.}} = 12
sub1Common3_LONG = 13
sub2Unique1{{.}} = 21
sub2Common2 = 22
sub2Common3 = 23
sub2Unique4{{.}} = 24
)
type commonInt int
type uniqueInt{{.}} int
func commonF() string {
return commonDep.Use("common")
}
func uniqueF() string {
C.utimes(0, 0)
return uniqueDep{{.}}.Use("{{.}}")
}
// Group4 comment
const (
sub3Common1 = 31
sub3Unique2{{.}} = 32
sub3Unique3{{.}} = 33
sub3Common4 = 34
sub4Common1, sub4Unique2{{.}} = 41, 42
sub4Unique3{{.}}, sub4Common4 = 43, 44
)
`))
// Filtered architecture files
outTmpl := template.Must(template.New("output").Parse(`// Package comments
// build directives for arch{{.}}
//go:build goos && arch{{.}}
// +build goos,arch{{.}}
package main
/*
#include <stdint.h>
#include <stddef.h>
int utimes(uintptr_t, uintptr_t);
int utimensat(int, uintptr_t, uintptr_t, int);
*/
import "C"
// The imports
import (
"commonDep"
"uniqueDep{{.}}"
)
// Vars
var (
commonVar = commonDep.Use("common")
uniqueVar{{.}} = "unique{{.}}"
)
const UNIQUE_INDEPENDENT_{{.}} = "UNIQUE_INDEPENDENT_{{.}}"
// Group comment
const (
UNIQUE_GROUP_{{.}} = "UNIQUE_GROUP_{{.}}"
)
// Group2 comment
const (
UNIQUE_GROUP21_{{.}} = "UNIQUE_GROUP21_{{.}}"
UNIQUE_GROUP22_{{.}} = "UNIQUE_GROUP22_{{.}}"
)
// Group3 comment
const (
sub1Unique2{{.}} = 12
sub2Unique1{{.}} = 21
sub2Unique4{{.}} = 24
)
type uniqueInt{{.}} int
func uniqueF() string {
C.utimes(0, 0)
return uniqueDep{{.}}.Use("{{.}}")
}
// Group4 comment
const (
sub3Unique2{{.}} = 32
sub3Unique3{{.}} = 33
sub4Common1, sub4Unique2{{.}} = 41, 42
sub4Unique3{{.}}, sub4Common4 = 43, 44
)
`))
const mergedFile = `// Package comments
package main
// The imports
import (
"commonDep"
)
// Common free standing comment
// Common comment
const COMMON_INDEPENDENT = 1234
// Group comment
const (
COMMON_GROUP = "COMMON_GROUP"
)
// Group3 comment
const (
sub1Common1 = 11
sub1Common3_LONG = 13
sub2Common2 = 22
sub2Common3 = 23
)
type commonInt int
func commonF() string {
return commonDep.Use("common")
}
// Group4 comment
const (
sub3Common1 = 31
sub3Common4 = 34
)
`
// Generate source code for different "architectures"
var inFiles, outFiles []srcFile
for _, arch := range strings.Fields("A B C D") {
buf := new(bytes.Buffer)
err := inTmpl.Execute(buf, arch)
if err != nil {
t.Fatal(err)
}
inFiles = append(inFiles, srcFile{"file" + arch, buf.Bytes()})
buf = new(bytes.Buffer)
err = outTmpl.Execute(buf, arch)
if err != nil {
t.Fatal(err)
}
outFiles = append(outFiles, srcFile{"file" + arch, buf.Bytes()})
}
t.Run("getCodeSet", func(t *testing.T) {
got, err := getCodeSet(inFiles[0].src)
if err != nil {
t.Fatal(err)
}
expectedElems := []codeElem{
{token.COMMENT, "Package comments\n"},
{token.COMMENT, "build directives for archA\n"},
{token.COMMENT, "+build goos,archA\n"},
{token.CONST, `COMMON_INDEPENDENT = 1234`},
{token.CONST, `UNIQUE_INDEPENDENT_A = "UNIQUE_INDEPENDENT_A"`},
{token.CONST, `COMMON_GROUP = "COMMON_GROUP"`},
{token.CONST, `UNIQUE_GROUP_A = "UNIQUE_GROUP_A"`},
{token.CONST, `UNIQUE_GROUP21_A = "UNIQUE_GROUP21_A"`},
{token.CONST, `UNIQUE_GROUP22_A = "UNIQUE_GROUP22_A"`},
{token.CONST, `sub1Common1 = 11`},
{token.CONST, `sub1Unique2A = 12`},
{token.CONST, `sub1Common3_LONG = 13`},
{token.CONST, `sub2Unique1A = 21`},
{token.CONST, `sub2Common2 = 22`},
{token.CONST, `sub2Common3 = 23`},
{token.CONST, `sub2Unique4A = 24`},
{token.CONST, `sub3Common1 = 31`},
{token.CONST, `sub3Unique2A = 32`},
{token.CONST, `sub3Unique3A = 33`},
{token.CONST, `sub3Common4 = 34`},
{token.CONST, `sub4Common1, sub4Unique2A = 41, 42`},
{token.CONST, `sub4Unique3A, sub4Common4 = 43, 44`},
{token.TYPE, `commonInt int`},
{token.TYPE, `uniqueIntA int`},
{token.FUNC, `func commonF() string {
return commonDep.Use("common")
}`},
{token.FUNC, `func uniqueF() string {
C.utimes(0, 0)
return uniqueDepA.Use("A")
}`},
}
expected := newCodeSet()
for _, d := range expectedElems {
expected.add(d)
}
if len(got.set) != len(expected.set) {
t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set))
}
for expElem := range expected.set {
if !got.has(expElem) {
t.Errorf("Didn't get expected codeElem %#v", expElem)
}
}
for gotElem := range got.set {
if !expected.has(gotElem) {
t.Errorf("Got unexpected codeElem %#v", gotElem)
}
}
})
t.Run("getCommonSet", func(t *testing.T) {
got, err := getCommonSet(inFiles)
if err != nil {
t.Fatal(err)
}
expected := newCodeSet()
expected.add(codeElem{token.COMMENT, "Package comments\n"})
expected.add(codeElem{token.CONST, `COMMON_INDEPENDENT = 1234`})
expected.add(codeElem{token.CONST, `COMMON_GROUP = "COMMON_GROUP"`})
expected.add(codeElem{token.CONST, `sub1Common1 = 11`})
expected.add(codeElem{token.CONST, `sub1Common3_LONG = 13`})
expected.add(codeElem{token.CONST, `sub2Common2 = 22`})
expected.add(codeElem{token.CONST, `sub2Common3 = 23`})
expected.add(codeElem{token.CONST, `sub3Common1 = 31`})
expected.add(codeElem{token.CONST, `sub3Common4 = 34`})
expected.add(codeElem{token.TYPE, `commonInt int`})
expected.add(codeElem{token.FUNC, `func commonF() string {
return commonDep.Use("common")
}`})
if len(got.set) != len(expected.set) {
t.Errorf("Got %d codeElems, expected %d", len(got.set), len(expected.set))
}
for expElem := range expected.set {
if !got.has(expElem) {
t.Errorf("Didn't get expected codeElem %#v", expElem)
}
}
for gotElem := range got.set {
if !expected.has(gotElem) {
t.Errorf("Got unexpected codeElem %#v", gotElem)
}
}
})
t.Run("filter(keepCommon)", func(t *testing.T) {
commonSet, err := getCommonSet(inFiles)
if err != nil {
t.Fatal(err)
}
got, err := filter(inFiles[0].src, commonSet.keepCommon)
expected := []byte(mergedFile)
if !bytes.Equal(got, expected) {
t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected))
diffLines(t, got, expected)
}
})
t.Run("filter(keepArchSpecific)", func(t *testing.T) {
commonSet, err := getCommonSet(inFiles)
if err != nil {
t.Fatal(err)
}
for i := range inFiles {
got, err := filter(inFiles[i].src, commonSet.keepArchSpecific)
if err != nil {
t.Fatal(err)
}
expected := outFiles[i].src
if !bytes.Equal(got, expected) {
t.Errorf("Got:\n%s\nExpected:\n%s", addLineNr(got), addLineNr(expected))
diffLines(t, got, expected)
}
}
})
}
func TestMergedName(t *testing.T) {
t.Run("getValidGOOS", func(t *testing.T) {
testcases := []struct {
filename, goos string
ok bool
}{
{"zerrors_aix.go", "aix", true},
{"zerrors_darwin.go", "darwin", true},
{"zerrors_dragonfly.go", "dragonfly", true},
{"zerrors_freebsd.go", "freebsd", true},
{"zerrors_linux.go", "linux", true},
{"zerrors_netbsd.go", "netbsd", true},
{"zerrors_openbsd.go", "openbsd", true},
{"zerrors_solaris.go", "solaris", true},
{"zerrors_multics.go", "", false},
}
for _, tc := range testcases {
goos, ok := getValidGOOS(tc.filename)
if goos != tc.goos {
t.Errorf("got GOOS %q, expected %q", goos, tc.goos)
}
if ok != tc.ok {
t.Errorf("got ok %v, expected %v", ok, tc.ok)
}
}
})
}
// Helper functions to diff test sources
func diffLines(t *testing.T, got, expected []byte) {
t.Helper()
gotLines := bytes.Split(got, []byte{'\n'})
expLines := bytes.Split(expected, []byte{'\n'})
i := 0
for i < len(gotLines) && i < len(expLines) {
if !bytes.Equal(gotLines[i], expLines[i]) {
t.Errorf("Line %d: Got:\n%q\nExpected:\n%q", i+1, gotLines[i], expLines[i])
return
}
i++
}
if i < len(gotLines) && i >= len(expLines) {
t.Errorf("Line %d: got %q, expected EOF", i+1, gotLines[i])
}
if i >= len(gotLines) && i < len(expLines) {
t.Errorf("Line %d: got EOF, expected %q", i+1, gotLines[i])
}
}
func addLineNr(src []byte) []byte {
lines := bytes.Split(src, []byte("\n"))
for i, line := range lines {
lines[i] = []byte(fmt.Sprintf("%d: %s", i+1, line))
}
return bytes.Join(lines, []byte("\n"))
}