--- /dev/null
+// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
+// Revel Framework source code and usage is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package revel
+
+import (
+ "net/url"
+ "reflect"
+ "testing"
+)
+
+// These tests verify that Controllers are initialized properly, given the range
+// of embedding possibilities..
+
+type P struct{ *Controller }
+
+type PN struct{ P }
+
+type PNN struct{ PN }
+
+// Embedded via two paths
+type P2 struct{ *Controller }
+type PP2 struct {
+ *Controller // Need to embed this explicitly to avoid duplicate selector.
+ P
+ P2
+ PNN
+}
+
+func TestFindControllers(t *testing.T) {
+ controllers = make(map[string]*ControllerType)
+ RegisterController((*P)(nil), nil)
+ RegisterController((*PN)(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, PNN{}, [][]int{{0, 0, 0}})
+ checkSearchResults(t, PP2{}, [][]int{{0}, {1, 0}, {2, 0}, {3, 0, 0, 0}})
+}
+
+func checkSearchResults(t *testing.T, obj interface{}, expected [][]int) {
+ actual := findControllers(reflect.TypeOf(obj))
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Indexes do not match. expected %v actual %v", expected, actual)
+ }
+}
+
+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 {
+ *Controller
+ x, y int
+ foo string
+ }
+ type Mixin2 struct {
+ *Controller
+ a, b float64
+ bar string
+ }
+
+ type Benchmark struct {
+ *Controller
+ Mixin1
+ Mixin2
+ user interface{}
+ guy string
+ }
+
+ RegisterController((*Mixin1)(nil), []*MethodType{{Name: "Method"}})
+ RegisterController((*Mixin2)(nil), []*MethodType{{Name: "Method"}})
+ RegisterController((*Benchmark)(nil), []*MethodType{{Name: "Method"}})
+ c := Controller{
+ ViewArgs: make(map[string]interface{}),
+ }
+
+ for i := 0; i < b.N; i++ {
+ if err := c.SetAction("Benchmark", "Method"); err != nil {
+ b.Errorf("Failed to set action: %s", err)
+ return
+ }
+ }
+}
+
+func BenchmarkInvoker(b *testing.B) {
+ startFakeBookingApp()
+ c := NewTestController(nil, showRequest)
+ c.ViewArgs = make(map[string]interface{})
+ if err := c.SetAction("Hotels", "Show"); err != nil {
+ b.Errorf("Failed to set action: %s", err)
+ return
+ }
+
+ c.Params = &Params{Values: make(url.Values)}
+ c.Params.Set("id", "3")
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ActionInvoker(c, nil)
+ }
+}