Skip to content

Commit

Permalink
Improved testing
Browse files Browse the repository at this point in the history
  • Loading branch information
robfig committed Jun 15, 2013
1 parent 2a7e77b commit 5f8324e
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 88 deletions.
17 changes: 5 additions & 12 deletions controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,7 @@ func (c *Controller) SetAction(controllerName, methodName string) error {
}

// This is a helper that initializes (zeros) a new app controller value.
// Generally, everything is set to its zero value, except:
// 1. Embedded controller pointers are newed up.
// 2. The revel.Controller embedded type is set to the value provided.
// Specifically, it sets all *revel.Controller embedded types to the provided controller.
// Returns a value representing a pointer to the new app controller.
func initNewAppController(appControllerType *ControllerType, c *Controller) reflect.Value {
var (
Expand All @@ -249,9 +247,8 @@ func initNewAppController(appControllerType *ControllerType, c *Controller) refl
}

func findControllers(appControllerType reflect.Type) (indexes [][]int) {
// It might be a multi-level embedding, so we have to create new controllers
// at every level of the hierarchy. To find the controllers, we follow every
// anonymous field, using depth-first search.
// It might be a multi-level embedding. To find the controllers, we follow
// every anonymous field, using breadth-first search.
type nodeType struct {
val reflect.Value
index []int
Expand Down Expand Up @@ -288,12 +285,8 @@ func findControllers(appControllerType reflect.Type) (indexes [][]int) {
continue
}

// Else, add it to the queue, after instantiating (if necessary).
if fieldValue.Kind() == reflect.Ptr {
INFO.Println("WARNING: Pointer detected")
fieldValue.Set(reflect.New(fieldType.Elem()))
}
queue = append(queue, nodeType{fieldValue, append(append([]int{}, node.index...), i)})
queue = append(queue,
nodeType{fieldValue, append(append([]int{}, node.index...), i)})
}
}
return
Expand Down
110 changes: 34 additions & 76 deletions invoker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,32 @@ import (
type P struct{ *Controller }

type PN struct{ P }
type PP struct{ *P }

type PNN struct{ PN }
type PPN struct{ PP }
type PNP struct{ *PN }
type PPP struct{ *PP }

// Embedded via two paths
type P2 struct{ *Controller }
type PP2 struct {
*Controller // Need to embed this explicitly to avoid duplicate selector.
P
P2
PNN
}

var GENERATIONS = [][]interface{}{
{P{}},
{PN{}, PP{}},
{PNN{}, PPN{}, PNP{}, PPP{}},
}
var GENERATIONS = []interface{}{P{}, PN{}, PNN{}}

func TestFindControllers(t *testing.T) {
controllers = make(map[string]*ControllerType)
RegisterController((*P)(nil), nil)
RegisterController((*PN)(nil), nil)
RegisterController((*PP)(nil), nil)
RegisterController((*PNN)(nil), nil)
RegisterController((*PP2)(nil), nil)

// Test construction of indexes to each *Controller
checkSearchResults(t, P{}, [][]int{{0}})
checkSearchResults(t, PN{}, [][]int{{0, 0}})
// checkSearchResults(t, PP{}, [][]int{{0, 0}}) // maybe not
checkSearchResults(t, PNN{}, [][]int{{0, 0, 0}})
checkSearchResults(t, PP2{}, [][]int{{0}, {1, 0}, {2, 0}})
checkSearchResults(t, PP2{}, [][]int{{0}, {1, 0}, {2, 0}, {3, 0, 0, 0}})
}

func checkSearchResults(t *testing.T, obj interface{}, expected [][]int) {
Expand All @@ -55,70 +47,36 @@ func checkSearchResults(t *testing.T, obj interface{}, expected [][]int) {
}
}

// // This test constructs a bunch of hypothetical app controllers, and verifies
// // that the embedded Controller field was set correctly.
// func TestNewAppController(t *testing.T) {
// controller := &Controller{Name: "Test"}
// for gen, structs := range GENERATIONS {
// for _, st := range structs {
// typ := reflect.TypeOf(st)
// val := initNewAppController(typ, controller)

// // Drill into the embedded fields to get to the Controller.
// for i := 0; i < gen+1; i++ {
// if val.Kind() == reflect.Ptr {
// val = val.Elem()
// }
// val = val.Field(0)
// }

// var name string
// if val.Type().Kind() == reflect.Ptr {
// name = val.Interface().(*Controller).Name
// } else {
// name = val.Interface().(Controller).Name
// }

// if name != "Test" {
// t.Error("Fail: " + typ.String())
// }
// }
// }
// }

// // // Since the test machinery that goes through all the structs is non-trivial,
// // have one redundant test that covers just one complicated case but is dead
// // simple.
// func TestNewAppController2(t *testing.T) {
// val := initNewAppController(reflect.TypeOf(PNP{}), &Controller{Name: "Test"})
// pnp := val.Interface().(*PNP)
// if pnp.PN.P.Controller.Name != "Test" {
// t.Error("PNP not initialized.")
// }
// if pnp.Controller.Name != "Test" {
// t.Error("PNP promotion not working.")
// }
// }

// func TestMultiEmbedding(t *testing.T) {
// val := initNewAppController(reflect.TypeOf(PP2{}), &Controller{Name: "Test"})
// pp2 := val.Interface().(*PP2)
// if pp2.P.Controller.Name != "Test" {
// t.Error("P not initialized.")
// }

// if pp2.P2.Controller.Name != "Test" {
// t.Error("P2 not initialized.")
// }

// if pp2.Controller.Name != "Test" {
// t.Error("PP2 promotion not working.")
// }

// if pp2.P.Controller != pp2.P2.Controller || pp2.Controller != pp2.P.Controller {
// t.Error("Controllers not pointing to the same thing.")
// }
// }
func TestSetAction(t *testing.T) {
controllers = make(map[string]*ControllerType)
RegisterController((*P)(nil), []*MethodType{{Name: "Method"}})
RegisterController((*PNN)(nil), []*MethodType{{Name: "Method"}})
RegisterController((*PP2)(nil), []*MethodType{{Name: "Method"}})

// Test that all *revel.Controllers are initialized.
c := &Controller{Name: "Test"}
if err := c.SetAction("P", "Method"); err != nil {
t.Error(err)
} else if c.AppController.(*P).Controller != c {
t.Errorf("P not initialized")
}

if err := c.SetAction("PNN", "Method"); err != nil {
t.Error(err)
} else if c.AppController.(*PNN).Controller != c {
t.Errorf("PNN not initialized")
}

// PP2 has 4 different slots for *Controller.
if err := c.SetAction("PP2", "Method"); err != nil {
t.Error(err)
} else if pp2 := c.AppController.(*PP2); pp2.Controller != c ||
pp2.P.Controller != c ||
pp2.P2.Controller != c ||
pp2.PNN.Controller != c {
t.Errorf("PP2 not initialized")
}
}

func BenchmarkSetAction(b *testing.B) {
type Mixin1 struct {
Expand Down

0 comments on commit 5f8324e

Please sign in to comment.