defined env type
the env type represents a test environment. This was added as an intermediate container that could store the saved fields of tests after they're run, so that future tests could load them. Previously a test could only get the attributes of the test that immediately preceded it. This change allows tests to load attributes further back in the history.g-counter
parent
2c68d4dbd5
commit
d523c73690
@ -0,0 +1,73 @@
|
||||
package tea
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type env struct {
|
||||
key string
|
||||
value interface{}
|
||||
parent *env
|
||||
}
|
||||
|
||||
func mkenv(test Test) *env {
|
||||
var e *env
|
||||
return e.save(test)
|
||||
}
|
||||
|
||||
// save looks at the Test t and saves the values of its fields marked with a
|
||||
// save tag
|
||||
func (e *env) save(test Test) *env {
|
||||
V := reflect.ValueOf(test)
|
||||
if V.Type().Kind() == reflect.Ptr {
|
||||
V = V.Elem()
|
||||
}
|
||||
T := V.Type()
|
||||
|
||||
for i := 0; i < T.NumField(); i++ {
|
||||
f := T.Field(i)
|
||||
if !isSaveField(f) {
|
||||
continue
|
||||
}
|
||||
|
||||
fv := V.Field(i)
|
||||
e = &env{
|
||||
key: f.Name,
|
||||
value: fv.Interface(),
|
||||
parent: e,
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *env) load(dest Test) error {
|
||||
destV := reflect.ValueOf(dest).Elem()
|
||||
destT := destV.Type()
|
||||
|
||||
for i := 0; i < destT.NumField(); i++ {
|
||||
f := destT.Field(i)
|
||||
if !isLoadField(f) {
|
||||
continue
|
||||
}
|
||||
fv := destV.Field(i)
|
||||
|
||||
set := false
|
||||
for e := e; e != nil; e = e.parent {
|
||||
if e.key == f.Name {
|
||||
ev := reflect.ValueOf(e.value)
|
||||
if ev.Type().AssignableTo(fv.Type()) {
|
||||
set = true
|
||||
fv.Set(ev)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !set {
|
||||
return fmt.Errorf("failed to set required field: %q", f.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package tea
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSave(t *testing.T) {
|
||||
type saveFoo struct {
|
||||
empty
|
||||
Foo int `tea:"save"`
|
||||
Bar string
|
||||
}
|
||||
|
||||
type loadFoo struct {
|
||||
empty
|
||||
Foo int `tea:"load"`
|
||||
Bar string
|
||||
}
|
||||
|
||||
t.Run("empty begets nil", func(t *testing.T) {
|
||||
e := mkenv(new(empty))
|
||||
if e != nil {
|
||||
t.Errorf("saw unexpected env value looking for nil: %v", e)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("unexported fields are ignored", func(t *testing.T) {
|
||||
type test struct {
|
||||
empty
|
||||
foo int `tea:"save"`
|
||||
}
|
||||
|
||||
if e := mkenv(test{foo: 5}); e != nil {
|
||||
t.Errorf("saw unexpected env value looking for nil: %v", e)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("save an int", func(t *testing.T) {
|
||||
e := mkenv(&saveFoo{Foo: 5})
|
||||
if e == nil {
|
||||
t.Fatalf("saw nil env when expecting a valid env")
|
||||
}
|
||||
|
||||
if e.key != "Foo" {
|
||||
t.Errorf("expected key %q but saw %q instead", "Foo", e.key)
|
||||
}
|
||||
|
||||
if e.value != 5 {
|
||||
t.Errorf("expected value %v but saw %v instead", 5, e.value)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("load an int", func(t *testing.T) {
|
||||
e := mkenv(&saveFoo{Foo: 5})
|
||||
test := new(loadFoo)
|
||||
|
||||
e.load(test)
|
||||
if test.Foo != 5 {
|
||||
t.Errorf("expected value %v but saw %v instead", 5, test.Foo)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("loads can fail", func(t *testing.T) {
|
||||
e := mkenv(new(empty))
|
||||
test := new(loadFoo)
|
||||
if err := e.load(test); err == nil {
|
||||
t.Errorf("expected a load error but did not see one")
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue