Radicade Public Code

This commit is contained in:
JogmansonReal
2026-10-16 23:33:13 -07:00
commit 55175acdf6
832 changed files with 363261 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RadicadeServer.Admin;
using RadicadeServer.DB;
using RadicadeServer.RecNet;
using RadicadeServer.RecNet.Enums;
using RadicadeServer.RecNet.Enums.Rooms;
using RadicadeServer.RecNet.Rooms;
using Xunit;
namespace RadicadeServer.Tests;
/// <summary>
/// Room creation through <c>POST admin/rooms/create/room</c>, which is how every import puts a
/// room on this server (the Taco archives, tools/import_room_dump.mjs).
///
/// The route reads its body with a helper that only knew scalars. Enums and arrays are neither,
/// so <c>Accessibility</c>, <c>WarningMask</c>, <c>MaxPlayerCalculationMode</c> and <c>Tags</c>
/// silently took their defaults while the strings and bools around them bound: an imported room
/// arrived Private (invisible to every list, unsearchable) and untagged, with nothing in the
/// response to say a field had been dropped. These pin the whole payload, and the defaults the
/// route still falls back to when a field is absent.
/// </summary>
public class AdminRoomCreateTests
{
private static RecDBContext NewDb() => new(
TestDbOptions.Create()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options);
private const string Secret = "test-bot-secret";
private static async Task<RecDBContext> CreateAsync(string json)
{
var db = NewDb();
var api = new AdminRoomAPI(db);
var original = DBConfig.AdminApiKey;
DBConfig.AdminApiKey = Secret;
try
{
var result = await api.CreateRoom(Secret, 2, JsonNode.Parse(json)!);
Assert.IsType<OkObjectResult>(result);
}
finally
{
DBConfig.AdminApiKey = original;
}
return db;
}
private const string RoomPayload = """
{
"Name": "MakeItToMidnight",
"Description": "A night of horror ensues.",
"Accessibility": 1,
"State": 0,
"IsRRO": true,
"IsDorm": false,
"ImageName": "default.png",
"MaxPlayers": 5,
"MaxPlayerCalculationMode": 1,
"WarningMask": 1,
"CloningAllowed": false,
"SupportsScreens": 1,
"SupportsWalkVR": true,
"SupportsTeleportVR": "true",
"SupportsJuniors": "1",
"Tags": [ { "Tag": "import", "Type": 1 } ],
"CreatedAt": "2023-07-26T23:23:35Z",
"SubRooms": [
{
"Name": "Home",
"Accessibility": 1,
"IsSandbox": true,
"MaxPlayers": 5,
"UnitySceneId": "a75f7547-79eb-47c6-8986-6767abcb4f92",
"DataBlob": "aq4a6u116zm6uathf9i9b7n0y.room"
}
]
}
""";
[Fact]
public async Task AnImportedRoomKeepsItsAccessibilityWarningMaskAndPlayerCountMode()
{
var db = await CreateAsync(RoomPayload);
var room = db.Rooms.Single();
Assert.Equal(Accessibility.Public, room.Accessibility);
Assert.Equal(WarningMask.Scary, room.WarningMask);
Assert.Equal(MaxPlayerMode.OnlyEntrySubrooms, room.MaxPlayerCalculationMode);
Assert.Equal(5, room.MaxPlayers);
Assert.True(room.IsRRO);
Assert.False(room.IsDorm);
Assert.Equal(2, room.CreatorAccountId);
Assert.Equal(new DateTime(2023, 7, 26, 23, 23, 35), room.CreatedAt);
}
[Fact]
public async Task TheTagListIsKeptWithItsTagTypes()
{
var db = await CreateAsync(RoomPayload);
// One tag, of type Auto - the same "name,type|name,type" string the room's own tag
// screen writes, which is what the tag doors and the list queries read back.
Assert.Equal("import,1", db.Rooms.Single().Tags);
}
[Fact]
public async Task EnumsArriveAsNumbersOrNamesAndBoolsAsTrueOnesOrStrings()
{
var db = await CreateAsync("""
{
"Name": "NamedEnums",
"Accessibility": "Public",
"WarningMask": "Scary",
"MaxPlayerCalculationMode": "OnlyEntrySubrooms",
"SupportsScreens": 1,
"SupportsWalkVR": true,
"SupportsQuest2": "true",
"SupportsTeleportVR": "false",
"IsRRO": 1
}
""");
var room = db.Rooms.Single();
Assert.Equal(Accessibility.Public, room.Accessibility);
Assert.Equal(WarningMask.Scary, room.WarningMask);
Assert.Equal(MaxPlayerMode.OnlyEntrySubrooms, room.MaxPlayerCalculationMode);
Assert.True(room.SupportsScreens);
Assert.True(room.SupportsWalkVR);
Assert.True(room.SupportsQuest2);
Assert.False(room.SupportsTeleportVR);
Assert.True(room.IsRRO);
}
[Fact]
public async Task AnAbsentFieldStillTakesTheRoutesDefault()
{
var db = await CreateAsync("""{ "Name": "BareRoom" }""");
var room = db.Rooms.Single();
Assert.Equal(Accessibility.Private, room.Accessibility);
Assert.Equal(WarningMask.None, room.WarningMask);
Assert.Equal(MaxPlayerMode.AllSubrooms, room.MaxPlayerCalculationMode); Assert.Equal("", room.Tags);
Assert.False(room.IsRRO);
// LoadScreens is the one field whose absence used to fail the insert outright: the
// column is NOT NULL and the payload's missing array was written over the default.
Assert.Equal("[]", room.loadScreen);
}
[Fact]
public async Task TheSubroomKeepsTheSceneAndTheSaveItWasImportedWith()
{
var db = await CreateAsync(RoomPayload);
var subRoom = db.SubRooms.Single();
Assert.Equal("Home", subRoom.Name);
Assert.Equal("a75f7547-79eb-47c6-8986-6767abcb4f92", subRoom.UnitySceneId);
Assert.Equal("aq4a6u116zm6uathf9i9b7n0y.room", subRoom.DataBlob);
Assert.Equal(2, subRoom.SavedByAccountId);
Assert.True(subRoom.IsSandbox);
Assert.Equal(Accessibility.Public, subRoom.Accessibility);
}
[Fact]
public async Task ASceneTheClientDoesNotKnowBecomesTheMakerRoom()
{
var db = await CreateAsync("""
{
"Name": "OddScene",
"SubRooms": [ { "Name": "Home", "UnitySceneId": "not-a-scene", "DataBlob": "empty.room" } ]
}
""");
Assert.Equal(SceneLocations.MakerRoom, db.SubRooms.Single().UnitySceneId);
}
}