180 lines
4.3 KiB
Go
180 lines
4.3 KiB
Go
package pathtree
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestColon(t *testing.T) {
|
|
n := New()
|
|
|
|
n.Add("/:first/:second/", 1)
|
|
n.Add("/:first", 2)
|
|
n.Add("/", 3)
|
|
|
|
found(t, n, "/", nil, 3)
|
|
found(t, n, "/a", []string{"a"}, 2)
|
|
found(t, n, "/a/", []string{"a"}, 2)
|
|
found(t, n, "/a/b", []string{"a", "b"}, 1)
|
|
found(t, n, "/a/b/", []string{"a", "b"}, 1)
|
|
|
|
notfound(t, n, "/a/b/c")
|
|
}
|
|
|
|
func TestStar(t *testing.T) {
|
|
n := New()
|
|
|
|
n.Add("/first/second/*star", 1)
|
|
n.Add("/:first/*star/", 2)
|
|
n.Add("/*star", 3)
|
|
n.Add("/", 4)
|
|
|
|
found(t, n, "/", nil, 4)
|
|
found(t, n, "/a", []string{"a"}, 3)
|
|
found(t, n, "/a/", []string{"a"}, 3)
|
|
found(t, n, "/a/b", []string{"a", "b"}, 2)
|
|
found(t, n, "/a/b/", []string{"a", "b"}, 2)
|
|
found(t, n, "/a/b/c", []string{"a", "b/c"}, 2)
|
|
found(t, n, "/a/b/c/", []string{"a", "b/c"}, 2)
|
|
found(t, n, "/a/b/c/d", []string{"a", "b/c/d"}, 2)
|
|
found(t, n, "/first/second", []string{"first", "second"}, 2)
|
|
found(t, n, "/first/second/", []string{"first", "second"}, 2)
|
|
found(t, n, "/first/second/third", []string{"third"}, 1)
|
|
}
|
|
|
|
func TestMixedTree(t *testing.T) {
|
|
n := New()
|
|
|
|
n.Add("/", 0)
|
|
n.Add("/path/to/nowhere", 1)
|
|
n.Add("/path/:i/nowhere", 2)
|
|
n.Add("/:id/to/nowhere", 3)
|
|
n.Add("/:a/:b", 4)
|
|
n.Add("/not/found", 5)
|
|
|
|
found(t, n, "/", nil, 0)
|
|
found(t, n, "/path/to/nowhere", nil, 1)
|
|
found(t, n, "/path/to/nowhere/", nil, 1)
|
|
found(t, n, "/path/from/nowhere", []string{"from"}, 2)
|
|
found(t, n, "/walk/to/nowhere", []string{"walk"}, 3)
|
|
found(t, n, "/path/to/", []string{"path", "to"}, 4)
|
|
found(t, n, "/path/to", []string{"path", "to"}, 4)
|
|
found(t, n, "/not/found", []string{"not", "found"}, 4)
|
|
notfound(t, n, "/path/to/somewhere")
|
|
notfound(t, n, "/path/to/nowhere/else")
|
|
notfound(t, n, "/path")
|
|
notfound(t, n, "/path/")
|
|
|
|
notfound(t, n, "")
|
|
notfound(t, n, "xyz")
|
|
notfound(t, n, "/path//to/nowhere")
|
|
}
|
|
|
|
func TestExtensions(t *testing.T) {
|
|
n := New()
|
|
|
|
n.Add("/:first/:second.json", 1)
|
|
n.Add("/a/:second.xml", 2)
|
|
n.Add("/:first/:second", 3)
|
|
|
|
found(t, n, "/a/b", []string{"a", "b"}, 3)
|
|
found(t, n, "/a/b.json", []string{"a", "b"}, 1)
|
|
found(t, n, "/a/b.xml", []string{"b"}, 2)
|
|
found(t, n, "/a/b.c.xml", []string{"b.c"}, 2)
|
|
found(t, n, "/other/b.xml", []string{"other", "b.xml"}, 3)
|
|
}
|
|
|
|
func TestErrors(t *testing.T) {
|
|
n := New()
|
|
fails(t, n.Add("//", 1), "empty path elements not allowed")
|
|
}
|
|
|
|
func BenchmarkTree100(b *testing.B) {
|
|
n := New()
|
|
n.Add("/", "root")
|
|
|
|
// Exact matches
|
|
for i := 0; i < 100; i++ {
|
|
depth := i%5 + 1
|
|
key := ""
|
|
for j := 0; j < depth-1; j++ {
|
|
key += fmt.Sprintf("/dir%d", j)
|
|
}
|
|
key += fmt.Sprintf("/resource%d", i)
|
|
n.Add(key, "literal")
|
|
// b.Logf("Adding %s", key)
|
|
}
|
|
|
|
// Wildcards at each level if no exact matches work.
|
|
for i := 0; i < 5; i++ {
|
|
var key string
|
|
for j := 0; j < i; j++ {
|
|
key += fmt.Sprintf("/dir%d", j)
|
|
}
|
|
key += "/:var"
|
|
n.Add(key, "var")
|
|
// b.Logf("Adding %s", key)
|
|
}
|
|
|
|
n.Add("/public/*filepath", "static")
|
|
// b.Logf("Adding /public/*filepath")
|
|
|
|
queries := map[string]string{
|
|
"/": "root",
|
|
"/dir0/dir1/dir2/dir3/resource4": "literal",
|
|
"/dir0/dir1/resource97": "literal",
|
|
"/dir0/variable": "var",
|
|
"/dir0/dir1/dir2/dir3/variable": "var",
|
|
"/public/stylesheets/main.css": "static",
|
|
"/public/images/icons/an-image.png": "static",
|
|
}
|
|
|
|
for query, answer := range queries {
|
|
leaf, _ := n.Find(query)
|
|
if leaf == nil {
|
|
b.Errorf("Failed to find leaf for querY %s", query)
|
|
return
|
|
}
|
|
if leaf.Value.(string) != answer {
|
|
b.Errorf("Incorrect answer for querY %s: expected: %s, actual: %s",
|
|
query, answer, leaf.Value.(string))
|
|
return
|
|
}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N/len(queries); i++ {
|
|
for k, _ := range queries {
|
|
n.Find(k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func notfound(t *testing.T, n *Node, p string) {
|
|
if leaf, _ := n.Find(p); leaf != nil {
|
|
t.Errorf("Should not have found: %s", p)
|
|
}
|
|
}
|
|
|
|
func found(t *testing.T, n *Node, p string, expectedExpansions []string, val interface{}) {
|
|
leaf, expansions := n.Find(p)
|
|
if leaf == nil {
|
|
t.Errorf("Didn't find: %s", p)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(expansions, expectedExpansions) {
|
|
t.Errorf("%s: Wildcard expansions (actual) %v != %v (expected)", p, expansions, expectedExpansions)
|
|
}
|
|
if leaf.Value != val {
|
|
t.Errorf("%s: Value (actual) %v != %v (expected)", p, leaf.Value, val)
|
|
}
|
|
}
|
|
|
|
func fails(t *testing.T, err error, msg string) {
|
|
if err == nil {
|
|
t.Errorf("expected an error. %s", msg)
|
|
}
|
|
}
|