using System.Reflection; using AcDream.App.Physics; using AcDream.App.Rendering; using AcDream.App.Rendering.Scene; using AcDream.App.Rendering.Vfx; using AcDream.App.Rendering.Wb; using AcDream.App.Streaming; using AcDream.App.World; using AcDream.Runtime.Entities; namespace AcDream.App.Tests.World; public sealed class RuntimeEntityOwnershipTests { [Fact] public void LiveEntityRuntime_ComposesCanonicalRuntimeDirectory() { FieldInfo directory = typeof(LiveEntityRuntime).GetField( "_directory", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException("Missing canonical entity directory."); FieldInfo sidecars = typeof(LiveEntityRuntime).GetField( "_projections", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException("Missing App projection sidecar store."); Assert.Equal(typeof(RuntimeEntityDirectory), directory.FieldType); Assert.Equal(typeof(LiveEntityProjectionStore), sidecars.FieldType); } [Fact] public void AppProjectionOwners_UseExactRuntimeKeysAndNoGuidDictionary() { FieldInfo[] runtimeFields = typeof(LiveEntityRuntime).GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(runtimeFields, IsGuidDictionary); FieldInfo[] storeFields = typeof(LiveEntityProjectionStore).GetFields( BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo[] exactStores = storeFields .Where(field => IsDictionaryWithKey(field, typeof(RuntimeEntityKey))) .ToArray(); Assert.NotEmpty(exactStores); Assert.All( exactStores, field => Assert.Equal( typeof(LiveEntityRecord), field.FieldType.GetGenericArguments()[1])); Assert.DoesNotContain(storeFields, IsGuidDictionary); } [Fact] public void MaterializedPresentationWorksets_AreExactKeyed() { AssertExactKeyFields( typeof(LiveEntityPresentationController), "_readyOwners", "_suspendedShadowOwners", "_activePlacementOwners"); AssertExactKeyFields(typeof(RemoteTeleportController), "_pending"); AssertExactKeyFields(typeof(LiveRenderProjectionJournal), "_byKey"); AssertExactKeyFields( typeof(EntityEffectController), "_liveProfiles", "_readyLiveOwners"); AssertExactKeyFields( typeof(LiveEntityLightController), "_trackedOwners", "_presentOwners"); AssertExactKeyFields( typeof(EquippedChildRenderController), "_attachedByChild", "_pendingUnparentByChild", "_pendingOrdinaryRemovalByRoot", "_pendingDetachedRemovalByChild", "_pendingReparentRemovalByChild", "_pendingPoseLossRemovalByChild", "_pendingOrphanRemovalByChild"); AssertExactKeyFields(typeof(LiveEntityAnimationScheduler), "_schedules"); AssertExactKeyFields(typeof(EntitySpawnAdapter), "_ownersByKey"); AssertExactKeyFields( typeof(LiveEntityLivenessTracker), "_deadlines", "_present"); AssertExactKeyFields( typeof(RemoteMovementObservationTracker), "_lastMove"); AssertExactKeyFields( typeof(GpuWorldState), "_liveProjectionByKey", "_visibleLiveProjectionCounts", "_visibilityBeforeMutation"); } [Fact] public void AppAssembly_HasNoGuidKeyedLiveEntityRecordDictionary() { FieldInfo[] forbidden = typeof(LiveEntityRuntime).Assembly .GetTypes() .SelectMany(type => type.GetFields( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) .Where(field => IsDictionaryWithKey(field, typeof(uint)) && field.FieldType.GetGenericArguments()[1] == typeof(LiveEntityRecord)) .ToArray(); Assert.Empty(forbidden); } [Fact] public void ExactOwners_HaveNoRetainedGuidIndex() { Type[] exactOwnerTypes = [ typeof(LiveEntityProjectionStore), typeof(LiveEntityPresentationController), typeof(RemoteTeleportController), typeof(LiveRenderProjectionJournal), typeof(LiveEntityLightController), typeof(EquippedChildRenderController), typeof(LiveEntityAnimationScheduler), typeof(EntitySpawnAdapter), typeof(LiveEntityLivenessTracker), typeof(RemoteMovementObservationTracker), ]; FieldInfo[] forbidden = exactOwnerTypes .SelectMany(type => type.GetFields( BindingFlags.Instance | BindingFlags.NonPublic)) .Where(field => field.Name.Contains("Guid", StringComparison.OrdinalIgnoreCase)) .ToArray(); Assert.Empty(forbidden); } [Fact] public void CanonicalRuntimeRecord_HasNoProjectionOrBackendSurface() { string[] forbiddenPropertyNames = [ "WorldEntity", "AnimationRuntime", "RemoteMotionRuntime", "ProjectileRuntime", "EffectProfile", "ResourcesRegistered", "IsSpatiallyProjected", "IsSpatiallyVisible", ]; PropertyInfo[] properties = typeof(RuntimeEntityRecord).GetProperties( BindingFlags.Instance | BindingFlags.Public); Assert.DoesNotContain( properties, property => forbiddenPropertyNames.Contains( property.Name, StringComparer.Ordinal)); Assert.DoesNotContain( properties, property => IsPresentationType(property.PropertyType)); } private static bool IsPresentationType(Type type) { string? ns = type.Namespace; return ns?.StartsWith("AcDream.App", StringComparison.Ordinal) == true || ns?.StartsWith("AcDream.UI", StringComparison.Ordinal) == true || ns?.StartsWith("Silk.NET", StringComparison.Ordinal) == true || ns?.StartsWith("ImGuiNET", StringComparison.Ordinal) == true; } private static bool IsGuidDictionary(FieldInfo field) => IsDictionaryWithKey(field, typeof(uint)); private static void AssertExactKeyFields( Type owner, params string[] fieldNames) { foreach (string fieldName in fieldNames) { FieldInfo field = owner.GetField( fieldName, BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException( $"{owner.Name}.{fieldName} is missing."); Assert.True( IsCollectionWithKey(field, typeof(RuntimeEntityKey)), $"{owner.Name}.{fieldName} must be keyed by RuntimeEntityKey, " + $"but was {field.FieldType}."); } } private static bool IsCollectionWithKey(FieldInfo field, Type keyType) { if (!field.FieldType.IsGenericType) return false; Type generic = field.FieldType.GetGenericTypeDefinition(); return (generic == typeof(Dictionary<,>) || generic == typeof(HashSet<>)) && field.FieldType.GetGenericArguments()[0] == keyType; } private static bool IsDictionaryWithKey(FieldInfo field, Type keyType) => field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>) && field.FieldType.GetGenericArguments()[0] == keyType; }