Improve error messages
diff --git a/router.go b/router.go index 5172c89..155b871 100644 --- a/router.go +++ b/router.go
@@ -213,7 +213,7 @@ // communication with a proxy). func (r *Router) Handle(method, path string, handle Handle) { if path[0] != '/' { - panic("path must begin with '/'") + panic("path must begin with '/' in path '" + path + "'") } if r.trees == nil { @@ -257,7 +257,7 @@ // router.ServeFiles("/src/*filepath", http.Dir("/var/www")) func (r *Router) ServeFiles(path string, root http.FileSystem) { if len(path) < 10 || path[len(path)-10:] != "/*filepath" { - panic("path must end with /*filepath") + panic("path must end with /*filepath in path '" + path + "'") } fileServer := http.FileServer(root)
diff --git a/tree.go b/tree.go index b741654..a15bc2c 100644 --- a/tree.go +++ b/tree.go
@@ -7,7 +7,6 @@ import ( "strings" "unicode" - "fmt" ) func min(a, b int) int { @@ -79,6 +78,7 @@ // addRoute adds a node with the given handle to the path. // Not concurrency-safe! func (n *node) addRoute(path string, handle Handle) { + fullPath := path n.priority++ numParams := countParams(path) @@ -148,7 +148,9 @@ } } - panic(fmt.Sprintf("conflict with wildcard route. has %q got %q", path, n.path)) + panic("path segment '" + path + + "' conflicts with existing wildcard '" + n.path + + "' in path '" + fullPath + "'") } c := path[0] @@ -180,23 +182,23 @@ n.incrementChildPrio(len(n.indices) - 1) n = child } - n.insertChild(numParams, path, handle) + n.insertChild(numParams, path, fullPath, handle) return } else if i == len(path) { // Make node a (in-path) leaf if n.handle != nil { - panic(fmt.Sprintf("a Handle is already registered for this path (%q)", path)) + panic("a handle is already registered for path ''" + fullPath + "'") } n.handle = handle } return } } else { // Empty tree - n.insertChild(numParams, path, handle) + n.insertChild(numParams, path, fullPath, handle) } } -func (n *node) insertChild(numParams uint8, path string, handle Handle) { +func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle) { var offset int // already handled bytes of the path // find prefix until first wildcard (beginning with ':'' or '*'') @@ -206,27 +208,29 @@ continue } - // check if this Node existing children which would be - // unreachable if we insert the wildcard here - if len(n.children) > 0 { - panic("wildcard route conflicts with existing children") - } - // find wildcard end (either '/' or path end) end := i + 1 for end < max && path[end] != '/' { switch path[end] { // the wildcard name must not contain ':' and '*' case ':', '*': - panic("only one wildcard per path segment is allowed") + panic("only one wildcard per path segment is allowed, has: '" + + path[i:] + "' in path '" + fullPath + "'") default: end++ } } + // check if this Node existing children which would be + // unreachable if we insert the wildcard here + if len(n.children) > 0 { + panic("wildcard route '" + path[i:end] + + "' conflicts with existing children in path '" + fullPath + "'") + } + // check if the wildcard has a name if end-i < 2 { - panic("wildcards must be named with a non-empty name") + panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") } if c == ':' { // param @@ -262,17 +266,17 @@ } else { // catchAll if end != max || numParams > 1 { - panic("catch-all routes are only allowed at the end of the path") + panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") } if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { - panic("catch-all conflicts with existing handle for the path segment root") + panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'") } // currently fixed width 1 for '/' i-- if path[i] != '/' { - panic("no / before catch-all") + panic("no / before catch-all in path '" + fullPath + "'") } n.path = path[offset:i] @@ -397,7 +401,7 @@ return default: - panic("Invalid node type") + panic("invalid node type") } } } else if path == n.path { @@ -508,7 +512,7 @@ return append(ciPath, path...), true default: - panic("Invalid node type") + panic("invalid node type") } } else { // We should have reached the node containing the handle.
diff --git a/tree_test.go b/tree_test.go index 262681b..64f26d1 100644 --- a/tree_test.go +++ b/tree_test.go
@@ -358,7 +358,7 @@ tree.addRoute(route, nil) }) - if rs, ok := recv.(string); !ok || rs != panicMsg { + if rs, ok := recv.(string); !ok || !strings.HasPrefix(rs, panicMsg) { t.Fatalf(`"Expected panic "%s" for route '%s', got "%v"`, panicMsg, route, recv) } } @@ -584,6 +584,8 @@ } func TestTreeInvalidNodeType(t *testing.T) { + const panicMsg = "invalid node type" + tree := &node{} tree.addRoute("/", fakeHandler("/")) tree.addRoute("/:page", fakeHandler("/:page")) @@ -595,15 +597,15 @@ recv := catchPanic(func() { tree.getValue("/test") }) - if rs, ok := recv.(string); !ok || rs != "Invalid node type" { - t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv) + if rs, ok := recv.(string); !ok || rs != panicMsg { + t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) } // case-insensitive lookup recv = catchPanic(func() { tree.findCaseInsensitivePath("/test", true) }) - if rs, ok := recv.(string); !ok || rs != "Invalid node type" { - t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv) + if rs, ok := recv.(string); !ok || rs != panicMsg { + t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) } }