Something went wrong. Try again.
Go boilerplate library for building atproto apps
atproto go
Something went wrong. Try again.
atp uri_test.go
4.9 kB · 197 lines
Go
at jetstream-v2
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198package atp
import ( "testing"
"github.com/stretchr/testify/assert")
func TestBuildATURI(t *testing.T) { got := BuildATURI("did:plc:abc", "app.bsky.feed.post", "3jxy") want := "at://did:plc:abc/app.bsky.feed.post/3jxy" if got != want { t.Fatalf("got %q, want %q", got, want) }}
func TestParseATURI(t *testing.T) { tests := []struct { name string input string wantDID string wantColl string wantRKey string wantErr bool }{ { name: "valid URI", input: "at://did:plc:abc/app.bsky.feed.post/3jxy", wantDID: "did:plc:abc", wantColl: "app.bsky.feed.post", wantRKey: "3jxy", }, { name: "invalid URI", input: "not-a-uri", wantErr: true, }, { name: "empty URI", input: "", wantErr: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { uri, err := ParseATURI(tc.input) if tc.wantErr { if err == nil { t.Fatal("expected error for invalid URI") } return } if err != nil { t.Fatal(err) } if uri == nil { t.Fatal("expected non-nil URI") } if uri.DID != tc.wantDID || uri.Collection != tc.wantColl || uri.RKey != tc.wantRKey { t.Fatalf("got DID=%q Collection=%q RKey=%q", uri.DID, uri.Collection, uri.RKey) } }) }}
func TestParseBuildRoundTrip(t *testing.T) { uri, err := ParseATURI("at://did:plc:abc/app.bsky.feed.post/3jxy") if err != nil { t.Fatal(err) } got := uri.String() want := "at://did:plc:abc/app.bsky.feed.post/3jxy" if got != want { t.Fatalf("got %q, want %q", got, want) }}
func TestRKeyFromURI(t *testing.T) { tests := []struct { name string input string want string }{ {"valid URI", "at://did:plc:abc/app.bsky.feed.post/3jxy", "3jxy"}, {"invalid URI", "garbage", ""}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := RKeyFromURI(tc.input) if got != tc.want { t.Fatalf("got %q, want %q", got, tc.want) } }) }}
func TestValidateRKey(t *testing.T) { tests := []struct { name string rkey string valid bool }{ {"valid TID", "3kfk4slgu6s2h", true}, {"valid simple", "abc123", true}, {"valid with hyphens", "record-001", true}, {"valid with underscores", "record_001", true}, {"valid with colons", "2021:01:01", true}, {"valid with dots", "v1.0", true}, {"empty string", "", false}, {"reserved dot", ".", false}, {"reserved dotdot", "..", false}, {"starts with hyphen", "-invalid", false}, {"too long", string(make([]byte, 513)), false}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := ValidateRKey(tc.rkey) if got != tc.valid { t.Errorf("ValidateRKey(%q) = %v, want %v", tc.rkey, got, tc.valid) } }) }}
func TestNormalizeHandle(t *testing.T) { cases := []struct { name string in string want string }{ {"plain ascii unchanged", "alice.example.com", "alice.example.com"}, {"strips at prefix", "@alice.example.com", "alice.example.com"}, {"lowercases", "Alice.Example.COM", "alice.example.com"}, {"trims whitespace", " alice.example.com ", "alice.example.com"}, {"empty stays empty", "", ""}, {"unicode to punycode", "café.example.com", "xn--caf-dma.example.com"}, {"punycode idempotent", "xn--caf-dma.example.com", "xn--caf-dma.example.com"}, {"mixed case unicode", "Café.Example.com", "xn--caf-dma.example.com"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.want, NormalizeHandle(tc.in)) }) }}
func TestDisplayHandle(t *testing.T) { cases := []struct { name string in string want string }{ {"plain ascii unchanged", "alice.example.com", "alice.example.com"}, {"empty stays empty", "", ""}, {"punycode to unicode", "xn--caf-dma.example.com", "café.example.com"}, {"unicode idempotent", "café.example.com", "café.example.com"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.want, DisplayHandle(tc.in)) }) }}
func TestNormalizeDisplayRoundTrip(t *testing.T) { inputs := []string{ "alice.example.com", "café.example.com", "xn--caf-dma.example.com", "Café.Example.COM", } for _, in := range inputs { t.Run(in, func(t *testing.T) { ascii := NormalizeHandle(in) display := DisplayHandle(ascii) assert.Equal(t, ascii, NormalizeHandle(display)) }) }}
func TestNormalizeHandle_InvalidUTF8(t *testing.T) { // Invalid UTF-8 bytes should fall back to the input (lowered, trimmed) in := "\xff\xfe\x00" got := NormalizeHandle(in) // Should not panic, returns lowered/trimmed version if got == "" { t.Log("empty result for invalid UTF-8 is acceptable") }}
func TestDisplayHandle_InvalidUTF8(t *testing.T) { in := "\xff\xfe\x00" got := DisplayHandle(in) if got != in { t.Logf("DisplayHandle returned %q for invalid input, expected fallback %q", got, in) }}