github.com/hhsnopek/up@v0.1.1/internal/redirect/redirect_test.go (about) 1 package redirect 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/tj/assert" 8 ) 9 10 func rule(from, to string) Rule { 11 r := Rule{ 12 Path: from, 13 Location: to, 14 } 15 16 r.Compile() 17 return r 18 } 19 20 func TestRule_URL(t *testing.T) { 21 t.Run("exact", func(t *testing.T) { 22 s := rule("/docs", "/help").URL("/docs") 23 assert.Equal(t, "/help", s) 24 }) 25 26 t.Run("splat one segment", func(t *testing.T) { 27 r := rule("/docs/*", "/help/:splat") 28 assert.Equal(t, "/help/foo", r.URL("/docs/foo")) 29 }) 30 31 t.Run("splat many segments", func(t *testing.T) { 32 r := rule("/docs/*", "/help/:splat") 33 assert.Equal(t, "/help/foo/bar/baz", r.URL("/docs/foo/bar/baz")) 34 }) 35 36 t.Run("placeholder", func(t *testing.T) { 37 r := rule("/shop/:brand", "/store/:brand") 38 assert.Equal(t, "/store/apple", r.URL("/shop/apple")) 39 }) 40 41 t.Run("placeholders", func(t *testing.T) { 42 r := rule("/shop/:brand/category/:cat", "/products/:brand/:cat") 43 assert.Equal(t, "/products/apple/laptops", r.URL("/shop/apple/category/laptops")) 44 }) 45 46 t.Run("placeholders trailing slash", func(t *testing.T) { 47 r := rule("/docs/:product/guides/:guide", "/help/:product/:guide") 48 assert.Equal(t, "/help/ping/alerting", r.URL("/docs/ping/guides/alerting/")) 49 }) 50 51 t.Run("placeholders rearranged", func(t *testing.T) { 52 r := rule("/shop/:brand/category/:cat", "/products/:cat/:brand") 53 assert.Equal(t, "/products/laptops/apple", r.URL("/shop/apple/category/laptops")) 54 }) 55 56 t.Run("placeholders mismatch", func(t *testing.T) { 57 // TODO: sorry :D 58 err := func() (err error) { 59 defer func() { 60 err = recover().(error) 61 }() 62 63 rule("/shop/:brand/category/:category", "/products/:cat/:brand") 64 return nil 65 }() 66 67 assert.EqualError(t, err, `placeholder ":cat" is not present in the path pattern "/shop/:brand/category/:category"`) 68 }) 69 } 70 71 func TestMatcher_Lookup(t *testing.T) { 72 rules := Rules{ 73 "/docs/:product/guides/:guide": Rule{ 74 Location: "/help/:product/:guide", 75 Status: 301, 76 }, 77 "/blog": Rule{ 78 Location: "https://blog.apex.sh", 79 Status: 302, 80 }, 81 "/articles/*": Rule{ 82 Location: "/guides/:splat", 83 }, 84 } 85 86 m, err := Compile(rules) 87 assert.NoError(t, err, "compile") 88 89 t.Run("exact", func(t *testing.T) { 90 assert.NotNil(t, m.Lookup("/blog")) 91 }) 92 93 t.Run("exact trailing slash", func(t *testing.T) { 94 assert.NotNil(t, m.Lookup("/blog/")) 95 }) 96 97 t.Run("placeholders", func(t *testing.T) { 98 assert.NotNil(t, m.Lookup("/docs/ping/guides/alerts")) 99 }) 100 101 // TODO: need to fork the trie to be less greedy 102 // t.Run("mismatch", func(t *testing.T) { 103 // r := m.Lookup("/docs/ping/another/guides/alerts") 104 // assert.NotNil(t, r) 105 // }) 106 107 t.Run("splat one segment", func(t *testing.T) { 108 assert.NotNil(t, m.Lookup("/articles/alerting")) 109 }) 110 111 t.Run("splat many segments", func(t *testing.T) { 112 assert.NotNil(t, m.Lookup("/articles/alerting/pagerduty")) 113 assert.NotNil(t, m.Lookup("/articles/alerting/pagerduty/")) 114 }) 115 } 116 117 func BenchmarkMatcher_Lookup(b *testing.B) { 118 rules := Rules{ 119 "/docs/:product/guides/:guide": Rule{ 120 Location: "/help/:product/:guide", 121 Status: 301, 122 }, 123 } 124 125 m, err := Compile(rules) 126 assert.NoError(b, err, "compile") 127 128 b.ResetTimer() 129 130 b.Run("match", func(b *testing.B) { 131 for i := 0; i < b.N; i++ { 132 fmt.Printf("%#v\n", m.Lookup("/docs/ping/guides/alerts")) 133 } 134 }) 135 136 b.Run("mismatch", func(b *testing.B) { 137 for i := 0; i < b.N; i++ { 138 m.Lookup("/some/other/page") 139 } 140 }) 141 }