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