using System.Text.Json; using RadicadeServer.Extensions; using RadicadeServer.RecNet.Board; using Xunit; namespace RadicadeServer.Tests; /// /// A board the admin panel saves has to reach players without a restart. The only lever the client /// offers for that is its notification table, which is keyed by name and drops any frame whose Id is /// not the exact registered key - the same contract the progression frame lives under. The server /// used to announce a save as the numeric enum 95 with an empty payload, which no handler matches. /// public class CommunityBoardRealtimeTests { private static CommunityBoard Board() => new() { FeaturedPlayer = new FeaturedPlayer { Id = 42, TitleOverride = "Community Legend", UrlOverride = "https://example/creator" }, FeaturedRoomGroup = new FeaturedRoomGroup { FeaturedRoomGroupId = 1, Name = "Top Picks", Rooms = new List { new() { RoomId = 1001, RoomName = "Dodgeball Arena", ImageName = "room-1.png" } } }, CurrentAnnouncement = new BoardAnnouncement { Message = "See you in the Rec Center.", MoreInfoUrl = "https://discord.gg/radicade" }, InstagramImages = new List { new() { ImageName = "cb-1.png", ImageUrl = "https://cdn/cb-1.png" } }, Videos = new List { new() { BlobName = "v.mp4", Title = "Trailer", Description = "Year in review", ThumbnailBlobName = "t.png", SourceUrl = "https://youtu.be/x" } } }; [Fact] public void TheBoardGoesOutUnderTheLiteralNameTheClientRegistersItsHandlerFor() { var frames = CommunityBoardBroadcast.BuildFrames(Board()); var boardFrame = frames[0]; Assert.Equal("CommunityBoardUpdate", (string)boardFrame.Id); Assert.Contains("\"Id\":\"CommunityBoardUpdate\"", boardFrame.ToJson()); // Not the numeric enum (95): the client registers the board handler by name and drops any // frame whose Id is not the exact key, which is why a saved board used to be invisible until // the game was restarted. Assert.DoesNotContain("\"Id\":\"95\"", boardFrame.ToJson()); } [Fact] public void TheBoardFrameCarriesTheWholeBoardSoTheClientNeedNotRefetch() { var frames = CommunityBoardBroadcast.BuildFrames(Board()); using var doc = JsonDocument.Parse(frames[0].ToJson()); var msg = doc.RootElement.GetProperty("Msg"); Assert.Equal("Community Legend", msg.GetProperty("FeaturedPlayer").GetProperty("TitleOverride").GetString()); Assert.Equal("Top Picks", msg.GetProperty("FeaturedRoomGroup").GetProperty("Name").GetString()); Assert.Equal("Dodgeball Arena", msg.GetProperty("FeaturedRoomGroup").GetProperty("Rooms")[0].GetProperty("RoomName").GetString()); Assert.Equal(1, msg.GetProperty("InstagramImages").GetArrayLength()); Assert.Equal("Trailer", msg.GetProperty("Videos")[0].GetProperty("Title").GetString()); } [Fact] public void TheAnnouncementGoesOutUnderItsOwnNumericHandler() { var frames = CommunityBoardBroadcast.BuildFrames(Board()); var announcementFrame = frames.Single(f => Equals(f.Id, "96")); Assert.Contains("\"Id\":\"96\"", announcementFrame.ToJson()); using var doc = JsonDocument.Parse(announcementFrame.ToJson()); var msg = doc.RootElement.GetProperty("Msg"); Assert.Equal("See you in the Rec Center.", msg.GetProperty("Message").GetString()); Assert.Equal("https://discord.gg/radicade", msg.GetProperty("MoreInfoUrl").GetString()); } [Fact] public void AnEmptyBoardStillSendsAWellFormedAnnouncementFrame() { var frames = CommunityBoardBroadcast.BuildFrames(new CommunityBoard()); Assert.Equal(2, frames.Count); using var doc = JsonDocument.Parse(frames[1].ToJson()); Assert.Equal(string.Empty, doc.RootElement.GetProperty("Msg").GetProperty("Message").GetString()); } [Fact] public void ANullBoardPushesNothing() { Assert.Empty(CommunityBoardBroadcast.BuildFrames(null)); } }