initial implementation

This commit is contained in:
juancwu 2026-04-25 20:26:07 +00:00
commit cb373e637b
16 changed files with 777 additions and 1 deletions

118
pkg/router/pattern_test.go Normal file
View file

@ -0,0 +1,118 @@
package router
import "testing"
func TestSplitPattern(t *testing.T) {
cases := []struct {
in string
method, host, path string
}{
{"/foo", "", "", "/foo"},
{"GET /foo", "GET", "", "/foo"},
{"POST /users/{id}", "POST", "", "/users/{id}"},
{"GET example.com/foo", "GET", "example.com", "/foo"},
{"example.com/foo", "", "example.com", "/foo"},
{"GET /", "GET", "", "/"},
{"/", "", "", "/"},
}
for _, c := range cases {
t.Run(c.in, func(t *testing.T) {
m, h, p := splitPattern(c.in)
if m != c.method || h != c.host || p != c.path {
t.Fatalf("splitPattern(%q) = (%q, %q, %q), want (%q, %q, %q)",
c.in, m, h, p, c.method, c.host, c.path)
}
})
}
}
func TestNormalizeGroupPrefix(t *testing.T) {
cases := map[string]string{
"": "",
"/": "",
"/api": "/api",
"/api/": "/api",
"/api/v1": "/api/v1",
"/api/v1/": "/api/v1",
}
for in, want := range cases {
if got := normalizeGroupPrefix(in); got != want {
t.Errorf("normalizeGroupPrefix(%q) = %q, want %q", in, got, want)
}
}
}
func TestJoinPath(t *testing.T) {
cases := []struct {
prefix, sub, want string
}{
{"", "/foo", "/foo"},
{"/api", "/foo", "/api/foo"},
{"/api", "", "/api"},
{"/api", "/", "/api/"},
{"", "", ""},
{"/api/v1", "/users/{id}", "/api/v1/users/{id}"},
}
for _, c := range cases {
got := joinPath(c.prefix, c.sub)
if got != c.want {
t.Errorf("joinPath(%q, %q) = %q, want %q", c.prefix, c.sub, got, c.want)
}
}
}
func TestJoinPathPanicsOnBadSub(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatal("expected panic on sub without leading /")
}
}()
joinPath("/api", "foo")
}
func TestValidateGroupPrefix(t *testing.T) {
good := []string{"", "/api", "/api/v1"}
for _, p := range good {
func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("validateGroupPrefix(%q) unexpected panic: %v", p, r)
}
}()
validateGroupPrefix(p)
}()
}
bad := []string{"api", "GET /api", "/api with space", "host.com/api"}
for _, p := range bad {
func() {
defer func() {
if r := recover(); r == nil {
t.Errorf("validateGroupPrefix(%q) expected panic", p)
}
}()
validateGroupPrefix(p)
}()
}
}
func TestBuildPattern(t *testing.T) {
cases := []struct {
method, prefix, pattern, want string
}{
{"", "", "/foo", "/foo"},
{"GET", "", "/foo", "GET /foo"},
{"GET", "/api", "/foo", "GET /api/foo"},
{"", "/api", "GET /foo", "GET /api/foo"},
{"", "/api", "GET example.com/foo", "GET example.com/api/foo"},
{"", "/api", "/", "/api/"},
{"GET", "/api", "/", "GET /api/"},
{"GET", "/api", "", "GET /api"},
}
for _, c := range cases {
got := buildPattern(c.method, c.prefix, c.pattern)
if got != c.want {
t.Errorf("buildPattern(%q, %q, %q) = %q, want %q",
c.method, c.prefix, c.pattern, got, c.want)
}
}
}