// Tests for EnvCellRenderer (Phase A8, 2026-05-28). // These cover the pure data-handling portions of EnvCellRenderer. // The GL-dependent Render() and RenderModernMDIInternal() paths require a // GL context and are visual-verified at the render frame (Task 10). using System.Collections.Generic; using AcDream.App.Rendering.Wb; using Xunit; namespace AcDream.App.Tests.Rendering.Wb; public class EnvCellRendererTests { // ----------------------------------------------------------------------- // GetEnvCellGeomId — verbatim port of WB EnvCellRenderManager.cs:94-103 // ----------------------------------------------------------------------- [Fact] public void GetEnvCellGeomId_DedupBitSet() { var id = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, new List { 1, 2, 3 }); // Bit 33 (0x2_0000_0000) must be set — distinguishes dedup geom from per-cell ids. Assert.NotEqual(0UL, id & 0x2_0000_0000UL); } [Fact] public void GetEnvCellGeomId_Deterministic() { var s = new List { 1, 2, 3 }; var a = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, s); var b = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, s); Assert.Equal(a, b); } [Fact] public void GetEnvCellGeomId_DiffersByEnvironmentId() { var a = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, new List { 1 }); var b = EnvCellRenderer.GetEnvCellGeomId(0x43, 7, new List { 1 }); Assert.NotEqual(a, b); } [Fact] public void GetEnvCellGeomId_DiffersByCellStructure() { var a = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, new List { 1 }); var b = EnvCellRenderer.GetEnvCellGeomId(0x42, 8, new List { 1 }); Assert.NotEqual(a, b); } [Fact] public void GetEnvCellGeomId_DiffersBySurfaces() { var a = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, new List { 1 }); var b = EnvCellRenderer.GetEnvCellGeomId(0x42, 7, new List { 2 }); Assert.NotEqual(a, b); } // ----------------------------------------------------------------------- // Constructor — pure data, no GL // ----------------------------------------------------------------------- [Fact] public void NewRenderer_NeedsPrepareIsTrue() { // GL and meshManager are null — only valid for pure-data tests (no // Initialize() is called, so no GL calls are made). var r = new EnvCellRenderer(gl: null!, meshManager: null!, frustum: new WbFrustum()); Assert.True(r.NeedsPrepare); } [Fact] public void NewRenderer_NotDisposed() { var r = new EnvCellRenderer(gl: null!, meshManager: null!, frustum: new WbFrustum()); Assert.False(r.IsDisposed); } // ----------------------------------------------------------------------- // RemoveLandblock — pure data path // ----------------------------------------------------------------------- [Fact] public void RemoveLandblock_NonExistent_DoesNotThrow() { var r = new EnvCellRenderer(gl: null!, meshManager: null!, frustum: new WbFrustum()); // Should silently no-op. r.RemoveLandblock(0xA9B40000u); Assert.True(r.NeedsPrepare); } // ----------------------------------------------------------------------- // GetEnvCellGeomId — additional edge cases // ----------------------------------------------------------------------- [Fact] public void GetEnvCellGeomId_EmptySurfaces_Deterministic() { var a = EnvCellRenderer.GetEnvCellGeomId(1, 0, new List()); var b = EnvCellRenderer.GetEnvCellGeomId(1, 0, new List()); Assert.Equal(a, b); Assert.NotEqual(0UL, a & 0x2_0000_0000UL); } [Fact] public void GetEnvCellGeomId_SurfaceOrderMatters() { var a = EnvCellRenderer.GetEnvCellGeomId(1, 1, new List { 10, 20 }); var b = EnvCellRenderer.GetEnvCellGeomId(1, 1, new List { 20, 10 }); // The hash is order-sensitive (matches WB's foreach loop), so // swapped order should produce a different id. Assert.NotEqual(a, b); } // (Render() requires a GL context — visual-verified in Task 10.) }