site/vendor/github.com/magefile/mage/mage/main_test.go

480 lines
11 KiB
Go

package mage
import (
"bytes"
"flag"
"fmt"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
"github.com/magefile/mage/build"
"github.com/magefile/mage/mg"
)
func TestMain(m *testing.M) {
os.Exit(testmain(m))
}
func testmain(m *testing.M) int {
// ensure we write our temporary binaries to a directory that we'll delete
// after running tests.
dir := "./testing"
abs, err := filepath.Abs(dir)
if err != nil {
log.Fatal(err)
}
if err := os.Setenv(mg.CacheEnv, abs); err != nil {
log.Fatal(err)
}
if err := os.Mkdir(dir, 0700); err != nil {
if os.IsExist(err) {
os.RemoveAll(dir)
} else {
log.Fatal(err)
}
}
defer os.RemoveAll(dir)
return m.Run()
}
func TestGoRun(t *testing.T) {
c := exec.Command("go", "run", "main.go")
c.Dir = "./testdata"
c.Env = os.Environ()
b, err := c.CombinedOutput()
if err != nil {
t.Error("error:", err)
}
actual := string(b)
expected := "stuff\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestVerbose(t *testing.T) {
stderr := &bytes.Buffer{}
stdout := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: stdout,
Stderr: stderr,
Args: []string{"testverbose"},
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual := stdout.String()
expected := ""
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
stderr.Reset()
stdout.Reset()
inv.Verbose = true
code = Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual = stderr.String()
expected = "Running target: TestVerbose\nhi!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestVerboseEnv(t *testing.T) {
os.Setenv("MAGE_VERBOSE", "true")
stdout := &bytes.Buffer{}
inv, _, _, err := Parse(stdout, []string{})
if err != nil {
t.Fatal("unexpected error", err)
}
expected := true
if inv.Verbose != true {
t.Fatalf("expected %t, but got %t ", expected, inv.Verbose)
}
os.Unsetenv("MAGE_VERBOSE")
}
func TestList(t *testing.T) {
stdout := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata/list",
Stdout: stdout,
Stderr: ioutil.Discard,
List: true,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual := stdout.String()
expected := `
Targets:
somePig* This is the synopsis for SomePig.
testVerbose
* default target
`[1:]
if actual != expected {
t.Logf("expected: %q", expected)
t.Logf(" actual: %q", actual)
t.Fatalf("expected:\n%v\n\ngot:\n%v", expected, actual)
}
}
func TestNoArgNoDefaultList(t *testing.T) {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "testdata/no_default",
Stdout: stdout,
Stderr: stderr,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
if err := stderr.String(); err != "" {
t.Errorf("unexpected stderr output:\n%s", err)
}
actual := stdout.String()
expected := `
Targets:
bazBuz Prints out 'BazBuz'.
fooBar Prints out 'FooBar'.
`[1:]
if actual != expected {
t.Fatalf("expected:\n%q\n\ngot:\n%q", expected, actual)
}
}
func TestTargetError(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"returnsnonnilerror"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: bang!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestStdinCopy(t *testing.T) {
stdout := &bytes.Buffer{}
stdin := strings.NewReader("hi!")
inv := Invocation{
Dir: "./testdata",
Stderr: ioutil.Discard,
Stdout: stdout,
Stdin: stdin,
Args: []string{"CopyStdin"},
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected 0, but got %v", code)
}
actual := stdout.String()
expected := "hi!"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestTargetPanics(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"panics"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: boom!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestPanicsErr(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"panicserr"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: kaboom!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
// ensure we include the hash of the mainfile template in determining the
// executable name to run, so we automatically create a new exe if the template
// changes.
func TestHashTemplate(t *testing.T) {
templ := tpl
defer func() { tpl = templ }()
name, err := ExeName([]string{"./testdata/func.go", "./testdata/command.go"})
if err != nil {
t.Fatal(err)
}
tpl = "some other template"
changed, err := ExeName([]string{"./testdata/func.go", "./testdata/command.go"})
if changed == name {
t.Fatal("expected executable name to chage if template changed")
}
}
// Test if the -keep flag does keep the mainfile around after running
func TestKeepFlag(t *testing.T) {
buildFile := fmt.Sprintf("./testdata/keep_flag/%s", mainfile)
os.Remove(buildFile)
defer os.Remove(buildFile)
w := tLogWriter{t}
inv := Invocation{
Dir: "./testdata/keep_flag",
Stdout: w,
Stderr: w,
List: true,
Keep: true,
Force: true, // need force so we always regenerate
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected code 0, but got %v", code)
}
if _, err := os.Stat(buildFile); err != nil {
t.Fatalf("expected file %q to exist but got err, %v", buildFile, err)
}
}
type tLogWriter struct {
*testing.T
}
func (t tLogWriter) Write(b []byte) (n int, err error) {
t.Log(string(b))
return len(b), nil
}
// Test if generated mainfile references anything other than the stdlib
func TestOnlyStdLib(t *testing.T) {
buildFile := fmt.Sprintf("./testdata/onlyStdLib/%s", mainfile)
os.Remove(buildFile)
defer os.Remove(buildFile)
w := tLogWriter{t}
inv := Invocation{
Dir: "./testdata/onlyStdLib",
Stdout: w,
Stderr: w,
List: true,
Keep: true,
Force: true, // need force so we always regenerate
Verbose: true,
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected code 0, but got %v", code)
}
if _, err := os.Stat(buildFile); err != nil {
t.Fatalf("expected file %q to exist but got err, %v", buildFile, err)
}
fset := &token.FileSet{}
// Parse src but stop after processing the imports.
f, err := parser.ParseFile(fset, buildFile, nil, parser.ImportsOnly)
if err != nil {
fmt.Println(err)
return
}
// Print the imports from the file's AST.
for _, s := range f.Imports {
// the path value comes in as a quoted string, i.e. literally \"context\"
path := strings.Trim(s.Path.Value, "\"")
pkg, err := build.Default.Import(path, "./testdata/keep_flag", build.FindOnly)
if err != nil {
t.Fatal(err)
}
if !filepath.HasPrefix(pkg.Dir, build.Default.GOROOT) {
t.Errorf("import of non-stdlib package: %s", s.Path.Value)
}
}
}
func TestMultipleTargets(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"TestVerbose", "ReturnsNilError"},
Verbose: true,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected 0, but got %v", code)
}
actual := stderr.String()
expected := "Running target: TestVerbose\nhi!\nRunning target: ReturnsNilError\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = "stuff\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestFirstTargetFails(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"ReturnsNonNilError", "ReturnsNilError"},
Verbose: true,
}
code := Invoke(inv)
if code != 1 {
t.Errorf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Running target: ReturnsNonNilError\nError: bang!\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = ""
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestBadSecondTargets(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"TestVerbose", "NotGonnaWork"},
}
code := Invoke(inv)
if code != 2 {
t.Errorf("expected 0, but got %v", code)
}
actual := stderr.String()
expected := "Unknown target specified: NotGonnaWork\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = ""
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestParse(t *testing.T) {
buf := &bytes.Buffer{}
inv, init, showVer, err := Parse(buf, []string{"-v", "build"})
if err != nil {
t.Fatal("unexpected error", err)
}
if init {
t.Fatal("init should be false but was true")
}
if showVer {
t.Fatal("showVersion should be false but was true")
}
if len(inv.Args) != 1 && inv.Args[0] != "build" {
t.Fatalf("expected args to be %q but got %q", []string{"build"}, inv.Args)
}
if s := buf.String(); s != "" {
t.Fatalf("expected no stdout output but got %q", s)
}
}
// Test the timeout option
func TestTimeout(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata/context",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"timeout"},
Timeout: time.Duration(100 * time.Millisecond),
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: context deadline exceeded\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestParseHelp(t *testing.T) {
buf := &bytes.Buffer{}
_, _, _, err := Parse(buf, []string{"-h"})
if err != flag.ErrHelp {
t.Fatal("unexpected error", err)
}
buf2 := &bytes.Buffer{}
_, _, _, err = Parse(buf2, []string{"--help"})
if err != flag.ErrHelp {
t.Fatal("unexpected error", err)
}
s := buf.String()
s2 := buf2.String()
if s != s2 {
t.Fatalf("expected -h and --help to produce same output, but got different.\n\n-h:\n%s\n\n--help:\n%s", s, s2)
}
}