Files

57 lines
1.5 KiB
Go

package web
import (
"testing"
"time"
)
type testCursor struct {
Name string `json:"n"`
ID int64 `json:"i"`
At time.Time `json:"t"`
}
func TestCursorRoundTrip(t *testing.T) {
want := testCursor{Name: "repeater-alpha", ID: 42, At: time.Unix(1_700_000_000, 0).UTC()}
got, ok := DecodeCursor[testCursor](EncodeCursor(want))
if !ok {
t.Fatal("DecodeCursor: ok=false for a token we just encoded")
}
if got.Name != want.Name || got.ID != want.ID || !got.At.Equal(want.At) {
t.Fatalf("round trip mismatch: got %+v want %+v", got, want)
}
}
func TestCursorTokenIsURLSafe(t *testing.T) {
// RawURLEncoding must not emit '+', '/', or '=' — the token rides in a query
// parameter unescaped.
tok := EncodeCursor(testCursor{Name: "a/b+c==", ID: 1})
for _, r := range tok {
switch r {
case '+', '/', '=':
t.Fatalf("token %q contains non-URL-safe rune %q", tok, r)
}
}
}
func TestDecodeCursorRejectsBadInput(t *testing.T) {
// A missing, malformed-base64, or malformed-JSON token must reset to the zero
// value with ok=false so a tampered URL just pages from the start.
cases := map[string]string{
"empty": "",
"not base64": "!!!not base64!!!",
"base64 non-json": EncodeCursor([]byte("plain string, not this struct's JSON")),
}
for name, tok := range cases {
t.Run(name, func(t *testing.T) {
got, ok := DecodeCursor[testCursor](tok)
if ok {
t.Fatalf("ok=true for %s input %q", name, tok)
}
if got != (testCursor{}) {
t.Fatalf("non-zero cursor %+v for %s input", got, name)
}
})
}
}