148 lines
3.1 KiB
Go
148 lines
3.1 KiB
Go
|
package mg_test
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/magefile/mage/mg"
|
||
|
)
|
||
|
|
||
|
func TestDepsRunOnce(t *testing.T) {
|
||
|
done := make(chan struct{})
|
||
|
f := func() {
|
||
|
done <- struct{}{}
|
||
|
}
|
||
|
go mg.Deps(f, f)
|
||
|
select {
|
||
|
case <-done:
|
||
|
// cool
|
||
|
case <-time.After(time.Millisecond * 100):
|
||
|
t.Fatal("func not run in a reasonable amount of time.")
|
||
|
}
|
||
|
select {
|
||
|
case <-done:
|
||
|
t.Fatal("func run twice!")
|
||
|
case <-time.After(time.Millisecond * 100):
|
||
|
// cool... this should be plenty of time for the goroutine to have run
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestDepsOfDeps(t *testing.T) {
|
||
|
ch := make(chan string, 3)
|
||
|
// this->f->g->h
|
||
|
h := func() {
|
||
|
ch <- "h"
|
||
|
}
|
||
|
g := func() {
|
||
|
mg.Deps(h)
|
||
|
ch <- "g"
|
||
|
}
|
||
|
f := func() {
|
||
|
mg.Deps(g)
|
||
|
ch <- "f"
|
||
|
}
|
||
|
mg.Deps(f)
|
||
|
|
||
|
res := <-ch + <-ch + <-ch
|
||
|
|
||
|
if res != "hgf" {
|
||
|
t.Fatal("expected h then g then f to run, but got " + res)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestDepError(t *testing.T) {
|
||
|
// TODO: this test is ugly and relies on implementation details. It should
|
||
|
// be recreated as a full-stack test.
|
||
|
|
||
|
f := func() error {
|
||
|
return errors.New("ouch!")
|
||
|
}
|
||
|
defer func() {
|
||
|
err := recover()
|
||
|
if err == nil {
|
||
|
t.Fatal("expected panic, but didn't get one")
|
||
|
}
|
||
|
actual := fmt.Sprint(err)
|
||
|
if "ouch!" != actual {
|
||
|
t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
|
||
|
}
|
||
|
}()
|
||
|
mg.Deps(f)
|
||
|
}
|
||
|
|
||
|
func TestDepFatal(t *testing.T) {
|
||
|
f := func() error {
|
||
|
return mg.Fatal(99, "ouch!")
|
||
|
}
|
||
|
defer func() {
|
||
|
v := recover()
|
||
|
if v == nil {
|
||
|
t.Fatal("expected panic, but didn't get one")
|
||
|
}
|
||
|
actual := fmt.Sprint(v)
|
||
|
if "ouch!" != actual {
|
||
|
t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
|
||
|
}
|
||
|
err, ok := v.(error)
|
||
|
if !ok {
|
||
|
t.Fatalf("expected recovered val to be error but was %T", v)
|
||
|
}
|
||
|
code := mg.ExitStatus(err)
|
||
|
if code != 99 {
|
||
|
t.Fatalf("Expected exit status 99, but got %v", code)
|
||
|
}
|
||
|
}()
|
||
|
mg.Deps(f)
|
||
|
}
|
||
|
|
||
|
func TestDepTwoFatal(t *testing.T) {
|
||
|
f := func() error {
|
||
|
return mg.Fatal(99, "ouch!")
|
||
|
}
|
||
|
g := func() error {
|
||
|
return mg.Fatal(11, "bang!")
|
||
|
}
|
||
|
defer func() {
|
||
|
v := recover()
|
||
|
if v == nil {
|
||
|
t.Fatal("expected panic, but didn't get one")
|
||
|
}
|
||
|
actual := fmt.Sprint(v)
|
||
|
// order is non-deterministic, so check for both orders
|
||
|
if "ouch!\nbang!" != actual && "bang!\nouch!" != actual {
|
||
|
t.Fatalf(`expected to get "ouch!" and "bang!" but got "%s"`, actual)
|
||
|
}
|
||
|
err, ok := v.(error)
|
||
|
if !ok {
|
||
|
t.Fatalf("expected recovered val to be error but was %T", v)
|
||
|
}
|
||
|
code := mg.ExitStatus(err)
|
||
|
// two different error codes returns, so we give up and just use error
|
||
|
// code 1.
|
||
|
if code != 1 {
|
||
|
t.Fatalf("Expected exit status 1, but got %v", code)
|
||
|
}
|
||
|
}()
|
||
|
mg.Deps(f, g)
|
||
|
}
|
||
|
|
||
|
func TestDepWithUnhandledFunc(t *testing.T) {
|
||
|
defer func() {
|
||
|
err := recover()
|
||
|
expected := "Invalid type for dependent function: func(string) string. Dependencies must be func(), func() error, func(context.Context) or func(context.Context) error"
|
||
|
actual, ok := err.(error)
|
||
|
if !ok {
|
||
|
t.Fatalf("Expected type string from panic")
|
||
|
}
|
||
|
if actual.Error() != expected {
|
||
|
t.Fatalf("Expected panic %v but got %v", expected, err)
|
||
|
}
|
||
|
}()
|
||
|
var NotValid func(string) string = func(a string) string {
|
||
|
return a
|
||
|
}
|
||
|
mg.Deps(NotValid)
|
||
|
}
|