#if !UNITY_DOTSPLAYER using UnityEngine; using NUnit.Framework; using System; using Unity.Burst; using Unity.Collections; using Unity.Jobs; using Unity.Entities; using Unity.Entities.Tests; using Unity.Collections.LowLevel.Unsafe; using Assert = NUnit.Framework.Assert; public class BlobTests : ECSTestsFixture { //@TODO: Test Prevent NativeArray and other containers inside of Blob data //@TODO: Test Prevent BlobPtr, BlobArray onto job struct //@TODO: Various tests trying to break the Allocator. eg. mix multiple BlobAllocator in the same BlobRoot... struct MyData { public BlobArray<float> floatArray; public BlobPtr<float> nullPtr; public BlobPtr<Vector3> oneVector3; public float embeddedFloat; public BlobArray<BlobArray<int>> nestedArray; public BlobString str; public BlobString emptyStr; } static unsafe BlobAssetReference<MyData> ConstructBlobData() { var builder = new BlobBuilder(Allocator.Temp); ref var root = ref builder.ConstructRoot<MyData>(); var floatArray = builder.Allocate(ref root.floatArray, 3); ref Vector3 oneVector3 = ref builder.Allocate(ref root.oneVector3); var nestedArrays = builder.Allocate(ref root.nestedArray, 2); var nestedArray0 = builder.Allocate(ref nestedArrays[0], 1); var nestedArray1 = builder.Allocate(ref nestedArrays[1], 2); builder.AllocateString(ref root.str, "Blah"); builder.AllocateString(ref root.emptyStr, ""); nestedArray0[0] = 0; nestedArray1[0] = 1; nestedArray1[1] = 2; floatArray[0] = 0; floatArray[1] = 1; floatArray[2] = 2; root.embeddedFloat = 4; oneVector3 = new Vector3(3, 3, 3); var blobAsset = builder.CreateBlobAssetReference<MyData>(Allocator.Persistent); builder.Dispose(); return blobAsset; } static void ValidateBlobData(ref MyData root) { // not using Assert.AreEqual here because the asserts have to execute in burst jobs if (3 != root.floatArray.Length) throw new AssertionException("ValidateBlobData didn‘t match"); if (0 != root.floatArray[0]) throw new AssertionException("ValidateBlobData didn‘t match"); if (1 != root.floatArray[1]) throw new AssertionException("ValidateBlobData didn‘t match"); if (2 != root.floatArray[2]) throw new AssertionException("ValidateBlobData didn‘t match"); if (new Vector3(3, 3, 3) != root.oneVector3.Value) throw new AssertionException("ValidateBlobData didn‘t match"); if (4 != root.embeddedFloat) throw new AssertionException("ValidateBlobData didn‘t match"); if (1 != root.nestedArray[0].Length) throw new AssertionException("ValidateBlobData didn‘t match"); if (2 != root.nestedArray[1].Length) throw new AssertionException("ValidateBlobData didn‘t match"); if (0 != root.nestedArray[0][0]) throw new AssertionException("ValidateBlobData didn‘t match"); if (1 != root.nestedArray[1][0]) throw new AssertionException("ValidateBlobData didn‘t match"); if (2 != root.nestedArray[1][1]) throw new AssertionException("ValidateBlobData didn‘t match"); ValidateBlobString(ref root); } [BurstDiscard] static void ValidateBlobString(ref MyData root) { var str = root.str.ToString(); if ("Blah" != str) throw new AssertionException("ValidateBlobData didn‘t match"); var emptyStr = root.emptyStr.ToString(); if ("" != emptyStr) throw new AssertionException("ValidateBlobData didn‘t match"); } static void ValidateBlobDataBurst(ref MyData root) { Assert.AreEqual(3, root.floatArray.Length); Assert.AreEqual(0, root.floatArray[0]); Assert.AreEqual(1, root.floatArray[1]); Assert.AreEqual(2, root.floatArray[2]); Assert.AreEqual(new Vector3(3, 3, 3), root.oneVector3.Value); Assert.AreEqual(4, root.embeddedFloat); Assert.AreEqual(1, root.nestedArray[0].Length); Assert.AreEqual(2, root.nestedArray[1].Length); Assert.AreEqual(0, root.nestedArray[0][0]); Assert.AreEqual(1, root.nestedArray[1][0]); Assert.AreEqual(2, root.nestedArray[1][1]); } [Test] public unsafe void CreateBlobData() { var blob = ConstructBlobData(); ValidateBlobData(ref blob.Value); blob.Dispose(); } [Test] public unsafe void BlobAccessAfterReleaseThrows() { var blob = ConstructBlobData(); var blobCopy = blob; blob.Dispose(); Assert.Throws<InvalidOperationException>(() => { blobCopy.GetUnsafePtr(); }); Assert.IsTrue(blob.GetUnsafePtr() == null); Assert.Throws<InvalidOperationException>(() => { var p = blobCopy.Value.embeddedFloat; }); Assert.Throws<InvalidOperationException>(() => { var p = blobCopy.Value.embeddedFloat; }); Assert.Throws<InvalidOperationException>(() => { blobCopy.Dispose(); }); Assert.Throws<InvalidOperationException>(() => { blob.Dispose(); }); } struct ComponentWithBlobData : IComponentData { public bool DidSucceed; public BlobAssetReference<MyData> blobAsset; } [BurstCompile(CompileSynchronously = true)] struct ConstructAccessAndDisposeBlobData : IJob { public void Execute() { var blobData = ConstructBlobData(); ValidateBlobData(ref blobData.Value); blobData.Dispose(); } } [Ignore("DisposeSentinel in NativeList prevents this. Fix should be in 19.3")] [Test] public void BurstedConstructionAndAccess() { new ConstructAccessAndDisposeBlobData().Schedule().Complete(); } [BurstCompile(CompileSynchronously = true)] struct AccessAndDisposeBlobDataBurst : IJobForEach<ComponentWithBlobData> { public void Execute(ref ComponentWithBlobData data) { ValidateBlobData(ref data.blobAsset.Value); data.blobAsset.Dispose(); data.DidSucceed = true; } } [Test] public void ReadAndDestroyBlobDataFromBurstJob() { var entities = CreateUniqueBlob(); new AccessAndDisposeBlobDataBurst().Schedule(EmptySystem).Complete(); foreach (var e in entities) { Assert.IsTrue(m_Manager.GetComponentData<ComponentWithBlobData>(e).DidSucceed); Assert.IsFalse(m_Manager.GetComponentData<ComponentWithBlobData>(e).blobAsset.IsCreated); } } struct ValidateBlobInComponentJob : IJobForEach<ComponentWithBlobData> { public bool ExpectException; public unsafe void Execute(ref ComponentWithBlobData component) { if (ExpectException) { var blobAsset = component.blobAsset; Assert.Throws<InvalidOperationException>(() => { blobAsset.GetUnsafePtr(); }); } else { ValidateBlobData(ref component.blobAsset.Value); } component.DidSucceed = true; } } [Test] public unsafe void ParallelBlobAccessFromEntityJob() { var blob = CreateSharedBlob(); var jobData = new ValidateBlobInComponentJob(); var jobHandle = jobData.Schedule(EmptySystem); ValidateBlobData(ref blob.Value); jobHandle.Complete(); blob.Dispose(); } [Test] public void DestroyedBlobAccessFromEntityJobThrows() { var blob = CreateSharedBlob(); blob.Dispose(); var jobData = new ValidateBlobInComponentJob(); jobData.ExpectException = true; jobData.Schedule(EmptySystem).Complete(); } [Test] public void BlobAssetReferenceIsComparable() { var blob1 = ConstructBlobData(); var blob2 = ConstructBlobData(); var blobNull = new BlobAssetReference<MyData>(); var temp1 = blob1; Assert.IsTrue(blob1 != blob2); Assert.IsTrue(blob1 != BlobAssetReference<MyData>.Null); Assert.IsTrue(blobNull == BlobAssetReference<MyData>.Null); Assert.IsTrue(blob1 == temp1); Assert.IsTrue(blob2 != temp1); blob1.Dispose(); blob2.Dispose(); } [Test] public void SourceBlobArrayThrowsOnIndex() { var builder = new BlobBuilder(Allocator.Temp); Assert.Throws<IndexOutOfRangeException>(() => { //can‘t access ref variable if it‘s created outside of the lambda ref var root = ref builder.ConstructRoot<MyData>(); builder.Allocate(ref root.floatArray, 3); // Throw on access expected here root.floatArray[0] = 7; }); builder.Dispose(); } [Test] public void BlobArrayToArrayCopiesResults() { var blob = ConstructBlobData(); ref MyData root = ref blob.Value; var floatArray = root.floatArray.ToArray(); Assert.AreEqual(new float[]{ 0, 1, 2 }, floatArray); blob.Dispose(); } [Test] public void SourceBlobPtrThrowsOnDereference() { var builder = new BlobBuilder(Allocator.Temp); Assert.Throws<InvalidOperationException>(() => { //can‘t access ref variable if it‘s created outside of the lambda ref var root = ref builder.ConstructRoot<MyData>(); builder.Allocate(ref root.oneVector3); // Throw on access expected here root.oneVector3.Value = Vector3.zero; }); builder.Dispose(); } struct AlignmentTest { public BlobPtr<short> shortPointer; public BlobPtr<int> intPointer; public BlobPtr<byte> bytePointer; public BlobArray<int> intArray; } static unsafe void AssertAlignment(void* p, int alignment) { ulong mask = (ulong) alignment - 1; Assert.IsTrue(((ulong) (IntPtr) p & mask) == 0); } [Test] public unsafe void BasicAlignmentWorks() { var builder = new BlobBuilder(Allocator.Temp); ref var root = ref builder.ConstructRoot<BlobArray<AlignmentTest>>(); Assert.AreEqual(4, UnsafeUtility.AlignOf<int>()); const int count = 100; var topLevelArray = builder.Allocate(ref root, count); for (int x = 0; x < count; ++x) { builder.Allocate(ref topLevelArray[x].shortPointer); builder.Allocate(ref topLevelArray[x].intPointer); builder.Allocate(ref topLevelArray[x].bytePointer); builder.Allocate(ref topLevelArray[x].intArray, x + 1); } var blob = builder.CreateBlobAssetReference<BlobArray<AlignmentTest>>(Allocator.Temp); builder.Dispose(); for (int x = 0; x < count; ++x) { AssertAlignment(blob.Value[x].shortPointer.GetUnsafePtr(), 2); AssertAlignment(blob.Value[x].intPointer.GetUnsafePtr(), 4); AssertAlignment(blob.Value[x].intArray.GetUnsafePtr(), 4); } blob.Dispose(); } [Test] public unsafe void CreatedBlobsAre16ByteAligned() { var blobAssetReference = BlobAssetReference<int>.Create(42); AssertAlignment(blobAssetReference.GetUnsafePtr(), 16); } [Test] public void BlobBuilderArrayThrowsOnOutOfBoundsIndex() { using (var builder = new BlobBuilder(Allocator.Temp, 128)) { Assert.Throws<IndexOutOfRangeException>(() => { ref var root = ref builder.ConstructRoot<BlobArray<int>>(); var array = builder.Allocate(ref root, 100); array[100] = 7; }); } } [Test] public void AllocationsLargerThanChunkSizeWorks() { var builder = new BlobBuilder(Allocator.Temp, 128); ref var root = ref builder.ConstructRoot<BlobArray<int>>(); const int count = 100; var array = builder.Allocate(ref root, count); for (int i = 0; i < count; i++) array[i] = i; var blob = builder.CreateBlobAssetReference<BlobArray<int>>(Allocator.Temp); builder.Dispose(); for (int i = 0; i < count; i++) Assert.AreEqual(i, blob.Value[i]); blob.Dispose(); } [Test] public void CreatingLargeBlobAssetWorks() { var builder = new BlobBuilder(Allocator.Temp, 512); ref var root = ref builder.ConstructRoot<BlobArray<BlobArray<BlobArray<BlobPtr<int>>>>>(); const int topLevelCount = 100; int expectedValue = 42; var level0 = builder.Allocate(ref root, topLevelCount); for (int x = 0; x < topLevelCount; x++) { var level1 = builder.Allocate(ref level0[x], x + 1); for (int y = 0; y < x + 1; y++) { var level2 = builder.Allocate(ref level1[y], y + 1); for (int z = 0; z < y + 1; z++) { ref var i = ref builder.Allocate(ref level2[z]); i = expectedValue++; } } } var blob = builder.CreateBlobAssetReference<BlobArray<BlobArray<BlobArray<BlobPtr<int>>>>>(Allocator.Temp); builder.Dispose(); expectedValue = 42; for (int x = 0; x < topLevelCount; x++) { for (int y = 0; y < x + 1; y++) { for (int z = 0; z < y + 1; z++) { int value = blob.Value[x][y][z].Value; if (expectedValue != value) Assert.AreEqual(expectedValue, value); expectedValue++; } } } blob.Dispose(); } public unsafe struct TestStruct256bytes { public BlobArray<int> intArray; public fixed int array[61]; public BlobPtr<int> intPointer; } [Test] public void BlobAssetWithRootLargerThanChunkSizeWorks() { Assert.AreEqual(256, UnsafeUtility.SizeOf<TestStruct256bytes>()); var builder = new BlobBuilder(Allocator.Temp, 128); ref var root = ref builder.ConstructRoot<TestStruct256bytes>(); var array = builder.Allocate(ref root.intArray, 100); for (int i = 0; i < array.Length; ++i) { array[i] = i; } builder.Allocate(ref root.intPointer); var blob = builder.CreateBlobAssetReference<TestStruct256bytes>(Allocator.Temp); builder.Dispose(); for (int i = 0; i < blob.Value.intArray.Length; ++i) { if (i != blob.Value.intArray[i]) Assert.AreEqual(i, blob.Value.intArray[i]); } blob.Dispose(); } BlobAssetReference<MyData> CreateSharedBlob() { var blob = ConstructBlobData(); for (int i = 0; i != 32; i++) { var entity = m_Manager.CreateEntity(); m_Manager.AddComponentData(entity, new ComponentWithBlobData() {blobAsset = blob}); } return blob; } NativeArray<Entity> CreateUniqueBlob() { var entities = new NativeArray<Entity>(32, Allocator.Temp); for (int i = 0; i != entities.Length; i++) { entities[i] = m_Manager.CreateEntity(); m_Manager.AddComponentData(entities[i], new ComponentWithBlobData() {blobAsset = ConstructBlobData()}); } return entities; } } #endif
原文:https://www.cnblogs.com/sifenkesi/p/12610079.html