1package records23import (4 "context"5 "fmt"6 "strconv"7 "strings"8 "testing"910 "github.com/FelineStateMachine/tinyrelay/internal/event"11 "github.com/FelineStateMachine/tinyrelay/internal/policy"12 "github.com/FelineStateMachine/tinyrelay/internal/storage"13)1415func TestFoldKeepsProfileAndRelayForSameAuthor(t *testing.T) {16 pk := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"17 events := []event.Event{18 {Kind: event.KIND_PROFILE, PubKey: pk, Content: `{"name":"Alice"}`},19 {Kind: 10002, PubKey: pk, Tags: [][]string{{"r", "wss://relay.example/"}}},20 }21 profiles, _ := fold("profiles", events, "", 100)22 relays, _ := fold("relays", events, "", 100)23 if len(profiles) != 1 || profiles[0][1] != pk {24 t.Fatalf("profiles = %#v", profiles)25 }26 if len(relays) != 1 || relays[0][1] != "wss://relay.example" {27 t.Fatalf("relays = %#v", relays)28 }29}3031func TestFoldCalendarWindowAndArticlesUsePublishedAt(t *testing.T) {32 now := int64(1_700_000_000)33 old := event.Event{Kind: 31923, PubKey: "a", Tags: [][]string{{"d", "old"}, {"start", strconv.FormatInt(now-2*86400, 10)}}}34 future := event.Event{Kind: 31923, PubKey: "a", Tags: [][]string{{"d", "future"}, {"start", strconv.FormatInt(now+2*86400, 10)}, {"title", "Future"}}}35 cal, _ := fold("calendar", []event.Event{old, future}, "", now)36 if len(cal) != 1 || cal[0][1] != "31923:a:future" {37 t.Fatalf("calendar = %#v", cal)38 }39 late := event.Event{Kind: 30023, PubKey: "a", CreatedAt: 10, Tags: [][]string{{"d", "late"}, {"published_at", "200"}}}40 early := event.Event{Kind: 30023, PubKey: "a", CreatedAt: 20, Tags: [][]string{{"d", "early"}, {"published_at", "100"}}}41 articles, _ := fold("articles", []event.Event{late, early}, "", now)42 if len(articles) != 2 || articles[0][1] != "30023:a:late" {43 t.Fatalf("articles = %#v", articles)44 }45}4647func TestFoldPodcastsSummarizesNativeEpisodesAndShows(t *testing.T) {48 show := "podcast"49 author := "author"50 events := []event.Event{51 {ID: "meta", PubKey: show, Kind: 10154, CreatedAt: 2, Tags: [][]string{{"title", "The Show"}, {"p", author, "host"}}},52 {PubKey: author, Kind: 10064, CreatedAt: 3, Tags: [][]string{{"p", show}}},53 {ID: "episode", PubKey: author, Kind: 54, CreatedAt: 4, Content: "An episode", Tags: [][]string{{"title", "Episode one"}, {"audio", "https://cdn.example/one.mp3", "audio/mpeg", "42"}}},54 }55 tags, content := foldPodcasts(events)56 if len(tags) != 2 || tags[0][0] != "p" || tags[0][1] != show || tags[1][0] != "e" || tags[1][1] != "episode" {57 t.Fatalf("podcast tags = %#v", tags)58 }59 if !strings.Contains(content, `"The Show"`) || !strings.Contains(content, `"Episode one"`) || strings.Contains(content, "An episode") {60 t.Fatalf("podcast content = %s", content)61 }62}6364func TestFoldPodcastsBoundsShowsAndEpisodes(t *testing.T) {65 events := make([]event.Event, 0, 205)66 for i := 0; i < 105; i++ {67 key := fmt.Sprintf("show-%03d", i)68 events = append(events, event.Event{ID: key, PubKey: key, Kind: 10154, CreatedAt: int64(i), Tags: [][]string{{"title", key}}})69 }70 for i := 0; i < 105; i++ {71 id := fmt.Sprintf("episode-%03d", i)72 events = append(events, event.Event{ID: id, PubKey: "author", Kind: 54, CreatedAt: int64(i), Tags: [][]string{{"title", id}, {"audio", "https://cdn.example/episode.mp3", "audio/mpeg"}}})73 }74 tags, content := foldPodcasts(events)75 if len(tags) != 200 || strings.Contains(content, "episode-000") || strings.Contains(content, "show-104") {76 t.Fatalf("bounded podcast view has %d tags and content %d bytes", len(tags), len(content))77 }78}7980func TestPodcastViewAppliesEventVisibilityCallback(t *testing.T) {81 s, ctx := testStore(t)82 owner := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"83 p := policy.Defaults(owner)84 visible := map[string]bool{"keep": true}85 r, err := New(ctx, Config{Community: emptyCommunityReader{}, Store: s, Policy: func() policy.Policy { return p }, RelayURL: "wss://relay.example", EventVisible: func(_ context.Context, e event.Event, _ policy.Access) bool { return visible[e.ID] }})86 if err != nil {87 t.Fatal(err)88 }89 for _, e := range []event.Event{90 {ID: "keep", PubKey: owner, Kind: 54, CreatedAt: 2, Tags: [][]string{{"title", "Kept"}, {"audio", "https://cdn.example/keep.mp3", "audio/mpeg"}}},91 {ID: "drop", PubKey: owner, Kind: 54, CreatedAt: 3, Tags: [][]string{{"title", "Blocked"}, {"audio", "https://cdn.example/drop.mp3", "audio/mpeg"}}},92 } {93 if _, err := s.Save(ctx, e, storage.SaveOptions{Now: e.CreatedAt}); err != nil {94 t.Fatal(err)95 }96 }97 view, err := r.View(ctx, "podcasts", policy.Access{Owner: true}, 10)98 if err != nil {99 t.Fatal(err)100 }101 if len(view.Event.Tags) != 4 || view.Event.Tags[3][1] != "keep" {102 t.Fatalf("filtered podcast view = %#v", view.Event.Tags)103 }104}