using System.Text.Json; using AcDream.App.Diagnostics; using AcDream.App.Streaming; using SixLabors.ImageSharp; namespace AcDream.App.Tests.Diagnostics; public sealed class WorldLifecycleAutomationControllerTests { [Fact] public void ScreenshotCapture_FlipsGlRowsAndWritesACompletePng() { string directory = NewDirectory(); // GL order: bottom row red/green, top row blue/white. byte[] rgba = [ 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 255, 255, 255, ]; var logs = new List(); var controller = new FrameScreenshotController( () => (2, 2), (_, _) => rgba, directory, logs.Add); try { Assert.True(controller.TryRequest("login_stable", out string error), error); Assert.False(controller.IsComplete("login_stable")); controller.CapturePending(); Assert.True(controller.IsComplete("login_stable")); string path = Path.Combine(directory, "login_stable.png"); using Image image = Image.Load(path); Assert.Equal(2, image.Width); Assert.Equal(2, image.Height); Assert.Contains(logs, line => line.Contains("screenshot-complete", StringComparison.Ordinal)); byte[] flipped = FrameScreenshotController.FlipRows(rgba, 2, 2); Assert.Equal(rgba.AsSpan(8, 8).ToArray(), flipped.AsSpan(0, 8).ToArray()); Assert.Equal(rgba.AsSpan(0, 8).ToArray(), flipped.AsSpan(8, 8).ToArray()); } finally { Directory.Delete(directory, recursive: true); } } [Theory] [InlineData("")] [InlineData("../escape")] [InlineData("has spaces")] [InlineData("name.png")] public void ArtifactNames_RejectPathsAndAmbiguousCharacters(string name) { Assert.False(AutomationArtifactName.TryValidate(name, out string error)); Assert.NotEmpty(error); } [Fact] public void Checkpoint_WritesCanonicalRevealAndResourceSnapshot() { string directory = NewDirectory(); var reveal = new WorldRevealLifecycleSnapshot( Generation: 7, Kind: WorldRevealKind.Portal, Readiness: new WorldRevealReadinessSnapshot( 0x8A020164u, IsIndoor: true, IsUnhydratable: false, RequiredRenderRadius: 0, IsRenderNeighborhoodReady: true, AreCompositeTexturesReady: true, IsCollisionReady: true), Materialized: true, Completed: true, Cancelled: false, WorldViewportObserved: true, InvariantFailureCount: 0); var resources = EmptyResources() with { LoadedLandblocks = 1, WorldEntities = 42, TrackedGpuBytes = 1234, }; var screenshots = new FrameScreenshotController( () => (1, 1), (_, _) => [0, 0, 0, 255], Path.Combine(directory, "screenshots")); var controller = new WorldLifecycleAutomationController( () => reveal, () => 3, () => resources, screenshots, directory); try { Assert.True(controller.IsWorldReady); Assert.True(controller.IsWorldViewportVisible); Assert.Equal(3, controller.PortalMaterializationCount); Assert.True(controller.TryWriteCheckpoint("dungeon", out string error), error); string line = Assert.Single(File.ReadAllLines( Path.Combine(directory, "world-lifecycle.checkpoints.jsonl"))); using JsonDocument json = JsonDocument.Parse(line); Assert.Equal("dungeon", json.RootElement.GetProperty("name").GetString()); Assert.Equal(7, json.RootElement.GetProperty("reveal").GetProperty("generation").GetInt64()); Assert.Equal(42, json.RootElement.GetProperty("resources").GetProperty("worldEntities").GetInt32()); Assert.True(File.Exists(Path.Combine(directory, "checkpoint-dungeon.json"))); } finally { Directory.Delete(directory, recursive: true); } } private static WorldLifecycleResourceSnapshot EmptyResources() => new( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0L, 0, 0L, 0L, 0, 0, 0, 0, 0, 0, 0, 0L, 0L, 0d, 0d, null); private static string NewDirectory() { string path = Path.Combine(Path.GetTempPath(), "acdream-world-gate-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(path); return path; } }