initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a7f04e028569f74e86bd76972ff7b2a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.TestTools.Constraints;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class AsyncOperationHandleTests
|
||||
{
|
||||
class FakeTypedOperation : AsyncOperationBase<GameObject>
|
||||
{
|
||||
public FakeTypedOperation()
|
||||
{
|
||||
m_RM = new ResourceManager();
|
||||
m_RM.postProfilerEvents = true;
|
||||
}
|
||||
|
||||
public object GetResultAsObject()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void IncreaseRefCount(AsyncOperationHandle handle, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
handle.Acquire();
|
||||
}
|
||||
|
||||
void IncreaseRefCount<TObject>(AsyncOperationHandle<TObject> handle, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
handle.Acquire();
|
||||
}
|
||||
|
||||
int DestructiveGetRefCount(AsyncOperationHandle handle)
|
||||
{
|
||||
int count = 0;
|
||||
while (handle.IsValid())
|
||||
{
|
||||
count++;
|
||||
var copy = handle;
|
||||
copy.Release();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int DestructiveGetRefCount<TObject>(AsyncOperationHandle<TObject> handle)
|
||||
{
|
||||
int count = 0;
|
||||
while (handle.IsValid())
|
||||
{
|
||||
count++;
|
||||
var copy = handle;
|
||||
copy.Release();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_ConvertToTyped_WithInvalidOpThrows()
|
||||
{
|
||||
var op = new FakeTypedOperation();
|
||||
AsyncOperationHandle handle = new AsyncOperationHandle(op);
|
||||
AsyncOperationHandle handle2 = new AsyncOperationHandle(op);
|
||||
handle2.Release();
|
||||
|
||||
Assert.Throws<Exception>(() => { handle.Convert<GameObject>(); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_ConvertToTyped_WithValidOpSucceeds()
|
||||
{
|
||||
var op = new FakeTypedOperation();
|
||||
AsyncOperationHandle handle = new AsyncOperationHandle(op);
|
||||
|
||||
AsyncOperationHandle<GameObject> typedHandle = handle.Convert<GameObject>();
|
||||
Assert.True(handle.IsValid());
|
||||
Assert.True(typedHandle.IsValid());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_ConvertToTypeless_MaintainsValidity()
|
||||
{
|
||||
var op = new FakeTypedOperation();
|
||||
AsyncOperationHandle<GameObject> typedHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
|
||||
//implicit conversion of valid op
|
||||
AsyncOperationHandle typelessHandle = (AsyncOperationHandle)typedHandle;
|
||||
|
||||
Assert.IsNotNull(typelessHandle);
|
||||
Assert.IsTrue(typedHandle.IsValid());
|
||||
Assert.IsTrue(typelessHandle.IsValid());
|
||||
|
||||
//make handle invalid
|
||||
AsyncOperationHandle<GameObject> typedHandle2 = new AsyncOperationHandle<GameObject>(op);
|
||||
typedHandle2.Release();
|
||||
|
||||
//implicit conversion of invalid op
|
||||
AsyncOperationHandle invalidHandle = (AsyncOperationHandle)typedHandle;
|
||||
|
||||
Assert.IsNotNull(invalidHandle);
|
||||
Assert.IsFalse(invalidHandle.IsValid());
|
||||
Assert.IsFalse(typedHandle.IsValid());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_Release_DecrementsRefCount()
|
||||
{
|
||||
int expectedCount = 10;
|
||||
var op = new FakeTypedOperation();
|
||||
|
||||
AsyncOperationHandle<GameObject> typedHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
AsyncOperationHandle<GameObject> validationHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
IncreaseRefCount(typedHandle, expectedCount - 1);
|
||||
|
||||
typedHandle.Release();
|
||||
expectedCount--;
|
||||
var actualRefCount = DestructiveGetRefCount(validationHandle);
|
||||
Assert.AreEqual(expectedCount, actualRefCount);
|
||||
|
||||
op = new FakeTypedOperation();
|
||||
|
||||
AsyncOperationHandle typelessHandle = new AsyncOperationHandle(op);
|
||||
AsyncOperationHandle typelessValidation = new AsyncOperationHandle(op);
|
||||
IncreaseRefCount(typelessHandle, expectedCount - 1);
|
||||
typelessHandle.Release();
|
||||
expectedCount--;
|
||||
actualRefCount = DestructiveGetRefCount(typelessValidation);
|
||||
Assert.AreEqual(expectedCount, actualRefCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_ReleaseToZero_InvalidatesAllHandles()
|
||||
{
|
||||
var op = new FakeTypedOperation();
|
||||
AsyncOperationHandle<GameObject> typedHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
AsyncOperationHandle<GameObject> typedHandle2 = new AsyncOperationHandle<GameObject>(op);
|
||||
typedHandle.Release();
|
||||
Assert.IsFalse(typedHandle.IsValid());
|
||||
Assert.IsFalse(typedHandle2.IsValid());
|
||||
|
||||
op = new FakeTypedOperation();
|
||||
AsyncOperationHandle typelessHandle = new AsyncOperationHandle(op);
|
||||
AsyncOperationHandle typelessHandle2 = new AsyncOperationHandle(op);
|
||||
typelessHandle.Release();
|
||||
Assert.IsFalse(typelessHandle.IsValid());
|
||||
Assert.IsFalse(typelessHandle2.IsValid());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_ReleaseToNonZero_InvalidatesOnlyCurrentHandle()
|
||||
{
|
||||
var op = new FakeTypedOperation();
|
||||
AsyncOperationHandle<GameObject> typedHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
IncreaseRefCount(typedHandle, 1);
|
||||
AsyncOperationHandle<GameObject> typedHandle2 = new AsyncOperationHandle<GameObject>(op);
|
||||
typedHandle.Release();
|
||||
Assert.IsFalse(typedHandle.IsValid());
|
||||
Assert.IsTrue(typedHandle2.IsValid());
|
||||
|
||||
op = new FakeTypedOperation();
|
||||
AsyncOperationHandle typelessHandle = new AsyncOperationHandle(op);
|
||||
IncreaseRefCount(typelessHandle, 1);
|
||||
AsyncOperationHandle typelessHandle2 = new AsyncOperationHandle(op);
|
||||
typelessHandle.Release();
|
||||
Assert.IsFalse(typelessHandle.IsValid());
|
||||
Assert.IsTrue(typelessHandle2.IsValid());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_Acquire_IncrementsRefCount()
|
||||
{
|
||||
int expectedCount = 2;
|
||||
var op = new FakeTypedOperation();
|
||||
|
||||
AsyncOperationHandle<GameObject> typedHandle = new AsyncOperationHandle<GameObject>(op);
|
||||
var copyTyped = typedHandle.Acquire();
|
||||
Assert.True(copyTyped.IsValid());
|
||||
Assert.True(typedHandle.IsValid());
|
||||
int actualCount = DestructiveGetRefCount(typedHandle);
|
||||
Assert.AreEqual(expectedCount, actualCount);
|
||||
|
||||
|
||||
op = new FakeTypedOperation();
|
||||
AsyncOperationHandle typelessHandle = new AsyncOperationHandle(op);
|
||||
var copyTypeless = typelessHandle.Acquire();
|
||||
Assert.True(copyTypeless.IsValid());
|
||||
Assert.True(typelessHandle.IsValid());
|
||||
actualCount = DestructiveGetRefCount(typelessHandle);
|
||||
Assert.AreEqual(expectedCount, actualCount);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 68204acf7cb1bb74091cd6779c3da569
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,377 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Linq;
|
||||
using UnityEngine.Scripting;
|
||||
using UnityEngine.TestTools.Constraints;
|
||||
|
||||
[assembly: Preserve]
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class BaseOperationBehaviorTests
|
||||
{
|
||||
Action<AsyncOperationHandle, Exception> m_PrevHandler;
|
||||
ResourceManager m_RM;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTeardown()
|
||||
{
|
||||
ResourceManager.ExceptionHandler = m_PrevHandler;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_RM = new ResourceManager();
|
||||
m_RM.CallbackHooksEnabled = false; // default for tests. disabled callback hooks. we will call update manually
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.Zero(m_RM.OperationCacheCount);
|
||||
m_RM.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenReferenceCountReachesZero_DestroyCallbackInvoked()
|
||||
{
|
||||
var op = m_RM.CreateCompletedOperation<int>(1, string.Empty);
|
||||
int resultInDestroyCallback = 0;
|
||||
op.Destroyed += (x) => resultInDestroyCallback = x.Convert<int>().Result;
|
||||
op.Release();
|
||||
Assert.AreEqual(1, resultInDestroyCallback);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhileCompletedCallbackIsDeferredOnCompletedOperation_ReferenceCountIsHeld()
|
||||
{
|
||||
var op = m_RM.CreateCompletedOperation<int>(1, string.Empty);
|
||||
int refCount = op.ReferenceCount;
|
||||
bool completedCalled = false;
|
||||
op.Completed += (x) => completedCalled = true; // callback is deferred to next update
|
||||
Assert.AreEqual(refCount + 1, op.ReferenceCount);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(refCount, op.ReferenceCount);
|
||||
Assert.AreEqual(true, completedCalled);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenInDestroyCallback_IncrementAndDecrementReferenceCount_Throws()
|
||||
{
|
||||
var op = m_RM.CreateCompletedOperation<int>(1, string.Empty);
|
||||
int resultInDestroyCallback = 0;
|
||||
Exception onInc = null;
|
||||
Exception onDec = null;
|
||||
op.Destroyed += (x) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
x.Acquire();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
onInc = e;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
x.Release();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
onDec = e;
|
||||
}
|
||||
|
||||
resultInDestroyCallback = x.Convert<int>().Result;
|
||||
};
|
||||
op.Release();
|
||||
Assert.NotNull(onInc);
|
||||
Assert.NotNull(onDec);
|
||||
}
|
||||
|
||||
class MockOperation<T> : AsyncOperationBase<T>
|
||||
{
|
||||
public Action ExecuteCallback = () => { };
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
ExecuteCallback();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenOperationHasDependency_ExecuteNotCalledUntilDependencyCompletes()
|
||||
{
|
||||
var op1 = new MockOperation<int>();
|
||||
var op2 = new MockOperation<int>();
|
||||
var handle1 = m_RM.StartOperation(op1, default(AsyncOperationHandle));
|
||||
op2.ExecuteCallback = () => { op2.Complete(0, true, string.Empty); };
|
||||
var handle2 = m_RM.StartOperation(op2, handle1);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(false, handle2.IsDone);
|
||||
op1.Complete(0, true, null);
|
||||
Assert.AreEqual(true, handle2.IsDone);
|
||||
handle1.Release();
|
||||
handle2.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenOperationIsSuccessfulButHasErrorMsg_FailsSilently_CompletesButExceptionHandlerIsCalled()
|
||||
{
|
||||
bool exceptionHandlerCalled = false;
|
||||
ResourceManager.ExceptionHandler += (h, ex) => exceptionHandlerCalled = true;
|
||||
|
||||
var op = m_RM.CreateCompletedOperationInternal<int>(1, true, new Exception("An exception occured."));
|
||||
|
||||
var status = AsyncOperationStatus.None;
|
||||
op.Completed += (x) => status = x.Status;
|
||||
|
||||
// callbacks are deferred to next update
|
||||
m_RM.Update(0.0f);
|
||||
|
||||
Assert.AreEqual(true, exceptionHandlerCalled);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, status);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncOperationHandle_TaskIsDelayedUntilAfterDelayedCompletedCallbacks()
|
||||
{
|
||||
var op = m_RM.CreateCompletedOperationInternal<int>(1, true, null);
|
||||
|
||||
var status = AsyncOperationStatus.None;
|
||||
op.Completed += (x) => status = x.Status;
|
||||
var t = op.Task;
|
||||
Assert.IsFalse(t.IsCompleted);
|
||||
|
||||
// callbacks are deferred to next update
|
||||
m_RM.Update(0.0f);
|
||||
|
||||
// the Task may not yet have continues after at this point on the update,
|
||||
// give the Synchronization a little time with a yield
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(t.IsCompleted);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_TaskIsCompletedWhenHandleIsCompleteWithoutDelayedCallbacks()
|
||||
{
|
||||
var op = m_RM.CreateCompletedOperationInternal<int>(1, true, null);
|
||||
var t = op.Task;
|
||||
Assert.IsTrue(t.IsCompleted);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// public void WhenOperationHasDependency_AndDependencyFails_DependentOpStillExecutes()
|
||||
|
||||
// Bad derived class behavior
|
||||
// public void CustomOperation_WhenCompleteCalledBeforeStartOperation_ThrowsOperationDoesNotComplete
|
||||
// public void CustomOperation_WhenCompleteCalledMultipleTimes_Throws
|
||||
// public void CustomOperation_WhenProgressCallbackThrowsException_ErrorLoggedAndHandleReturnsZero
|
||||
// public void CustomOperation_WhenDestroyThrowsException_ErrorLogged
|
||||
// public void CustomOperation_WhenExecuteThrows_ErrorLoggedAndOperationSetAsFailed
|
||||
|
||||
// TEST: Per operation update behavior
|
||||
|
||||
// public void AsyncOperationHandle_WhenReleaseOnInvalidHandle_Throws
|
||||
// public void AsyncOperationHandle_WhenConvertToIncompatibleHandleType_Throws
|
||||
//
|
||||
|
||||
[Test]
|
||||
public void AsyncOperationHandle_EventSubscriptions_UnsubscribingToNonSubbedEventsShouldHaveNoEffect()
|
||||
{
|
||||
var op = new MockOperation<int>();
|
||||
var handle = m_RM.StartOperation(op, default(AsyncOperationHandle));
|
||||
|
||||
Assert.False(op.CompletedEventHasListeners);
|
||||
handle.Completed -= oph => { };
|
||||
Assert.False(op.CompletedEventHasListeners);
|
||||
|
||||
Assert.False(op.DestroyedEventHasListeners);
|
||||
handle.Destroyed -= oph => { };
|
||||
Assert.False(op.DestroyedEventHasListeners);
|
||||
|
||||
handle.Release();
|
||||
}
|
||||
|
||||
internal class ManualDownloadPercentCompleteOperation : AsyncOperationBase<IAssetBundleResource>
|
||||
{
|
||||
public long m_bytesDownloaded = 0;
|
||||
public long m_totalBytes = 1024;
|
||||
public bool m_IsDone = false;
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
}
|
||||
|
||||
public void CompleteNow()
|
||||
{
|
||||
m_bytesDownloaded = m_totalBytes;
|
||||
Complete(null, true, null);
|
||||
}
|
||||
|
||||
internal override DownloadStatus GetDownloadStatus(HashSet<object> visited)
|
||||
{
|
||||
return new DownloadStatus() {DownloadedBytes = m_bytesDownloaded, TotalBytes = m_totalBytes, IsDone = m_IsDone};
|
||||
}
|
||||
}
|
||||
|
||||
static void AssertExpectedDownloadStatus(DownloadStatus dls, long dl, long tot, float per)
|
||||
{
|
||||
Assert.AreEqual(dl, dls.DownloadedBytes);
|
||||
Assert.AreEqual(tot, dls.TotalBytes);
|
||||
Assert.AreEqual(per, dls.Percent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadStatusWithNoBytes_WithIsDoneFalse_Returns_PercentCompleteZero()
|
||||
{
|
||||
var dls = new DownloadStatus() {DownloadedBytes = 0, TotalBytes = 0, IsDone = false};
|
||||
Assert.AreEqual(0f, dls.Percent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadStatusWithNoBytes_WithIsDoneTrue_Returns_PercentCompleteOne()
|
||||
{
|
||||
var dls = new DownloadStatus() {DownloadedBytes = 0, TotalBytes = 0, IsDone = true};
|
||||
Assert.AreEqual(1f, dls.Percent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GroupOperation_WithOpsThatImplementGetDownloadStatus_ComputesExpectedDownloadPercentComplete()
|
||||
{
|
||||
var ops = new List<AsyncOperationHandle>();
|
||||
var mdpco = new List<ManualDownloadPercentCompleteOperation>();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var o = m_RM.CreateOperation<ManualDownloadPercentCompleteOperation>(typeof(ManualDownloadPercentCompleteOperation), 1, null, null);
|
||||
o.Start(m_RM, default, null);
|
||||
mdpco.Add(o);
|
||||
ops.Add(new AsyncOperationHandle(o));
|
||||
}
|
||||
|
||||
var gOp = m_RM.CreateGenericGroupOperation(ops, true);
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 0, 4096, 0);
|
||||
mdpco[0].m_bytesDownloaded = 512;
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 512, 4096, .125f);
|
||||
foreach (var o in mdpco)
|
||||
o.CompleteNow();
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 4096, 4096, 1f);
|
||||
m_RM.Release(gOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChainOperation_WithOpThatImplementGetDownloadStatus_ComputesExpectedDownloadPercentComplete()
|
||||
{
|
||||
var depOp = m_RM.CreateOperation<ManualDownloadPercentCompleteOperation>(typeof(ManualDownloadPercentCompleteOperation), 1, null, null);
|
||||
depOp.Start(m_RM, default, null);
|
||||
var chainOp = m_RM.CreateChainOperation<object>(new AsyncOperationHandle(depOp), s => m_RM.CreateCompletedOperationInternal<object>(null, true, null));
|
||||
|
||||
AssertExpectedDownloadStatus(chainOp.GetDownloadStatus(), 0, 1024, 0f);
|
||||
depOp.m_bytesDownloaded = 512;
|
||||
AssertExpectedDownloadStatus(chainOp.GetDownloadStatus(), 512, 1024, .5f);
|
||||
depOp.CompleteNow();
|
||||
m_RM.Update(.1f);
|
||||
Assert.IsTrue(chainOp.IsDone);
|
||||
AssertExpectedDownloadStatus(chainOp.GetDownloadStatus(), 1024, 1024, 1f);
|
||||
m_RM.Release(chainOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PercentComplete_ReturnsZero_WhenChainOperationHasNotBegun()
|
||||
{
|
||||
var baseOperation = m_RM.CreateChainOperation<AsyncOperationHandle>(
|
||||
new AsyncOperationHandle(new ManualPercentCompleteOperation(1f)),
|
||||
(obj) => { return new AsyncOperationHandle<AsyncOperationHandle>(); });
|
||||
|
||||
Assert.AreEqual(0, baseOperation.PercentComplete);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GroupOperation_WithDuplicateOpThatImplementGetDownloadStatus_DoesNotOverCountValues()
|
||||
{
|
||||
var ops = new List<AsyncOperationHandle>();
|
||||
var o = m_RM.CreateOperation<ManualDownloadPercentCompleteOperation>(typeof(ManualDownloadPercentCompleteOperation), 1, null, null);
|
||||
o.Start(m_RM, default, null);
|
||||
for (int i = 0; i < 4; i++)
|
||||
ops.Add(new AsyncOperationHandle(o));
|
||||
|
||||
var gOp = m_RM.CreateGenericGroupOperation(ops, true);
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 0, 1024, 0);
|
||||
o.m_bytesDownloaded = 512;
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 512, 1024, .5f);
|
||||
o.CompleteNow();
|
||||
AssertExpectedDownloadStatus(gOp.GetDownloadStatus(), 1024, 1024, 1f);
|
||||
m_RM.Release(gOp);
|
||||
}
|
||||
|
||||
class TestOp : AsyncOperationBase<int>
|
||||
{
|
||||
protected override void Execute()
|
||||
{
|
||||
InvokeCompletionEvent();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CompletionEvents_AreInvoked_InOrderAdded()
|
||||
{
|
||||
var op = new TestOp();
|
||||
int count = 0;
|
||||
op.Completed += o =>
|
||||
{
|
||||
Assert.AreEqual(0, count);
|
||||
count++;
|
||||
};
|
||||
op.CompletedTypeless += o =>
|
||||
{
|
||||
Assert.AreEqual(1, count);
|
||||
count++;
|
||||
};
|
||||
op.Completed += o =>
|
||||
{
|
||||
Assert.AreEqual(2, count);
|
||||
count++;
|
||||
};
|
||||
op.CompletedTypeless += o =>
|
||||
{
|
||||
Assert.AreEqual(3, count);
|
||||
count++;
|
||||
};
|
||||
op.Start(null, default, null);
|
||||
op.Complete(1, true, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenOperationIsReused_HasExecutedIsReset()
|
||||
{
|
||||
var op = new TestOp();
|
||||
op.Start(null, default, null);
|
||||
op.Complete(1, true, null);
|
||||
|
||||
Assert.IsTrue(op.HasExecuted);
|
||||
var dep = new AsyncOperationHandle(new TestOp());
|
||||
op.Start(null, dep, null);
|
||||
Assert.IsFalse(op.HasExecuted);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4f6ca99e013fe6c49bb6b98f8ec1897b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,46 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
public class ChainOperationTests
|
||||
{
|
||||
[Test]
|
||||
public void ChainOperationWithTypedDependency_DoesNotReturnInvalidDependencyHandles()
|
||||
{
|
||||
//Setup
|
||||
ChainOperation<object, object> chainOp = new ChainOperation<object, object>();
|
||||
AsyncOperationHandle<object> chainOpHandle = new AsyncOperationHandle<object>(new ProviderOperation<object>());
|
||||
chainOp.Init(chainOpHandle, null, false);
|
||||
|
||||
//Test
|
||||
List<AsyncOperationHandle> dependencies = new List<AsyncOperationHandle>();
|
||||
AsyncOperationHandle handle = new AsyncOperationHandle(chainOp);
|
||||
chainOpHandle.m_InternalOp.m_Version = 1;
|
||||
handle.GetDependencies(dependencies);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(0, dependencies.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChainOperationWithTypelessDependency_DoesNotReturnInvalidDependencyHandles()
|
||||
{
|
||||
//Setup
|
||||
ChainOperationTypelessDepedency<object> chainOp = new ChainOperationTypelessDepedency<object>();
|
||||
AsyncOperationHandle<object> chainOpHandle = new AsyncOperationHandle<object>(new ProviderOperation<object>());
|
||||
chainOp.Init(chainOpHandle, null, false);
|
||||
|
||||
//Test
|
||||
List<AsyncOperationHandle> dependencies = new List<AsyncOperationHandle>();
|
||||
AsyncOperationHandle handle = new AsyncOperationHandle(chainOp);
|
||||
chainOpHandle.m_InternalOp.m_Version = 1;
|
||||
handle.GetDependencies(dependencies);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(0, dependencies.Count);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b42ee6f5a38f94b4baafd3c426bee7f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,664 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
internal class ManualPercentCompleteOperation : AsyncOperationBase<GameObject>
|
||||
{
|
||||
public ManualPercentCompleteOperation(float percentComplete)
|
||||
{
|
||||
m_PercentComplete = percentComplete;
|
||||
}
|
||||
|
||||
public float m_PercentComplete;
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
Complete(new GameObject(), true, "");
|
||||
}
|
||||
|
||||
protected override float Progress => m_PercentComplete;
|
||||
}
|
||||
|
||||
public class ProviderOperationTests
|
||||
{
|
||||
MockProvider m_Provider;
|
||||
MockProvider m_Provider2;
|
||||
Action<AsyncOperationHandle, Exception> m_PrevHandler;
|
||||
ResourceManager m_RM;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTeardown()
|
||||
{
|
||||
ResourceManager.ExceptionHandler = m_PrevHandler;
|
||||
}
|
||||
|
||||
private void ProvideBasicCallback(ProvideHandle provideHandle)
|
||||
{
|
||||
provideHandle.Complete(provideHandle.Location.InternalId, true, null);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_RM = new ResourceManager();
|
||||
m_RM.CallbackHooksEnabled = false;
|
||||
m_RM.postProfilerEvents = true;
|
||||
|
||||
m_Provider = new MockProvider();
|
||||
m_Provider.ProvideCallback = ProvideBasicCallback;
|
||||
m_Provider2 = new MockProvider();
|
||||
m_Provider2._ProviderId = "MockId2";
|
||||
m_Provider2.ProvideCallback = ProvideBasicCallback;
|
||||
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
m_RM.ResourceProviders.Add(m_Provider2);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
m_RM.ResourceProviders.Remove(m_Provider);
|
||||
m_RM.ResourceProviders.Remove(m_Provider2);
|
||||
Assert.Zero(m_RM.OperationCacheCount);
|
||||
m_RM.Dispose();
|
||||
m_RM = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenDependency_ProvideCalledAfterDependencyFinishes()
|
||||
{
|
||||
ProvideHandle provideHandle = default(ProvideHandle);
|
||||
m_Provider2.ProvideCallback = x => { provideHandle = x; };
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.False(op.IsDone);
|
||||
provideHandle.Complete(2, true, null);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.True(op.IsDone);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnDestroyed_DepOpReleasedAndProviderReleased()
|
||||
{
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
ResourceLocationBase loc2 = new ResourceLocationBase("2", "2", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
var op1 = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(1, m_Provider2.ProvideLog.Count);
|
||||
var op2 = m_RM.ProvideResource<object>(loc2);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(1, m_Provider2.ProvideLog.Count);
|
||||
|
||||
Assert.AreEqual(2, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op1.Status);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op2.Status);
|
||||
|
||||
// decrement the first op. the second op should still be holding the dependency
|
||||
op1.Release();
|
||||
Assert.AreEqual(0, m_Provider2.ReleaseLog.Count);
|
||||
|
||||
// decrement the second op. the dependency should now have been released
|
||||
op2.Release();
|
||||
Assert.AreEqual(1, m_Provider2.ReleaseLog.Count);
|
||||
|
||||
Assert.AreEqual(2, m_Provider.ReleaseLog.Count);
|
||||
Assert.AreEqual(1, m_Provider2.ReleaseLog.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenDependentOpFails_ProvideIsNotCalled()
|
||||
{
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", "unknown provider", typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
op.Release();
|
||||
Assert.AreEqual(0, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(0, m_Provider.ReleaseLog.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenDependentOpFails_AndProviderSupportsFailedDependencies_OperationContinues()
|
||||
{
|
||||
m_Provider._BehaviourFlags = ProviderBehaviourFlags.CanProvideWithFailedDependencies;
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", "unknown provider", typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual("1", op.Result);
|
||||
op.Release();
|
||||
Assert.AreEqual(1, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(1, m_Provider.ReleaseLog.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderCompletesInsideProvideCall_CallbackIsNotDeferred()
|
||||
{
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
ProvideHandle depHandle = new ProvideHandle();
|
||||
m_Provider2.ProvideCallback = (x) => { depHandle = x; };
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
|
||||
bool callbackCalled = false;
|
||||
Assert.AreEqual(AsyncOperationStatus.None, op.Status);
|
||||
op.Completed += x => callbackCalled = true;
|
||||
|
||||
// mark dependency complete
|
||||
depHandle.Complete(1, true, null);
|
||||
Assert.IsTrue(callbackCalled);
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderCompletesOutsideProvideCall_CallbackIsImmediate()
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
ProvideHandle depHandle = new ProvideHandle();
|
||||
m_Provider.ProvideCallback = (x) => { depHandle = x; };
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
|
||||
bool callbackCalled = false;
|
||||
Assert.AreEqual(AsyncOperationStatus.None, op.Status);
|
||||
op.Completed += x => callbackCalled = true;
|
||||
|
||||
// mark dependency complete
|
||||
Assert.IsFalse(callbackCalled);
|
||||
depHandle.Complete(1, true, null);
|
||||
Assert.IsTrue(callbackCalled);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UsingProviderHandleWithInvalidVersion_ThrowsException()
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
ProvideHandle handle = new ProvideHandle();
|
||||
m_Provider.ProvideCallback = (x) => { handle = x; };
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
handle.Complete<object>(null, true, null);
|
||||
Assert.Catch(() => handle.Complete<object>(null, true, null), ProviderOperation<object>.kInvalidHandleMsg);
|
||||
Assert.Catch(() => handle.GetDependencies(new List<object>()), ProviderOperation<object>.kInvalidHandleMsg);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDependency_InsertsDependenciesIntoList()
|
||||
{
|
||||
List<object> deps = new List<object>();
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep1", "dep1", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase depLoc2 = new ResourceLocationBase("dep2", "dep2", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc, depLoc2);
|
||||
m_Provider.ProvideCallback = (handle) =>
|
||||
{
|
||||
handle.GetDependencies(deps);
|
||||
handle.Complete(0, true, null);
|
||||
};
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(deps[0], "dep1");
|
||||
Assert.AreEqual(deps[1], "dep2");
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProviderOperation_PercentComplete_DoesNotDecreaseAfterPercentCallbackIsSet()
|
||||
{
|
||||
var providerOp = new ProviderOperation<GameObject>();
|
||||
providerOp.m_DepOp = new AsyncOperationHandle<IList<AsyncOperationHandle>>();
|
||||
providerOp.m_DepOp.m_InternalOp = new ProviderOperation<IList<AsyncOperationHandle>>();
|
||||
providerOp.m_DepOp.m_InternalOp.Result = new List<AsyncOperationHandle>();
|
||||
providerOp.m_DepOp.m_InternalOp.Result.Add(new ManualPercentCompleteOperation(1.0f).Handle);
|
||||
|
||||
Assert.AreEqual(0.5f, providerOp.PercentComplete);
|
||||
|
||||
providerOp.SetProgressCallback(() => 0.5f);
|
||||
|
||||
Assert.AreEqual(0.75f, providerOp.PercentComplete);
|
||||
}
|
||||
|
||||
class Type1
|
||||
{
|
||||
}
|
||||
|
||||
class Type2
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderCallsComplete_AndTypeIsIncorrect_Throws()
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
Exception testException = null;
|
||||
m_Provider.ProvideCallback = (x) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
x.Complete(new Type2(), true, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
testException = e;
|
||||
}
|
||||
};
|
||||
var op = m_RM.ProvideResource<Type1>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.IsNotNull(testException);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.IsNull(op.Result);
|
||||
Assert.IsTrue(op.OperationException.Message.Contains("Provider of type"));
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderThrowsExceptionOnProvide_OperationFails()
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
m_Provider.ProvideCallback = (x) => { throw new Exception("I have failed"); };
|
||||
var op = m_RM.ProvideResource<Type1>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderThrowsExceptionInProgressCallback_ProgressReturnsZero()
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
ProvideHandle handle = new ProvideHandle();
|
||||
bool didThrow = false;
|
||||
m_Provider.ProvideCallback = (x) =>
|
||||
{
|
||||
handle = x;
|
||||
handle.SetProgressCallback(() =>
|
||||
{
|
||||
didThrow = true;
|
||||
throw new Exception("I have failed");
|
||||
});
|
||||
};
|
||||
var op = m_RM.ProvideResource<Type1>(loc);
|
||||
Assert.AreEqual(0.0f, op.PercentComplete);
|
||||
Assert.True(didThrow);
|
||||
handle.Complete<object>(null, true, null);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
public void ProvideWithoutSpecifiedType_UsesDefaultProviderType()
|
||||
{
|
||||
ResourceLocationBase depLoc = new ResourceLocationBase("dep", "dep", m_Provider2.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc);
|
||||
ProvideHandle handle = default(ProvideHandle);
|
||||
m_Provider2.ProvideCallback = (x) => { handle = x; };
|
||||
m_Provider2.DefaultType = typeof(Type2);
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
|
||||
Assert.AreEqual(typeof(Type2), handle.Type);
|
||||
handle.Complete(new Type2(), true, null);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
void ProviderCompleteTypeTest<TRequestType, TResultType>(TResultType result, string exceptionMessage)
|
||||
{
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
ProvideHandle handle = default(ProvideHandle);
|
||||
m_Provider.ProvideCallback = (x) => { handle = x; };
|
||||
var op = m_RM.ProvideResource<TRequestType>(loc);
|
||||
|
||||
if (string.IsNullOrEmpty(exceptionMessage))
|
||||
{
|
||||
handle.Complete(result, true, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: assert contents of exception
|
||||
Assert.Catch(() => handle.Complete(result, true, null));
|
||||
}
|
||||
|
||||
Assert.True(op.IsDone);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
class Type3 : Type2
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideHandle_CompleteWithExactType_Succeeds()
|
||||
{
|
||||
ProviderCompleteTypeTest<Type2, Type2>(new Type2(), null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideHandle_CompleteWithDerivedTypeAsResult_Succeeds()
|
||||
{
|
||||
ProviderCompleteTypeTest<Type2, Type3>(new Type3(), null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideHandle_CompleteWithBaseTypeAsResult_Succeeds()
|
||||
{
|
||||
ProviderCompleteTypeTest<Type3, Type2>(new Type3(), null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideHandle_CompleteWithNullForReferencedType_Succeeds()
|
||||
{
|
||||
ProviderCompleteTypeTest<Type1, Type1>(null, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideHandle_CompleteWithNonAssignableType_Throws()
|
||||
{
|
||||
ProviderCompleteTypeTest<Type2, Type1>(new Type1(), "Failed");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_WhenDependencyFailsToLoad_AndProviderCannotLoadWithFailedDependencies_ProvideNotCalled()
|
||||
{
|
||||
m_Provider.ProvideCallback = (pi) => { throw new Exception("This Should Not Have Been Called"); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
ResourceLocationBase locDep = new ResourceLocationBase("depasset", "depasset", "unkonwn", typeof(object));
|
||||
ResourceLocationBase locRoot = new ResourceLocationBase("rootasset", "rootasset", m_Provider.ProviderId, typeof(object), locDep);
|
||||
AsyncOperationHandle<object> op = m_RM.ProvideResource<object>(locRoot);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_WhenDependencyFailsToLoad_AndProviderCanLoadWithFailedDependencies_ProviderStillProvides()
|
||||
{
|
||||
m_Provider._BehaviourFlags = ProviderBehaviourFlags.CanProvideWithFailedDependencies;
|
||||
m_Provider.ProvideCallback = (pi) => { pi.Complete(5, true, null); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
ResourceLocationBase locDep = new ResourceLocationBase("depasset", "depasset", "unkonwn", typeof(object));
|
||||
ResourceLocationBase locRoot = new ResourceLocationBase("rootasset", "rootasset", m_Provider.ProviderId, typeof(object), locDep);
|
||||
AsyncOperationHandle<object> op = m_RM.ProvideResource<object>(locRoot);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(5, op.Result);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_ReceiveDiagnosticsCallback_IGenericProviderOperationHasLocation()
|
||||
{
|
||||
m_Provider.ProvideCallback = (pi) => { pi.Complete(int.Parse(pi.Location.InternalId), true, null); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
List<ResourceManager.DiagnosticEventContext> eventsRecieved = new List<ResourceManager.DiagnosticEventContext>();
|
||||
m_RM.RegisterDiagnosticCallback(ctx => { eventsRecieved.Add(ctx); });
|
||||
|
||||
var locations = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
AsyncOperationHandle<object> op = m_RM.ProvideResource<object>(locations);
|
||||
|
||||
m_RM.Update(0.0f);
|
||||
m_RM.ClearDiagnosticCallbacks();
|
||||
|
||||
for (int i = 0; i < eventsRecieved.Count; ++i)
|
||||
{
|
||||
if (eventsRecieved[i].OperationHandle.m_InternalOp is IGenericProviderOperation)
|
||||
{
|
||||
Assert.NotNull(eventsRecieved[i].Location);
|
||||
Assert.IsTrue(eventsRecieved[i].Location.InternalId == "1");
|
||||
}
|
||||
}
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_ReceiveDiagnosticsCallback_CreateAndComplete()
|
||||
{
|
||||
m_Provider.ProvideCallback = (pi) => { pi.Complete(int.Parse(pi.Location.InternalId), true, null); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
List<ResourceManager.DiagnosticEventContext> eventsRecieved = new List<ResourceManager.DiagnosticEventContext>();
|
||||
m_RM.RegisterDiagnosticCallback(ctx => { eventsRecieved.Add(ctx); });
|
||||
|
||||
var locations = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
AsyncOperationHandle<object> op = m_RM.ProvideResource<object>(locations);
|
||||
|
||||
m_RM.Update(0.0f);
|
||||
m_RM.ClearDiagnosticCallbacks();
|
||||
|
||||
bool created = false;
|
||||
bool completed = false;
|
||||
for (int i = 0; i < eventsRecieved.Count; ++i)
|
||||
{
|
||||
if (eventsRecieved[i].Type == ResourceManager.DiagnosticEventType.AsyncOperationCreate)
|
||||
{
|
||||
Assert.NotNull(eventsRecieved[i].Location);
|
||||
Assert.IsTrue(eventsRecieved[i].Location.InternalId == "1");
|
||||
Assert.IsFalse(completed);
|
||||
Assert.IsFalse(created);
|
||||
created = true;
|
||||
}
|
||||
else if (eventsRecieved[i].Type == ResourceManager.DiagnosticEventType.AsyncOperationComplete)
|
||||
{
|
||||
Assert.NotNull(eventsRecieved[i].Location);
|
||||
Assert.True(eventsRecieved[i].Location.InternalId == "1");
|
||||
Assert.IsFalse(completed);
|
||||
Assert.IsTrue(created);
|
||||
completed = true;
|
||||
}
|
||||
else if (eventsRecieved[i].Type == ResourceManager.DiagnosticEventType.AsyncOperationDestroy)
|
||||
{
|
||||
Assert.NotNull(eventsRecieved[i].Location);
|
||||
Assert.True(eventsRecieved[i].Location.InternalId == "1");
|
||||
Assert.IsTrue(completed);
|
||||
Assert.IsTrue(created);
|
||||
}
|
||||
}
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_ReceiveDiagnosticsCallback_MultipleCallbacks()
|
||||
{
|
||||
m_Provider.ProvideCallback = (pi) => { pi.Complete(int.Parse(pi.Location.InternalId), true, null); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
|
||||
bool callback1 = false, callback2 = false;
|
||||
m_RM.RegisterDiagnosticCallback(ctx => { callback1 = true; });
|
||||
m_RM.RegisterDiagnosticCallback(ctx => { callback2 = true; });
|
||||
|
||||
var locations = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object));
|
||||
AsyncOperationHandle<object> op = m_RM.ProvideResource<object>(locations);
|
||||
|
||||
m_RM.Update(0.0f);
|
||||
m_RM.ClearDiagnosticCallbacks();
|
||||
|
||||
Assert.IsTrue(callback1);
|
||||
Assert.IsTrue(callback2);
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_CanLoadAndUnloadMultipleResources()
|
||||
{
|
||||
m_Provider.ProvideCallback = (pi) => { pi.Complete(int.Parse(pi.Location.InternalId), true, null); };
|
||||
m_RM.ResourceProviders.Add(m_Provider);
|
||||
var locations = new List<IResourceLocation>()
|
||||
{
|
||||
new ResourceLocationBase("0", "0", m_Provider.ProviderId, typeof(object)),
|
||||
new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object)),
|
||||
};
|
||||
AsyncOperationHandle<IList<object>> op = m_RM.ProvideResources<object>(locations);
|
||||
m_RM.Update(0.0f);
|
||||
for (int i = 0; i < locations.Count; i++)
|
||||
{
|
||||
Assert.AreEqual((int)op.Result[i], i);
|
||||
}
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_CanLoadNestedDepdendencies()
|
||||
{
|
||||
m_Provider._BehaviourFlags = ProviderBehaviourFlags.CanProvideWithFailedDependencies;
|
||||
List<IResourceLocation> loadOrder = new List<IResourceLocation>();
|
||||
m_Provider.ProvideCallback = (pi) =>
|
||||
{
|
||||
loadOrder.Add(pi.Location);
|
||||
pi.Complete(0, true, null);
|
||||
};
|
||||
IResourceLocation i3 = new ResourceLocationBase("3", "3", m_Provider.ProviderId, typeof(object));
|
||||
IResourceLocation i2 = new ResourceLocationBase("2", "2", m_Provider.ProviderId, typeof(object), i3);
|
||||
IResourceLocation i1 = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), i2);
|
||||
var op = m_RM.ProvideResource<object>(i1);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(5, m_RM.OperationCacheCount);
|
||||
Assert.AreSame(i3, loadOrder[0]);
|
||||
Assert.AreSame(i2, loadOrder[1]);
|
||||
Assert.AreSame(i1, loadOrder[2]);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResource_WhenSomeDependenciesFail_SuccessfulDependenciesRelease()
|
||||
{
|
||||
ResourceLocationBase depLoc1 = new ResourceLocationBase("dep1", "dep1", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2 = new ResourceLocationBase("dep2", "dep2", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc1, depLoc2);
|
||||
|
||||
var op = m_RM.ProvideResource<object>(loc);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(1, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(1, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNull(op.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_PartialSuccess_AllowsForSomeFailures()
|
||||
{
|
||||
ResourceLocationBase loc_a = new ResourceLocationBase("dep1", "dep1", "unknown provider", typeof(object));
|
||||
ResourceLocationBase loc_b = new ResourceLocationBase("dep2", "dep2", m_Provider.ProviderId, typeof(object));
|
||||
|
||||
var op = m_RM.ProvideResources<object>(
|
||||
new List<IResourceLocation> {loc_a, loc_b},
|
||||
false,
|
||||
null);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(1, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(0, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(2, op.Result.Count);
|
||||
Assert.IsNull(op.Result[0]);
|
||||
Assert.AreEqual("dep2", op.Result[1]);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_ReleaseDependenciesOnFailure_DoesApplyToLocationDependencies()
|
||||
{
|
||||
ResourceLocationBase depLoc1a = new ResourceLocationBase("dep1a", "dep1a", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2a = new ResourceLocationBase("dep2a", "dep2a", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_a = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc1a, depLoc2a);
|
||||
ResourceLocationBase depLoc1b = new ResourceLocationBase("dep1b", "dep1b", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2b = new ResourceLocationBase("dep2b", "dep2b", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_b = new ResourceLocationBase("2", "2", m_Provider.ProviderId, typeof(object), depLoc1b, depLoc2b);
|
||||
|
||||
var op = m_RM.ProvideResources<object>(new List<IResourceLocation> {loc_a, loc_b}, true, null);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(2, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(2, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNull(op.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_DoNotReleaseDependenciesOnFailure_DoesApplyToLocationDependencies()
|
||||
{
|
||||
ResourceLocationBase depLoc1a = new ResourceLocationBase("dep1a", "dep1a", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2a = new ResourceLocationBase("dep2a", "dep2a", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_a = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc1a, depLoc2a);
|
||||
ResourceLocationBase depLoc1b = new ResourceLocationBase("dep1b", "dep1b", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2b = new ResourceLocationBase("dep2b", "dep2b", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_b = new ResourceLocationBase("2", "2", m_Provider.ProviderId, typeof(object), depLoc1b, depLoc2b);
|
||||
|
||||
var op = m_RM.ProvideResources<object>(new List<IResourceLocation> {loc_a, loc_b}, false, null);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(2, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(0, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNull(op.Result);
|
||||
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_DoNotReleaseDependenciesOnFailure_ReleaseAllLocationsAfterCallingRelease()
|
||||
{
|
||||
ResourceLocationBase depLoc1a = new ResourceLocationBase("dep1a", "dep1a", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2a = new ResourceLocationBase("dep2a", "dep2a", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_a = new ResourceLocationBase("1", "1", m_Provider.ProviderId, typeof(object), depLoc1a, depLoc2a);
|
||||
ResourceLocationBase depLoc1b = new ResourceLocationBase("dep1b", "dep1b", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2b = new ResourceLocationBase("dep2b", "dep2b", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_b = new ResourceLocationBase("2", "2", m_Provider.ProviderId, typeof(object), depLoc1b, depLoc2b);
|
||||
|
||||
var op = m_RM.ProvideResources<object>(new List<IResourceLocation> {loc_a, loc_b}, false, null);
|
||||
m_RM.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(2, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(0, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNull(op.Result);
|
||||
|
||||
op.Release();
|
||||
|
||||
Assert.AreEqual(2, m_Provider.ReleaseLog.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvideResources_ReleaseDependenciesOnFailure_DoesNotOverReleaseAfterCallingRelease()
|
||||
{
|
||||
ResourceLocationBase depLoc1a = new ResourceLocationBase("dep1a", "dep1a", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2a = new ResourceLocationBase("dep2a", "dep2a", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_a = new ResourceLocationBase("loc_a", "1", m_Provider.ProviderId, typeof(object), depLoc1a, depLoc2a);
|
||||
ResourceLocationBase depLoc1b = new ResourceLocationBase("dep1b", "dep1b", "unknown provider", typeof(object));
|
||||
ResourceLocationBase depLoc2b = new ResourceLocationBase("dep2b", "dep2b", m_Provider.ProviderId, typeof(object));
|
||||
ResourceLocationBase loc_b = new ResourceLocationBase("loc_b", "2", m_Provider.ProviderId, typeof(object), depLoc1b, depLoc2b);
|
||||
ResourceLocationBase loc_shared = new ResourceLocationBase("loc_shared", "3", m_Provider.ProviderId, typeof(object), depLoc2a);
|
||||
|
||||
var op_shared = m_RM.ProvideResources<object>(new List<IResourceLocation> {loc_shared}, true, null);
|
||||
var op = m_RM.ProvideResources<object>(new List<IResourceLocation> {loc_a, loc_b}, true, null);
|
||||
m_RM.Update(0.0f);
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op_shared.Status);
|
||||
Assert.AreEqual(3, m_Provider.ProvideLog.Count);
|
||||
Assert.AreEqual(1, m_Provider.ReleaseLog.Count);
|
||||
Assert.IsNull(op.Result);
|
||||
op.Release();
|
||||
Assert.AreEqual(1, m_Provider.ReleaseLog.Count);
|
||||
op_shared.Release();
|
||||
Assert.AreEqual(3, m_Provider.ReleaseLog.Count);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d07c590681843734482b565ad928be3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,137 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class OperationsCacheTests
|
||||
{
|
||||
ResourceManager m_ResourceManager;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_ResourceManager = new ResourceManager();
|
||||
m_ResourceManager.CallbackHooksEnabled = false; // default for tests. disabled callback hooks. we will call update manually
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.Zero(m_ResourceManager.OperationCacheCount);
|
||||
m_ResourceManager.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OperationCache_CollisionsAreProperlyHandled()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
Assert.Zero(m_ResourceManager.OperationCacheCount);
|
||||
var provType = typeof(InstanceProvider);
|
||||
var loc1 = new TestResourceLocation("asset1", "asset1", provType.FullName, typeof(GameObject));
|
||||
var key1 = new LocationCacheKey(loc1, typeof(GameObject));
|
||||
var opType = typeof(TestOperation);
|
||||
m_ResourceManager.CreateOperation<TestOperation>(opType, opType.GetHashCode(), key1, null);
|
||||
|
||||
Assert.AreEqual(1, m_ResourceManager.CachedOperationCount());
|
||||
Assert.IsTrue(m_ResourceManager.IsOperationCached(key1));
|
||||
|
||||
var loc2 = new TestResourceLocation("asset2", "asset2", provType.FullName, typeof(GameObject));
|
||||
var key2 = new LocationCacheKey(loc2, typeof(GameObject));
|
||||
Assert.IsFalse(m_ResourceManager.IsOperationCached(key2));
|
||||
|
||||
Assert.IsTrue(m_ResourceManager.RemoveOperationFromCache(key1));
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
#endif
|
||||
}
|
||||
|
||||
class TestOperation : AsyncOperationBase<GameObject>, ICachable
|
||||
{
|
||||
protected override void Execute()
|
||||
{
|
||||
}
|
||||
|
||||
public IOperationCacheKey Key { get; set; }
|
||||
}
|
||||
|
||||
class TestResourceLocation : IResourceLocation
|
||||
{
|
||||
public TestResourceLocation(string name, string id, string providerId, Type t, params IResourceLocation[] dependencies)
|
||||
{
|
||||
PrimaryKey = name;
|
||||
InternalId = id;
|
||||
ProviderId = providerId;
|
||||
Dependencies = new List<IResourceLocation>(dependencies);
|
||||
ResourceType = t == null ? typeof(object) : t;
|
||||
}
|
||||
|
||||
public string InternalId { get; }
|
||||
public string ProviderId { get; }
|
||||
public IList<IResourceLocation> Dependencies { get; }
|
||||
|
||||
public int Hash(Type type)
|
||||
{
|
||||
// Returning a constant hashcode to force collisions.
|
||||
return 1337;
|
||||
}
|
||||
|
||||
public int DependencyHashCode => 0;
|
||||
public bool HasDependencies => Dependencies.Count > 0;
|
||||
public object Data { get; }
|
||||
public string PrimaryKey { get; }
|
||||
public Type ResourceType { get; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Locations_WithDiffNames_LocationEquals_Returns_True()
|
||||
{
|
||||
var l1 = new ResourceLocationBase("a", "b", "c", typeof(Mesh));
|
||||
var l2 = new ResourceLocationBase("x", "b", "c", typeof(Mesh));
|
||||
Assert.IsTrue(LocationUtils.LocationEquals(l1, l2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Locations_WithDiffIds_LocationEquals_Returns_False()
|
||||
{
|
||||
var l1 = new ResourceLocationBase("a", "b", "c", typeof(Mesh));
|
||||
var l2 = new ResourceLocationBase("a", "x", "c", typeof(Mesh));
|
||||
Assert.IsFalse(LocationUtils.LocationEquals(l1, l2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Locations_WithDiffProvider_LocationEquals_Returns_False()
|
||||
{
|
||||
var l1 = new ResourceLocationBase("a", "b", "c", typeof(Mesh));
|
||||
var l2 = new ResourceLocationBase("a", "b", "x", typeof(Mesh));
|
||||
Assert.IsFalse(LocationUtils.LocationEquals(l1, l2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Locations_WithDiffResourceTypes_LocationEquals_Returns_True()
|
||||
{
|
||||
var l1 = new ResourceLocationBase("a", "b", "c", typeof(Mesh));
|
||||
var l2 = new ResourceLocationBase("a", "b", "c", typeof(Material));
|
||||
Assert.IsFalse(LocationUtils.LocationEquals(l1, l2));
|
||||
}
|
||||
|
||||
class ResourceLocatonTestSub : ResourceLocationBase
|
||||
{
|
||||
public ResourceLocatonTestSub(string n, string id, string pr, Type t) : base(n, id, pr, t)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Locations_WithDiffTypes_LocationEquals_Returns_True()
|
||||
{
|
||||
var l1 = new ResourceLocationBase("a", "b", "c", typeof(Mesh));
|
||||
var l2 = new ResourceLocatonTestSub("a", "b", "c", typeof(Mesh));
|
||||
Assert.IsTrue(LocationUtils.LocationEquals(l1, l2));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1fd8a0466f984a08874b05c3243189f6
|
||||
timeCreated: 1620745004
|
|
@ -0,0 +1,249 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public abstract class ResourceManagerBaseTests
|
||||
{
|
||||
const int kAssetCount = 25;
|
||||
|
||||
protected string RootFolder
|
||||
{
|
||||
get { return string.Format("Assets/{0}_AssetsToDelete", GetType().Name); }
|
||||
}
|
||||
|
||||
List<IResourceLocation> m_Locations = new List<IResourceLocation>();
|
||||
|
||||
protected virtual string AssetPathPrefix
|
||||
{
|
||||
get { return ""; }
|
||||
}
|
||||
|
||||
protected abstract IResourceLocation[] SetupLocations(KeyValuePair<string, string>[] assets);
|
||||
|
||||
string GetAssetPath(int i)
|
||||
{
|
||||
return RootFolder + "/" + AssetPathPrefix + "asset" + i + ".prefab";
|
||||
}
|
||||
|
||||
protected ResourceManager m_ResourceManager;
|
||||
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void Cleanup()
|
||||
{
|
||||
m_ResourceManager.Dispose();
|
||||
#if UNITY_EDITOR
|
||||
AssetDatabase.DeleteAsset(RootFolder);
|
||||
#endif
|
||||
}
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_ResourceManager = new ResourceManager();
|
||||
#if UNITY_EDITOR
|
||||
AssetDatabase.StartAssetEditing();
|
||||
for (int i = 0; i < kAssetCount; i++)
|
||||
{
|
||||
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
go.name = "asset" + i;
|
||||
var assetPath = GetAssetPath(i);
|
||||
if (!Directory.Exists(Path.GetDirectoryName(assetPath)))
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(assetPath));
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(go, assetPath);
|
||||
|
||||
Object.DestroyImmediate(go, false);
|
||||
}
|
||||
|
||||
AssetDatabase.StopAssetEditing();
|
||||
#endif
|
||||
|
||||
var assetList = new List<KeyValuePair<string, string>>();
|
||||
for (int i = 0; i < kAssetCount; i++)
|
||||
assetList.Add(new KeyValuePair<string, string>("asset" + i, GetAssetPath(i)));
|
||||
|
||||
m_Locations.AddRange(SetupLocations(assetList.ToArray()));
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
Assert.Zero(m_ResourceManager.OperationCacheCount);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.Zero(m_ResourceManager.OperationCacheCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanProvideWithCallback()
|
||||
{
|
||||
GameObject[] goResult = new GameObject[] {null};
|
||||
bool[] wasCallbackCalled = new bool[] {false};
|
||||
var op = m_ResourceManager.ProvideResource<GameObject>(m_Locations[0]);
|
||||
op.Completed += (x) =>
|
||||
{
|
||||
wasCallbackCalled[0] = true;
|
||||
goResult[0] = x.Result;
|
||||
};
|
||||
yield return op;
|
||||
Assert.IsTrue(wasCallbackCalled[0]);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
private void Op_Completed(AsyncOperationHandle<GameObject> obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanProvideWithYield()
|
||||
{
|
||||
var op = m_ResourceManager.ProvideResource<GameObject>(m_Locations[0]);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanGetOperationFromCache()
|
||||
{
|
||||
AsyncOperationHandle<GameObject> op = m_ResourceManager.ProvideResource<GameObject>(m_Locations[0]);
|
||||
try
|
||||
{
|
||||
var cachedOp = m_ResourceManager.GetOperationFromCache(m_Locations[0], typeof(GameObject));
|
||||
Assert.IsNotNull(cachedOp);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(op.m_InternalOp, cachedOp);
|
||||
}
|
||||
finally
|
||||
{
|
||||
op.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanProvideMultipleResources()
|
||||
{
|
||||
AsyncOperationHandle<IList<GameObject>> op = m_ResourceManager.ProvideResources<GameObject>(m_Locations);
|
||||
yield return op;
|
||||
Assert.AreEqual(op.Result.Count, m_Locations.Count);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
class AsyncComponent : MonoBehaviour
|
||||
{
|
||||
public ResourceManager resourceManager;
|
||||
public IResourceLocation location;
|
||||
public GameObject result;
|
||||
public bool done = false;
|
||||
public AsyncOperationHandle<GameObject> operation;
|
||||
|
||||
async void Start()
|
||||
{
|
||||
operation = resourceManager.ProvideResource<GameObject>(location);
|
||||
await operation.Task;
|
||||
result = operation.Result;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncOperationHandle_Await_BlocksUntilCompletion()
|
||||
{
|
||||
var go = new GameObject("test", typeof(AsyncComponent));
|
||||
var comp = go.GetComponent<AsyncComponent>();
|
||||
comp.resourceManager = m_ResourceManager;
|
||||
comp.location = m_Locations[0];
|
||||
while (!comp.done)
|
||||
yield return null;
|
||||
Assert.IsNotNull(comp.result);
|
||||
comp.operation.Release();
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
|
||||
class AsyncAwaitMultipleComponent : MonoBehaviour
|
||||
{
|
||||
public ResourceManager resourceManager;
|
||||
public IResourceLocation location;
|
||||
public GameObject result;
|
||||
public bool done = false;
|
||||
public AsyncOperationHandle<GameObject> operation;
|
||||
public bool addCompletedCallback;
|
||||
public bool callbackDone = false;
|
||||
|
||||
async void Start()
|
||||
{
|
||||
operation = resourceManager.ProvideResource<GameObject>(location);
|
||||
if (addCompletedCallback)
|
||||
operation.Completed += handle => { callbackDone = true; };
|
||||
|
||||
await operation.Task;
|
||||
result = operation.Result;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAsyncOperationIsDone_TaskIsCompleted()
|
||||
{
|
||||
// Setup
|
||||
var go = new GameObject("test", typeof(AsyncAwaitMultipleComponent));
|
||||
var comp = go.GetComponent<AsyncAwaitMultipleComponent>();
|
||||
comp.resourceManager = m_ResourceManager;
|
||||
comp.location = m_Locations[0];
|
||||
|
||||
// Test
|
||||
while (!comp.done)
|
||||
yield return null;
|
||||
Assert.IsNotNull(comp.result);
|
||||
Assert.True(comp.operation.PercentComplete == 1 && comp.operation.IsDone);
|
||||
Assert.True(comp.operation.Task.IsCompleted);
|
||||
|
||||
// Cleanup
|
||||
comp.operation.Release();
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAsyncOperationIsDone_TasksAndCallbackIsCompleted()
|
||||
{
|
||||
// Setup
|
||||
var go = new GameObject("test", typeof(AsyncAwaitMultipleComponent));
|
||||
var comp = go.GetComponent<AsyncAwaitMultipleComponent>();
|
||||
comp.resourceManager = m_ResourceManager;
|
||||
comp.location = m_Locations[0];
|
||||
comp.addCompletedCallback = true;
|
||||
|
||||
// Test
|
||||
while (!comp.done)
|
||||
yield return null;
|
||||
Assert.IsNotNull(comp.result);
|
||||
Assert.True(comp.operation.PercentComplete == 1 && comp.operation.IsDone);
|
||||
Assert.True(comp.operation.Task.IsCompleted, "Task has not completed before component was done");
|
||||
Assert.True(comp.callbackDone, "Callback had not completed before component was done");
|
||||
|
||||
// Cleanup
|
||||
comp.operation.Release();
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: de4318cbbab37fa40bc08ac8c2f51a9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class ResourceManagerFastModeTests : ResourceManagerBaseTests
|
||||
{
|
||||
protected override IResourceLocation[] SetupLocations(KeyValuePair<string, string>[] assets)
|
||||
{
|
||||
IResourceLocation[] locs = new IResourceLocation[assets.Length];
|
||||
for (int i = 0; i < locs.Length; i++)
|
||||
locs[i] = CreateLocationForAsset(assets[i].Key, assets[i].Value);
|
||||
m_ResourceManager.ResourceProviders.Add(new AssetDatabaseProvider());
|
||||
return locs;
|
||||
}
|
||||
|
||||
IResourceLocation CreateLocationForAsset(string name, string path)
|
||||
{
|
||||
return new ResourceLocationBase(name, path, typeof(AssetDatabaseProvider).FullName, typeof(UnityEngine.Object));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6d71bdd364b36340962d0eb7f11980c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using System.IO;
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class ResourceManagerTestsLegacy : ResourceManagerBaseTests
|
||||
{
|
||||
protected override string AssetPathPrefix
|
||||
{
|
||||
get { return "Resources/"; }
|
||||
}
|
||||
|
||||
protected IResourceLocation CreateLocationForAsset(string name, string path)
|
||||
{
|
||||
return new ResourceLocationBase(name, Path.GetFileNameWithoutExtension(path), typeof(LegacyResourcesProvider).FullName, typeof(UnityEngine.Object));
|
||||
}
|
||||
|
||||
protected override IResourceLocation[] SetupLocations(KeyValuePair<string, string>[] assets)
|
||||
{
|
||||
IResourceLocation[] locs = new IResourceLocation[assets.Length];
|
||||
for (int i = 0; i < locs.Length; i++)
|
||||
locs[i] = CreateLocationForAsset(assets[i].Key, assets[i].Value);
|
||||
m_ResourceManager.ResourceProviders.Add(new LegacyResourcesProvider());
|
||||
return locs;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a6e1ac52851690b48bdf019059b98207
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class ResourceManagerPackedModeTests
|
||||
{
|
||||
//TODO: implement tests that create bundles
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bf2de0e8cc0a18b4d8887aad8e168377
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,452 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Linq;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.ResourceManagement.Exceptions;
|
||||
using UnityEngine.TestTools.Constraints;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class ResourceManagerTests
|
||||
{
|
||||
Action<AsyncOperationHandle, Exception> m_PrevHandler;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTeardown()
|
||||
{
|
||||
ResourceManager.ExceptionHandler = m_PrevHandler;
|
||||
}
|
||||
|
||||
ResourceManager m_ResourceManager;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
m_ResourceManager = new ResourceManager();
|
||||
m_ResourceManager.CallbackHooksEnabled = false; // default for tests. disabled callback hooks. we will call update manually
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.Zero(m_ResourceManager.OperationCacheCount);
|
||||
m_ResourceManager.Dispose();
|
||||
}
|
||||
|
||||
class TestUpdateReceiver : IUpdateReceiver
|
||||
{
|
||||
public bool invoked = false;
|
||||
|
||||
public void Update(float unscaledDeltaTime)
|
||||
{
|
||||
invoked = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenIUpdateReceiverAdded_CallbackIsInvoked()
|
||||
{
|
||||
var ur = new TestUpdateReceiver();
|
||||
m_ResourceManager.AddUpdateReceiver(ur);
|
||||
m_ResourceManager.Update(0);
|
||||
Assert.IsTrue(ur.invoked);
|
||||
m_ResourceManager.RemoveUpdateReciever(ur);
|
||||
ur.invoked = false;
|
||||
m_ResourceManager.Update(0);
|
||||
Assert.IsFalse(ur.invoked);
|
||||
}
|
||||
|
||||
class RMTestOp : AsyncOperationBase<object>
|
||||
{
|
||||
public int CompletedEventTriggeredCount = 0;
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
m_RM.RegisterForDeferredCallback(this);
|
||||
}
|
||||
|
||||
protected override bool InvokeWaitForCompletion()
|
||||
{
|
||||
m_RM.Update(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class RMTestUpdateReceiver : IUpdateReceiver
|
||||
{
|
||||
public int UpdateCount = 0;
|
||||
|
||||
public void Update(float unscaledDeltaTime)
|
||||
{
|
||||
UpdateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reentering_UpdateMethod_ThrowsException()
|
||||
{
|
||||
var op = new RMTestOp();
|
||||
op.Completed += o =>
|
||||
{
|
||||
(o.m_InternalOp as RMTestOp).CompletedEventTriggeredCount++;
|
||||
Assert.Throws<Exception>(() => o.WaitForCompletion());
|
||||
};
|
||||
var rec = new RMTestUpdateReceiver();
|
||||
m_ResourceManager.AddUpdateReceiver(rec);
|
||||
m_ResourceManager.StartOperation(op, default);
|
||||
op.WaitForCompletion();
|
||||
m_ResourceManager.RemoveUpdateReciever(rec);
|
||||
Assert.AreEqual(1, op.CompletedEventTriggeredCount);
|
||||
Assert.AreEqual(1, rec.UpdateCount);
|
||||
}
|
||||
|
||||
class TestUpdateReceiverThatRemovesSelfDuringUpdate : IUpdateReceiver
|
||||
{
|
||||
public ResourceManager rm;
|
||||
public bool removeSelf;
|
||||
public int updateCount = 0;
|
||||
|
||||
public void Update(float unscaledDeltaTime)
|
||||
{
|
||||
updateCount++;
|
||||
if (removeSelf)
|
||||
rm.RemoveUpdateReciever(this);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenMultipleIUpdateReceivers_AddedToResourceManager_MonoBehaviorCallbackHooksDelegateList_DoesNotGrow()
|
||||
{
|
||||
var prevCBHooks = m_ResourceManager.CallbackHooksEnabled;
|
||||
m_ResourceManager.CallbackHooksEnabled = true;
|
||||
var startingCBCount = MonoBehaviourCallbackHooks.Instance.m_OnUpdateDelegate == null ? 0 : MonoBehaviourCallbackHooks.Instance.m_OnUpdateDelegate.GetInvocationList().Length;
|
||||
m_ResourceManager.AddUpdateReceiver(new TestUpdateReceiverThatRemovesSelfDuringUpdate() {rm = m_ResourceManager, removeSelf = true});
|
||||
Assert.AreEqual(startingCBCount + 1, MonoBehaviourCallbackHooks.Instance.m_OnUpdateDelegate.GetInvocationList().Length);
|
||||
m_ResourceManager.AddUpdateReceiver(new TestUpdateReceiverThatRemovesSelfDuringUpdate() {rm = m_ResourceManager, removeSelf = true});
|
||||
Assert.AreEqual(startingCBCount + 1, MonoBehaviourCallbackHooks.Instance.m_OnUpdateDelegate.GetInvocationList().Length);
|
||||
MonoBehaviourCallbackHooks.Instance.Update();
|
||||
m_ResourceManager.CallbackHooksEnabled = prevCBHooks;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenIUpdateReceiverRemovesSelfDuringCallback_ListIsMaintained()
|
||||
{
|
||||
var ur1 = new TestUpdateReceiverThatRemovesSelfDuringUpdate() {rm = m_ResourceManager, removeSelf = false};
|
||||
var ur2 = new TestUpdateReceiverThatRemovesSelfDuringUpdate() {rm = m_ResourceManager, removeSelf = true};
|
||||
var ur3 = new TestUpdateReceiverThatRemovesSelfDuringUpdate() {rm = m_ResourceManager, removeSelf = false};
|
||||
m_ResourceManager.AddUpdateReceiver(ur1);
|
||||
m_ResourceManager.AddUpdateReceiver(ur2);
|
||||
m_ResourceManager.AddUpdateReceiver(ur3);
|
||||
m_ResourceManager.Update(0);
|
||||
Assert.AreEqual(1, ur1.updateCount);
|
||||
Assert.AreEqual(1, ur2.updateCount);
|
||||
Assert.AreEqual(1, ur3.updateCount);
|
||||
m_ResourceManager.Update(0);
|
||||
Assert.AreEqual(2, ur1.updateCount);
|
||||
Assert.AreEqual(1, ur2.updateCount);
|
||||
Assert.AreEqual(2, ur3.updateCount);
|
||||
m_ResourceManager.RemoveUpdateReciever(ur1);
|
||||
m_ResourceManager.RemoveUpdateReciever(ur3);
|
||||
}
|
||||
|
||||
class IntOperation : AsyncOperationBase<int>
|
||||
{
|
||||
protected override void Execute()
|
||||
{
|
||||
Complete(0, true, null);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenOperationReturnsValueType_NoGCAllocs()
|
||||
{
|
||||
var op = new IntOperation();
|
||||
Assert.That(() =>
|
||||
{
|
||||
var handle = m_ResourceManager.StartOperation(op, default);
|
||||
handle.Release();
|
||||
}, TestTools.Constraints.Is.Not.AllocatingGCMemory(), "GC Allocation detected");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProviderImplementsIReceiverUpdate_UpdateIsCalledWhileInProviderList()
|
||||
{
|
||||
MockProvider provider = new MockProvider();
|
||||
m_ResourceManager.ResourceProviders.Add(provider);
|
||||
m_ResourceManager.Update(0.0f);
|
||||
Assert.AreEqual(1, provider.UpdateCount);
|
||||
|
||||
// Update isn't called after removing provider
|
||||
m_ResourceManager.ResourceProviders.Remove(provider);
|
||||
m_ResourceManager.Update(0.0f);
|
||||
Assert.AreEqual(1, provider.UpdateCount);
|
||||
}
|
||||
|
||||
class MockInstanceProvider : IInstanceProvider
|
||||
{
|
||||
public Func<ResourceManager, AsyncOperationHandle<GameObject>, InstantiationParameters, GameObject> ProvideInstanceCallback;
|
||||
public Action<ResourceManager, GameObject> ReleaseInstanceCallback;
|
||||
|
||||
public GameObject ProvideInstance(ResourceManager rm, AsyncOperationHandle<GameObject> prefabHandle, InstantiationParameters instantiateParameters)
|
||||
{
|
||||
return ProvideInstanceCallback(rm, prefabHandle, instantiateParameters);
|
||||
}
|
||||
|
||||
public void ReleaseInstance(ResourceManager rm, GameObject instance)
|
||||
{
|
||||
ReleaseInstanceCallback(rm, instance);
|
||||
}
|
||||
}
|
||||
|
||||
class GameObjectProvider : IResourceProvider
|
||||
{
|
||||
public string ProviderId
|
||||
{
|
||||
get { return "GOPRovider"; }
|
||||
}
|
||||
|
||||
public ProviderBehaviourFlags BehaviourFlags
|
||||
{
|
||||
get { return ProviderBehaviourFlags.None; }
|
||||
}
|
||||
|
||||
public bool CanProvide(Type t, IResourceLocation location)
|
||||
{
|
||||
return t == typeof(GameObject);
|
||||
}
|
||||
|
||||
public Type GetDefaultType(IResourceLocation location)
|
||||
{
|
||||
return typeof(GameObject);
|
||||
}
|
||||
|
||||
public bool Initialize(string id, string data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Provide(ProvideHandle provideHandle)
|
||||
{
|
||||
var result = new GameObject(provideHandle.Location.InternalId);
|
||||
provideHandle.Complete(result, true, null);
|
||||
}
|
||||
|
||||
public void Release(IResourceLocation location, object asset)
|
||||
{
|
||||
GameObject.Destroy((GameObject)asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ReleaseInstance_BeforeDependencyCompletes_InstantiatesAndReleasesAfterDependencyCompletes()
|
||||
{
|
||||
var prefabProv = new MockProvider();
|
||||
ProvideHandle[] provHandle = new ProvideHandle[1];
|
||||
prefabProv.ProvideCallback = h => provHandle[0] = h;
|
||||
m_ResourceManager.ResourceProviders.Add(prefabProv);
|
||||
|
||||
ResourceLocationBase locDep = new ResourceLocationBase("prefab", "prefab1", prefabProv.ProviderId, typeof(UnityEngine.GameObject));
|
||||
var iProvider = new MockInstanceProvider();
|
||||
bool provideCalled = false;
|
||||
bool releaseCalled = false;
|
||||
iProvider.ProvideInstanceCallback = (rm, prefabHandle, iParam) =>
|
||||
{
|
||||
provideCalled = true;
|
||||
prefabHandle.Release();
|
||||
return null;
|
||||
};
|
||||
iProvider.ReleaseInstanceCallback = (rm, go) => { releaseCalled = true; };
|
||||
var instHandle = m_ResourceManager.ProvideInstance(iProvider, locDep, default(InstantiationParameters));
|
||||
Assert.IsFalse(instHandle.IsDone);
|
||||
m_ResourceManager.Release(instHandle);
|
||||
Assert.IsTrue(instHandle.IsValid());
|
||||
Assert.IsFalse(provideCalled);
|
||||
Assert.IsFalse(releaseCalled);
|
||||
provHandle[0].Complete<GameObject>(null, true, null);
|
||||
Assert.IsTrue(provideCalled);
|
||||
Assert.IsTrue(releaseCalled);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// To test: release via operation,
|
||||
// Edge cases: game object fails to load, callback throws exception, Release called on handle before operation completes
|
||||
//
|
||||
[Test]
|
||||
public void ProvideInstance_CanProvide()
|
||||
{
|
||||
m_ResourceManager.ResourceProviders.Add(new GameObjectProvider());
|
||||
ResourceLocationBase locDep = new ResourceLocationBase("prefab", "prefab1", "GOPRovider", typeof(UnityEngine.GameObject));
|
||||
|
||||
MockInstanceProvider iProvider = new MockInstanceProvider();
|
||||
InstantiationParameters instantiationParameters = new InstantiationParameters(null, true);
|
||||
AsyncOperationHandle<GameObject>[] refResource = new AsyncOperationHandle<GameObject>[1];
|
||||
iProvider.ProvideInstanceCallback = (rm, prefabHandle, iParam) =>
|
||||
{
|
||||
refResource[0] = prefabHandle;
|
||||
Assert.AreEqual("prefab1", prefabHandle.Result.name);
|
||||
return new GameObject("instance1");
|
||||
};
|
||||
iProvider.ReleaseInstanceCallback = (rm, go) =>
|
||||
{
|
||||
rm.Release(refResource[0]);
|
||||
GameObject.Destroy(go);
|
||||
};
|
||||
|
||||
AsyncOperationHandle<GameObject> obj = m_ResourceManager.ProvideInstance(iProvider, locDep, instantiationParameters);
|
||||
m_ResourceManager.Update(0.0f);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.AreEqual("instance1", obj.Result.name);
|
||||
Assert.AreEqual(1, m_ResourceManager.OperationCacheCount);
|
||||
obj.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ProvideResource_WhenRemote_ExceptionHandlerReceivesExceptionWithWebRequestError()
|
||||
{
|
||||
m_ResourceManager.ResourceProviders.Add(new AssetBundleProvider());
|
||||
|
||||
ResourceLocationBase location = new ResourceLocationBase("nonExistingResource", "http://urlThatCantPossiblyExistsaaaaaaaa.com/bundleName.bundle",
|
||||
typeof(AssetBundleProvider).FullName, typeof(IAssetBundleResource));
|
||||
location.Data = new AssetBundleRequestOptions()
|
||||
{
|
||||
BundleName = "bundleName",
|
||||
Timeout = 0
|
||||
};
|
||||
|
||||
var prevHandler = ResourceManager.ExceptionHandler;
|
||||
|
||||
bool exceptionWithRequestResultReceived = false;
|
||||
ResourceManager.ExceptionHandler += (h, ex) => { exceptionWithRequestResultReceived |= ex is RemoteProviderException pEx && pEx.WebRequestResult != null; };
|
||||
|
||||
AsyncOperationHandle<IAssetBundleResource> handle;
|
||||
|
||||
using (new IgnoreFailingLogMessage())
|
||||
{
|
||||
handle = m_ResourceManager.ProvideResource<IAssetBundleResource>(location);
|
||||
yield return handle;
|
||||
}
|
||||
|
||||
ResourceManager.ExceptionHandler = prevHandler;
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, handle.Status);
|
||||
Assert.IsTrue(exceptionWithRequestResultReceived);
|
||||
|
||||
handle.Release();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityTest]
|
||||
public IEnumerator WebRequestQueue_CompletesAllOperations()
|
||||
{
|
||||
int numberOfCompletedOperations = 0;
|
||||
int totalOperations = 500;
|
||||
WebRequestQueue.SetMaxConcurrentRequests(3);
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists("Temp"))
|
||||
Directory.CreateDirectory("Temp");
|
||||
|
||||
// save files to be 'downloaded'
|
||||
for (int i = 0; i < totalOperations; i++)
|
||||
System.IO.File.WriteAllText($"Temp/testFile{i}.txt", $"my contents {i}");
|
||||
|
||||
for (int i = 0; i < totalOperations; i++)
|
||||
{
|
||||
string url = "file://" + System.IO.Path.GetFullPath($"Temp/testfile{i}.txt");
|
||||
UnityWebRequest uwr = new UnityWebRequest(url);
|
||||
var requestOp = WebRequestQueue.QueueRequest(uwr);
|
||||
if (requestOp.IsDone)
|
||||
numberOfCompletedOperations++;
|
||||
else
|
||||
requestOp.OnComplete += op => { numberOfCompletedOperations++; };
|
||||
}
|
||||
|
||||
while (WebRequestQueue.s_QueuedOperations.Count > 0)
|
||||
yield return null;
|
||||
|
||||
Assert.AreEqual(totalOperations, numberOfCompletedOperations);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete files
|
||||
for (int i = 0; i < totalOperations; i++)
|
||||
{
|
||||
string fullPath = System.IO.Path.GetFullPath($"Temp/testfile{i}.txt");
|
||||
if (System.IO.File.Exists(fullPath))
|
||||
System.IO.File.Delete(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void SubclassesOfAssetBundleProvider_UseIdCacheKey_ForAsyncOperations()
|
||||
{
|
||||
var cacheKey = m_ResourceManager.CreateCacheKeyForLocation(new AssetBundleProviderDerived(), new ResourceLocationBase("fake", "fake", "fake", null));
|
||||
Assert.IsTrue(cacheKey is IdCacheKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetBundleProvider_UseIdCacheKey_ForAsyncOperations()
|
||||
{
|
||||
var cacheKey = m_ResourceManager.CreateCacheKeyForLocation(new AssetBundleProvider(), new ResourceLocationBase("fake", "fake", "fake", null));
|
||||
Assert.IsTrue(cacheKey is IdCacheKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JsonProvider_DoesNotUseIdCacheKey_ForAsyncOperations()
|
||||
{
|
||||
var cacheKey = m_ResourceManager.CreateCacheKeyForLocation(new JsonAssetProvider(), new ResourceLocationBase("fake", "fake", "fake", null), typeof(string));
|
||||
Assert.IsFalse(cacheKey is IdCacheKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BundledAssetProvider_DoesNotUseIdCacheKey_ForAsyncOperations()
|
||||
{
|
||||
var cacheKey = m_ResourceManager.CreateCacheKeyForLocation(new BundledAssetProvider(), new ResourceLocationBase("fake", "fake", "fake", null), typeof(string));
|
||||
Assert.IsFalse(cacheKey is IdCacheKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WebRequestQueue_BeginsWithAbortedOperation()
|
||||
{
|
||||
UnityWebRequest webRequest = UnityWebRequestAssetBundle.GetAssetBundle("fake");
|
||||
webRequest.Abort();
|
||||
Assert.DoesNotThrow(() => WebRequestQueue.QueueRequest(webRequest));
|
||||
}
|
||||
|
||||
class AssetBundleProviderDerived : AssetBundleProvider
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Test]
|
||||
public void AssetDatabaseProvider_LoadAssetAtPath_WhenNotInAssetDatabase_DoesNotThrow()
|
||||
{
|
||||
var loc = new ResourceLocationBase("name", "id", "providerId", typeof(object));
|
||||
ProviderOperation<Object> op = new ProviderOperation<Object>();
|
||||
op.Init(m_ResourceManager, null, loc, new AsyncOperationHandle<IList<AsyncOperationHandle>>());
|
||||
ProvideHandle handle = new ProvideHandle(m_ResourceManager, op);
|
||||
|
||||
Assert.DoesNotThrow(() => AssetDatabaseProvider.LoadAssetAtPath("doesnotexist", handle));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aaa68dbe5d4e2b24281d446a29c84c78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,221 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Constraints;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class DelayedActionManagerTests
|
||||
{
|
||||
class DamTest
|
||||
{
|
||||
public bool methodInvoked;
|
||||
public int frameInvoked;
|
||||
public float timeInvoked;
|
||||
|
||||
public void Method()
|
||||
{
|
||||
frameInvoked = Time.frameCount;
|
||||
timeInvoked = Time.unscaledTime;
|
||||
methodInvoked = true;
|
||||
}
|
||||
|
||||
public void MethodWithParams(int p1, string p2, bool p3, float p4)
|
||||
{
|
||||
Assert.AreEqual(p1, 5);
|
||||
Assert.AreEqual(p2, "testValue");
|
||||
Assert.AreEqual(p3, true);
|
||||
Assert.AreEqual(p4, 3.14f);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DelayedActionManagerInvokeSameFrame()
|
||||
{
|
||||
var testObj = new DamTest();
|
||||
int frameCalled = Time.frameCount;
|
||||
DelayedActionManager.AddAction((Action)testObj.Method);
|
||||
yield return null;
|
||||
Assert.AreEqual(frameCalled, testObj.frameInvoked);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DelayedActionManagerInvokeDelayed()
|
||||
{
|
||||
var testObj = new DamTest();
|
||||
float timeCalled = Time.unscaledTime;
|
||||
DelayedActionManager.AddAction((Action)testObj.Method, 2);
|
||||
while (!testObj.methodInvoked)
|
||||
yield return null;
|
||||
//make sure delay was at least 1 second (to account for test slowness)
|
||||
Assert.Greater(testObj.timeInvoked, timeCalled + 1);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DelayedActionManagerInvokeWithParameters()
|
||||
{
|
||||
var testObj = new DamTest();
|
||||
DelayedActionManager.AddAction((Action<int, string, bool, float>)testObj.MethodWithParams, 0, 5, "testValue", true, 3.14f);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkedListNodeCacheTests
|
||||
{
|
||||
LinkedListNodeCache<T> CreateCache<T>(int count)
|
||||
{
|
||||
var cache = new LinkedListNodeCache<T>();
|
||||
var temp = new List<LinkedListNode<T>>();
|
||||
for (int i = 0; i < count; i++)
|
||||
temp.Add(cache.Acquire(default(T)));
|
||||
Assert.AreEqual(count, cache.CreatedNodeCount);
|
||||
foreach (var t in temp)
|
||||
cache.Release(t);
|
||||
Assert.AreEqual(count, cache.CachedNodeCount);
|
||||
return cache;
|
||||
}
|
||||
|
||||
void PopulateCache_AddRemove<T>()
|
||||
{
|
||||
var cache = CreateCache<T>(1);
|
||||
Assert.That(() => { cache.Release(cache.Acquire(default(T))); }, TestTools.Constraints.Is.Not.AllocatingGCMemory(), "GC Allocation detected");
|
||||
Assert.AreEqual(1, cache.CreatedNodeCount);
|
||||
Assert.AreEqual(1, cache.CachedNodeCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenRefTypeAndCacheNotEmpty_AddRemove_DoesNotAlloc()
|
||||
{
|
||||
PopulateCache_AddRemove<string>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenValueTypeAndCacheNotEmpty_AddRemove_DoesNotAlloc()
|
||||
{
|
||||
PopulateCache_AddRemove<int>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Release_ResetsValue()
|
||||
{
|
||||
var cache = new LinkedListNodeCache<string>();
|
||||
var node = cache.Acquire(null);
|
||||
Assert.IsNull(node.Value);
|
||||
node.Value = "TestString";
|
||||
cache.Release(node);
|
||||
Assert.IsNull(node.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public class DelegateListTests
|
||||
{
|
||||
[Test]
|
||||
public void WhenDelegateRemoved_DelegateIsNotInvoked()
|
||||
{
|
||||
var cache = new LinkedListNodeCache<Action<string>>();
|
||||
var delList = new DelegateList<string>(cache.Acquire, cache.Release);
|
||||
bool called = false;
|
||||
Action<string> del = s => { called = true; };
|
||||
delList.Add(del);
|
||||
delList.Remove(del);
|
||||
delList.Invoke(null);
|
||||
Assert.IsFalse(called);
|
||||
Assert.AreEqual(cache.CreatedNodeCount, cache.CreatedNodeCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenAddInsideInvoke_NewDelegatesAreCalled()
|
||||
{
|
||||
bool addedDelegateCalled = false;
|
||||
var delList = CreateDelegateList<string>();
|
||||
delList.Add(s => delList.Add(s2 => addedDelegateCalled = true));
|
||||
delList.Invoke(null);
|
||||
Assert.IsTrue(addedDelegateCalled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCleared_DelegateIsNotInvoked()
|
||||
{
|
||||
var delList = CreateDelegateList<string>();
|
||||
int invocationCount = 0;
|
||||
delList.Add(s => invocationCount++);
|
||||
delList.Clear();
|
||||
delList.Invoke(null);
|
||||
Assert.AreEqual(0, invocationCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DuringInvoke_CanRemoveNextDelegate()
|
||||
{
|
||||
var delList = CreateDelegateList<string>();
|
||||
bool del1Called = false;
|
||||
Action<string> del1 = s => { del1Called = true; };
|
||||
Action<string> del2 = s => delList.Remove(del1);
|
||||
delList.Add(del2);
|
||||
delList.Add(del1);
|
||||
delList.Invoke(null);
|
||||
Assert.IsFalse(del1Called);
|
||||
}
|
||||
|
||||
DelegateList<T> CreateDelegateList<T>()
|
||||
{
|
||||
var cache = new LinkedListNodeCache<Action<T>>();
|
||||
return new DelegateList<T>(cache.Acquire, cache.Release);
|
||||
}
|
||||
|
||||
void InvokeAllocTest<T>(T p)
|
||||
{
|
||||
var delList = CreateDelegateList<T>();
|
||||
delList.Add(s => { });
|
||||
Assert.That(() => { delList.Invoke(p); }, TestTools.Constraints.Is.Not.AllocatingGCMemory(), "GC Allocation detected");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DelegateNoGCWithRefType()
|
||||
{
|
||||
InvokeAllocTest<string>(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DelegateNoGCWithValueType()
|
||||
{
|
||||
InvokeAllocTest<int>(0);
|
||||
}
|
||||
|
||||
static object[] KeyResultData =
|
||||
{
|
||||
new object[] {null, false, null, null},
|
||||
new object[] {"", false, null, null},
|
||||
new object[] {5, false, null, null},
|
||||
new object[] {"k", false, null, null},
|
||||
new object[] {"[k]", false, null, null},
|
||||
new object[] {"k]s[", false, null, null},
|
||||
new object[] {"k[s", false, null, null},
|
||||
new object[] {"[s]k", false, null, null},
|
||||
new object[] {"k]s", false, null, null},
|
||||
new object[] {"k[s]", true, "k", "s"},
|
||||
new object[] {"k[[s]", true, "k", "[s"},
|
||||
new object[] {"k[s[]", true, "k", "s["},
|
||||
new object[] {"k[s]]", true, "k", "s]"},
|
||||
new object[] {"k[]s]", true, "k", "]s"},
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(KeyResultData))]
|
||||
public void ResourceManagerConfigExtractKeyAndSubKey_WhenPassedKey_ReturnsExpectedValue(object key, bool expectedReturn, string expectedMainKey, string expectedSubKey)
|
||||
{
|
||||
Assert.AreEqual(expectedReturn, ResourceManagerConfig.ExtractKeyAndSubKey(key, out string mainKey, out string subKey));
|
||||
Assert.AreEqual(expectedMainKey, mainKey);
|
||||
Assert.AreEqual(expectedSubKey, subKey);
|
||||
}
|
||||
|
||||
[TestCase(RuntimePlatform.WebGLPlayer, false)]
|
||||
[TestCase(RuntimePlatform.OSXEditor, true)]
|
||||
public void CanIdentifyMultiThreadedPlatforms(RuntimePlatform platform, bool usesMultiThreading)
|
||||
{
|
||||
Assert.AreEqual(usesMultiThreading, PlatformUtilities.PlatformUsesMultiThreading(platform));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 89f8257facdc8e04fbf8eefd512ee6a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine.ResourceManagement.ResourceProviders.Simulation;
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
public class ResourceManagerVirtualModeTests : ResourceManagerBaseTests
|
||||
{
|
||||
VirtualAssetBundleRuntimeData virtualBundleData = null;
|
||||
List<IResourceLocation> sharedBundleLocations = null;
|
||||
Dictionary<string, VirtualAssetBundle> bundleMap = null;
|
||||
const int kBundleCount = 10;
|
||||
|
||||
protected override IResourceLocation[] SetupLocations(KeyValuePair<string, string>[] assets)
|
||||
{
|
||||
Random.InitState(0);
|
||||
virtualBundleData = new VirtualAssetBundleRuntimeData();
|
||||
sharedBundleLocations = new List<IResourceLocation>();
|
||||
bundleMap = new Dictionary<string, VirtualAssetBundle>();
|
||||
for (int i = 0; i < kBundleCount; i++)
|
||||
{
|
||||
var bundleName = "shared" + i;
|
||||
var b = new VirtualAssetBundle("shared" + i, i % 2 == 0, 0, "");
|
||||
virtualBundleData.AssetBundles.Add(b);
|
||||
bundleMap.Add(b.Name, b);
|
||||
sharedBundleLocations.Add(new ResourceLocationBase(bundleName, bundleName, typeof(AssetBundleProvider).FullName, typeof(IAssetBundleResource)));
|
||||
}
|
||||
|
||||
IResourceLocation[] locs = new IResourceLocation[assets.Length];
|
||||
for (int i = 0; i < locs.Length; i++)
|
||||
locs[i] = CreateLocationForAsset(assets[i].Key, assets[i].Value);
|
||||
|
||||
foreach (var b in virtualBundleData.AssetBundles)
|
||||
{
|
||||
b.SetSize(2048, 1024);
|
||||
b.OnAfterDeserialize();
|
||||
}
|
||||
|
||||
m_ResourceManager.ResourceProviders.Insert(0, new VirtualAssetBundleProvider(virtualBundleData));
|
||||
m_ResourceManager.ResourceProviders.Insert(0, new VirtualBundledAssetProvider());
|
||||
return locs;
|
||||
}
|
||||
|
||||
protected IResourceLocation CreateLocationForAsset(string name, string path)
|
||||
{
|
||||
int sharedBundleIndex = 0;
|
||||
Random.Range(0, sharedBundleLocations.Count - 3);
|
||||
IResourceLocation bundle = sharedBundleLocations[sharedBundleIndex];
|
||||
VirtualAssetBundle vBundle = bundleMap[bundle.InternalId];
|
||||
var vab = new VirtualAssetBundleEntry(path, Random.Range(1024, 1024 * 1024));
|
||||
vab.m_AssetPath = path;
|
||||
vBundle.Assets.Add(vab);
|
||||
IResourceLocation dep1Location = sharedBundleLocations[sharedBundleIndex + 1];
|
||||
IResourceLocation dep2Location = sharedBundleLocations[sharedBundleIndex + 2];
|
||||
return new ResourceLocationBase(path, path, typeof(BundledAssetProvider).FullName, typeof(object), bundle, dep1Location, dep2Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4c30a288c553aa7488774857f37eee83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3e098a01716164d41a666ccd8d2c1cf5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
class MockProvider : IResourceProvider, IUpdateReceiver
|
||||
{
|
||||
public string _ProviderId = "MockProvider";
|
||||
public ProviderBehaviourFlags _BehaviourFlags = ProviderBehaviourFlags.None;
|
||||
public List<KeyValuePair<IResourceLocation, object>> ReleaseLog = new List<KeyValuePair<IResourceLocation, object>>();
|
||||
public List<IResourceLocation> ProvideLog = new List<IResourceLocation>();
|
||||
|
||||
public int UpdateCount = 0;
|
||||
|
||||
public string ProviderId
|
||||
{
|
||||
get { return _ProviderId; }
|
||||
}
|
||||
|
||||
public ProviderBehaviourFlags BehaviourFlags
|
||||
{
|
||||
get { return _BehaviourFlags; }
|
||||
}
|
||||
|
||||
public Action<ProvideHandle> ProvideCallback;
|
||||
public Type DefaultType = typeof(object);
|
||||
|
||||
public Func<Type, IResourceLocation, bool> CanProvideCallback = (x, y) => true;
|
||||
|
||||
public void Update(float unscaledDeltaTime)
|
||||
{
|
||||
UpdateCount++;
|
||||
}
|
||||
|
||||
public void Release(IResourceLocation location, object asset)
|
||||
{
|
||||
ReleaseLog.Add(new KeyValuePair<IResourceLocation, object>(location, asset));
|
||||
}
|
||||
|
||||
public void Provide(ProvideHandle provideHandle)
|
||||
{
|
||||
ProvideLog.Add(provideHandle.Location);
|
||||
if (ProvideCallback != null && (ProvideCallback as Action<ProvideHandle>) != null)
|
||||
{
|
||||
ProvideCallback(provideHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Type GetDefaultType(IResourceLocation location)
|
||||
{
|
||||
return DefaultType;
|
||||
}
|
||||
|
||||
public bool CanProvide(Type t, IResourceLocation location)
|
||||
{
|
||||
return CanProvideCallback(t, location);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: df92c48909f708647b98ae363e7618d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Unity.ResourceManager.Tests",
|
||||
"references": [
|
||||
"Unity.ResourceManager",
|
||||
"Unity.Addressables.Tests"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b1d1d33334b51724b9bc4457a3ebd9ee
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,140 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine.ResourceManagement.ResourceProviders.Simulation;
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace UnityEngine.ResourceManagement.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class VirtualAssetBundleProviderTests
|
||||
{
|
||||
Action<AsyncOperationHandle, Exception> m_PrevHandler;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTeardown()
|
||||
{
|
||||
ResourceManager.ExceptionHandler = m_PrevHandler;
|
||||
}
|
||||
|
||||
private ResourceLocationBase AddNewBundle(VirtualAssetBundleRuntimeData data, string bundleName, bool local, int dataSize, int headerSize)
|
||||
{
|
||||
VirtualAssetBundle bundle = new VirtualAssetBundle(bundleName, local, 0, "");
|
||||
bundle.SetSize(dataSize, headerSize);
|
||||
data.AssetBundles.Add(bundle);
|
||||
ResourceLocationBase bundleLocation = new ResourceLocationBase(bundleName, bundleName, typeof(AssetBundleProvider).FullName, typeof(IAssetBundleResource));
|
||||
bundle.SetSize(dataSize, headerSize);
|
||||
return bundleLocation;
|
||||
}
|
||||
|
||||
private List<ResourceLocationBase> CreateBundleSet(VirtualAssetBundleRuntimeData data, int count, bool local, int dataSize, int headerSize)
|
||||
{
|
||||
List<ResourceLocationBase> locations = new List<ResourceLocationBase>();
|
||||
for (int i = 0; i < count; i++)
|
||||
locations.Add(AddNewBundle(data, "bundle" + i.ToString(), local, dataSize, headerSize));
|
||||
return locations;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenMultipleBundlesLoading_BandwidthIsAmortizedAcrossAllBundles([Values(true, false)] bool localBundles)
|
||||
{
|
||||
const int kBundleCount = 4;
|
||||
const int kLocalBW = 800;
|
||||
const int kRemoteBW = 2000;
|
||||
const int kHeaderSize = 2000;
|
||||
const int kDataSize = 4000;
|
||||
const float kTimeSlize = 0.5f;
|
||||
|
||||
int kUpdatesForRemoteDownload = (int)Math.Ceiling((((kDataSize * kBundleCount) / kRemoteBW) / kTimeSlize));
|
||||
int kUpdatesLocalLoad = (int)Math.Ceiling((((kHeaderSize * kBundleCount) / kLocalBW) / kTimeSlize));
|
||||
|
||||
ResourceManager rm = new ResourceManager();
|
||||
rm.CallbackHooksEnabled = false;
|
||||
|
||||
VirtualAssetBundleRuntimeData data = new VirtualAssetBundleRuntimeData(kLocalBW, kRemoteBW);
|
||||
List<ResourceLocationBase> locations = CreateBundleSet(data, kBundleCount, localBundles, kDataSize, kHeaderSize);
|
||||
VirtualAssetBundleProvider provider = new VirtualAssetBundleProvider(data);
|
||||
rm.ResourceProviders.Add(provider);
|
||||
var ops = new List<AsyncOperationHandle<VirtualAssetBundle>>();
|
||||
foreach (IResourceLocation loc in locations)
|
||||
ops.Add(rm.ProvideResource<VirtualAssetBundle>(loc));
|
||||
|
||||
|
||||
int totalUpdatesNeeded = kUpdatesLocalLoad + (localBundles ? 0 : kUpdatesForRemoteDownload);
|
||||
for (int i = 0; i < totalUpdatesNeeded; i++)
|
||||
{
|
||||
foreach (AsyncOperationHandle<VirtualAssetBundle> op in ops)
|
||||
{
|
||||
Assert.IsFalse(op.IsDone);
|
||||
Assert.Less(op.PercentComplete, 1.0f);
|
||||
}
|
||||
|
||||
provider.Update(kTimeSlize);
|
||||
}
|
||||
|
||||
foreach (var op in ops)
|
||||
{
|
||||
Assert.IsTrue(op.IsDone);
|
||||
Assert.AreEqual(1.0f, op.PercentComplete);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
op.Release();
|
||||
}
|
||||
|
||||
Assert.Zero(rm.OperationCacheCount);
|
||||
rm.Dispose();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenLoadingUnknownBundle_OperationFailsWithMessage()
|
||||
{
|
||||
ResourceManager rm = new ResourceManager();
|
||||
rm.CallbackHooksEnabled = false;
|
||||
|
||||
VirtualAssetBundleRuntimeData data = new VirtualAssetBundleRuntimeData();
|
||||
VirtualAssetBundleProvider provider = new VirtualAssetBundleProvider(data);
|
||||
rm.ResourceProviders.Add(provider);
|
||||
ResourceLocationBase unknownLocation = new ResourceLocationBase("unknown", "unknown", typeof(AssetBundleProvider).FullName, typeof(IAssetBundleResource));
|
||||
var op = rm.ProvideResource<VirtualAssetBundle>(unknownLocation);
|
||||
// wait for delayed action manager.
|
||||
// TODO: refactor delayed action manager so we can pump it instead of waiting a frame
|
||||
yield return null;
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
StringAssert.Contains("Unable to unload virtual bundle", op.OperationException.Message);
|
||||
op.Release();
|
||||
|
||||
Assert.Zero(rm.OperationCacheCount);
|
||||
rm.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenInBundleLoadCompleteCallback_CanLoadAnotherBundle()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenInBundleLoadCompleteCallback_CanUnloadAnotherBundle()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5e17c64e4d2cf1742879de399aad96bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue