can copy field values between successive tests

this isn't going to work permanently, if there's a save field in one
test, then an intermediate test without that field, then a load field,
it won't be visible at the end test.
g-counter
Jordan Orelli 4 years ago
parent 2853ecfb38
commit 2c68d4dbd5

@ -2,15 +2,15 @@ package tea
import (
"reflect"
"strings"
"testing"
)
// Run runs a tree of tests, starting from its root.
func Run(t *testing.T, tree *Tree) {
t.Run(tree.name, func(t *testing.T) {
setup(t, tree)
clone(tree.test).Run(t)
test := setup(t, tree)
test.Run(t)
for _, child := range tree.children {
if t.Failed() || t.Skipped() {
@ -22,11 +22,14 @@ func Run(t *testing.T, tree *Tree) {
})
}
func setup(t *testing.T, tree *Tree) {
func setup(t *testing.T, tree *Tree) Test {
test := clone(tree.test)
if tree.parent != nil {
setup(t, tree.parent)
clone(tree.parent.test).Run(t)
p := setup(t, tree.parent)
p.Run(t)
test = merge(test, p)
}
return test
}
func skip(t *testing.T, tree *Tree) {
@ -59,6 +62,8 @@ func (t *Tree) Child(test Test) *Tree {
return child
}
// clone clones a test value, yielding a new test value that can be executed
// and mutated such that the original is not mutated.
func clone(t Test) Test {
srcV := reflect.ValueOf(t).Elem()
destV := reflect.New(srcV.Type())
@ -66,6 +71,53 @@ func clone(t Test) Test {
return destV.Interface().(Test)
}
// merge merges into dest the fields on the src test that are marked as worth
// saving
func merge(dest Test, src Test) Test {
destV := reflect.ValueOf(dest).Elem()
srcV := reflect.ValueOf(src).Elem()
for i := 0; i < srcV.NumField(); i++ {
sf := srcV.Type().Field(i)
if isSaveField(sf) {
df, ok := destV.Type().FieldByName(sf.Name)
if ok && isLoadField(df) {
if sf.Type == df.Type {
sfv := srcV.FieldByName(sf.Name)
dfv := destV.FieldByName(sf.Name)
dfv.Set(sfv)
}
}
}
}
return dest
}
// isSaveField takes a struct field and checks its tags for a save tag,
// indicating that the field's value should persist between tests
func isSaveField(f reflect.StructField) bool {
parts := strings.Split(f.Tag.Get("tea"), ",")
for _, part := range parts {
if part == "save" {
return true
}
}
return false
}
// isLoadField takes a struct field and checks its tags for a load tag,
// indicating that the field's value should be populated by a saved value from
// a prior test in the chain.
func isLoadField(f reflect.StructField) bool {
parts := strings.Split(f.Tag.Get("tea"), ",")
for _, part := range parts {
if part == "load" {
return true
}
}
return false
}
func parseName(test Test) string {
if s, ok := test.(interface{ String() string }); ok {
return s.String()

@ -10,20 +10,21 @@ import (
)
type testThingSetup struct {
thing *Thing
Thing *Thing `tea:"save"`
}
func (test *testThingSetup) Run(t *testing.T) {
t.Logf("[%s] running testThingSetup", t.Name())
if test.thing != nil {
if test.Thing != nil {
t.Fatal("should be nil")
}
test.thing = new(Thing)
test.Thing = new(Thing)
}
func (test testThingSetup) String() string { return "thingSetup" }
type setKey struct {
Thing *Thing `tea:"load"`
key string
value string
bad bool
@ -35,9 +36,8 @@ func (test setKey) String() string {
func (test *setKey) Run(t *testing.T) {
t.Logf("[%s] running setKey key: %q value: %q", t.Name(), test.key, test.value)
thing := new(Thing)
err := thing.Set(test.key, test.value)
err := test.Thing.Set(test.key, test.value)
if !test.bad && err != nil {
t.Errorf("should be able to set %q=%q but saw error %v", test.key, test.value, err)
}

Loading…
Cancel
Save