func loadDenco(routes []route) http.Handler { handler := &dencoHandler{routerMap: map[string]*denco.Router{ "GET": denco.New(), "POST": denco.New(), "PUT": denco.New(), "PATCH": denco.New(), "DELETE": denco.New(), }} recordMap := make(map[string][]denco.Record) for _, route := range routes { var f http.HandlerFunc switch route.method { case "GET": f = handler.Get case "POST": f = handler.Post case "PUT": f = handler.Put case "PATCH": f = handler.Patch case "DELETE": f = handler.Delete } recordMap[route.method] = append(recordMap[route.method], denco.NewRecord(route.path, f)) } for method, records := range recordMap { if err := handler.routerMap[method].Build(records); err != nil { panic(err) } } return handler }
func TestRouter_Build_withSizeHint(t *testing.T) { for _, v := range []struct { key string sizeHint int expect int }{ {"/user", 0, 0}, {"/user", 1, 1}, {"/user", 2, 2}, {"/user/:id", 3, 3}, {"/user/:id/:group", 0, 0}, {"/user/:id/:group", 1, 1}, } { r := denco.New() r.SizeHint = v.sizeHint records := []denco.Record{ {v.key, "value"}, } if err := r.Build(records); err != nil { t.Fatal(err) } actual := r.SizeHint expect := v.expect if !reflect.DeepEqual(actual, expect) { t.Errorf(`Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expect) } } }
func TestRouter_Build_withoutSizeHint(t *testing.T) { for _, v := range []struct { keys []string sizeHint int }{ {[]string{"/user"}, 0}, {[]string{"/user/:id"}, 1}, {[]string{"/user/:id/post"}, 1}, {[]string{"/user/:id/:group"}, 2}, {[]string{"/user/:id/post/:cid"}, 2}, {[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid"}, 2}, {[]string{"/user/:id", "/admin/:id/post/:cid"}, 2}, {[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid/:type"}, 3}, } { r := denco.New() actual := r.SizeHint expect := -1 if !reflect.DeepEqual(actual, expect) { t.Errorf(`before Build; Router.SizeHint => (%[1]T=%#[1]v); want (%[2]T=%#[2]v)`, actual, expect) } records := make([]denco.Record, len(v.keys)) for i, k := range v.keys { records[i] = denco.Record{k, "value"} } if err := r.Build(records); err != nil { t.Fatal(err) } actual = r.SizeHint expect = v.sizeHint if !reflect.DeepEqual(actual, expect) { t.Errorf(`Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expect) } } }
// buildForward builds forward router. func (router *Router) buildForward() error { records := make([]denco.Record, len(router.routeTable)) for i, route := range router.routeTable { records[i] = denco.NewRecord(route.Path, route) } router.forward = denco.New() return router.forward.Build(records) }
func benchmarkRouterBuild(b *testing.B, records []denco.Record) { for i := 0; i < b.N; i++ { router := denco.New() if err := router.Build(records); err != nil { b.Fatal(err) } } }
func loadDencoSingle(method, path string, handler *dencoHandler, hfunc http.HandlerFunc) http.Handler { handler.routerMap = map[string]*denco.Router{ method: denco.New(), } if err := handler.routerMap[method].Build([]denco.Record{ denco.NewRecord(path, hfunc), }); err != nil { panic(err) } return handler }
func (d *defaultRouteBuilder) Build() *defaultRouter { routers := make(map[string]*denco.Router) for method, records := range d.records { router := denco.New() router.Build(records) routers[method] = router } return &defaultRouter{ spec: d.spec, routers: routers, } }
func TestRouter_Build(t *testing.T) { // test for duplicate name of path parameters. func() { r := denco.New() if err := r.Build([]denco.Record{ {"/:user/:id/:id", "testroute0"}, {"/:user/:user/:id", "testroute0"}, }); err == nil { t.Errorf("no error returned by duplicate name of path parameters") } }() }
func runLookupTest(t *testing.T, records []denco.Record, testcases []testcase) { r := denco.New() if err := r.Build(records); err != nil { t.Fatal(err) } for _, testcase := range testcases { data, params, found := r.Lookup(testcase.path) if !reflect.DeepEqual(data, testcase.value) || !reflect.DeepEqual(params, denco.Params(testcase.params)) || !reflect.DeepEqual(found, testcase.found) { t.Errorf("Router.Lookup(%q) => (%#v, %#v, %#v), want (%#v, %#v, %#v)", testcase.path, data, params, found, testcase.value, denco.Params(testcase.params), testcase.found) } } }
func benchmarkRouterLookupSingleParam(b *testing.B, records []denco.Record) { router := denco.New() if err := router.Build(records); err != nil { b.Fatal(err) } record := pickTestRecord(records) b.ResetTimer() for i := 0; i < b.N; i++ { if _, _, found := router.Lookup(record.Key); !found { b.Fail() } } }
func benchmarkRouterLookupStatic(b *testing.B, n int) { b.StopTimer() router := denco.New() records := makeTestStaticRecords(n) if err := router.Build(records); err != nil { b.Fatal(err) } record := pickTestRecord(records) b.StartTimer() for i := 0; i < b.N; i++ { if r, _, _ := router.Lookup(record.Key); r != record.Value { b.Fail() } } }
func TestRouter_Lookup_withManyRoutes(t *testing.T) { n := 1000 rand.Seed(time.Now().UnixNano()) records := make([]denco.Record, n) for i := 0; i < n; i++ { records[i] = denco.Record{Key: "/" + randomString(rand.Intn(50)+10), Value: fmt.Sprintf("route%d", i)} } router := denco.New() if err := router.Build(records); err != nil { t.Fatal(err) } for _, r := range records { data, params, found := router.Lookup(r.Key) if !reflect.DeepEqual(data, r.Value) || len(params) != 0 || !reflect.DeepEqual(found, true) { t.Errorf("Router.Lookup(%q) => (%#v, %#v, %#v), want (%#v, %#v, %#v)", r.Key, data, len(params), found, r.Value, 0, true) } } }
// Build compiles registered routes. Routes that are added after building will not // be handled. A new call to build will be required. func (t *Router) Build() error { t.data = denco.New() return t.data.Build(t.records) }