clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / tinygit / metadata_external_test.go
metadata_external_test.go 3.7K
1package tinygit_test23import (4 "reflect"5 "strings"6 "testing"78 "github.com/FelineStateMachine/tinyrelay/tinygit"9)1011func TestParseMetadataRejectsInvalidShapes(t *testing.T) {12 oid := strings.Repeat("a", 40)13 for name, tags := range map[string][][]string{14 "missing identifier": {},15 "unsafe identifier": {{"d", "../demo"}},16 "invalid ref": {{"d", "demo"}, {"refs/heads/a..b", oid}},17 "invalid oid": {{"d", "demo"}, {"refs/heads/main", "not-a-sha1"}},18 "uppercase oid": {{"d", "demo"}, {"refs/heads/main", strings.Repeat("A", 40)}},19 "zero oid": {{"d", "demo"}, {"refs/heads/main", strings.Repeat("0", 40)}},20 "empty oid": {{"d", "demo"}, {"refs/heads/main", ""}},21 "duplicate ref": {{"d", "demo"}, {"refs/heads/main", oid}, {"refs/heads/main", oid}},22 "duplicate head": {{"d", "demo"}, {"HEAD", "ref: refs/heads/main"}, {"HEAD", "ref: refs/heads/main"}},23 "short head": {{"d", "demo"}, {"HEAD"}},24 "long head": {{"d", "demo"}, {"HEAD", "ref: refs/heads/main", "extra"}},25 "detached head": {{"d", "demo"}, {"HEAD", oid}},26 "nonbranch head": {{"d", "demo"}, {"HEAD", "ref: refs/nostr/topic"}},27 "invalid head ref": {{"d", "demo"}, {"HEAD", "ref: refs/heads/bad..name"}},28 } {29 t.Run(name, func(t *testing.T) {30 m, err := tinygit.ParseMetadata(tinygit.Event{Kind: 30618, Tags: tags})31 if err == nil || !strings.HasPrefix(err.Error(), "invalid:") || !reflect.DeepEqual(m, tinygit.Metadata{}) {32 t.Fatalf("invalid shape: metadata=%#v err=%v", m, err)33 }34 })35 }36 if _, err := tinygit.ParseMetadata(tinygit.Event{Kind: 1, Tags: [][]string{{"d", "demo"}}}); err == nil || !strings.HasPrefix(err.Error(), "unsupported:") {37 t.Fatalf("unsupported kind: %v", err)38 }39}4041func TestParseMetadataPreservesAnnouncementClaims(t *testing.T) {42 e := tinygit.Event{Kind: 30617, PubKey: "author", Tags: [][]string{43 {}, {"d", "demo"}, {"d", "ignored-second-identifier"},44 {"private", "true"}, {"clone", "https://one", "https://two"}, {"clone", "https://three"},45 {"relays", "wss://one", "wss://two"}, {"maintainers", "claimed-key", "another-key"},46 {"unknown"}, {"HEAD", "not-state"},47 }}48 m, err := tinygit.ParseMetadata(e)49 if err != nil {50 t.Fatal(err)51 }52 if !m.Private || m.Identifier != "demo" || m.Author != "author" || m.Head != "" || len(m.Refs) != 0 ||53 !reflect.DeepEqual(m.Clone, []string{"https://one", "https://two", "https://three"}) ||54 !reflect.DeepEqual(m.Relays, []string{"wss://one", "wss://two"}) ||55 !reflect.DeepEqual(m.Maintainers, []string{"claimed-key", "another-key"}) {56 t.Fatalf("announcement claims = %#v", m)57 }58 m.Clone[0], m.Relays[0], m.Maintainers[0] = "changed", "changed", "changed"59 again, err := tinygit.ParseMetadata(e)60 if err != nil || again.Clone[0] != "https://one" || again.Relays[0] != "wss://one" || again.Maintainers[0] != "claimed-key" {61 t.Fatalf("metadata aliases input tags: %#v, %v", again, err)62 }63}6465func TestParseMetadataWithoutSignatureOrHost(t *testing.T) {66 // Shape parsing is useful before signing. These are claims, not authority.67 e := tinygit.Event{Kind: 30618, PubKey: "unsigned-author", ID: "unverified-id", Tags: [][]string{68 {"d", "demo"}, {"HEAD", "ref: refs/heads/unborn"},69 {"refs/heads/main", strings.Repeat("a", 40), "extension"},70 {"refs/tags/v1", strings.Repeat("b", 40)}, {"unknown", "ignored"},71 }}72 m, err := tinygit.ParseMetadata(e)73 if err != nil {74 t.Fatal(err)75 }76 if m.Kind != e.Kind || m.Author != e.PubKey || m.EventID != e.ID || m.Identifier != "demo" || m.Head != "ref: refs/heads/unborn" {77 t.Fatalf("metadata claims = %#v", m)78 }79 if !reflect.DeepEqual(m.Refs, map[string]string{"refs/heads/main": strings.Repeat("a", 40), "refs/tags/v1": strings.Repeat("b", 40)}) {80 t.Fatalf("refs = %#v", m.Refs)81 }82}