1package podcasts23import (4 "strings"5 "testing"67 "github.com/FelineStateMachine/tinyrelay/internal/event"8)910func TestParseEpisodeUsesNativeAudioTracks(t *testing.T) {11 e := event.Event{ID: "episode", PubKey: strings.Repeat("a", 64), Kind: 54, CreatedAt: 123, Content: "## Show notes", Tags: [][]string{12 {"title", "Episode one"}, {"description", "A conversation"}, {"image", "https://example.test/cover.png"},13 {"audio", "javascript:alert(1)"}, {"audio", "https://example.test/one", "audio/mpeg"},14 {"audio", "https://example.test/one", "audio/mpeg"}, {"audio", "https://example.test/one.ogg"},15 {"imeta", "url https://example.test/one", "size 1234", "m audio/mpeg"},16 }}17 got, ok := ParseEpisode(e)18 if !ok || got.Title != "Episode one" || got.Description != "A conversation" || got.Content != e.Content || len(got.Audio) != 2 {19 t.Fatalf("episode: %#v, %v", got, ok)20 }21 if got.Audio[0].Length != 1234 || got.Audio[0].MIME != "audio/mpeg" || got.Audio[1].MIME != "audio/ogg" {22 t.Fatalf("audio: %#v", got.Audio)23 }24 for _, kind := range []int{1, 30023} {25 e.Kind = kind26 if _, ok := ParseEpisode(e); ok {27 t.Fatalf("kind %d treated as native podcast", kind)28 }29 }30 e.Kind, e.Tags = 54, [][]string{{"imeta", "url https://example.test/one.mp3", "m audio/mpeg"}}31 if _, ok := ParseEpisode(e); ok {32 t.Fatal("kind 54 without an F4 audio track treated as podcast")33 }34}3536func TestAudioMetadataIsOptional(t *testing.T) {37 e := event.Event{Kind: 54, Tags: [][]string{{"audio", "https://example.test/audio"}, {"imeta", "url https://example.test/audio", "size -20"}}}38 got, ok := ParseEpisode(e)39 if !ok || got.Audio[0].Length != 0 || got.Audio[0].MIME != "application/octet-stream" {40 t.Fatalf("optional metadata: %#v, %v", got, ok)41 }42 e.Tags = append(e.Tags, []string{"audio", "https://example.test/audio.mp3", "video/mp4"})43 got, _ = ParseEpisode(e)44 if len(got.Audio) != 1 {45 t.Fatal("non-audio declared type accepted")46 }47}4849func TestShowsUseLatestMetadataAndReciprocalAuthorship(t *testing.T) {50 show, host, fake := strings.Repeat("a", 64), strings.Repeat("b", 64), strings.Repeat("c", 64)51 rows := []event.Event{52 {ID: "z", Kind: 10154, PubKey: show, CreatedAt: 20, Tags: [][]string{{"title", "Latest"}, {"image", "https://example.test/cover.jpg"}, {"website", "https://example.test"}, {"p", host, "host"}, {"p", fake, "cohost"}}},53 {ID: "old", Kind: 10154, PubKey: show, CreatedAt: 10, Tags: [][]string{{"title", "Old"}}},54 {ID: "host", Kind: 10064, PubKey: host, CreatedAt: 10, Tags: [][]string{{"p", show}}},55 {ID: "fake-old", Kind: 10064, PubKey: fake, CreatedAt: 10, Tags: [][]string{{"p", show}}},56 {ID: "fake-new", Kind: 10064, PubKey: fake, CreatedAt: 20},57 }58 got := Shows(rows)[show]59 if got.Title != "Latest" || len(got.Websites) != 1 || len(got.Authors) != 1 || got.Authors[0].Pubkey != host || got.Authors[0].Role != "host" {60 t.Fatalf("show: %#v", got)61 }62 rows = append(rows, event.Event{ID: "a", Kind: 10154, PubKey: show, CreatedAt: 20, Tags: [][]string{{"title", "Tie winner"}}})63 if got := Shows(rows)[show]; got.Title != "Tie winner" || len(got.Authors) != 0 {64 t.Fatalf("replacement tie: %#v", got)65 }66}