using PrivaPub.Federation.Actors; using PrivaPub.Federation.Rendering; using PrivaPub.Models.Federation; using PrivaPub.Models.Post; using System.Text.Json.Nodes; namespace PrivaPub.Tests.Federation { public class RendererTests { static readonly LocalActor Alice = new() { Id = "a1", Kind = LocalActorKind.Person, UserName = "alice", Name = "Alice", Summary = "I **like** cats", PublicKeyPem = Keys.NewKeyPair().PublicKeyPem, Published = new DateTime(2026, 9, 30, 17, 45, 12, DateTimeKind.Utc), Fields = new Dictionary { ["site"] = "https://alice.example", ["mood"] = "ok" }, BaseAddress = "https://privapub.test" }; [Fact] public void An_actor_looks_like_a_mastodon_actor_with_our_route_names() { var actor = ActivityPubRenderer.Actor(Alice); Assert.Equal("https://privapub.test/peasants/alice", actor["id"]!.GetValue()); Assert.Equal("https://privapub.test/@alice", actor["url"]!.GetValue()); Assert.Equal("https://privapub.test/peasants/alice/mouth", actor["inbox"]!.GetValue()); Assert.Equal("https://privapub.test/peasants/alice/anus", actor["outbox"]!.GetValue()); Assert.Equal("https://privapub.test/peasants/alice/groupies", actor["followers"]!.GetValue()); Assert.Equal("https://privapub.test/peasants/alice/stalking", actor["following"]!.GetValue()); Assert.Equal("https://privapub.test/human-centipede", actor["endpoints"]!["sharedInbox"]!.GetValue()); Assert.Equal("2026-09-30T00:00:00Z", actor["published"]!.GetValue()); Assert.Equal("alice@privapub.test", actor["webfinger"]!.GetValue()); Assert.False(actor["indexable"]!.GetValue()); Assert.Equal("

I like <b>cats</b>

", actor["summary"]!.GetValue()); var fields = actor["attachment"]!.AsArray(); Assert.Contains("rel=\"nofollow noopener noreferrer me\"", fields[0]!["value"]!.GetValue()); Assert.Equal("<i>ok</i>", fields[1]!["value"]!.GetValue()); Assert.Equal("https://privapub.test/peasants/alice#main-key", actor["publicKey"]!["id"]!.GetValue()); Assert.Equal(actor["id"]!.GetValue(), actor["publicKey"]!["owner"]!.GetValue()); } [Fact] public void A_titled_post_with_a_warning_keeps_the_title_visible_on_mastodon() { var post = new Post { ID = "p1", Title = "On ", ContentHtml = "

body

", HasContentWarning = true, Language = "en", Mentions = new() { new PostMention { ActorURI = "https://m.example/users/bob", Handle = "@bob@m.example" } }, Tags = new() { "cats" }, CreationDate = new DateTime(2026, 9, 30, 17, 45, 12, 345, DateTimeKind.Utc) }; var note = ActivityPubRenderer.Note(post, Alice, default, "https://m.example/users/bob/statuses/1"); Assert.Equal("https://privapub.test/peasants/alice/scribbles/p1", note["id"]!.GetValue()); Assert.Equal("https://privapub.test/@alice/p1", note["url"]!.GetValue()); Assert.Equal("

On <cats>

body

", note["content"]!.GetValue()); Assert.Equal("On ", note["summary"]!.GetValue()); Assert.True(note["sensitive"]!.GetValue()); Assert.Equal("2026-09-30T17:45:12.345Z", note["published"]!.GetValue()); Assert.Equal(new[] { ActivityPubRenderer.Public }, note["to"]!.AsArray().Select(n => n!.GetValue())); Assert.Equal(new[] { Alice.Followers, "https://m.example/users/bob" }, note["cc"]!.AsArray().Select(n => n!.GetValue())); var tags = note["tag"]!.AsArray(); Assert.Equal("@bob@m.example", tags[0]!["name"]!.GetValue()); Assert.Equal("https://privapub.test/tags/cats", tags[1]!["href"]!.GetValue()); Assert.Equal("https://m.example/users/bob/statuses/1", note["inReplyTo"]!.GetValue()); Assert.NotNull(note["contentMap"]!["en"]); } [Fact] public void A_warning_without_a_title_or_spoiler_gets_a_generic_summary() { var note = ActivityPubRenderer.Note(new Post { ID = "p2", ContentHtml = "

x

", HasContentWarning = true }, Alice, default, default); Assert.Equal(ActivityPubRenderer.ContentWarning, note["summary"]!.GetValue()); } [Fact] public void A_direct_note_is_addressed_to_its_recipients_only() { var post = new Post { ID = "p3", ContentHtml = "

psst

", Visibility = PostVisibility.Direct }; var note = ActivityPubRenderer.DirectNote(post, Alice, new[] { ("https://m.example/users/bob", "bob@m.example") }, Alice.ConversationUri("c1")); Assert.Equal(new[] { "https://m.example/users/bob" }, note["to"]!.AsArray().Select(n => n!.GetValue())); Assert.Empty(note["cc"]!.AsArray()); Assert.Equal("https://privapub.test/peasants/alice/whispers/c1", note["context"]!.GetValue()); Assert.StartsWith("

()); Assert.Equal("Mention", note["tag"]![0]!["type"]!.GetValue()); } } }