109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
package server
|
|
|
|
import (
|
|
"net/url"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
func TestSplitObjectsPath(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
wantTag, wantRef string
|
|
wantErr bool
|
|
}{
|
|
{"page", "page", "", false},
|
|
{"page/index", "page", "index", false},
|
|
// Tag with slash: encoded as %2F, must round-trip as one segment.
|
|
{"meta%2Flibrary", "meta/library", "", false},
|
|
{"meta%2Flibrary/Some%20Page", "meta/library", "Some Page", false},
|
|
// Ref containing %2F decodes to a single ref with `/` in it.
|
|
{"task/Daily%2F2026-05-14%40L3", "task", "Daily/2026-05-14@L3", false},
|
|
// Empty / bad percent escape
|
|
{"", "", "", false}, // empty: caller will reject empty tag
|
|
{"%ZZ/x", "", "", true},
|
|
}
|
|
for _, c := range cases {
|
|
gotTag, gotRef, err := splitObjectsPath(c.in)
|
|
if c.wantErr {
|
|
if err == nil {
|
|
t.Errorf("%q: expected error", c.in)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("%q: unexpected error %v", c.in, err)
|
|
continue
|
|
}
|
|
if gotTag != c.wantTag || gotRef != c.wantRef {
|
|
t.Errorf("%q: got (%q, %q) want (%q, %q)", c.in, gotTag, gotRef, c.wantTag, c.wantRef)
|
|
}
|
|
}
|
|
}
|
|
|
|
func sortFilters(in []Filter) []Filter {
|
|
out := append([]Filter(nil), in...)
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Field < out[j].Field })
|
|
return out
|
|
}
|
|
|
|
func TestParseObjectsQuery_Empty(t *testing.T) {
|
|
q, err := parseObjectsQuery(url.Values{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if q.Limit != 100 || q.Offset != 0 || len(q.Filters) != 0 {
|
|
t.Fatalf("unexpected defaults: %+v", q)
|
|
}
|
|
}
|
|
|
|
func TestParseObjectsQuery_WhereVariants(t *testing.T) {
|
|
v := url.Values{}
|
|
v.Add("where[name]", "foo")
|
|
v.Add("where[age][gte]", "10")
|
|
v.Add("where[status][in]", "open,pending")
|
|
v.Add("order", "name")
|
|
v.Add("order", "age:desc")
|
|
v.Add("limit", "20")
|
|
v.Add("offset", "5")
|
|
v.Add("select", "name,age")
|
|
q, err := parseObjectsQuery(v)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []Filter{
|
|
{Field: "name", Op: "eq", Value: "foo"},
|
|
{Field: "age", Op: "gte", Value: "10"},
|
|
{Field: "status", Op: "in", Value: "open,pending"},
|
|
}
|
|
if !reflect.DeepEqual(sortFilters(q.Filters), sortFilters(want)) {
|
|
t.Fatalf("filters: got %+v want %+v", q.Filters, want)
|
|
}
|
|
if q.Limit != 20 || q.Offset != 5 {
|
|
t.Fatalf("paging: %+v", q)
|
|
}
|
|
if len(q.Order) != 2 || q.Order[0].Field != "name" || q.Order[1].Desc != true {
|
|
t.Fatalf("order: %+v", q.Order)
|
|
}
|
|
if !reflect.DeepEqual(q.Select, []string{"name", "age"}) {
|
|
t.Fatalf("select: %+v", q.Select)
|
|
}
|
|
}
|
|
|
|
func TestParseObjectsQuery_Errors(t *testing.T) {
|
|
cases := []url.Values{
|
|
{"limit": {"abc"}},
|
|
{"limit": {"-1"}},
|
|
{"limit": {"1001"}},
|
|
{"offset": {"-1"}},
|
|
{"where[bad name]": {"v"}},
|
|
{"where[f][nope]": {"v"}},
|
|
}
|
|
for _, c := range cases {
|
|
if _, err := parseObjectsQuery(c); err == nil {
|
|
t.Errorf("expected error for %v", c)
|
|
}
|
|
}
|
|
}
|