using System.Collections.Generic; using AcDream.App.Streaming; using AcDream.Core.World; using DatReaderWriter.DBObjs; using Xunit; namespace AcDream.Core.Tests.Streaming; public class StreamingControllerTests { private sealed class FakeStreamer { public List Loads { get; } = new(); public List Unloads { get; } = new(); public Queue Pending { get; } = new(); public void EnqueueLoad(uint id) => Loads.Add(id); public void EnqueueUnload(uint id) => Unloads.Add(id); public IReadOnlyList DrainCompletions(int max) { var batch = new List(); while (batch.Count < max && Pending.Count > 0) batch.Add(Pending.Dequeue()); return batch; } } [Fact] public void FirstTick_EnqueuesWholeVisibleWindow() { var state = new GpuWorldState(); var fake = new FakeStreamer(); var controller = new StreamingController( enqueueLoad: fake.EnqueueLoad, enqueueUnload: fake.EnqueueUnload, drainCompletions: fake.DrainCompletions, applyTerrain: _ => { }, state: state, radius: 2); // Center at (50, 50); no landblocks loaded yet. controller.Tick(observerCx: 50, observerCy: 50); // 5×5 window = 25 loads enqueued, 0 unloads. Assert.Equal(25, fake.Loads.Count); Assert.Empty(fake.Unloads); } [Fact] public void SecondTick_SamePosition_EnqueuesNothing() { var state = new GpuWorldState(); var fake = new FakeStreamer(); var controller = new StreamingController( fake.EnqueueLoad, fake.EnqueueUnload, fake.DrainCompletions, _ => { }, state, radius: 2); controller.Tick(50, 50); fake.Loads.Clear(); controller.Tick(50, 50); Assert.Empty(fake.Loads); Assert.Empty(fake.Unloads); } [Fact] public void DrainingLoadedResult_AddsToState() { var state = new GpuWorldState(); var fake = new FakeStreamer(); var applied = new List(); var controller = new StreamingController( fake.EnqueueLoad, fake.EnqueueUnload, fake.DrainCompletions, applied.Add, state, radius: 2); // Note: LoadedLandblock's actual fields are LandblockId, Heightmap, // Entities (positional record). Adjust if the first positional arg // name differs. var lb = new LoadedLandblock(0x32320FFEu, new LandBlock(), System.Array.Empty()); fake.Pending.Enqueue(new LandblockStreamResult.Loaded(0x32320FFEu, lb)); controller.Tick(50, 50); Assert.Single(applied); Assert.True(state.IsLoaded(0x32320FFEu)); } [Fact] public void DrainingUnloadedResult_RemovesFromState() { var state = new GpuWorldState(); var fake = new FakeStreamer(); var controller = new StreamingController( fake.EnqueueLoad, fake.EnqueueUnload, fake.DrainCompletions, _ => { }, state, radius: 2); var lb = new LoadedLandblock(0x32320FFEu, new LandBlock(), System.Array.Empty()); state.AddLandblock(lb); fake.Pending.Enqueue(new LandblockStreamResult.Unloaded(0x32320FFEu)); controller.Tick(50, 50); Assert.False(state.IsLoaded(0x32320FFEu)); } }