initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
|
@ -0,0 +1,140 @@
|
|||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace AddressableAssetSettingsResourceLocationTests
|
||||
{
|
||||
public abstract class AddressableAssetSettingsResourceLocationTests : AddressablesTestFixture
|
||||
{
|
||||
const string k_ValidKey = "key";
|
||||
const string k_InvalidKey = "[key]";
|
||||
|
||||
const string k_FolderAddress = "Folder";
|
||||
const string k_SubFolderAddress = "Folder/subfolder.prefab";
|
||||
const string k_SceneSubFolderAddress = "Folder/subscene.unity";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
string folderGuid = AssetDatabase.CreateFolder(tempAssetFolder, k_FolderAddress);
|
||||
|
||||
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
|
||||
EditorSceneManager.SaveScene(scene, $"{tempAssetFolder}/{k_FolderAddress}/subscene.unity");
|
||||
EditorSceneManager.CloseScene(scene, true);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
GameObject testObject = new GameObject("TestObject");
|
||||
GameObject testObject2 = new GameObject("TestObject2");
|
||||
GameObject subFolderEntry = new GameObject("SubFolder");
|
||||
string path = tempAssetFolder + "/test.prefab";
|
||||
string path2 = tempAssetFolder + "/test2.prefab";
|
||||
string path3 = $"{tempAssetFolder}/{k_FolderAddress}/subfolder.prefab";
|
||||
PrefabUtility.SaveAsPrefabAsset(testObject, path);
|
||||
PrefabUtility.SaveAsPrefabAsset(testObject2, path2);
|
||||
PrefabUtility.SaveAsPrefabAsset(subFolderEntry, path3);
|
||||
string guid = AssetDatabase.AssetPathToGUID(path);
|
||||
string guid2 = AssetDatabase.AssetPathToGUID(path2);
|
||||
|
||||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, settings.DefaultGroup);
|
||||
entry.address = k_ValidKey;
|
||||
|
||||
entry = settings.CreateOrMoveEntry(guid2, settings.DefaultGroup);
|
||||
entry.address = k_InvalidKey;
|
||||
|
||||
AddressableAssetEntry folder = settings.CreateOrMoveEntry(folderGuid, settings.DefaultGroup);
|
||||
folder.address = k_FolderAddress;
|
||||
folder.IsFolder = true;
|
||||
|
||||
bool currentIgnoreState = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = false;
|
||||
LogAssert.Expect(LogType.Error, $"Address '{entry.address}' cannot contain '[ ]'.");
|
||||
LogAssert.ignoreFailingMessages = currentIgnoreState;
|
||||
}
|
||||
|
||||
protected override void OnRuntimeSetup()
|
||||
{
|
||||
// Only keep AddressableAssetSettingsLocator
|
||||
List<IResourceLocator> locators = m_Addressables.ResourceLocators.ToList();
|
||||
foreach (IResourceLocator locator in locators)
|
||||
{
|
||||
if (locator.GetType() != typeof(AddressableAssetSettingsLocator))
|
||||
m_Addressables.RemoveResourceLocator(locator);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenKeyIsValid_AddressableAssetSettingsLocator_ReturnsLocations()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations(k_ValidKey, typeof(GameObject), out IList<IResourceLocation> locs);
|
||||
Assert.IsTrue(res);
|
||||
Assert.IsNotNull(locs);
|
||||
Assert.AreEqual(1, locs.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetResourceLocations_IncludesFolderGameObjectSubEntries_NullType()
|
||||
{
|
||||
IList<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
yield return m_Addressables.GetResourceLocations(k_SubFolderAddress, null, out locations);
|
||||
Assert.AreEqual(1, locations.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetResourceLocations_IncludesFolderGameObjectSubEntries_RuntimeType()
|
||||
{
|
||||
IList<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
yield return m_Addressables.GetResourceLocations(k_SubFolderAddress, typeof(GameObject), out locations);
|
||||
Assert.AreEqual(1, locations.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetResourceLocations_IncludesFolderSceneSubEntries_NullType()
|
||||
{
|
||||
IList<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
yield return m_Addressables.GetResourceLocations(k_SceneSubFolderAddress, null, out locations);
|
||||
Assert.AreEqual(1, locations.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetResourceLocations_IncludesFolderSceneSubEntries_RuntimeSceneType()
|
||||
{
|
||||
IList<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
yield return m_Addressables.GetResourceLocations(k_SceneSubFolderAddress, typeof(SceneInstance), out locations);
|
||||
Assert.AreEqual(1, locations.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenKeyHasSquareBrackets_AddressableAssetSettingsLocator_ThrowsExceptionAndReturnsNoLocations()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations(k_InvalidKey, typeof(GameObject), out IList<IResourceLocation> locs);
|
||||
LogAssert.Expect(LogType.Error, $"Address '{k_InvalidKey}' cannot contain '[ ]'.");
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class AddressableAssetSettingsResourceLocationTests_FastMode : AddressableAssetSettingsResourceLocationTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 03115f3e85a5cee4ba080db3d02670e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,533 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AddressableAssetsIntegrationTests
|
||||
{
|
||||
internal abstract partial class AddressablesIntegrationTests
|
||||
{
|
||||
Action<AsyncOperationHandle, Exception> m_prevHandler;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_prevHandler = ResourceManager.ExceptionHandler;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TestCleanup()
|
||||
{
|
||||
m_KeysHashSet.Clear();
|
||||
if (Directory.Exists(kCatalogFolderPath))
|
||||
Directory.Delete(kCatalogFolderPath, true);
|
||||
PostTearDownEvent = ResetAddressables;
|
||||
ResourceManager.ExceptionHandler = m_prevHandler;
|
||||
}
|
||||
|
||||
private void AssertDownloadDependencyBundlesAreValid(AsyncOperationHandle op)
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.IsTrue(op.IsValid());
|
||||
var opList = (List<IAssetBundleResource>)op.Result;
|
||||
Assert.AreEqual(2, opList.Count);
|
||||
if (opList.Count > 0)
|
||||
{
|
||||
foreach (var resultBundle in opList)
|
||||
{
|
||||
Assert.NotNull(resultBundle.GetAssetBundle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CustomExceptionHandler()
|
||||
{
|
||||
yield return Init();
|
||||
|
||||
var prevHandler = ResourceManager.ExceptionHandler;
|
||||
AssetReference ar = new AssetReference();
|
||||
bool handlerCalled = false;
|
||||
ResourceManager.ExceptionHandler = (handle, exception) => handlerCalled = true;
|
||||
var op = ar.InstantiateAsync();
|
||||
yield return op;
|
||||
Assert.IsTrue(op.IsDone);
|
||||
Assert.IsTrue(handlerCalled);
|
||||
ResourceManager.ExceptionHandler = prevHandler;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_ChainOperation_DefaultReturnedWhenNotInit()
|
||||
{
|
||||
yield return Init();
|
||||
|
||||
AsyncOperationHandle testChainOperation = m_Addressables.ChainOperation;
|
||||
Assert.IsFalse(testChainOperation.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_InitializeAsync_CanGetInitializationOp()
|
||||
{
|
||||
yield return Init();
|
||||
|
||||
var initialOp = m_Addressables.InitializeAsync();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, initialOp.Status);
|
||||
Assert.IsTrue(initialOp.IsValid());
|
||||
|
||||
yield return initialOp;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_InitializeAsync_HandleReleasedAfterSecondInit()
|
||||
{
|
||||
// Setup
|
||||
m_Addressables = null;
|
||||
initializationComplete = false;
|
||||
yield return InitWithoutInitializeAsync();
|
||||
|
||||
m_Addressables.hasStartedInitialization = true;
|
||||
var initialOp = m_Addressables.InitializeAsync();
|
||||
yield return initialOp;
|
||||
|
||||
// Test
|
||||
Assert.IsFalse(initialOp.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_InitializeAsync_RespectsAutoReleaseHandleParameterOnFirstInitializationCall()
|
||||
{
|
||||
m_Addressables = null;
|
||||
initializationComplete = false;
|
||||
yield return InitWithoutInitializeAsync();
|
||||
|
||||
// Setup
|
||||
var initialOp = m_Addressables.InitializeAsync(m_RuntimeSettingsPath, "BASE", false);
|
||||
yield return initialOp;
|
||||
|
||||
// Test
|
||||
Assert.IsTrue(initialOp.IsValid());
|
||||
|
||||
//Cleanup
|
||||
initialOp.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_InitializeAsync_RespectsAutoReleaseHandleParameterOnSecondInitializationCall()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
//The Init above should have already initialized Addressables, making this the second call
|
||||
var initialOp = m_Addressables.InitializeAsync(false);
|
||||
yield return initialOp;
|
||||
|
||||
// Test
|
||||
Assert.IsTrue(initialOp.IsValid());
|
||||
|
||||
//Cleanup
|
||||
initialOp.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_InitializeAsync_CanCreateCompleted()
|
||||
{
|
||||
// Setup
|
||||
m_Addressables = null;
|
||||
initializationComplete = false;
|
||||
yield return InitWithoutInitializeAsync();
|
||||
|
||||
m_Addressables.hasStartedInitialization = true;
|
||||
var initialOp = m_Addressables.InitializeAsync(m_RuntimeSettingsPath, "BASE", false);
|
||||
yield return initialOp;
|
||||
|
||||
// Test
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, initialOp.Status);
|
||||
Assert.IsTrue(initialOp.IsValid());
|
||||
|
||||
// Cleanup
|
||||
initialOp.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_LoadContentCatalogAsync_CanLoad()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_LoadContentCatalogAsync_CanLoad)} for {TypeName}");
|
||||
}
|
||||
|
||||
var location = m_Addressables.m_ResourceLocators[0].CatalogLocation;
|
||||
var op1 = m_Addressables.LoadContentCatalogAsync(location.InternalId, false);
|
||||
yield return op1;
|
||||
|
||||
// Test
|
||||
Assert.IsTrue(op1.IsValid());
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op1.Status);
|
||||
Assert.NotNull(op1.Result);
|
||||
|
||||
// Cleanup
|
||||
op1.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_LoadContentCatalogAsync_CanLoadReleaseHandle()
|
||||
{
|
||||
yield return Init();
|
||||
|
||||
// Setup
|
||||
if (TypeName == "BuildScriptFastMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_LoadContentCatalogAsync_CanLoadReleaseHandle)} for {TypeName}");
|
||||
}
|
||||
|
||||
var location = m_Addressables.m_ResourceLocators[0].CatalogLocation;
|
||||
var op1 = m_Addressables.LoadContentCatalogAsync(location.InternalId, true);
|
||||
yield return op1;
|
||||
|
||||
// Test
|
||||
Assert.IsFalse(op1.IsValid());
|
||||
}
|
||||
|
||||
class AsyncAwaitLoadContentCatalog : MonoBehaviour
|
||||
{
|
||||
public AddressablesImpl addressables;
|
||||
public IResourceLocation location;
|
||||
public bool autoReleaseHandle = false;
|
||||
public bool done = false;
|
||||
public AsyncOperationHandle<IResourceLocator> operation;
|
||||
public string errorMsg;
|
||||
|
||||
async void Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
operation = addressables.LoadContentCatalogAsync(location.InternalId, autoReleaseHandle);
|
||||
await operation.Task;
|
||||
operation.Completed += handle => done = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMsg = e.Message;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_LoadContentCatalogAsync_WhenOpReleased_RegisteringCompleteCallback_ThrowsException()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode")
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_LoadContentCatalogAsync_CanLoad)} for {TypeName}");
|
||||
|
||||
var go = new GameObject("test", typeof(AsyncAwaitLoadContentCatalog));
|
||||
var comp = go.GetComponent<AsyncAwaitLoadContentCatalog>();
|
||||
comp.addressables = m_Addressables;
|
||||
comp.location = m_Addressables.m_ResourceLocators[0].CatalogLocation;
|
||||
comp.autoReleaseHandle = true;
|
||||
|
||||
// Test
|
||||
while (!comp.done)
|
||||
yield return null;
|
||||
Assert.AreEqual("Attempting to use an invalid operation handle", comp.errorMsg);
|
||||
|
||||
// Cleanup
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_LoadContentCatalogAsync_WhenOpNotReleased_RegisteringCompleteCallback_DoesNotThrow()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode")
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_LoadContentCatalogAsync_CanLoad)} for {TypeName}");
|
||||
|
||||
var go = new GameObject("test", typeof(AsyncAwaitLoadContentCatalog));
|
||||
var comp = go.GetComponent<AsyncAwaitLoadContentCatalog>();
|
||||
comp.addressables = m_Addressables;
|
||||
comp.location = m_Addressables.m_ResourceLocators[0].CatalogLocation;
|
||||
comp.autoReleaseHandle = false;
|
||||
|
||||
// Test
|
||||
while (!comp.done)
|
||||
yield return null;
|
||||
Assert.IsTrue(string.IsNullOrEmpty(comp.errorMsg), comp.errorMsg);
|
||||
|
||||
// Cleanup
|
||||
comp.operation.Release();
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromKey()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromKey)} for {TypeName}");
|
||||
}
|
||||
#if ENABLE_CACHING
|
||||
Caching.ClearCache();
|
||||
#endif
|
||||
string label = AddressablesTestUtility.GetPrefabLabel("BASE");
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(label);
|
||||
yield return op;
|
||||
|
||||
// Test
|
||||
AssertDownloadDependencyBundlesAreValid(op);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CantDownloadWhenGetResourceLocFailsKey()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
string label = "badLabel";
|
||||
AsyncOperationHandle op = new AsyncOperationHandle();
|
||||
using (new IgnoreFailingLogMessage())
|
||||
{
|
||||
op = m_Addressables.DownloadDependenciesAsync(label);
|
||||
yield return op;
|
||||
}
|
||||
|
||||
// Test
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.IsTrue(op.OperationException.Message.Contains("InvalidKey"));
|
||||
Assert.IsNull(op.Result);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CantDownloadWhenGetResourceLocFailsAutoReleasesKey()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
string label = "badLabel";
|
||||
bool autoRelease = true;
|
||||
AsyncOperationHandle op = new AsyncOperationHandle();
|
||||
using (new IgnoreFailingLogMessage())
|
||||
{
|
||||
op = m_Addressables.DownloadDependenciesAsync(label, autoRelease);
|
||||
yield return op;
|
||||
}
|
||||
|
||||
// Test
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDoWithChainKey()
|
||||
{
|
||||
// Setup
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDoWithChainKey)} for {TypeName}");
|
||||
}
|
||||
|
||||
yield return Init();
|
||||
|
||||
string label = AddressablesTestUtility.GetPrefabLabel("BASE");
|
||||
m_Addressables.hasStartedInitialization = false;
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(label, false);
|
||||
m_Addressables.hasStartedInitialization = true;
|
||||
yield return op;
|
||||
|
||||
// Test
|
||||
var wrapOp = op.Convert<IList<IAssetBundleResource>>();
|
||||
AssertDownloadDependencyBundlesAreValid(wrapOp);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromOpHandle()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromOpHandle)} for {TypeName}");
|
||||
}
|
||||
|
||||
IList<IResourceLocation> locations;
|
||||
var ret = m_Addressables.GetResourceLocations(new object[] {"prefabs_evenBASE"}, typeof(GameObject), Addressables.MergeMode.Intersection, out locations);
|
||||
|
||||
Assert.IsTrue(ret);
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(locations);
|
||||
yield return op;
|
||||
|
||||
// Test
|
||||
AssertDownloadDependencyBundlesAreValid(op);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DownloadDependenciesAsync_AutoReleaseHandle_ReleasesCorrectHandle()
|
||||
{
|
||||
yield return Init();
|
||||
IList<IResourceLocation> locations;
|
||||
m_Addressables.GetResourceLocations(new object[] {"prefabs_evenBASE"}, typeof(GameObject), Addressables.MergeMode.Intersection, out locations);
|
||||
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(locations, true);
|
||||
yield return op;
|
||||
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDoWithChainOpHandle()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDoWithChainOpHandle)} for {TypeName}");
|
||||
}
|
||||
|
||||
IList<IResourceLocation> locations;
|
||||
var ret = m_Addressables.GetResourceLocations(new object[] {"prefabs_evenBASE"}, typeof(GameObject), Addressables.MergeMode.Intersection, out locations);
|
||||
|
||||
Assert.IsTrue(ret);
|
||||
m_Addressables.hasStartedInitialization = false;
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(locations, false);
|
||||
m_Addressables.hasStartedInitialization = true;
|
||||
yield return op;
|
||||
|
||||
// Test
|
||||
var wrapOp = op.Convert<IList<IAssetBundleResource>>();
|
||||
AssertDownloadDependencyBundlesAreValid(wrapOp);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromObjectList()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesFromObjectList)} for {TypeName}");
|
||||
}
|
||||
|
||||
List<object> deps = new List<object>();
|
||||
deps.Add(AddressablesTestUtility.GetPrefabLabel("BASE"));
|
||||
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(deps, Addressables.MergeMode.Intersection, false);
|
||||
yield return op;
|
||||
|
||||
// Test
|
||||
AssertDownloadDependencyBundlesAreValid(op);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesWithChainFromObjectList()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
if (TypeName == "BuildScriptFastMode" || TypeName == "BuildScriptVirtualMode")
|
||||
{
|
||||
Assert.Ignore($"Skipping test {nameof(AddressablesImpl_DownloadDependenciesAsync_CanDownloadDependenciesWithChainFromObjectList)} for {TypeName}");
|
||||
}
|
||||
|
||||
List<object> deps = new List<object>();
|
||||
deps.Add(AddressablesTestUtility.GetPrefabLabel("BASE"));
|
||||
|
||||
m_Addressables.hasStartedInitialization = false;
|
||||
AsyncOperationHandle op = m_Addressables.DownloadDependenciesAsync(deps, Addressables.MergeMode.Intersection, false);
|
||||
yield return op;
|
||||
m_Addressables.hasStartedInitialization = true;
|
||||
|
||||
// Test
|
||||
var wrapOp = op.Convert<IList<IAssetBundleResource>>();
|
||||
AssertDownloadDependencyBundlesAreValid(wrapOp);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CantDownloadWhenGetResourceLocFailsObjectList()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
var deps = new List<object>();
|
||||
var provideHandle = new ProvideHandle(m_Addressables.ResourceManager, new ProviderOperation<AssetBundleResource>());
|
||||
provideHandle.GetDependencies(deps);
|
||||
|
||||
AsyncOperationHandle op = new AsyncOperationHandle();
|
||||
using (new IgnoreFailingLogMessage())
|
||||
{
|
||||
op = m_Addressables.DownloadDependenciesAsync(deps, Addressables.MergeMode.Intersection, false);
|
||||
yield return op;
|
||||
}
|
||||
|
||||
// Test
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.IsTrue(op.OperationException.Message.Contains("InvalidKey"));
|
||||
Assert.IsNull(op.Result);
|
||||
|
||||
// Cleanup
|
||||
op.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_DownloadDependenciesAsync_CantDownloadWhenGetResourceLocFailsAutoReleasesObjectList()
|
||||
{
|
||||
// Setup
|
||||
yield return Init();
|
||||
|
||||
var deps = new List<object>();
|
||||
var provideHandle = new ProvideHandle(m_Addressables.ResourceManager, new ProviderOperation<AssetBundleResource>());
|
||||
provideHandle.GetDependencies(deps);
|
||||
|
||||
bool autoRelease = true;
|
||||
AsyncOperationHandle op = new AsyncOperationHandle();
|
||||
using (new IgnoreFailingLogMessage())
|
||||
{
|
||||
op = m_Addressables.DownloadDependenciesAsync(deps, Addressables.MergeMode.Intersection, autoRelease);
|
||||
yield return op;
|
||||
}
|
||||
|
||||
// Test
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cfcdca687c6d4574928e2741e1fb9287
|
||||
timeCreated: 1597077093
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace AddressableAssetsIntegrationTests
|
||||
{
|
||||
internal abstract partial class AddressablesIntegrationTests : IPrebuildSetup
|
||||
{
|
||||
internal protected AddressablesImpl m_Addressables;
|
||||
Dictionary<object, int> m_KeysHashSet = new Dictionary<object, int>();
|
||||
List<object> m_PrefabKeysList = new List<object>();
|
||||
|
||||
Action<AsyncOperationHandle, Exception> m_PrevHandler;
|
||||
protected const string kCatalogExt =
|
||||
#if ENABLE_BINARY_CATALOG
|
||||
".bin";
|
||||
#else
|
||||
".json";
|
||||
#endif
|
||||
protected const string k_TestConfigName = "AddressableAssetSettings.Tests";
|
||||
protected const string k_TestConfigFolder = "Assets/AddressableAssetsData_AddressableAssetSettingsIntegrationTests";
|
||||
|
||||
protected abstract string TypeName { get; }
|
||||
|
||||
protected virtual string PathFormat
|
||||
{
|
||||
get { return "Assets/{0}_AssetsToDelete_{1}"; }
|
||||
}
|
||||
|
||||
protected virtual string GetRuntimePath(string testType, string suffix)
|
||||
{
|
||||
return string.Format("{0}" + Addressables.LibraryPath + "settings_{1}_TEST_{2}.json", "file://{UnityEngine.Application.dataPath}/../", testType, suffix);
|
||||
}
|
||||
|
||||
protected virtual ILocationSizeData CreateLocationSizeData(string name, long size, uint crc, string hash)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private object AssetReferenceObjectKey
|
||||
{
|
||||
get { return m_PrefabKeysList.FirstOrDefault(s => s.ToString().Contains("AssetReferenceBehavior")); }
|
||||
}
|
||||
|
||||
public virtual void Setup()
|
||||
{
|
||||
AddressablesTestUtility.Setup(TypeName, PathFormat, "BASE");
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public virtual void DeleteTempFiles()
|
||||
{
|
||||
ResourceManager.ExceptionHandler = m_PrevHandler;
|
||||
AddressablesTestUtility.TearDown(TypeName, PathFormat, "BASE");
|
||||
}
|
||||
|
||||
int m_StartingOpCount;
|
||||
int m_StartingTrackedHandleCount;
|
||||
int m_StartingInstanceCount;
|
||||
|
||||
private Action PostTearDownEvent = null;
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (m_Addressables != null)
|
||||
{
|
||||
Assert.AreEqual(m_StartingOpCount, m_Addressables.ResourceManager.OperationCacheCount);
|
||||
Assert.AreEqual(m_StartingTrackedHandleCount, m_Addressables.TrackedHandleCount,
|
||||
$"Starting tracked handle count [{m_StartingInstanceCount}], not equal to current tracked handle count [{m_Addressables.TrackedHandleCount}]");
|
||||
Assert.AreEqual(m_StartingInstanceCount, m_Addressables.ResourceManager.InstanceOperationCount);
|
||||
}
|
||||
|
||||
PostTearDownEvent?.Invoke();
|
||||
PostTearDownEvent = null;
|
||||
}
|
||||
|
||||
//we must wait for Addressables initialization to complete since we are clearing out all of its data for the tests.
|
||||
public bool initializationComplete;
|
||||
string currentInitType = null;
|
||||
|
||||
string m_RuntimeSettingsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var runtimeSettingsPath = m_Addressables.RuntimePath + "/settingsBASE.json";
|
||||
#if UNITY_EDITOR
|
||||
|
||||
runtimeSettingsPath = GetRuntimePath(currentInitType, "BASE");
|
||||
#endif
|
||||
runtimeSettingsPath = m_Addressables.ResolveInternalId(runtimeSettingsPath);
|
||||
return runtimeSettingsPath;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator Init()
|
||||
{
|
||||
if (!initializationComplete || TypeName != currentInitType)
|
||||
{
|
||||
if (m_Addressables == null)
|
||||
m_Addressables = new AddressablesImpl(new LRUCacheAllocationStrategy(1000, 1000, 100, 10));
|
||||
|
||||
if (TypeName != currentInitType)
|
||||
{
|
||||
currentInitType = TypeName;
|
||||
yield return m_Addressables.InitializeAsync(m_RuntimeSettingsPath, "BASE", false);
|
||||
|
||||
foreach (var locator in m_Addressables.ResourceLocators)
|
||||
{
|
||||
if (locator.Keys == null)
|
||||
continue;
|
||||
|
||||
foreach (var key in locator.Keys)
|
||||
{
|
||||
IList<IResourceLocation> locs;
|
||||
if (locator.Locate(key, typeof(object), out locs))
|
||||
{
|
||||
var isPrefab = locs.All(s => s.InternalId.EndsWith(".prefab"));
|
||||
if (!m_KeysHashSet.ContainsKey(key))
|
||||
{
|
||||
if (isPrefab)
|
||||
m_PrefabKeysList.Add(key);
|
||||
m_KeysHashSet.Add(key, locs.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_KeysHashSet[key] = m_KeysHashSet[key] + locs.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializationComplete = true;
|
||||
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
m_Addressables.ResourceManager.ClearDiagnosticCallbacks();
|
||||
m_StartingOpCount = m_Addressables.ResourceManager.OperationCacheCount;
|
||||
m_StartingTrackedHandleCount = m_Addressables.TrackedHandleCount;
|
||||
m_StartingInstanceCount = m_Addressables.ResourceManager.InstanceOperationCount;
|
||||
}
|
||||
|
||||
IEnumerator InitWithoutInitializeAsync()
|
||||
{
|
||||
if (!initializationComplete || TypeName != currentInitType)
|
||||
{
|
||||
if (m_Addressables == null)
|
||||
m_Addressables = new AddressablesImpl(new LRUCacheAllocationStrategy(1000, 1000, 100, 10));
|
||||
|
||||
currentInitType = TypeName;
|
||||
|
||||
yield return this;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var locator = new DynamicResourceLocator(m_Addressables);
|
||||
m_Addressables.AddResourceLocator(locator);
|
||||
}
|
||||
|
||||
initializationComplete = true;
|
||||
|
||||
m_PrevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
m_Addressables.ResourceManager.ClearDiagnosticCallbacks();
|
||||
m_StartingOpCount = m_Addressables.ResourceManager.OperationCacheCount;
|
||||
m_StartingTrackedHandleCount = m_Addressables.TrackedHandleCount;
|
||||
m_StartingInstanceCount = m_Addressables.ResourceManager.InstanceOperationCount;
|
||||
}
|
||||
|
||||
private void ResetAddressables()
|
||||
{
|
||||
m_Addressables = null;
|
||||
currentInitType = null;
|
||||
initializationComplete = false;
|
||||
}
|
||||
|
||||
internal class DumbUpdateOperation : AsyncOperationBase<List<IResourceLocator>>
|
||||
{
|
||||
protected override void Execute()
|
||||
{
|
||||
}
|
||||
|
||||
public void CallComplete()
|
||||
{
|
||||
Complete(new List<IResourceLocator>(), true, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class AddressablesIntegrationTestsFastMode : AddressablesIntegrationTests
|
||||
{
|
||||
protected override string TypeName
|
||||
{
|
||||
get { return "BuildScriptFastMode"; }
|
||||
}
|
||||
|
||||
protected override string GetRuntimePath(string testType, string suffix)
|
||||
{
|
||||
return PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath + TypeName, "");
|
||||
}
|
||||
}
|
||||
|
||||
class AddressablesIntegrationTestsVirtualMode : AddressablesIntegrationTests
|
||||
{
|
||||
protected override string TypeName
|
||||
{
|
||||
get { return "BuildScriptVirtualMode"; }
|
||||
}
|
||||
|
||||
protected override string GetRuntimePath(string testType, string suffix)
|
||||
{
|
||||
return string.Format("{0}" + Addressables.LibraryPath + "settings_TEST_{1}.json", "file://{UnityEngine.Application.dataPath}/../", suffix);
|
||||
}
|
||||
|
||||
protected override ILocationSizeData CreateLocationSizeData(string name, long size, uint crc, string hash)
|
||||
{
|
||||
return new UnityEngine.ResourceManagement.ResourceProviders.Simulation.VirtualAssetBundleRequestOptions()
|
||||
{
|
||||
BundleName = name,
|
||||
BundleSize = size,
|
||||
Crc = crc,
|
||||
Hash = hash
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AddressablesIntegrationTestsPackedPlayMode : AddressablesIntegrationTests
|
||||
{
|
||||
protected override string TypeName
|
||||
{
|
||||
get { return "BuildScriptPackedPlayMode"; }
|
||||
}
|
||||
|
||||
protected override string GetRuntimePath(string testType, string suffix)
|
||||
{
|
||||
return "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/settings" + suffix + ".json";
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
AddressablesTestUtility.Setup("BuildScriptPackedMode", PathFormat, "BASE");
|
||||
AddressablesTestUtility.Setup(TypeName, PathFormat, "BASE");
|
||||
}
|
||||
|
||||
public override void DeleteTempFiles()
|
||||
{
|
||||
AddressablesTestUtility.TearDown("BuildScriptPackedMode", PathFormat, "BASE");
|
||||
AddressablesTestUtility.TearDown(TypeName, PathFormat, "BASE");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetDownloadSize_CalculatesCachedBundles()
|
||||
{
|
||||
return GetDownloadSize_CalculatesCachedBundlesInternal();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator GetDownloadSize_WithList_CalculatesCachedBundles()
|
||||
{
|
||||
return GetDownloadSize_WithList_CalculatesCachedBundlesInternal();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetDownloadSize_WithList_CalculatesCorrectSize_WhenAssetsReferenceSameBundle()
|
||||
{
|
||||
return GetDownloadSize_WithList_CalculatesCorrectSize_WhenAssetsReferenceSameBundleInternal();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class AddressablesIntegrationPlayer : AddressablesIntegrationTests
|
||||
{
|
||||
protected override string TypeName
|
||||
{
|
||||
get { return "BuildScriptPackedMode"; }
|
||||
}
|
||||
|
||||
protected override string GetRuntimePath(string testType, string suffix)
|
||||
{
|
||||
return "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/settings" + suffix + ".json";
|
||||
}
|
||||
|
||||
protected override ILocationSizeData CreateLocationSizeData(string name, long size, uint crc, string hash)
|
||||
{
|
||||
return new AssetBundleRequestOptions()
|
||||
{
|
||||
BundleName = name,
|
||||
BundleSize = size,
|
||||
Crc = crc,
|
||||
Hash = hash
|
||||
};
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetDownloadSize_CalculatesCachedBundles()
|
||||
{
|
||||
return GetDownloadSize_CalculatesCachedBundlesInternal();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator GetDownloadSize_WithList_CalculatesCachedBundles()
|
||||
{
|
||||
return GetDownloadSize_WithList_CalculatesCachedBundlesInternal();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetDownloadSize_WithList_CalculatesCorrectSize_WhenAssetsReferenceSameBundle()
|
||||
{
|
||||
return GetDownloadSize_WithList_CalculatesCorrectSize_WhenAssetsReferenceSameBundleInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3f0645bd0f9b0ea46a9bec32c403ab9e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bf5e6ef0e57ead045be2e03ae1ec38b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Build;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Build.DataBuilders;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
public abstract class AddressablesTestFixture : IPrebuildSetup, IPostBuildCleanup
|
||||
{
|
||||
internal AddressablesImpl m_Addressables;
|
||||
internal string m_RuntimeSettingsPath;
|
||||
internal readonly string m_UniqueTestName;
|
||||
protected const string kCatalogExt =
|
||||
#if ENABLE_BINARY_CATALOG
|
||||
".bin";
|
||||
#else
|
||||
".json";
|
||||
#endif
|
||||
protected AddressablesTestFixture()
|
||||
{
|
||||
m_UniqueTestName = this.GetType().Name;
|
||||
}
|
||||
|
||||
protected enum TestBuildScriptMode
|
||||
{
|
||||
Fast,
|
||||
Virtual,
|
||||
PackedPlaymode,
|
||||
Packed
|
||||
}
|
||||
|
||||
protected virtual TestBuildScriptMode BuildScriptMode { get; }
|
||||
|
||||
protected string GetGeneratedAssetsPath()
|
||||
{
|
||||
return Path.Combine("Assets", "gen", m_UniqueTestName);
|
||||
}
|
||||
|
||||
[UnitySetUp]
|
||||
public virtual IEnumerator RuntimeSetup()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
Caching.ClearCache();
|
||||
#endif
|
||||
Assert.IsNull(m_Addressables);
|
||||
m_Addressables = new AddressablesImpl(new LRUCacheAllocationStrategy(1000, 1000, 100, 10));
|
||||
m_RuntimeSettingsPath = m_Addressables.ResolveInternalId(GetRuntimeAddressablesSettingsPath(m_UniqueTestName));
|
||||
var op = m_Addressables.InitializeAsync(m_RuntimeSettingsPath, null, false);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
OnRuntimeSetup();
|
||||
if (op.IsValid())
|
||||
op.Release();
|
||||
}
|
||||
|
||||
protected virtual void OnRuntimeSetup()
|
||||
{
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public virtual void RuntimeTeardown()
|
||||
{
|
||||
m_Addressables.ResourceManager.Dispose();
|
||||
m_Addressables = null;
|
||||
}
|
||||
|
||||
void IPrebuildSetup.Setup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
bool currentIgnoreState = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var activeScenePath = EditorSceneManager.GetActiveScene().path;
|
||||
|
||||
string rootFolder = GetGeneratedAssetsPath();
|
||||
AddressableAssetSettings settings = CreateSettings("Settings", rootFolder);
|
||||
|
||||
Setup(settings, rootFolder);
|
||||
RunBuilder(settings);
|
||||
|
||||
if (activeScenePath != EditorSceneManager.GetActiveScene().path)
|
||||
EditorSceneManager.OpenScene(activeScenePath, OpenSceneMode.Single);
|
||||
LogAssert.ignoreFailingMessages = currentIgnoreState;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPostBuildCleanup.Cleanup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string path = Path.Combine("Assets", "gen");
|
||||
if (Directory.Exists(path))
|
||||
AssetDatabase.DeleteAsset(path);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
internal virtual void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
}
|
||||
|
||||
protected AddressableAssetSettings CreateSettings(string name, string rootFolder)
|
||||
{
|
||||
if (Directory.Exists(rootFolder))
|
||||
Directory.Delete(rootFolder, true);
|
||||
Directory.CreateDirectory(rootFolder);
|
||||
return AddressableAssetSettings.Create(Path.Combine(rootFolder, name), "AddressableAssetSettings.Tests", false, true);
|
||||
}
|
||||
|
||||
protected virtual void RunBuilder(AddressableAssetSettings settings)
|
||||
{
|
||||
RunBuilder(settings, m_UniqueTestName);
|
||||
}
|
||||
|
||||
protected void RunBuilder(AddressableAssetSettings settings, string id)
|
||||
{
|
||||
var buildContext = new AddressablesDataBuilderInput(settings);
|
||||
buildContext.RuntimeSettingsFilename = "settings" + id + ".json";
|
||||
buildContext.RuntimeCatalogFilename = "catalog" + id + kCatalogExt;
|
||||
// buildContext.PathFormat = "{0}" + Addressables.LibraryPath + "{1}_" + id + kCatalogExt;
|
||||
buildContext.PathSuffix = "_" + id;
|
||||
if (BuildScriptMode == TestBuildScriptMode.PackedPlaymode)
|
||||
{
|
||||
IDataBuilder packedModeBuilder = GetBuilderOfType(settings, typeof(BuildScriptPackedMode));
|
||||
packedModeBuilder.BuildData<AddressableAssetBuildResult>(buildContext);
|
||||
}
|
||||
|
||||
IDataBuilder b = GetBuilderOfType(settings, GetBuildScriptTypeFromMode(BuildScriptMode));
|
||||
b.BuildData<AddressableAssetBuildResult>(buildContext);
|
||||
PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath + id, PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath, ""));
|
||||
}
|
||||
|
||||
static IDataBuilder GetBuilderOfType(AddressableAssetSettings settings, Type modeType)
|
||||
{
|
||||
foreach (var db in settings.DataBuilders)
|
||||
{
|
||||
var b = db;
|
||||
if (b.GetType() == modeType)
|
||||
return b as IDataBuilder;
|
||||
}
|
||||
|
||||
throw new Exception("DataBuilder not found");
|
||||
}
|
||||
|
||||
protected Type GetBuildScriptTypeFromMode(TestBuildScriptMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case TestBuildScriptMode.Fast: return typeof(BuildScriptFastMode);
|
||||
case TestBuildScriptMode.Virtual: return typeof(BuildScriptVirtualMode);
|
||||
case TestBuildScriptMode.Packed: return typeof(BuildScriptPackedMode);
|
||||
case TestBuildScriptMode.PackedPlaymode: return typeof(BuildScriptPackedPlayMode);
|
||||
}
|
||||
|
||||
throw new Exception("Unknown script mode");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected string GetRuntimeAddressablesSettingsPath(string id)
|
||||
{
|
||||
if (BuildScriptMode == TestBuildScriptMode.Packed || BuildScriptMode == TestBuildScriptMode.PackedPlaymode)
|
||||
return "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/settings" + id + ".json";
|
||||
else if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
{
|
||||
return PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath + id, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Format("{0}" + Addressables.LibraryPath + "settings_{1}.json", "file://{UnityEngine.Application.dataPath}/../", id);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CreateAssetPath(string rootFolder, string key, string extension)
|
||||
{
|
||||
return Path.Combine(rootFolder, String.Concat(key, extension));
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal static string CreateScene(string assetPath)
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Additive);
|
||||
EditorSceneManager.SaveScene(scene, assetPath);
|
||||
return AssetDatabase.AssetPathToGUID(scene.path);
|
||||
}
|
||||
|
||||
internal static string CreatePrefab(string assetPath)
|
||||
{
|
||||
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
PrefabUtility.SaveAsPrefabAsset(go, assetPath);
|
||||
Object.DestroyImmediate(go, false);
|
||||
return AssetDatabase.AssetPathToGUID(assetPath);
|
||||
}
|
||||
protected string CreateFolderDeep(string path)
|
||||
{
|
||||
path = path.Replace('\\', '/');
|
||||
if (!path.StartsWith("Assets/", StringComparison.Ordinal))
|
||||
return null;
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
if (AssetDatabase.IsValidFolder(path))
|
||||
return AssetDatabase.AssetPathToGUID(path);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
return AssetDatabase.AssetPathToGUID(path);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
return AssetDatabase.AssetPathToGUID(path);
|
||||
}
|
||||
protected string CreateAsset(string assetPath, string objectName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(objectName))
|
||||
objectName = Path.GetFileNameWithoutExtension(assetPath);
|
||||
|
||||
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
go.name = objectName;
|
||||
//this is to ensure that bundles are different for every run.
|
||||
go.transform.localPosition = UnityEngine.Random.onUnitSphere;
|
||||
var mat = new Material(Shader.Find("Standard"));
|
||||
var tex = new Texture2D(32, 32);
|
||||
var texPath = assetPath.Replace(".prefab", ".png");
|
||||
File.WriteAllBytes(texPath, tex.EncodeToPNG());
|
||||
AssetDatabase.ImportAsset(texPath, ImportAssetOptions.ForceSynchronousImport);
|
||||
mat.mainTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath);
|
||||
var matPath = assetPath.Replace(".prefab", ".mat");
|
||||
AssetDatabase.CreateAsset(mat, matPath);
|
||||
AssetDatabase.ImportAsset(matPath, ImportAssetOptions.ForceSynchronousImport);
|
||||
go.GetComponent<MeshRenderer>().sharedMaterial = AssetDatabase.LoadAssetAtPath<Material>(matPath);
|
||||
string directoryName = Path.GetDirectoryName(assetPath);
|
||||
CreateFolderDeep(directoryName);
|
||||
try
|
||||
{
|
||||
Assert.IsTrue(AssetDatabase.IsValidFolder(directoryName), "Attempting to save prefab to invalid Folder : " + directoryName);
|
||||
Assert.IsTrue(Directory.Exists(directoryName), "Folder is not in FileSystem, but is in ADB : " + directoryName);
|
||||
Assert.IsNotNull(go, "Attempting to save null GameObject to Prefab");
|
||||
PrefabUtility.SaveAsPrefabAsset(go, assetPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Error while attempting to save prefab {objectName} to {assetPath} with Exception message {e.Message}");
|
||||
throw e;
|
||||
}
|
||||
|
||||
UnityEngine.Object.DestroyImmediate(go, false);
|
||||
return AssetDatabase.AssetPathToGUID(assetPath);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
internal static IEnumerator UnloadSceneFromHandler(AsyncOperationHandle<SceneInstance> op, AddressablesImpl addressables)
|
||||
{
|
||||
string sceneName = op.Result.Scene.name;
|
||||
Assert.IsNotNull(sceneName);
|
||||
var unloadOp = addressables.UnloadSceneAsync(op, UnloadSceneOptions.None, false);
|
||||
yield return unloadOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, unloadOp.Status);
|
||||
Assert.IsFalse(unloadOp.Result.Scene.isLoaded);
|
||||
Assert.IsTrue(unloadOp.IsDone);
|
||||
addressables.Release(unloadOp);
|
||||
Assert.IsNull(SceneManager.GetSceneByName(sceneName).name);
|
||||
}
|
||||
|
||||
internal static IEnumerator UnloadSceneFromHandlerRefCountCheck(AsyncOperationHandle<SceneInstance> op, AddressablesImpl addressables)
|
||||
{
|
||||
string sceneName = op.Result.Scene.name;
|
||||
Assert.IsNotNull(sceneName);
|
||||
var prevRefCount = op.ReferenceCount;
|
||||
var unloadOp = addressables.UnloadSceneAsync(op, UnloadSceneOptions.None, false);
|
||||
yield return unloadOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, unloadOp.Status);
|
||||
Assert.IsFalse(unloadOp.Result.Scene.isLoaded);
|
||||
if (op.IsValid())
|
||||
Assert.AreEqual(prevRefCount - 1, op.ReferenceCount);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 488e0dbf9a6f5ac48bbe7875855651f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.U2D;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Build;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
using UnityEditor.U2D;
|
||||
#endif
|
||||
|
||||
static class AddressablesTestUtility
|
||||
{
|
||||
static public void Reset(AddressablesImpl aa)
|
||||
{
|
||||
aa.ClearResourceLocators();
|
||||
aa.ResourceManager.ResourceProviders.Clear();
|
||||
aa.InstanceProvider = null;
|
||||
}
|
||||
|
||||
static public void TearDown(string testType, string pathFormat, string suffix)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Reset(Addressables.Instance);
|
||||
var RootFolder = string.Format(pathFormat, testType, suffix);
|
||||
AssetDatabase.DeleteAsset(RootFolder);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public string GetPrefabLabel(string suffix)
|
||||
{
|
||||
return "prefabs" + suffix;
|
||||
}
|
||||
|
||||
static public string GetPrefabAlternatingLabel(string suffix, int index)
|
||||
{
|
||||
return string.Format("prefabs_{0}{1}", ((index % 2) == 0) ? "even" : "odd", suffix);
|
||||
}
|
||||
|
||||
static public string GetPrefabUniqueLabel(string suffix, int index)
|
||||
{
|
||||
return string.Format("prefab_{0}{1}", index, suffix);
|
||||
}
|
||||
|
||||
public const int kPrefabCount = 10;
|
||||
public const int kMaxWebRequestCount = 5;
|
||||
|
||||
static public void Setup(string testType, string pathFormat, string suffix)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
bool currentIgnoreState = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var RootFolder = string.Format(pathFormat, testType, suffix);
|
||||
|
||||
Directory.CreateDirectory(RootFolder);
|
||||
|
||||
var settings = AddressableAssetSettings.Create(RootFolder + "/Settings", "AddressableAssetSettings.Tests", false, true);
|
||||
settings.MaxConcurrentWebRequests = kMaxWebRequestCount;
|
||||
var group = settings.FindGroup("TestStuff" + suffix);
|
||||
|
||||
if (group == null)
|
||||
group = settings.CreateGroup("TestStuff" + suffix, true, false, false, null, typeof(BundledAssetGroupSchema));
|
||||
group.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
settings.DefaultGroup = group;
|
||||
for (int i = 0; i < kPrefabCount; i++)
|
||||
{
|
||||
var guid = CreateAsset(RootFolder + "/test" + i + suffix + ".prefab", "testPrefab" + i);
|
||||
var entry = settings.CreateOrMoveEntry(guid, group, false, false);
|
||||
entry.address = Path.GetFileNameWithoutExtension(entry.AssetPath);
|
||||
|
||||
entry.SetLabel(GetPrefabLabel(suffix), true, true);
|
||||
entry.SetLabel(GetPrefabAlternatingLabel(suffix, i), true, true);
|
||||
entry.SetLabel(GetPrefabUniqueLabel(suffix, i), true, true);
|
||||
entry.SetLabel("mixed", true, true, false);
|
||||
}
|
||||
|
||||
var texture = new Texture2D(32, 32);
|
||||
var data = ImageConversion.EncodeToPNG(texture);
|
||||
UnityEngine.Object.DestroyImmediate(texture);
|
||||
AssetDatabase.GenerateUniqueAssetPath(RootFolder);
|
||||
var spritePath = RootFolder + "/sprite.png";
|
||||
File.WriteAllBytes(spritePath, data);
|
||||
|
||||
AssetDatabase.ImportAsset(spritePath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
|
||||
var spriteGuid = AssetDatabase.AssetPathToGUID(spritePath);
|
||||
var importer = (TextureImporter)AssetImporter.GetAtPath(spritePath);
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Multiple;
|
||||
|
||||
#pragma warning disable 618
|
||||
importer.spritesheet = new SpriteMetaData[]
|
||||
{
|
||||
new SpriteMetaData() {name = "topleft", pivot = Vector2.zero, rect = new Rect(0, 0, 16, 16)},
|
||||
new SpriteMetaData() {name = "botright", pivot = Vector2.zero, rect = new Rect(16, 16, 16, 16)}
|
||||
};
|
||||
#pragma warning restore 618
|
||||
|
||||
importer.SaveAndReimport();
|
||||
|
||||
var spriteEntry = settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(spritePath), group, false, false);
|
||||
spriteEntry.address = "sprite";
|
||||
|
||||
var so = ScriptableObject.CreateInstance<UnityEngine.AddressableAssets.Tests.TestObject>();
|
||||
var sub = ScriptableObject.CreateInstance<UnityEngine.AddressableAssets.Tests.TestObject>();
|
||||
sub.name = "sub-shown";
|
||||
var sub2 = ScriptableObject.CreateInstance<UnityEngine.AddressableAssets.Tests.TestObject>();
|
||||
sub2.hideFlags |= HideFlags.HideInHierarchy;
|
||||
sub2.name = "sub2-hidden";
|
||||
so.name = "main";
|
||||
AssetDatabase.CreateAsset(so, RootFolder + "/assetWithSubObjects.asset");
|
||||
AssetDatabase.AddObjectToAsset(sub, RootFolder + "/assetWithSubObjects.asset");
|
||||
AssetDatabase.AddObjectToAsset(sub2, RootFolder + "/assetWithSubObjects.asset");
|
||||
AssetDatabase.ImportAsset(RootFolder + "/assetWithSubObjects.asset", ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
var assetWithSubObjectsGUID = AssetDatabase.AssetPathToGUID(RootFolder + "/assetWithSubObjects.asset");
|
||||
string assetRefGuid = CreateAsset(RootFolder + "/testIsReference.prefab", "IsReference");
|
||||
GameObject go = new GameObject("AssetReferenceBehavior");
|
||||
AssetReferenceTestBehavior aRefTestBehavior = go.AddComponent<AssetReferenceTestBehavior>();
|
||||
var scriptableObject = settings.CreateOrMoveEntry(assetWithSubObjectsGUID, settings.DefaultGroup);
|
||||
scriptableObject.address = "assetWithSubObjects";
|
||||
scriptableObject.SetLabel("mixed", true, true, false);
|
||||
aRefTestBehavior.Reference = settings.CreateAssetReference(assetRefGuid);
|
||||
aRefTestBehavior.ReferenceWithSubObject = settings.CreateAssetReference(assetWithSubObjectsGUID);
|
||||
aRefTestBehavior.ReferenceWithSubObject.SubObjectName = "sub-shown";
|
||||
aRefTestBehavior.LabelReference = new AssetLabelReference()
|
||||
{
|
||||
labelString = settings.labelTable.labelNames[0]
|
||||
};
|
||||
|
||||
string hasBehaviorPath = RootFolder + "/AssetReferenceBehavior.prefab";
|
||||
|
||||
//AssetDatabase.StopAssetEditing();
|
||||
|
||||
ScriptableObject assetWithDifferentTypedSubAssets = ScriptableObject.CreateInstance<UnityEngine.AddressableAssets.Tests.TestObject>();
|
||||
AssetDatabase.CreateAsset(assetWithDifferentTypedSubAssets, $"{RootFolder}/assetWithDifferentTypedSubAssets.asset");
|
||||
|
||||
Material mat = new Material(Shader.Find("Transparent/Diffuse"));
|
||||
Mesh mesh = new Mesh();
|
||||
AssetDatabase.AddObjectToAsset(mat, assetWithDifferentTypedSubAssets);
|
||||
AssetDatabase.AddObjectToAsset(mesh, assetWithDifferentTypedSubAssets);
|
||||
|
||||
AssetDatabase.ImportAsset($"{RootFolder}/assetWithDifferentTypedSubAssets.asset", ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
var assetWithDifferentTypedSubObjectsGUID = AssetDatabase.AssetPathToGUID($"{RootFolder}/assetWithDifferentTypedSubAssets.asset");
|
||||
var multiTypedSubAssetsEntry = settings.CreateOrMoveEntry(assetWithDifferentTypedSubObjectsGUID, settings.DefaultGroup);
|
||||
multiTypedSubAssetsEntry.address = "assetWithDifferentTypedSubAssets";
|
||||
aRefTestBehavior.ReferenceWithMultiTypedSubObject = settings.CreateAssetReference(multiTypedSubAssetsEntry.guid);
|
||||
aRefTestBehavior.ReferenceWithMultiTypedSubObjectSubReference = settings.CreateAssetReference(multiTypedSubAssetsEntry.guid);
|
||||
aRefTestBehavior.ReferenceWithMultiTypedSubObjectSubReference.SetEditorSubObject(mat);
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(go, hasBehaviorPath);
|
||||
settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(hasBehaviorPath), group, false, false);
|
||||
|
||||
CreateFolderEntryAssets(RootFolder, settings, group);
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
|
||||
RunBuilder(settings, testType, suffix);
|
||||
LogAssert.ignoreFailingMessages = currentIgnoreState;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static void CreateFolderEntryAssets(string RootFolder, AddressableAssetSettings settings, AddressableAssetGroup group)
|
||||
{
|
||||
AssetDatabase.CreateFolder(RootFolder, "folderEntry");
|
||||
string folderPath = RootFolder + "/folderEntry";
|
||||
|
||||
{
|
||||
var texture = new Texture2D(32, 32);
|
||||
var data = ImageConversion.EncodeToPNG(texture);
|
||||
UnityEngine.Object.DestroyImmediate(texture);
|
||||
AssetDatabase.GenerateUniqueAssetPath(RootFolder);
|
||||
var spritePath = folderPath + "/spritesheet.png";
|
||||
File.WriteAllBytes(spritePath, data);
|
||||
|
||||
AssetDatabase.ImportAsset(spritePath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
|
||||
var spriteGuid = AssetDatabase.AssetPathToGUID(spritePath);
|
||||
var importer = (TextureImporter)AssetImporter.GetAtPath(spritePath);
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Multiple;
|
||||
|
||||
#pragma warning disable 618
|
||||
importer.spritesheet = new SpriteMetaData[]
|
||||
{
|
||||
new SpriteMetaData() {name = "topleft", pivot = Vector2.zero, rect = new Rect(0, 0, 16, 16)},
|
||||
new SpriteMetaData() {name = "botright", pivot = Vector2.zero, rect = new Rect(16, 16, 16, 16)}
|
||||
};
|
||||
#pragma warning restore 618
|
||||
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
{
|
||||
var texture = new Texture2D(32, 32);
|
||||
var data = ImageConversion.EncodeToPNG(texture);
|
||||
UnityEngine.Object.DestroyImmediate(texture);
|
||||
|
||||
var spritePath = folderPath + "/sprite.png";
|
||||
File.WriteAllBytes(spritePath, data);
|
||||
AssetDatabase.ImportAsset(spritePath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
|
||||
var spriteGuid = AssetDatabase.AssetPathToGUID(spritePath);
|
||||
var importer = (TextureImporter)AssetImporter.GetAtPath(spritePath);
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Single;
|
||||
importer.SaveAndReimport();
|
||||
|
||||
string atlasPath = folderPath + "/atlas.spriteatlas";
|
||||
var sa = new SpriteAtlas();
|
||||
AssetDatabase.CreateAsset(sa, atlasPath);
|
||||
sa.Add(new UnityEngine.Object[]
|
||||
{
|
||||
AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(AssetDatabase.GUIDToAssetPath(spriteGuid))
|
||||
});
|
||||
SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] {sa}, EditorUserBuildSettings.activeBuildTarget, false);
|
||||
}
|
||||
|
||||
var folderEntry = settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(folderPath), group, false, false);
|
||||
folderEntry.address = "folderEntry";
|
||||
}
|
||||
|
||||
static string CreateAsset(string assetPath, string objectName)
|
||||
{
|
||||
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
go.name = objectName;
|
||||
//this is to ensure that bundles are different for every run.
|
||||
go.transform.localPosition = UnityEngine.Random.onUnitSphere;
|
||||
PrefabUtility.SaveAsPrefabAsset(go, assetPath);
|
||||
UnityEngine.Object.DestroyImmediate(go, false);
|
||||
return AssetDatabase.AssetPathToGUID(assetPath);
|
||||
}
|
||||
const string kCatalogExt =
|
||||
#if ENABLE_BINARY_CATALOG
|
||||
".bin";
|
||||
#else
|
||||
".json";
|
||||
#endif
|
||||
static void RunBuilder(AddressableAssetSettings settings, string testType, string suffix)
|
||||
{
|
||||
var buildContext = new AddressablesDataBuilderInput(settings);
|
||||
buildContext.RuntimeSettingsFilename = "settings" + suffix + ".json";
|
||||
buildContext.RuntimeCatalogFilename = "catalog" + suffix + kCatalogExt;
|
||||
foreach (var db in settings.DataBuilders)
|
||||
{
|
||||
var b = db as IDataBuilder;
|
||||
if (b.GetType().Name != testType)
|
||||
continue;
|
||||
|
||||
buildContext.PathSuffix = "_TEST_" + suffix;
|
||||
b.BuildData<AddressableAssetBuildResult>(buildContext);
|
||||
PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath + testType, PlayerPrefs.GetString(Addressables.kAddressablesRuntimeDataPath, ""));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 58d7919bd300ea94c8bc969913548cd8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyCompany("Unity Technologies")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Addressables.Samples.Tests")]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 738ea664e66824aa885346392956abc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AddressableTests.SyncAddressables
|
||||
{
|
||||
public abstract class AssetBundleProviderTests : AddressablesTestFixture
|
||||
{
|
||||
protected string m_PrefabKey = "syncprefabkey";
|
||||
protected string m_InvalidKey = "notarealkey";
|
||||
protected string m_SceneKey = "syncscenekey";
|
||||
|
||||
const int kForceUWRBundleCount = 10;
|
||||
const int kMaxConcurrentRequests = 3;
|
||||
|
||||
string GetForceUWRAddrName(int i)
|
||||
{
|
||||
return $"forceuwrasset{i}";
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
AddressableAssetGroup regGroup = settings.CreateGroup("localNoUWRGroup", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
regGroup.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
AddressableAssetGroup forceUWRGroup = settings.CreateGroup("ForceUWRGroup", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
forceUWRGroup.GetSchema<BundledAssetGroupSchema>().UseUnityWebRequestForLocalBundles = true;
|
||||
forceUWRGroup.GetSchema<BundledAssetGroupSchema>().BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackSeparately;
|
||||
forceUWRGroup.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
settings.MaxConcurrentWebRequests = kMaxConcurrentRequests;
|
||||
|
||||
for (int i = 0; i < kForceUWRBundleCount; i++)
|
||||
{
|
||||
string s = GetForceUWRAddrName(i);
|
||||
string guid = CreatePrefab(tempAssetFolder + $"/{s}.prefab");
|
||||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, forceUWRGroup);
|
||||
entry.address = s;
|
||||
}
|
||||
|
||||
{
|
||||
string guid = CreatePrefab(tempAssetFolder + $"/testprefab.prefab");
|
||||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, regGroup);
|
||||
entry.address = "testprefab";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
Caching.ClearCache();
|
||||
#endif
|
||||
if (m_Addressables != null)
|
||||
m_Addressables.WebRequestOverride = null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenUWRExceedsMaxLimit_UWRAreQueued()
|
||||
{
|
||||
List<AsyncOperationHandle<GameObject>> l =
|
||||
Enumerable.Range(0, kForceUWRBundleCount).Select(x => m_Addressables.LoadAssetAsync<GameObject>(GetForceUWRAddrName(x))).ToList();
|
||||
Assert.AreEqual(kMaxConcurrentRequests, WebRequestQueue.s_ActiveRequests.Count);
|
||||
Assert.AreEqual((kForceUWRBundleCount - kMaxConcurrentRequests), WebRequestQueue.s_QueuedOperations.Count);
|
||||
foreach (AsyncOperationHandle<GameObject> h in l)
|
||||
{
|
||||
yield return h;
|
||||
h.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenUWRExceedsMaxLimit_CompletesSynchronously()
|
||||
{
|
||||
List<AsyncOperationHandle<GameObject>> loadOps =
|
||||
Enumerable.Range(0, kForceUWRBundleCount).Select(x => m_Addressables.LoadAssetAsync<GameObject>(GetForceUWRAddrName(x))).ToList();
|
||||
|
||||
AsyncOperationHandle<GameObject> lastHandle = loadOps[kForceUWRBundleCount - 1];
|
||||
lastHandle.WaitForCompletion();
|
||||
lastHandle.Release();
|
||||
|
||||
for (int i = 0; i < kForceUWRBundleCount - 1; i++)
|
||||
{
|
||||
AsyncOperationHandle<GameObject> handle = loadOps[i];
|
||||
yield return loadOps[i];
|
||||
handle.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public void WhenUWRIsUsed_CompletesSynchronously()
|
||||
{
|
||||
AsyncOperationHandle<GameObject> h = m_Addressables.LoadAssetAsync<GameObject>(GetForceUWRAddrName(0));
|
||||
h.WaitForCompletion();
|
||||
h.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenAssetBundleIsLocal_AndForceUWRIsEnabled_UWRIsUsed()
|
||||
{
|
||||
AsyncOperationHandle<GameObject> h = m_Addressables.LoadAssetAsync<GameObject>(GetForceUWRAddrName(0));
|
||||
Assert.AreEqual(1, WebRequestQueue.s_ActiveRequests.Count);
|
||||
yield return h;
|
||||
h.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenAssetBundleIsLocal_AndForceUWRIsDisabled_UWRIsNotUsed()
|
||||
{
|
||||
AsyncOperationHandle<GameObject> h = m_Addressables.LoadAssetAsync<GameObject>("testprefab");
|
||||
Assert.AreEqual(0, WebRequestQueue.s_ActiveRequests.Count);
|
||||
yield return h;
|
||||
h.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenWebRequestOverrideIsSet_CallbackIsCalled_AssetBundleProvider()
|
||||
{
|
||||
bool webRequestOverrideCalled = false;
|
||||
m_Addressables.WebRequestOverride = request => webRequestOverrideCalled = true;
|
||||
|
||||
var prev = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var nonExistingPath = "http://127.0.0.1/non-existing-bundle";
|
||||
var loc = new ResourceLocationBase(nonExistingPath, nonExistingPath, typeof(AssetBundleProvider).FullName, typeof(AssetBundleResource));
|
||||
loc.Data = new AssetBundleRequestOptions();
|
||||
var h = m_Addressables.ResourceManager.ProvideResource<AssetBundleResource>(loc);
|
||||
yield return h;
|
||||
|
||||
if (h.IsValid()) h.Release();
|
||||
LogAssert.ignoreFailingMessages = prev;
|
||||
Assert.IsTrue(webRequestOverrideCalled);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenWebRequestFails_RetriesCorrectAmount_AssetBundleProvider()
|
||||
{
|
||||
var prev = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var nonExistingPath = "http://127.0.0.1/non-existing-bundle";
|
||||
var loc = new ResourceLocationBase(nonExistingPath, nonExistingPath, typeof(AssetBundleProvider).FullName, typeof(AssetBundleResource));
|
||||
var d = new AssetBundleRequestOptions();
|
||||
d.RetryCount = 3;
|
||||
loc.Data = d;
|
||||
|
||||
LogAssert.Expect(LogType.Log, new Regex(@"^(Web request failed, retrying \(0/3)"));
|
||||
LogAssert.Expect(LogType.Log, new Regex(@"^(Web request failed, retrying \(1/3)"));
|
||||
LogAssert.Expect(LogType.Log, new Regex(@"^(Web request failed, retrying \(2/3)"));
|
||||
var h = m_Addressables.ResourceManager.ProvideResource<AssetBundleResource>(loc);
|
||||
yield return h;
|
||||
|
||||
if (h.IsValid()) h.Release();
|
||||
LogAssert.ignoreFailingMessages = prev;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Platform(Exclude = "PS5")]
|
||||
[TestCase("Relative/Local/Path", true, false)]
|
||||
[TestCase("Relative/Local/Path", true, true)]
|
||||
[TestCase("http://127.0.0.1/Web/Path", false, true)]
|
||||
[TestCase("jar:file://Local/Path", true, false)]
|
||||
[TestCase("jar:file://Local/Path", true, true)]
|
||||
public void AssetBundleLoadPathsCorrectForGetLoadInfo(string internalId, bool isLocal, bool useUnityWebRequestForLocalBundles)
|
||||
{
|
||||
if (internalId.StartsWith("jar") && Application.platform != RuntimePlatform.Android)
|
||||
Assert.Ignore($"Skipping test {TestContext.CurrentContext.Test.Name} due jar based tests are only for running on Android Platform.");
|
||||
|
||||
var loc = new ResourceLocationBase("dummy", internalId, "dummy", typeof(Object));
|
||||
loc.Data = new AssetBundleRequestOptions {UseUnityWebRequestForLocalBundles = useUnityWebRequestForLocalBundles};
|
||||
ProviderOperation<Object> op = new ProviderOperation<Object>();
|
||||
op.Init(m_Addressables.ResourceManager, null, loc, new AsyncOperationHandle<IList<AsyncOperationHandle>>());
|
||||
ProvideHandle h = new ProvideHandle(m_Addressables.ResourceManager, op);
|
||||
|
||||
AssetBundleResource.GetLoadInfo(h, out AssetBundleResource.LoadType loadType, out string path);
|
||||
var expectedLoadType = isLocal ? useUnityWebRequestForLocalBundles ? AssetBundleResource.LoadType.Web : AssetBundleResource.LoadType.Local : AssetBundleResource.LoadType.Web;
|
||||
Assert.AreEqual(expectedLoadType, loadType, "Incorrect load type found for internalId " + internalId);
|
||||
var expectedPath = internalId;
|
||||
if (isLocal && useUnityWebRequestForLocalBundles)
|
||||
{
|
||||
expectedPath = internalId.StartsWith("jar") ? internalId : "file:///" + Path.GetFullPath(internalId);
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedPath, path);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadBundleAsync_WithUnfinishedUnload_WaitsForUnloadAndCompletes()
|
||||
{
|
||||
var h = m_Addressables.LoadAssetAsync<GameObject>("testprefab");
|
||||
yield return h;
|
||||
Assert.IsNotNull(h.Result);
|
||||
h.Release();
|
||||
h = m_Addressables.LoadAssetAsync<GameObject>("testprefab");
|
||||
yield return h;
|
||||
Assert.IsNotNull(h.Result);
|
||||
h.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadBundleSync_WithUnfinishedUnload_WaitsForUnloadAndCompletes()
|
||||
{
|
||||
var h = m_Addressables.LoadAssetAsync<GameObject>("testprefab");
|
||||
yield return h;
|
||||
Assert.IsNotNull(h.Result);
|
||||
h.Release();
|
||||
h = m_Addressables.LoadAssetAsync<GameObject>("testprefab");
|
||||
h.WaitForCompletion();
|
||||
Assert.IsNotNull(h.Result);
|
||||
h.Release();
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Only testing against important errors instead of full list
|
||||
[TestCase("", true)]
|
||||
[TestCase("Unknown error", true)]
|
||||
[TestCase("Request aborted", false)]
|
||||
[TestCase("Unable to write data", false)]
|
||||
public void UnityWebRequestResult_ShouldRetryReturnsExpected(string error, bool expected)
|
||||
{
|
||||
UnityWebRequestResult rst = new UnityWebRequestResult(new UnityWebRequest());
|
||||
rst.Error = error;
|
||||
bool result = rst.ShouldRetryDownloadError();
|
||||
Assert.AreEqual(expected, result, "Unexpected retry value for the input error.");
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
class AssetBundleProviderTests_PackedPlaymodeMode : AssetBundleProviderTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class AssetBundleProviderTests_PackedMode : AssetBundleProviderTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9c9765ad9de06ee4193e087e7732d756
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.GUI;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AssetReferenceDrawerTests
|
||||
{
|
||||
public abstract class AssetReferenceDrawerTests : AddressablesTestFixture
|
||||
{
|
||||
const string textureName = "testTexture";
|
||||
readonly string[] allowedLabels = new string[] {"label1", "label2"};
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
var group = settings.CreateGroup("TestStuff", true, false, false, null, typeof(BundledAssetGroupSchema));
|
||||
group.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
Directory.CreateDirectory(tempAssetFolder);
|
||||
var texturePath = Path.Combine(tempAssetFolder, string.Concat(GetBuildScriptTypeFromMode(BuildScriptMode), textureName, ".png"));
|
||||
CreateTextureOnPath(texturePath);
|
||||
var texEntry = settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(texturePath), group, false, false);
|
||||
texEntry.address = textureName;
|
||||
texEntry.SetLabel(allowedLabels[0], true, true);
|
||||
}
|
||||
|
||||
void CreateTextureOnPath(string spritePath)
|
||||
{
|
||||
var data = ImageConversion.EncodeToPNG(new Texture2D(32, 32));
|
||||
File.WriteAllBytes(spritePath, data);
|
||||
AssetDatabase.ImportAsset(spritePath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
#endif
|
||||
string LabelsToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool first = true;
|
||||
foreach (var t in allowedLabels)
|
||||
{
|
||||
if (!first)
|
||||
sb.Append(',');
|
||||
first = false;
|
||||
sb.Append(t);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUIRestriction_WithoutUNITYEDITOR_Initializes()
|
||||
{
|
||||
AssetReferenceUILabelRestriction uiLabelRest = new AssetReferenceUILabelRestriction(allowedLabels);
|
||||
string restAllowedLabels = uiLabelRest.ToString();
|
||||
Assert.IsNotEmpty(restAllowedLabels);
|
||||
Assert.AreEqual(restAllowedLabels, LabelsToString());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AssetReferenceUILabelRestriction_WithoutUNITYEDITOR_Validates()
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<Texture>(textureName);
|
||||
yield return op;
|
||||
AssetReferenceUILabelRestriction uiLabelRest = new AssetReferenceUILabelRestriction(allowedLabels);
|
||||
Texture tex = op.Result;
|
||||
bool isValid = uiLabelRest.ValidateAsset(tex);
|
||||
Assert.IsTrue(isValid);
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Test]
|
||||
public void AssetReferenceUIRestriction_Surrogate_Initializes()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(typeof(AssetReferenceUILabelRestriction));
|
||||
Assert.IsNotNull(surrogate);
|
||||
var surrogateInstance = Activator.CreateInstance(surrogate) as AssetReferenceUIRestrictionSurrogate;
|
||||
Assert.IsNotNull(surrogateInstance);
|
||||
surrogateInstance.Init(new AssetReferenceUILabelRestriction());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUtilityGetSurrogate_PassNullArgument_ReturnsNull()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(null);
|
||||
Assert.IsNull(surrogate);
|
||||
LogAssert.Expect(LogType.Error, "targetType cannot be null");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUtilityGetSurrogate_PassInvalidType_ReturnsNull()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(typeof(NUnit.Env));
|
||||
Assert.IsNull(surrogate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUtilityGetSurrogate_PassValidType_ReturnsSurrogate()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(typeof(AssetReferenceUILabelRestriction));
|
||||
Assert.IsNotNull(surrogate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUtilityGetSurrogate_IfSurrogateExistsInDifferentAssembly_ReturnsSurrogate()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(typeof(AssetReferenceUILabelRestriction));
|
||||
Assert.AreEqual(typeof(AssetReferenceUILabelRestrictionSurrogate), surrogate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssetReferenceUtilityGetSurrogate_IfSurrogateNotStronglyTyped_ReturnsSurrogateLowestInHierarchy()
|
||||
{
|
||||
var surrogate = AssetReferenceUtility.GetSurrogate(typeof(TestAssetReferenceUICustomRestriction));
|
||||
Assert.AreEqual(typeof(TestAssetReferenceUIRestrictionSurrogate3), surrogate);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||
class TestAssetReferenceUICustomRestriction : AssetReferenceUIRestriction
|
||||
{
|
||||
}
|
||||
|
||||
class TestAssetReferenceUICustomRestrictionSurrogate : AssetReferenceUIRestrictionSurrogate
|
||||
{
|
||||
}
|
||||
|
||||
class TestAssetReferenceUIRestrictionSurrogate1 : TestAssetReferenceUICustomRestrictionSurrogate
|
||||
{
|
||||
}
|
||||
|
||||
class TestAssetReferenceUIRestrictionSurrogate2 : TestAssetReferenceUIRestrictionSurrogate1
|
||||
{
|
||||
}
|
||||
|
||||
class TestAssetReferenceUIRestrictionSurrogate3 : TestAssetReferenceUIRestrictionSurrogate2
|
||||
{
|
||||
}
|
||||
|
||||
class AssetReferenceDrawerTests_FastMode : AssetReferenceDrawerTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class AssetReferenceDrawerTests_VirtualMode : AssetReferenceDrawerTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class AssetReferenceDrawerTests_PackedPlaymodeMode : AssetReferenceDrawerTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class AssetReferenceDrawerTests_PackedMode : AssetReferenceDrawerTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07426e5d16eb07442847b80692e452c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
public class AssetReferenceTestBehavior : MonoBehaviour
|
||||
{
|
||||
public AssetReference Reference;
|
||||
public AssetReference InValidAssetReference;
|
||||
public AssetReference ReferenceWithSubObject;
|
||||
public AssetReference ReferenceWithMultiTypedSubObject;
|
||||
public AssetReference ReferenceWithMultiTypedSubObjectSubReference;
|
||||
|
||||
public string AssetReferenceAddress;
|
||||
|
||||
public AssetLabelReference LabelReference;
|
||||
public AssetLabelReference InvalidLabelReference;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfa3710e9aeaad547bae8719bd664926
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Build;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Build.DataBuilders;
|
||||
using UnityEditor.SceneManagement;
|
||||
using System.IO;
|
||||
|
||||
#endif
|
||||
|
||||
namespace AddressableTests.AsyncTask
|
||||
{
|
||||
public abstract class AsyncTaskTests : AddressablesTestFixture
|
||||
{
|
||||
const int loadCount = 100;
|
||||
#if UNITY_EDITOR
|
||||
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
for(int i = 0 ; i < loadCount; i++)
|
||||
{
|
||||
var guid = CreateAsset( $"{GetGeneratedAssetsPath()}/test{i}.prefab");
|
||||
var entry = new AddressableAssetEntry(guid, i.ToString(), settings.DefaultGroup, false);
|
||||
entry.SetLabel("all", true, true, false);
|
||||
settings.DefaultGroup.AddAssetEntry(entry);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncTask_LoadAll_Separately()
|
||||
{
|
||||
yield return LoadAllImp(LoadAll);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncTask_LoadAll_Batched()
|
||||
{
|
||||
yield return LoadAllImp(LoadAllBatch);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncTask_LoadAll_Label()
|
||||
{
|
||||
yield return LoadAllImp(LoadAllLabel);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncTask_LoadAll_Group_Operation()
|
||||
{
|
||||
yield return LoadAllImp(LoadAllGroupOp);
|
||||
}
|
||||
|
||||
IEnumerator LoadAllImp(Func<AddressablesImpl, List<AsyncOperationHandle>, Task> func)
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = impl.InitializeAsync(m_RuntimeSettingsPath);
|
||||
var task = op.Task;
|
||||
while (!task.IsCompleted)
|
||||
yield return null;
|
||||
yield return null; //need deferred callbacks to get called
|
||||
Stopwatch w = Stopwatch.StartNew();
|
||||
var handles = new List<AsyncOperationHandle>();
|
||||
var loadTask = func(impl, handles);
|
||||
while (!loadTask.IsCompleted)
|
||||
yield return null;
|
||||
UnityEngine.Debug.Log("Complete in " + w.ElapsedMilliseconds);
|
||||
foreach (var h in handles)
|
||||
h.Release();
|
||||
yield return new WaitForSecondsRealtime(.5f);
|
||||
}
|
||||
|
||||
async Task LoadAll(AddressablesImpl impl, List<AsyncOperationHandle> handles)
|
||||
{
|
||||
for (int i = 0; i < loadCount; i++)
|
||||
{
|
||||
var h = impl.LoadAssetAsync<GameObject>(i.ToString());
|
||||
handles.Add(h);
|
||||
await h.Task;
|
||||
}
|
||||
}
|
||||
async Task LoadAllGroupOp(AddressablesImpl impl, List<AsyncOperationHandle> handles)
|
||||
{
|
||||
for (int i = 0; i < loadCount; i++)
|
||||
{
|
||||
var h = impl.LoadAssetAsync<GameObject>(i.ToString());
|
||||
handles.Add(h);
|
||||
}
|
||||
var gop = impl.ResourceManager.CreateGenericGroupOperation(handles);
|
||||
|
||||
await gop.Task;
|
||||
}
|
||||
|
||||
async Task LoadAllBatch(AddressablesImpl impl, List<AsyncOperationHandle> handles)
|
||||
{
|
||||
List<Task<GameObject>> tasks = new List<Task<GameObject>>(loadCount);
|
||||
for (int i = 0; i < loadCount; i++)
|
||||
{
|
||||
var h = impl.LoadAssetAsync<GameObject>(i.ToString());
|
||||
handles.Add(h);
|
||||
tasks.Add(h.Task);
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
async Task LoadAllLabel(AddressablesImpl impl, List<AsyncOperationHandle> handles)
|
||||
{
|
||||
var h = impl.LoadAssetsAsync<GameObject>("all", null, true);
|
||||
handles.Add(h);
|
||||
await h.Task;
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator AsyncTask_MaintainsCorrectRefCountAfterCompletion()
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = impl.InitializeAsync(m_RuntimeSettingsPath);
|
||||
var task = op.Task;
|
||||
while (!task.IsCompleted)
|
||||
yield return null;
|
||||
yield return null; //need deferred callbacks to get called
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Ignore("Ignoring until task refactor is complete.")]
|
||||
public IEnumerator AsyncTask_DoesNotReturnNull_StressTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = impl.InitializeAsync(m_RuntimeSettingsPath);
|
||||
var task = op.Task;
|
||||
while (!task.IsCompleted)
|
||||
yield return null;
|
||||
var result = op.Task.Result;
|
||||
yield return null; //need deferred callbacks to get called
|
||||
Assert.IsNotNull(op.Task.Result, $"task.Result is null! For task number [{i}]");
|
||||
op.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
class AsyncTaskTests_FastMode : AsyncTaskTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncTaskTests_VirtualMode : AsyncTaskTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncTaskTests_PackedPlaymodeMode : AsyncTaskTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class AsyncTaskTests_PackedMode : AsyncTaskTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f4d1d59e25085e489592b2342c86673
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#if UNITY_2019_3_OR_NEWER
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace BuiltInDataTests
|
||||
{
|
||||
abstract class BuiltInDataTests : AddressablesTestFixture
|
||||
{
|
||||
const string prefabKey = "prefabKey";
|
||||
const string sceneKey = "sceneKey";
|
||||
int m_StartingSceneCount;
|
||||
#if UNITY_EDITOR
|
||||
EditorBuildSettingsScene[] m_BuiltInSceneCache;
|
||||
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
AddressableAssetSettings.CreateBuiltInData(settings);
|
||||
|
||||
AssetDatabase.CreateFolder(tempAssetFolder, "Resources");
|
||||
string prefabPath = CreateAssetPath(Path.Combine(tempAssetFolder, "Resources"), prefabKey, ".prefab");
|
||||
CreatePrefab(prefabPath);
|
||||
|
||||
string builtInScenePath = CreateAssetPath(tempAssetFolder, sceneKey, ".unity");
|
||||
CreateScene(builtInScenePath);
|
||||
m_BuiltInSceneCache = BuiltinSceneCache.scenes;
|
||||
BuiltinSceneCache.scenes = new EditorBuildSettingsScene[]
|
||||
{
|
||||
new EditorBuildSettingsScene(builtInScenePath, true)
|
||||
};
|
||||
}
|
||||
#endif
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_StartingSceneCount = m_Addressables.SceneOperationCount;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.AreEqual(m_StartingSceneCount, m_Addressables.SceneOperationCount);
|
||||
#if UNITY_EDITOR
|
||||
BuiltinSceneCache.scenes = m_BuiltInSceneCache;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSceneIsInScenesList_LoadSceneAsync_Succeeds()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKey, new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKey, SceneManager.GetSceneByName(sceneKey).name);
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAssetIsInResources_LoadAssetAsync_Succeeds()
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<GameObject>(prefabKey);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class BuiltInDataTests_VirtualMode : BuiltInDataTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class BuiltInDataTests_PackedPlaymodeMode : BuiltInDataTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//[Bug: https://jira.unity3d.com/browse/ADDR-1215]
|
||||
//[UnityPlatform(exclude = new[] { RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor })]
|
||||
//class BuiltInDataTests_PackedMode : BuiltInDataTests { protected override TestBuildScriptMode BuildScriptMode { get { return TestBuildScriptMode.Packed; } } }
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e59bf5e81ff06ac4ca62188908370bbb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.AddressableAssets.Initialization;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AddressableAssetsIntegrationTests
|
||||
{
|
||||
public abstract class CleanBundleCacheTests : AddressablesTestFixture
|
||||
{
|
||||
const int kAssetCount = 5;
|
||||
const int kMaxConcurrentRequests = 3;
|
||||
|
||||
const string kOldBuildId = "Old";
|
||||
const string kNewBuildId = "New";
|
||||
|
||||
string GetNonRefAsset(int i)
|
||||
{
|
||||
return $"{kOldBuildId}{i}";
|
||||
}
|
||||
|
||||
string GetRefAsset(int i)
|
||||
{
|
||||
return $"{kNewBuildId}{i}";
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
CreateGroup(settings, tempAssetFolder, kOldBuildId, GetNonRefAsset);
|
||||
RunBuilder(settings, m_UniqueTestName + kOldBuildId);
|
||||
|
||||
settings = AddressableAssetSettings.Create(Path.Combine(tempAssetFolder, "Settings" + kNewBuildId), "AddressableAssetSettings.Tests", false, true);
|
||||
CreateGroup(settings, tempAssetFolder, kNewBuildId, GetRefAsset);
|
||||
RunBuilder(settings, m_UniqueTestName + kNewBuildId);
|
||||
}
|
||||
|
||||
AddressableAssetGroup CreateGroup(AddressableAssetSettings settings, string tempAssetFolder, string buildId, Func<int, string> objNaming)
|
||||
{
|
||||
AddressableAssetGroup remoteGroup = settings.CreateGroup($"Remote{buildId}", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
remoteGroup.GetSchema<BundledAssetGroupSchema>().UseUnityWebRequestForLocalBundles = true;
|
||||
remoteGroup.GetSchema<BundledAssetGroupSchema>().BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackSeparately;
|
||||
remoteGroup.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
settings.MaxConcurrentWebRequests = kMaxConcurrentRequests;
|
||||
|
||||
for (int i = 0; i < kAssetCount; i++)
|
||||
{
|
||||
string s = objNaming(i);
|
||||
string guid = CreatePrefab(tempAssetFolder + $"/{s}.prefab");
|
||||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, remoteGroup);
|
||||
entry.address = s;
|
||||
}
|
||||
|
||||
return remoteGroup;
|
||||
}
|
||||
|
||||
protected override void RunBuilder(AddressableAssetSettings settings)
|
||||
{
|
||||
// Do nothing, we build content during our custom Setup()
|
||||
}
|
||||
|
||||
#endif
|
||||
[UnitySetUp]
|
||||
public override IEnumerator RuntimeSetup()
|
||||
{
|
||||
// Do nothing, we initialize Addressables in our tests
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void RuntimeTeardown()
|
||||
{
|
||||
// Do nothing, we release Addressables in our tests
|
||||
}
|
||||
|
||||
protected override void OnRuntimeSetup()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
Caching.ClearCache();
|
||||
#endif
|
||||
Assert.IsNull(m_Addressables);
|
||||
}
|
||||
|
||||
IEnumerator InitializeSettings(string buildId)
|
||||
{
|
||||
if (m_Addressables != null)
|
||||
m_Addressables.ResourceManager.Dispose();
|
||||
m_Addressables = new AddressablesImpl(new LRUCacheAllocationStrategy(1000, 1000, 100, 10));
|
||||
m_RuntimeSettingsPath = m_Addressables.ResolveInternalId(GetRuntimeAddressablesSettingsPath(m_UniqueTestName + buildId));
|
||||
var op = m_Addressables.InitializeAsync(m_RuntimeSettingsPath, null, false);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
if (op.IsValid())
|
||||
op.Release();
|
||||
}
|
||||
|
||||
void ReleaseAddressables()
|
||||
{
|
||||
if (m_Addressables != null)
|
||||
m_Addressables.ResourceManager.Dispose();
|
||||
m_Addressables = null;
|
||||
}
|
||||
|
||||
IEnumerator CacheEntries(Func<int, string> keyNaming)
|
||||
{
|
||||
for (int i = 0; i < kAssetCount; i++)
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<GameObject>(keyNaming(i));
|
||||
yield return op;
|
||||
op.Release();
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, string> GetCacheEntries(string key)
|
||||
{
|
||||
var cacheEntries = new Dictionary<string, string>();
|
||||
m_Addressables.GetResourceLocations(new object[] {key}, typeof(GameObject), Addressables.MergeMode.Intersection, out IList<IResourceLocation> locations);
|
||||
Assert.AreEqual(1, locations?.Count);
|
||||
|
||||
if (locations[0].HasDependencies)
|
||||
{
|
||||
foreach (IResourceLocation dep in locations[0].Dependencies)
|
||||
{
|
||||
if (dep.Data is AssetBundleRequestOptions options)
|
||||
{
|
||||
if (!cacheEntries.ContainsKey(options.BundleName))
|
||||
cacheEntries.Add(options.BundleName, options.Hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cacheEntries;
|
||||
}
|
||||
|
||||
#if ENABLE_CACHING
|
||||
HashSet<CachedAssetBundle> GetAllEntries(Func<int, string> keyNaming)
|
||||
{
|
||||
var cacheEntries = new HashSet<CachedAssetBundle>();
|
||||
for (int i = 0; i < kAssetCount; i++)
|
||||
{
|
||||
var result = GetCacheEntries(keyNaming(i));
|
||||
foreach (var entry in result)
|
||||
{
|
||||
CachedAssetBundle cab = new CachedAssetBundle(entry.Key, Hash128.Parse(entry.Value));
|
||||
if (!cacheEntries.Contains(cab))
|
||||
cacheEntries.Add(cab);
|
||||
}
|
||||
}
|
||||
|
||||
return cacheEntries;
|
||||
}
|
||||
|
||||
void AssertEntriesAreRemoved(HashSet<CachedAssetBundle> entries)
|
||||
{
|
||||
foreach (CachedAssetBundle entry in entries)
|
||||
{
|
||||
Assert.IsFalse(Caching.IsVersionCached(entry));
|
||||
}
|
||||
}
|
||||
|
||||
void AssertEntriesArePreserved(HashSet<CachedAssetBundle> entries)
|
||||
{
|
||||
foreach (CachedAssetBundle entry in entries)
|
||||
{
|
||||
Assert.IsTrue(Caching.IsVersionCached(entry));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenValidCatalogId_RemovesNonReferencedBundlesFromCache([Values(true, false)] bool forceSingleThreading)
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
yield return CacheEntries(GetNonRefAsset);
|
||||
HashSet<CachedAssetBundle> entriesToRemove = GetAllEntries(GetNonRefAsset);
|
||||
|
||||
yield return InitializeSettings(kNewBuildId);
|
||||
yield return CacheEntries(GetRefAsset);
|
||||
HashSet<CachedAssetBundle> entriesToPreserve = GetAllEntries(GetRefAsset);
|
||||
entriesToRemove.ExceptWith(entriesToPreserve);
|
||||
|
||||
string locatorId = m_Addressables.m_ResourceLocators[0].Locator.LocatorId;
|
||||
var handle = m_Addressables.CleanBundleCache(new List<string> {locatorId}, forceSingleThreading);
|
||||
yield return handle;
|
||||
handle.Release();
|
||||
|
||||
AssertEntriesAreRemoved(entriesToRemove);
|
||||
AssertEntriesArePreserved(entriesToPreserve);
|
||||
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator WhenCatalogIdListNull_UsesLoadedCatalogs_AndRemovesNonReferencedBundlesFromCache()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
yield return CacheEntries(GetNonRefAsset);
|
||||
HashSet<CachedAssetBundle> entriesToRemove = GetAllEntries(GetNonRefAsset);
|
||||
|
||||
yield return InitializeSettings(kNewBuildId);
|
||||
yield return CacheEntries(GetRefAsset);
|
||||
HashSet<CachedAssetBundle> entriesToPreserve = GetAllEntries(GetRefAsset);
|
||||
entriesToRemove.ExceptWith(entriesToPreserve);
|
||||
|
||||
var handle = m_Addressables.CleanBundleCache(null, false);
|
||||
yield return handle;
|
||||
handle.Release();
|
||||
|
||||
AssertEntriesAreRemoved(entriesToRemove);
|
||||
AssertEntriesArePreserved(entriesToPreserve);
|
||||
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenCatalogIdListNull_AndUsingFastMode_ReturnsException()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode != TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Test only intended to run on fast mode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var handle = m_Addressables.CleanBundleCache(null, false);
|
||||
yield return handle;
|
||||
|
||||
Assert.AreEqual("Provided catalogs do not load data from a catalog file. This can occur when using the \"Use Asset Database (fastest)\" playmode script. Bundle cache was not modified.",
|
||||
handle.OperationException.Message);
|
||||
handle.Release();
|
||||
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenInvalidCatalogId_ReturnsException()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var handle = m_Addressables.CleanBundleCache(new List<string> {"invalidId"}, false);
|
||||
yield return handle;
|
||||
|
||||
Assert.AreEqual("Provided catalogs do not load data from a catalog file. This can occur when using the \"Use Asset Database (fastest)\" playmode script. Bundle cache was not modified.",
|
||||
handle.OperationException.Message);
|
||||
handle.Release();
|
||||
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAnotherOpAlreadyInProgress_ReturnsException()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var handle = m_Addressables.CleanBundleCache(null, false);
|
||||
var handle2 = m_Addressables.CleanBundleCache(null, false);
|
||||
yield return handle2;
|
||||
|
||||
Assert.AreEqual("Bundle cache is already being cleaned.", handle2.OperationException.Message);
|
||||
handle2.Release();
|
||||
|
||||
yield return handle;
|
||||
handle.Release();
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenCachingDisabled_CleanBundleCache_ReturnsException()
|
||||
{
|
||||
#if !ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
yield return InitializeSettings(kOldBuildId);
|
||||
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var handle = m_Addressables.CleanBundleCache(null, false);
|
||||
yield return handle;
|
||||
|
||||
Assert.AreEqual("Caching not enabled. There is no bundle cache to modify.", handle.OperationException.Message);
|
||||
handle.Release();
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
ReleaseAddressables();
|
||||
#else
|
||||
Assert.Ignore("Caching is enabled, but test expects to run on caching-disabled platforms.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class CleanBundleCacheTests_FastMode : CleanBundleCacheTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class CleanBundleCacheTests_PackedPlaymodeMode : CleanBundleCacheTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class CleanBundleCacheTests_PackedMode : CleanBundleCacheTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 541f73e53f31a9c45aada1a7441da18a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.Diagnostics;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace DiagnosticEventCollectorIntegrationTests
|
||||
{
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
abstract class DiagnosticEventCollectorIntegrationTests : AddressablesTestFixture
|
||||
{
|
||||
protected abstract bool PostProfilerEvents();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void RunBuilder(AddressableAssetSettings settings)
|
||||
{
|
||||
bool oldState = ProjectConfigData.PostProfilerEvents;
|
||||
ProjectConfigData.PostProfilerEvents = PostProfilerEvents();
|
||||
base.RunBuilder(settings);
|
||||
ProjectConfigData.PostProfilerEvents = oldState;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected override TestBuildScriptMode BuildScriptMode => TestBuildScriptMode.Packed;
|
||||
}
|
||||
|
||||
class DiagnosticEventCollectorTests : DiagnosticEventCollectorIntegrationTests
|
||||
{
|
||||
protected override bool PostProfilerEvents()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DummyHandler(DiagnosticEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
private void DummyHandler2(DiagnosticEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
private void TrackingHandler(DiagnosticEvent evt)
|
||||
{
|
||||
Debug.Log(evt.Frame);
|
||||
}
|
||||
|
||||
private DiagnosticEvent createGenericDiagnosticEvent(int id, int stream, int frame)
|
||||
{
|
||||
return new DiagnosticEvent("N/A", "DummyEvent" + id, id, stream, frame, 1, new int[] { });
|
||||
}
|
||||
|
||||
int opCreate = (int)ResourceManager.DiagnosticEventType.AsyncOperationCreate;
|
||||
int opRefcount = (int)ResourceManager.DiagnosticEventType.AsyncOperationReferenceCount;
|
||||
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_ReturnsTrueOnNonexistentSingletonAndCreateEqualsTrue()
|
||||
{
|
||||
//Prepare
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
|
||||
//Act/Assert
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.Exists, "Singleton exists when it should not have been initialized.");
|
||||
Assert.AreEqual(true, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, true, true),
|
||||
"RegisterEventHandler returning false, not registering handler when registration was expected. ");
|
||||
|
||||
//Cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_ReturnsFalseOnNonexistentSingletonAndCreateEqualsFalse()
|
||||
{
|
||||
//Prepare
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
//Act/Assert
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.Exists, "Singleton exists when it should not have been initialized.");
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, true, false),
|
||||
"RegisterEventHandler returning true when Exists and create should both be false. ");
|
||||
|
||||
//Cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_ReturnsFalseOnUnregisterOnNonexistentHandler()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
var handlerCount = DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count;
|
||||
|
||||
//Act/Assert
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, false, false), "Event handler returned registered a handler despite register being false.");
|
||||
Assert.AreEqual(handlerCount, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "Event handler was registered when no registration should've occurred. ");
|
||||
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_ProperlyRegistersHandlerOnRegisterCreate()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
var handlerCount = DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count;
|
||||
|
||||
//Act/Assert
|
||||
Assert.AreEqual(true, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, true, true), "Handler was not registered despite create and exist both being true.");
|
||||
Assert.AreEqual(handlerCount + 1, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "Event Handler was not properly assigned in s_EventHandlers.");
|
||||
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_ProperlyRegistersHandlerOnRegisterTrue()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
var handlerCount = DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count;
|
||||
//Act/Assert
|
||||
|
||||
Assert.AreEqual(true, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, true, false),
|
||||
"Handler was not registered despite register being true and the Singleton being intitalized.");
|
||||
Assert.AreEqual(handlerCount + 1, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "Event Handler was not properly assigned in s_EventHandlers.");
|
||||
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegisterEventHandler_TwoRegisterEmptyRemoval()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes and has an empty list of eventhandlers
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
var handlerCount = DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count;
|
||||
|
||||
//Act/Assert
|
||||
Assert.AreEqual(true, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, true, false), "Handler was not registered despite Exists being true.");
|
||||
Assert.AreEqual(handlerCount + 1, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "DummyHandler was not properly assigned in s_EventHandlers.");
|
||||
Assert.AreEqual(true, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler2, true, false), "Handler was not registered despite Exists being true");
|
||||
Assert.AreEqual(handlerCount + 2, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "DummyHandler2 was not properly assigned in s_EventHandlers.");
|
||||
|
||||
//Remove each delegate
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, false, false), "DummyHandler was not unregistered despite register being false.");
|
||||
Assert.AreEqual(handlerCount + 1, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "DummyHandler was not properly removed from s_EventHandlers.");
|
||||
Assert.AreEqual(false, DiagnosticEventCollectorSingleton.RegisterEventHandler(DummyHandler, false, false), "Registration occurred despite register being false.");
|
||||
Assert.AreEqual(handlerCount + 1, DiagnosticEventCollectorSingleton.Instance.s_EventHandlers.Count, "DummyHandler2 was removed when no removal should've occurred.");
|
||||
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HandleUnhandledEvents_EventsHandledInProperOrder()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes and has an empty list of eventhandlers
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents = new List<DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(0, opCreate, 1));
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents = new Dictionary<int, DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(0, createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(1, createGenericDiagnosticEvent(1, opCreate, 1));
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.RegisterEventHandler(TrackingHandler);
|
||||
|
||||
//This is ensuring that the events are handled in the proper order
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
|
||||
Assert.AreEqual(0, DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Count, "Unhandled event queue should be completely emptied after HandleUnhandledEvents is called.");
|
||||
Assert.AreEqual(2, DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Count, "Number of events in CreatedEvents should not be affected. ");
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HandleUnhandledEvents_LargeNumberOfUnhandledEvents()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes and has an empty list of eventhandlers
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents = new List<DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opCreate, 1));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 2));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 3));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 4));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 5));
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents = new Dictionary<int, DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(0, createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(1, createGenericDiagnosticEvent(1, opCreate, 1));
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.RegisterEventHandler(TrackingHandler);
|
||||
|
||||
//This is ensuring that the events are handled in the proper order
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "2");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "3");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "4");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "5");
|
||||
|
||||
Assert.AreEqual(0, DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Count, "Unhandled event queue should be completely emptied after HandleUnhandledEvents is called.");
|
||||
Assert.AreEqual(2, DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Count, "Number of events in CreatedEvents should not be affected. ");
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HandleUnhandledEvents_UnaffectedByIncorrectEventOrder()
|
||||
{
|
||||
//Prepare
|
||||
//Create a brand new singleton, ensure it initializes and has an empty list of eventhandlers
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents = new List<DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 2));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 4));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opCreate, 1));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 5));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(1, opRefcount, 3));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Add(createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents = new Dictionary<int, DiagnosticEvent>();
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(1, createGenericDiagnosticEvent(1, opCreate, 1));
|
||||
DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Add(0, createGenericDiagnosticEvent(0, opCreate, 0));
|
||||
|
||||
|
||||
DiagnosticEventCollectorSingleton.Instance.RegisterEventHandler(TrackingHandler);
|
||||
|
||||
//This is ensuring that the events are handled in the proper order
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "0");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "1");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "2");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "3");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "4");
|
||||
LogAssert.Expect(UnityEngine.LogType.Log, "5");
|
||||
|
||||
Assert.AreEqual(0, DiagnosticEventCollectorSingleton.Instance.m_UnhandledEvents.Count, "Unhandled event queue should be completely emptied after HandleUnhandledEvents is called.");
|
||||
Assert.AreEqual(2, DiagnosticEventCollectorSingleton.Instance.m_CreatedEvents.Count, "Number of events in CreatedEvents should not be affected. ");
|
||||
//cleanup
|
||||
DiagnosticEventCollectorSingleton.DestroySingleton();
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticEventCollectorIntegrationTestsPostProfilerEventsIsTrue : DiagnosticEventCollectorIntegrationTests
|
||||
{
|
||||
protected override bool PostProfilerEvents() => true;
|
||||
|
||||
[Test]
|
||||
[Ignore("Unstable: https://jira.unity3d.com/browse/ADDR-2645")]
|
||||
public void WhenPostProfilerEventsIsTrue_DiagnosticEventsCollectorIsCreated()
|
||||
{
|
||||
Assert.AreEqual(1, Resources.FindObjectsOfTypeAll(typeof(DiagnosticEventCollectorSingleton)).Length);
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticEventCollectorIntegrationTestsPostProfilerEventsIsFalse : DiagnosticEventCollectorIntegrationTests
|
||||
{
|
||||
protected override bool PostProfilerEvents() => false;
|
||||
|
||||
[Test]
|
||||
[Ignore("Unstable: https://jira.unity3d.com/browse/ADDR-2645")]
|
||||
public void WhenPostProfilerEventsIsFalse_DiagnosticEventsCollectorIsNotCreated()
|
||||
{
|
||||
Assert.AreEqual(0, Resources.FindObjectsOfTypeAll(typeof(DiagnosticEventCollectorSingleton)).Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc13c309185f5ef4cb30649341ab86fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,533 @@
|
|||
using AddressableAssetsIntegrationTests;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.AddressableAssets.ResourceProviders.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class DynamicContentUpdateTests : AddressablesTestFixture
|
||||
{
|
||||
class TestLocator : IResourceLocator
|
||||
{
|
||||
Dictionary<object, IList<IResourceLocation>> m_Locations = new Dictionary<object, IList<IResourceLocation>>();
|
||||
public IEnumerable<object> Keys => m_Locations.Keys;
|
||||
|
||||
public string LocatorId { get; set; }
|
||||
|
||||
public IEnumerable<IResourceLocation> AllLocations => throw new NotImplementedException();
|
||||
|
||||
public TestLocator(string id, params ResourceLocationBase[] locs)
|
||||
{
|
||||
LocatorId = id;
|
||||
foreach (var l in locs)
|
||||
m_Locations.Add(l.PrimaryKey, new List<IResourceLocation>(new IResourceLocation[] {l}));
|
||||
}
|
||||
|
||||
public bool Locate(object key, Type type, out IList<IResourceLocation> locations)
|
||||
{
|
||||
return m_Locations.TryGetValue(key, out locations);
|
||||
}
|
||||
}
|
||||
|
||||
class TestHashProvider : ResourceProviderBase
|
||||
{
|
||||
string m_Hash;
|
||||
|
||||
public TestHashProvider(string id, string hash)
|
||||
{
|
||||
m_ProviderId = id;
|
||||
m_Hash = hash;
|
||||
}
|
||||
|
||||
public override void Provide(ProvideHandle provideHandle)
|
||||
{
|
||||
provideHandle.Complete(m_Hash, true, null);
|
||||
}
|
||||
}
|
||||
|
||||
class TestCatalogProvider : ResourceProviderBase
|
||||
{
|
||||
string m_LocatorId;
|
||||
|
||||
public TestCatalogProvider(string locatorId)
|
||||
{
|
||||
m_LocatorId = locatorId;
|
||||
}
|
||||
|
||||
public override void Provide(ProvideHandle provideHandle)
|
||||
{
|
||||
var deps = new List<object>();
|
||||
provideHandle.GetDependencies(deps);
|
||||
provideHandle.Complete(new TestLocator(m_LocatorId), true, null);
|
||||
}
|
||||
}
|
||||
|
||||
const string kRemoteHashProviderId = "RemoteHashProvider";
|
||||
const string kLocalHashProviderId = "LocalHashProvider";
|
||||
const string kLocatorId = "Locator";
|
||||
const string kNewLocatorId = "NewLocator";
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckForUpdates_Returns_EmptyList_When_HashesMatch()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider), typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId), "same", catalogLoc);
|
||||
var op = m_Addressables.CheckForCatalogUpdates(false);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(0, op.Result.Count);
|
||||
Assert.AreEqual(0, m_Addressables.CatalogsWithAvailableUpdates.Count());
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckForUpdates_Returns_NonEmptyList_When_HashesDontMatch()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider), typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId), "same", catalogLoc);
|
||||
var op = m_Addressables.CheckForCatalogUpdates(false);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(1, op.Result.Count);
|
||||
Assert.AreEqual(1, m_Addressables.CatalogsWithAvailableUpdates.Count());
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckForUpdates_Initializes_Addressables()
|
||||
{
|
||||
m_Addressables.hasStartedInitialization = false;
|
||||
yield return m_Addressables.CheckForCatalogUpdates();
|
||||
Assert.IsTrue(m_Addressables.hasStartedInitialization);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckForUpdates_Returns_OnlyModifiedResults()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash1", "Remote", kRemoteHashProviderId + 1, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash1", "Local", kLocalHashProviderId + 1, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat1", "cat_id", nameof(TestCatalogProvider), typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
var remoteHashLoc2 = new ResourceLocationBase("RemoteHash2", "Remote", kRemoteHashProviderId + 2, typeof(string));
|
||||
var localHashLoc2 = new ResourceLocationBase("LocalHash2", "Local", kLocalHashProviderId + 2, typeof(string));
|
||||
var catalogLoc2 = new ResourceLocationBase("cat2", "cat_id", nameof(TestCatalogProvider), typeof(IResourceLocator), remoteHashLoc2, localHashLoc2);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId + 1, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId + 1, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId + 2, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId + 2, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId), "same", catalogLoc);
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId + 2), "same", catalogLoc2);
|
||||
|
||||
var op = m_Addressables.CheckForCatalogUpdates(false);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(1, op.Result.Count);
|
||||
Assert.AreEqual(kLocatorId + 2, op.Result[0]);
|
||||
Assert.AreEqual(1, m_Addressables.CatalogsWithAvailableUpdates.Count());
|
||||
Assert.AreEqual(kLocatorId + 2, m_Addressables.CatalogsWithAvailableUpdates.First());
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UpdateContent_UpdatesCatalogs_Returns_ListOfLocators()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", typeof(TestCatalogProvider).FullName, typeof(object), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId, remoteHashLoc, localHashLoc, catalogLoc), "same", catalogLoc);
|
||||
var op = m_Addressables.CheckForCatalogUpdates(false);
|
||||
yield return op;
|
||||
Assert.IsNotNull(op.Result);
|
||||
Assert.AreEqual(1, op.Result.Count);
|
||||
var updateOp = m_Addressables.UpdateCatalogs(op.Result, false);
|
||||
m_Addressables.Release(op);
|
||||
|
||||
yield return updateOp;
|
||||
Assert.IsNotNull(updateOp.Result);
|
||||
Assert.AreEqual(1, updateOp.Result.Count);
|
||||
Assert.AreEqual(kNewLocatorId, updateOp.Result[0].LocatorId);
|
||||
m_Addressables.Release(updateOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UpdateContent_UpdatesCatalogs_Returns_ListOfLocators_WhenCheckForUpdateIsNotCalled()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", typeof(TestCatalogProvider).FullName, typeof(object), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId, remoteHashLoc, localHashLoc, catalogLoc), "same", catalogLoc);
|
||||
|
||||
var updateOp = m_Addressables.UpdateCatalogs(null, false);
|
||||
|
||||
yield return updateOp;
|
||||
Assert.IsNotNull(updateOp.Result);
|
||||
Assert.AreEqual(1, updateOp.Result.Count);
|
||||
Assert.AreEqual(kNewLocatorId, updateOp.Result[0].LocatorId);
|
||||
m_Addressables.Release(updateOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Platform(Exclude = "PS5")]
|
||||
public IEnumerator UpdateContent_UpdatesCatalogs_WhenAutoCleanCacheEnabled_RemovesNonReferencedBundlesFromCache()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", typeof(TestCatalogProvider).FullName, typeof(object), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId, remoteHashLoc, localHashLoc, catalogLoc), "same", catalogLoc);
|
||||
|
||||
string cachedBundleName = "UpdatesCatalogsTestFakeBundle";
|
||||
string hash = "123";
|
||||
string fakeCachePath = AddressablesIntegrationTests.CreateFakeCachedBundle(cachedBundleName, hash);
|
||||
|
||||
var updateOp = m_Addressables.UpdateCatalogs(null, false, true);
|
||||
yield return updateOp;
|
||||
|
||||
string fakeCacheFolder = Path.GetDirectoryName(fakeCachePath);
|
||||
Assert.AreEqual(0, Directory.GetDirectories(fakeCacheFolder).Length);
|
||||
|
||||
m_Addressables.Release(updateOp);
|
||||
Directory.Delete(fakeCacheFolder);
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UpdateContent_UpdatesCatalogs_WhenAutoCleanCacheDisabled_NoBundlesRemovedFromCache()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", typeof(TestCatalogProvider).FullName, typeof(object), remoteHashLoc, localHashLoc);
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId, remoteHashLoc, localHashLoc, catalogLoc), "same", catalogLoc);
|
||||
|
||||
string cachedBundleName = "UpdatesCatalogsTestFakeBundle";
|
||||
string hash = "123";
|
||||
string fakeCachePath = AddressablesIntegrationTests.CreateFakeCachedBundle(cachedBundleName, hash);
|
||||
|
||||
var updateOp = m_Addressables.UpdateCatalogs(null, false, false);
|
||||
yield return updateOp;
|
||||
|
||||
string fakeCacheFolder = Path.GetDirectoryName(fakeCachePath);
|
||||
Assert.IsTrue(Directory.GetDirectories(fakeCacheFolder).Length > 0);
|
||||
|
||||
m_Addressables.Release(updateOp);
|
||||
Directory.Delete(fakeCacheFolder, true);
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UpdateContent_UpdatesCatalogs_WhenAutoCleanCacheEnabled_AndCachingDisabled_ReturnsException()
|
||||
{
|
||||
#if !ENABLE_CACHING && !PLATFORM_SWITCH
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", typeof(TestCatalogProvider).FullName, typeof(object), remoteHashLoc, localHashLoc);
|
||||
|
||||
//causes a compile err. Needs re-evaluation on ps4
|
||||
//m_Addressables.RuntimePath = m_RuntimeSettingsPath;
|
||||
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kRemoteHashProviderId, "different"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestHashProvider(kLocalHashProviderId, "same"));
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new TestCatalogProvider(kNewLocatorId));
|
||||
m_Addressables.AddResourceLocator(new TestLocator(kLocatorId, remoteHashLoc, localHashLoc, catalogLoc), "same", catalogLoc);
|
||||
LogAssert.Expect(LogType.Error, "System.Exception: Caching not enabled. There is no bundle cache to modify.");
|
||||
var updateOp = m_Addressables.UpdateCatalogs(null, false, true);
|
||||
yield return updateOp;
|
||||
|
||||
LogAssert.Expect(LogType.Error,
|
||||
"OperationException : CompletedOperation, status=Failed, result=False catalogs updated, but failed to clean bundle cache.");
|
||||
Assert.AreEqual(updateOp.OperationException.Message, "ChainOperation failed because dependent operation failed");
|
||||
Assert.AreEqual(updateOp.OperationException.InnerException.Message, "CompletedOperation, status=Failed, result=False catalogs updated, but failed to clean bundle cache.");
|
||||
|
||||
m_Addressables.Release(updateOp);
|
||||
#else
|
||||
Assert.Ignore("Caching is enabled, but test expects to run on caching-disabled platforms or platform was skipped.");
|
||||
yield return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(AsyncOperationStatus.Failed, "Failed to load catalog:")]
|
||||
[TestCase(AsyncOperationStatus.None, "Catalog loading operation is still in progress when it should already be completed.")]
|
||||
public void UpdateContent_UpdatesCatalogs_ThrowsCorrectError_DuringNonSuccessState(AsyncOperationStatus opState, string expectedMessage)
|
||||
{
|
||||
var updateOp = new UpdateCatalogsOperation(m_Addressables);
|
||||
var failedDepOp = new AsyncOperationHandle<IList<AsyncOperationHandle>>();
|
||||
|
||||
failedDepOp.m_InternalOp = new ProviderOperation<IList<AsyncOperationHandle>>();
|
||||
failedDepOp.m_InternalOp.m_Status = opState;
|
||||
failedDepOp.m_InternalOp.Result = new List<AsyncOperationHandle>();
|
||||
failedDepOp.m_InternalOp.m_Error = new Exception();
|
||||
|
||||
updateOp.m_DepOp = failedDepOp;
|
||||
updateOp.m_Error = failedDepOp.m_InternalOp.m_Error;
|
||||
updateOp.m_RM = m_Addressables.ResourceManager;
|
||||
|
||||
updateOp.InvokeExecute();
|
||||
Assert.IsTrue(updateOp.OperationException != null);
|
||||
LogAssert.Expect(LogType.Error, $"OperationException : Cannot update catalogs. {expectedMessage} {updateOp.m_DepOp.OperationException.Message}\n");
|
||||
}
|
||||
|
||||
internal class ExceptionTestOperation : AsyncOperationBase<string>
|
||||
{
|
||||
internal ExceptionTestOperation(Exception ex, string desiredResult, bool success = false)
|
||||
{
|
||||
m_RM = new ResourceManager();
|
||||
Complete(desiredResult, success, ex);
|
||||
Result = desiredResult;
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessDependentOpResults_FailsWithErrorMessageOnInternalError()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider),
|
||||
typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
var op1 = new ExceptionTestOperation(new Exception("Bad operation"), null);
|
||||
var handle1 = new AsyncOperationHandle(op1);
|
||||
var results = new List<AsyncOperationHandle>();
|
||||
|
||||
var loc = new TestLocator(kLocatorId);
|
||||
var locInfo = new ResourceLocatorInfo(loc, "same", catalogLoc);
|
||||
var locInfos = new List<ResourceLocatorInfo>();
|
||||
locInfos.Add(locInfo);
|
||||
|
||||
var trivialHashes = new List<string>(new[] {"badHash"});
|
||||
results.Add(handle1);
|
||||
bool success;
|
||||
string errorString;
|
||||
var result =
|
||||
CheckCatalogsOperation.ProcessDependentOpResults(results, locInfos, trivialHashes, out errorString,
|
||||
out success);
|
||||
|
||||
LogAssert.Expect(LogType.Error, "System.Exception: Bad operation");
|
||||
Assert.AreEqual(false, success, "Operation should not succeed when underlying operation op1 has a non null OperationException");
|
||||
Assert.AreEqual(true, errorString.Contains("Bad operation"), "Error string should contain the error message thrown by the underlying operation");
|
||||
Assert.IsNull(result, "Result should be null in the case where every operation within it failed.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessDependentOpResults_SucceedsOnNoErrorMessage()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider),
|
||||
typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
var op1 = new ExceptionTestOperation(null, "good result", true);
|
||||
var handle1 = new AsyncOperationHandle(op1);
|
||||
var results = new List<AsyncOperationHandle>();
|
||||
|
||||
var loc = new TestLocator(kLocatorId);
|
||||
var locInfo = new ResourceLocatorInfo(loc, "same", catalogLoc);
|
||||
var locInfos = new List<ResourceLocatorInfo>();
|
||||
locInfos.Add(locInfo);
|
||||
|
||||
var trivialHashes = new List<string>(new[] {"same"});
|
||||
results.Add(handle1);
|
||||
bool success;
|
||||
string errorString;
|
||||
var result =
|
||||
CheckCatalogsOperation.ProcessDependentOpResults(results, locInfos, trivialHashes, out errorString,
|
||||
out success);
|
||||
|
||||
Assert.AreEqual(true, success, "Operation should succeed when underlying operation op1 has a null OperationException");
|
||||
Assert.IsNull(errorString, "Error string should be null when operation is succeeding without errors.");
|
||||
Assert.NotNull(result, "Result should only be null when every operation within it fails.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessDependentOpResults_ReturnsFailureOnOneErrorMessage()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider),
|
||||
typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
var op1 = new ExceptionTestOperation(null, "good result", true);
|
||||
var op2 = new ExceptionTestOperation(new Exception("Bad operation"), null);
|
||||
var handle1 = new AsyncOperationHandle(op1);
|
||||
var handle2 = new AsyncOperationHandle(op2);
|
||||
var results = new List<AsyncOperationHandle>();
|
||||
results.Add(handle1);
|
||||
results.Add(handle2);
|
||||
|
||||
var loc = new TestLocator(kLocatorId);
|
||||
var locInfo1 = new ResourceLocatorInfo(loc, "same", catalogLoc);
|
||||
var locInfo2 = new ResourceLocatorInfo(loc, "bad", catalogLoc);
|
||||
var locInfos = new List<ResourceLocatorInfo>();
|
||||
locInfos.Add(locInfo1);
|
||||
locInfos.Add(locInfo2);
|
||||
|
||||
var trivialHashes = new List<string>(new[] {"same", "good"});
|
||||
|
||||
bool success;
|
||||
string errorString;
|
||||
var result =
|
||||
CheckCatalogsOperation.ProcessDependentOpResults(results, locInfos, trivialHashes, out errorString,
|
||||
out success);
|
||||
|
||||
LogAssert.Expect(LogType.Error, "System.Exception: Bad operation");
|
||||
Assert.AreEqual(false, success, "Operation should fail when underlying operation op1 has a null OperationException, even if op2 has a non null OperationException");
|
||||
Assert.AreEqual(true, errorString.Contains("Bad operation"), "Error string should contain the error message thrown by the underlying operation");
|
||||
Assert.NotNull(result, "Result should only be null if every underlying operation fails.");
|
||||
Assert.NotNull(result[0], "Only failed operations should be null in the result list.");
|
||||
Assert.IsNull(result[1], "Failed operations should be null in the result list.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessDependentOpResults_FailsWithMultipleErrorMessageOnMultipleFailures()
|
||||
{
|
||||
var remoteHashLoc = new ResourceLocationBase("RemoteHash", "Remote", kRemoteHashProviderId, typeof(string));
|
||||
var localHashLoc = new ResourceLocationBase("LocalHash", "Local", kLocalHashProviderId, typeof(string));
|
||||
var catalogLoc = new ResourceLocationBase("cat", "cat_id", nameof(TestCatalogProvider),
|
||||
typeof(IResourceLocator), remoteHashLoc, localHashLoc);
|
||||
|
||||
var op1 = new ExceptionTestOperation(new Exception("Very bad operation"), null);
|
||||
var op2 = new ExceptionTestOperation(new Exception("Bad operation"), null);
|
||||
var handle1 = new AsyncOperationHandle(op1);
|
||||
var handle2 = new AsyncOperationHandle(op2);
|
||||
var results = new List<AsyncOperationHandle>();
|
||||
results.Add(handle1);
|
||||
results.Add(handle2);
|
||||
|
||||
var loc = new TestLocator(kLocatorId);
|
||||
var locInfo1 = new ResourceLocatorInfo(loc, "worse", catalogLoc);
|
||||
var locInfo2 = new ResourceLocatorInfo(loc, "bad", catalogLoc);
|
||||
var locInfos = new List<ResourceLocatorInfo>();
|
||||
locInfos.Add(locInfo1);
|
||||
locInfos.Add(locInfo2);
|
||||
|
||||
var trivialHashes = new List<string>(new[] {"same", "good"});
|
||||
|
||||
bool success;
|
||||
string errorString;
|
||||
var result =
|
||||
CheckCatalogsOperation.ProcessDependentOpResults(results, locInfos, trivialHashes, out errorString,
|
||||
out success);
|
||||
|
||||
LogAssert.Expect(LogType.Error, "System.Exception: Very bad operation");
|
||||
LogAssert.Expect(LogType.Error, "System.Exception: Bad operation");
|
||||
Assert.AreEqual(false, success, "Operation should succeed when underlying operation op1 has a null OperationException");
|
||||
Assert.AreEqual(true, errorString.Contains("Bad operation"), "Error string should contain the error message thrown by the underlying operation");
|
||||
Assert.AreEqual(true, errorString.Contains("Very bad operation"), "Error string should contain the error message thrown by the underlying operation");
|
||||
Assert.IsNull(result, "Result list should be null if every operation contained within fails.");
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class DynamicContentUpdateTests_FastMode : DynamicContentUpdateTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicContentUpdateTests_VirtualMode : DynamicContentUpdateTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicContentUpdateTests_PackedPlaymode : DynamicContentUpdateTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class DynamicContentUpdateTests_Packed : DynamicContentUpdateTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
protected override void RunBuilder(AddressableAssetSettings settings)
|
||||
{
|
||||
//Because we're testing an API that indirectly inits Addr, we need to build using the regular naming convention.
|
||||
RunBuilder(settings, "");
|
||||
}
|
||||
|
||||
#endif
|
||||
[UnitySetUp]
|
||||
public override IEnumerator RuntimeSetup()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
Caching.ClearCache();
|
||||
#endif
|
||||
Assert.IsNull(m_Addressables);
|
||||
m_Addressables = new AddressablesImpl(new LRUCacheAllocationStrategy(1000, 1000, 100, 10));
|
||||
var op = m_Addressables.InitializeAsync(false);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
OnRuntimeSetup();
|
||||
if (op.IsValid())
|
||||
op.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c5676580c9e682d4da654a6c5440b917
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.U2D;
|
||||
using System;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEngine.AddressableAssets.DynamicResourceLocators
|
||||
{
|
||||
public abstract class DynamicLocatorTests : AddressablesTestFixture
|
||||
{
|
||||
const string kGoKey = "go";
|
||||
const string kSpriteKey = "sprite";
|
||||
|
||||
class TestLocator : IResourceLocator
|
||||
{
|
||||
struct KeyType : IEquatable<KeyType>
|
||||
{
|
||||
public object key;
|
||||
public Type type;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return type.GetHashCode() * 31 + key.GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(KeyType other)
|
||||
{
|
||||
return key.Equals(other.key) && type.Equals(other.type);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<KeyType, IList<IResourceLocation>> m_Locations = new Dictionary<KeyType, IList<IResourceLocation>>();
|
||||
|
||||
public TestLocator()
|
||||
{
|
||||
m_Locations.Add(new KeyType() {key = kGoKey, type = typeof(GameObject)}, new List<IResourceLocation>(new IResourceLocation[]
|
||||
{
|
||||
new ResourceLocationBase("go1", "internalId1", "provider", typeof(GameObject)),
|
||||
new ResourceLocationBase("go2", "internalId2", "provider", typeof(GameObject)),
|
||||
}));
|
||||
|
||||
m_Locations.Add(new KeyType() {key = kSpriteKey, type = typeof(SpriteAtlas)}, new List<IResourceLocation>(new IResourceLocation[]
|
||||
{
|
||||
new ResourceLocationBase("spriteAtlas1", "internalId1", "provider", typeof(SpriteAtlas)),
|
||||
new ResourceLocationBase("spriteAtlas2", "internalId2", "provider", typeof(SpriteAtlas)),
|
||||
}));
|
||||
}
|
||||
|
||||
public string LocatorId => "";
|
||||
public IEnumerable<object> Keys => null;
|
||||
|
||||
public IEnumerable<IResourceLocation> AllLocations => throw new NotImplementedException();
|
||||
|
||||
public bool Locate(object key, Type type, out IList<IResourceLocation> locations)
|
||||
{
|
||||
return m_Locations.TryGetValue(new KeyType() {key = key, type = type}, out locations);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRuntimeSetup()
|
||||
{
|
||||
m_Addressables.ClearResourceLocators();
|
||||
m_Addressables.AddResourceLocator(new TestLocator());
|
||||
m_Addressables.AddResourceLocator(new DynamicResourceLocator(m_Addressables));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WhenLocationExistsAndTypeIsCorrect_LocationIsReturned()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations($"{kGoKey}[blah]", typeof(GameObject), out IList<IResourceLocation> locs);
|
||||
Assert.IsTrue(res);
|
||||
Assert.AreEqual(2, locs.Count);
|
||||
foreach (var l in locs)
|
||||
Assert.AreEqual(typeof(GameObject), l.ResourceType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateDynamicLocations_CreatesLocationsWithResourceTypes()
|
||||
{
|
||||
//Setup
|
||||
DynamicResourceLocator locator = new DynamicResourceLocator(m_Addressables);
|
||||
List<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
IResourceLocation location = new ResourceLocationBase("test", "test", typeof(BundledAssetProvider).FullName, typeof(GameObject));
|
||||
|
||||
//Test
|
||||
locator.CreateDynamicLocations(null, locations, "test", "test", location);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(typeof(GameObject), locations[0].ResourceType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateDynamicLocations_WithDepdencies_CreatesLocationsWithResourceTypes()
|
||||
{
|
||||
//Setup
|
||||
DynamicResourceLocator locator = new DynamicResourceLocator(m_Addressables);
|
||||
List<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
IResourceLocation depLocation = new ResourceLocationBase("dep1", "dep1", typeof(BundledAssetProvider).FullName, typeof(Texture2D));
|
||||
IResourceLocation location = new ResourceLocationBase("test", "test", typeof(BundledAssetProvider).FullName, typeof(GameObject), depLocation);
|
||||
|
||||
//Test
|
||||
locator.CreateDynamicLocations(null, locations, "test", "test", location);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(typeof(GameObject), locations[0].ResourceType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateDynamicLocations_WithSpriteAtlas_CreatesLocationsSpriteResourceTypes()
|
||||
{
|
||||
//Setup
|
||||
DynamicResourceLocator locator = new DynamicResourceLocator(m_Addressables);
|
||||
List<IResourceLocation> locations = new List<IResourceLocation>();
|
||||
IResourceLocation location = new ResourceLocationBase("test", "test", typeof(BundledAssetProvider).FullName, typeof(U2D.SpriteAtlas));
|
||||
|
||||
//Test
|
||||
locator.CreateDynamicLocations(typeof(Sprite), locations, "test", "test", location);
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(typeof(Sprite), locations[0].ResourceType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WithInvalidMainKey_DoesNotReturnALocation()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations("none[blah]", typeof(GameObject), out IList<IResourceLocation> locs);
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WithInvalidType_DoesNotReturnALocation()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations($"{kGoKey}[blah]", typeof(Sprite), out IList<IResourceLocation> locs);
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WhenSpriteWithoutSubkey_DoesNotReturnALocation()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations(kSpriteKey, typeof(Sprite), out IList<IResourceLocation> locs);
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WithInvalidMainKeyAndSpriteType_DoesNotReturnALocation()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations("none[blah]", typeof(Sprite), out IList<IResourceLocation> locs);
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WhenSpecifiedTypeDoesNotMatch_NoLocationReturned()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations($"{kSpriteKey}[blah]", typeof(GameObject), out IList<IResourceLocation> locs);
|
||||
Assert.IsFalse(res);
|
||||
Assert.IsNull(locs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetResourceLocations_WithCorrectBaseTypeForSprite_ReturnsTrue()
|
||||
{
|
||||
var res = m_Addressables.GetResourceLocations($"{kSpriteKey}[blah]", typeof(Sprite), out IList<IResourceLocation> locs);
|
||||
Assert.IsTrue(res);
|
||||
Assert.AreEqual(2, locs.Count);
|
||||
foreach (var l in locs)
|
||||
{
|
||||
Assert.AreEqual(1, l.Dependencies.Count);
|
||||
Assert.AreEqual(typeof(SpriteAtlas), l.Dependencies[0].ResourceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class DynamicLocatorTests_FastMode : DynamicLocatorTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicLocatorTests_VirtualMode : DynamicLocatorTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicLocatorTests_PackedPlaymodeMode : DynamicLocatorTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class DynamicLocatorTests_PackedMode : DynamicLocatorTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cfc18942d8f87f147a241b9de540a2a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class IgnoreFailingLogMessage : IDisposable
|
||||
{
|
||||
private bool m_SavedIgnoreFailingMessagesFlag;
|
||||
|
||||
public IgnoreFailingLogMessage()
|
||||
{
|
||||
m_SavedIgnoreFailingMessagesFlag = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogAssert.ignoreFailingMessages = m_SavedIgnoreFailingMessagesFlag;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aa28bcae85fa11447917912c39d705c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6faf7d815764fef408b2e42c8982f2d0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.AddressableAssets.Initialization;
|
||||
|
||||
namespace AddrRuntimePropertiesTests
|
||||
{
|
||||
public class AddrRuntimePropertiesTests
|
||||
{
|
||||
[Test]
|
||||
public void RuntimeProperties_CanAddValue()
|
||||
{
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
AddressablesRuntimeProperties.SetPropertyValue("name", "val");
|
||||
|
||||
Assert.AreEqual(1, AddressablesRuntimeProperties.GetCachedValueCount());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_CanSetValueMultipleTimes()
|
||||
{
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
AddressablesRuntimeProperties.SetPropertyValue("name", "val");
|
||||
AddressablesRuntimeProperties.SetPropertyValue("name", "val2");
|
||||
|
||||
Assert.AreEqual(1, AddressablesRuntimeProperties.GetCachedValueCount());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_ClearCacheClears()
|
||||
{
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
AddressablesRuntimeProperties.SetPropertyValue("name", "val");
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
|
||||
Assert.AreEqual(0, AddressablesRuntimeProperties.GetCachedValueCount());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluatePropertyCanEvaluateSetValue()
|
||||
{
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
string expectedResult = "myVal";
|
||||
string key = "myName";
|
||||
AddressablesRuntimeProperties.SetPropertyValue(key, expectedResult);
|
||||
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateProperty(key);
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
public static string ReflectableStringValue = "myReflectionResult";
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_CanEvaluateReflection()
|
||||
{
|
||||
AddressablesRuntimeProperties.ClearCachedPropertyValues();
|
||||
string expectedResult = ReflectableStringValue;
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateProperty("AddrRuntimePropertiesTests.AddrRuntimePropertiesTests.ReflectableStringValue");
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluateStringCanParseAutomaticTokens()
|
||||
{
|
||||
string tok1 = "cheese";
|
||||
string tok2 = "cows";
|
||||
string tok3 = "moo";
|
||||
|
||||
string toEval = tok1 + '{' + tok2 + '}' + tok3;
|
||||
string expectedResult = tok1 + tok2 + tok3;
|
||||
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval);
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluateStringCanParseInExplicitOverride()
|
||||
{
|
||||
string tok1 = "cheese";
|
||||
string tok2 = "cows";
|
||||
string tok3 = "moo";
|
||||
string replacement = "_parsed_";
|
||||
char delim = '?';
|
||||
|
||||
string toEval = tok1 + delim + tok2 + delim + tok3;
|
||||
|
||||
string expectedResult = tok1 + replacement + tok3;
|
||||
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return replacement; });
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(1000)]
|
||||
public void RuntimeProperties_CanDetectCyclicLoops()
|
||||
{
|
||||
string a = "[B]";
|
||||
string b = "[A]";
|
||||
string toEval = "Test_[A]_";
|
||||
string expectedResult = "Test_#ERROR-CyclicToken#_";
|
||||
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, '[', ']', s =>
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case "A":
|
||||
return a;
|
||||
case "B":
|
||||
return b;
|
||||
}
|
||||
|
||||
return "";
|
||||
});
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(1000)]
|
||||
public void RuntimeProperties_CanEvaluateInnerProperties()
|
||||
{
|
||||
Dictionary<string, string> stringLookup = new Dictionary<string, string>();
|
||||
stringLookup.Add("B", "inner");
|
||||
stringLookup.Add("With_inner", "Success");
|
||||
string toEval = "Test_[With_[B]]";
|
||||
string expectedResult = "Test_Success";
|
||||
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, '[', ']', s =>
|
||||
{
|
||||
if (stringLookup.TryGetValue(s, out string val))
|
||||
return val;
|
||||
return "";
|
||||
});
|
||||
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluateString_CreatesLocalStackOnRecursiveCall()
|
||||
{
|
||||
string testString = "[{[{correct}]bad}]";
|
||||
string expectedResult = "CORRECTBAD";
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => { return AddressablesRuntimeProperties.EvaluateString(s, '{', '}', str => str.ToUpper()); });
|
||||
Assert.AreEqual(expectedResult, actualResult, "EvaluateString does not properly initialize a local stack for recursive/simultaneous calls.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluateString_CreatesLocalStacksOnDeepRecursiveCall()
|
||||
{
|
||||
string testString = "[{([{(correct)}]bad)}]";
|
||||
string expectedResult = "CORRECTBAD";
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']',
|
||||
s => { return AddressablesRuntimeProperties.EvaluateString(s, '{', '}', str => { return AddressablesRuntimeProperties.EvaluateString(str, '(', ')', str2 => str2.ToUpper()); }); });
|
||||
Assert.AreEqual(expectedResult, actualResult, "EvaluateString does not properly initialize a local stack for recursive/simultaneous calls.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnUnmatchedEndingDelimiter()
|
||||
{
|
||||
string testString = "[correct]bad]";
|
||||
string expectedResult = "#ERROR-" + testString + " contains unmatched delimiters#";
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s);
|
||||
Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop with unmatched ending delimiter");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnUnmatchedStartingDelimiter()
|
||||
{
|
||||
string testString = "[[correct]bad";
|
||||
string expectedResult = "[correctbad";
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s);
|
||||
Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop with unmatched starting delimiter");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnImproperlyOrderedDelimiters()
|
||||
{
|
||||
string testString = "][correct][bad";
|
||||
string expectedResult = "]correct[bad";
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s);
|
||||
Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop on reversed delimiters");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeProperties_EvaluateStringIgnoresSingleDelim()
|
||||
{
|
||||
string tok1 = "cheese";
|
||||
string tok2 = "cows";
|
||||
string tok3 = "moo";
|
||||
|
||||
string toEval = tok1 + tok2 + '}' + tok3;
|
||||
string expectedResult = toEval;
|
||||
string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval);
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
|
||||
|
||||
toEval = tok1 + '{' + tok2 + tok3;
|
||||
expectedResult = toEval;
|
||||
actualResult = AddressablesRuntimeProperties.EvaluateString(toEval);
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
|
||||
|
||||
string replacement = "_parsed_";
|
||||
char delim = '?';
|
||||
toEval = tok1 + tok2 + delim + tok3;
|
||||
expectedResult = toEval;
|
||||
actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return replacement; });
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
|
||||
toEval = tok1 + delim + tok2 + tok3;
|
||||
expectedResult = toEval;
|
||||
actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return replacement; });
|
||||
Assert.AreEqual(expectedResult, actualResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e6c1d0b0ab4d44f42a99963de99d60ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.ResourceManagement;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Build.DataBuilders;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace AddressableTests.FastModeInitTests
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public class FastModeInitializationTests : AddressablesTestFixture
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode => TestBuildScriptMode.Fast;
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void FastModeInit_EventViewerSetup_InitializesPostProfilerEventsValue(bool sendProfilerEvents)
|
||||
{
|
||||
//Setup
|
||||
bool originalValue = ProjectConfigData.PostProfilerEvents;
|
||||
ProjectConfigData.PostProfilerEvents = sendProfilerEvents;
|
||||
var settings = AddressableAssetSettings.Create(Path.Combine(GetGeneratedAssetsPath(), "Settings"), "AddressableAssetSettings.Tests", false, true);
|
||||
|
||||
//Test
|
||||
FastModeInitializationOperation fmInit = new FastModeInitializationOperation(m_Addressables, settings);
|
||||
fmInit.InvokeExecute();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(sendProfilerEvents, m_Addressables.ResourceManager.postProfilerEvents);
|
||||
|
||||
//Cleanup
|
||||
ProjectConfigData.PostProfilerEvents = originalValue;
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void FastModeInit_EventViewerSetup_InitializesDiagnosticEventCollectorCorrectly(bool sendProfilerEvents)
|
||||
{
|
||||
//Setup
|
||||
bool originalValue = ProjectConfigData.PostProfilerEvents;
|
||||
ProjectConfigData.PostProfilerEvents = sendProfilerEvents;
|
||||
var settings = AddressableAssetSettings.Create(Path.Combine(GetGeneratedAssetsPath(), "Settings"), "AddressableAssetSettings.Tests", false, true);
|
||||
|
||||
//Test
|
||||
FastModeInitializationOperation fmInit = new FastModeInitializationOperation(m_Addressables, settings);
|
||||
fmInit.InvokeExecute();
|
||||
|
||||
//Assert
|
||||
if (sendProfilerEvents)
|
||||
Assert.IsNotNull(fmInit.m_Diagnostics, "Diagnostic event collector was null when send profiler events was set to true.");
|
||||
else
|
||||
Assert.IsNull(fmInit.m_Diagnostics, "Diagnostic event collector was not null when send profiler events was false.");
|
||||
|
||||
//Cleanup
|
||||
ProjectConfigData.PostProfilerEvents = originalValue;
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void FastModeInitialization_SetsExceptionHandlerToNull_WhenLogRuntimeExceptionsIsOff(bool logRuntimeExceptions)
|
||||
{
|
||||
//Setup
|
||||
var settings = AddressableAssetSettings.Create(Path.Combine(GetGeneratedAssetsPath(), "Settings"), "AddressableAssetSettings.Tests", false, true);
|
||||
settings.buildSettings.LogResourceManagerExceptions = logRuntimeExceptions;
|
||||
|
||||
//Test
|
||||
FastModeInitializationOperation fmInit = new FastModeInitializationOperation(m_Addressables, settings);
|
||||
fmInit.InvokeExecute();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(logRuntimeExceptions, ResourceManager.ExceptionHandler != null);
|
||||
}
|
||||
|
||||
public class FastModeInitializationTestsBuildScriptFastMode : BuildScriptFastMode
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FastModeInitialization_GetBuilderOfType_ReturnsDirectAndSubclasses()
|
||||
{
|
||||
var settings = base.CreateSettings("AddressableAssetSettings.Tests", Path.Combine(GetGeneratedAssetsPath(), "Settings"));
|
||||
var db = FastModeInitializationOperation.GetBuilderOfType<BuildScriptFastMode>(settings, true);
|
||||
|
||||
// default fast mode should be added on Validate of the settings object
|
||||
Assert.IsNotNull(db, "Failed to find the FastMode build script");
|
||||
Assert.AreEqual(db.GetType(), typeof(BuildScriptFastMode), "Fast mode build script expected to be BuildScriptFastMode type");
|
||||
|
||||
Assert.IsTrue(settings.AddDataBuilder(settings.CreateScriptAsset<FastModeInitializationTestsBuildScriptFastMode>(), false), "Failed to Add custom buildScript FastMode");
|
||||
db = FastModeInitializationOperation.GetBuilderOfType<BuildScriptFastMode>(settings, true);
|
||||
Assert.IsNotNull(db, "Failed to find the FastMode build script");
|
||||
Assert.AreEqual(db.GetType(), typeof(FastModeInitializationTestsBuildScriptFastMode), "Fast mode build script expected to be FastModeInitializationTestsBuildScriptFastMode type");
|
||||
|
||||
db = FastModeInitializationOperation.GetBuilderOfType<BuildScriptFastMode>(settings, false);
|
||||
Assert.IsNotNull(db, "Failed to find the FastMode build script");
|
||||
Assert.AreEqual(db.GetType(), typeof(BuildScriptFastMode), "Fast mode build script expected to be BuildScriptFastMode type, where requesting exact type and exists in the settings");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 441d6ab2de7dd3948b7b50882e4370e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets.Initialization;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public abstract class InitializationObjectsAsyncTests : AddressablesTestFixture
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator InitializationObjects_CompletesWhenNoObjectsPresent()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Debug.Log($"{nameof(InitializationObjects_CompletesWhenNoObjectsPresent)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
yield break;
|
||||
}
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
op.Completed += obj =>
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.IsTrue(obj.Result);
|
||||
};
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(op, rtdOp);
|
||||
yield return handle;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializationObjects_CompletesSyncWhenNoObjectsPresent()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Assert.Ignore($"{nameof(InitializationObjects_CompletesWhenNoObjectsPresent)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
}
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
op.Completed += obj =>
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.IsTrue(obj.Result);
|
||||
};
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(op, rtdOp);
|
||||
handle.WaitForCompletion();
|
||||
Assert.IsTrue(handle.IsDone);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializationObjects_OperationRegistersForCallbacks()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Debug.Log($"{nameof(InitializationObjects_OperationRegistersForCallbacks)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
return;
|
||||
}
|
||||
|
||||
//We're checking to make sure we've created a new ResourceManagerCallbacks object. If this isn't null
|
||||
//then we won't create a new one. This would never be needed in a legitimate scenario.
|
||||
MonoBehaviourCallbackHooks.DestroySingleton();
|
||||
int startCount = Resources.FindObjectsOfTypeAll<MonoBehaviourCallbackHooks>().Length;
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
|
||||
//Test
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
int endCount = Resources.FindObjectsOfTypeAll<MonoBehaviourCallbackHooks>().Length;
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(startCount, endCount);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityTest]
|
||||
public IEnumerator InitializationObjects_CompletesWhenObjectsPresent()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Debug.Log($"{nameof(InitializationObjects_CompletesWhenObjectsPresent)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
yield break;
|
||||
}
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
op.Completed += obj =>
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.IsTrue(obj.Result);
|
||||
};
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
rtdOp.Completed += obj =>
|
||||
{
|
||||
ObjectInitializationData opData = ObjectInitializationData.CreateSerializedInitializationData<FakeInitializationObject>("fake", "fake");
|
||||
obj.Result.InitializationObjects.Add(opData);
|
||||
};
|
||||
yield return rtdOp;
|
||||
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(op, rtdOp);
|
||||
yield return handle;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializationObjects_CompletesSyncWhenObjectsPresent()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Assert.Ignore($"{nameof(InitializationObjects_CompletesWhenObjectsPresent)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
}
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
op.Completed += obj =>
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.IsTrue(obj.Result);
|
||||
};
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
rtdOp.Completed += obj =>
|
||||
{
|
||||
ObjectInitializationData opData = ObjectInitializationData.CreateSerializedInitializationData<FakeInitializationObject>("fake", "fake");
|
||||
obj.Result.InitializationObjects.Add(opData);
|
||||
};
|
||||
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(op, rtdOp);
|
||||
handle.WaitForCompletion();
|
||||
Assert.IsTrue(handle.IsDone);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator InitializationAsync_HandlesEmptyData()
|
||||
{
|
||||
if (m_RuntimeSettingsPath.StartsWith("GUID:"))
|
||||
{
|
||||
Debug.Log($"{nameof(InitializationAsync_HandlesEmptyData)} skipped due to not having a runtime settings asset (Fast mode does not create this).");
|
||||
yield break;
|
||||
}
|
||||
|
||||
InitalizationObjectsOperation op = new InitalizationObjectsOperation();
|
||||
op.Completed += obj =>
|
||||
{
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, obj.Status);
|
||||
Assert.IsTrue(obj.Result);
|
||||
};
|
||||
var runtimeDataLocation = new ResourceLocationBase("RuntimeData", m_RuntimeSettingsPath, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));
|
||||
var rtdOp = m_Addressables.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
|
||||
rtdOp.Completed += obj => { obj.Result.InitializationObjects.Add(default(ObjectInitializationData)); };
|
||||
yield return rtdOp;
|
||||
|
||||
op.Init(rtdOp, m_Addressables);
|
||||
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(op, rtdOp);
|
||||
yield return handle;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator InitializationObjectsOperation_DoesNotThrow_WhenRuntimeDataOpFails()
|
||||
{
|
||||
var initObjectsOp = new InitalizationObjectsOperation();
|
||||
initObjectsOp.Init(new AsyncOperationHandle<ResourceManagerRuntimeData>()
|
||||
{
|
||||
m_InternalOp = new ProviderOperation<ResourceManagerRuntimeData>()
|
||||
{
|
||||
Result = null
|
||||
}
|
||||
}, m_Addressables);
|
||||
LogAssert.Expect(LogType.Error, "RuntimeData is null. Please ensure you have built the correct Player Content.");
|
||||
var handle = m_Addressables.ResourceManager.StartOperation(initObjectsOp, default);
|
||||
yield return handle;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, handle.Status);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.XboxOne, RuntimePlatform.GameCoreXboxOne, RuntimePlatform.PS5, RuntimePlatform.Android})]
|
||||
public IEnumerator CacheInitializationObject_FullySetsCachingData()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
//SaveData for cleanup
|
||||
CacheInitializationData preTestCacheData = new CacheInitializationData()
|
||||
{
|
||||
CacheDirectoryOverride = Caching.currentCacheForWriting.path,
|
||||
CompressionEnabled = Caching.compressionEnabled,
|
||||
//ExpirationDelay = Caching.currentCacheForWriting.expirationDelay,
|
||||
MaximumCacheSize = Caching.currentCacheForWriting.maximumAvailableStorageSpace
|
||||
};
|
||||
|
||||
string cacheDirectoryOverride = "TestDirectory";
|
||||
//int expirationDelay = 4321;
|
||||
long maxCacheSize = 9876;
|
||||
bool compressionEnabled = !preTestCacheData.CompressionEnabled;
|
||||
|
||||
CacheInitializationData cacheData = new CacheInitializationData()
|
||||
{
|
||||
CacheDirectoryOverride = cacheDirectoryOverride,
|
||||
CompressionEnabled = compressionEnabled,
|
||||
//ExpirationDelay = expirationDelay,
|
||||
LimitCacheSize = true,
|
||||
MaximumCacheSize = maxCacheSize
|
||||
};
|
||||
|
||||
string json = JsonUtility.ToJson(cacheData);
|
||||
|
||||
CacheInitialization ci = new CacheInitialization();
|
||||
var handle = ci.InitializeAsync(m_Addressables.ResourceManager, "TestCacheInit", json);
|
||||
yield return handle;
|
||||
|
||||
Assert.AreEqual(cacheDirectoryOverride, Caching.currentCacheForWriting.path);
|
||||
//Assert.AreEqual(expirationDelay, Caching.currentCacheForWriting.expirationDelay);
|
||||
Assert.AreEqual(compressionEnabled, Caching.compressionEnabled);
|
||||
Assert.AreEqual(maxCacheSize, Caching.currentCacheForWriting.maximumAvailableStorageSpace);
|
||||
|
||||
//Cleanup
|
||||
Cache cache = Caching.GetCacheByPath(preTestCacheData.CacheDirectoryOverride);
|
||||
Caching.compressionEnabled = preTestCacheData.CompressionEnabled;
|
||||
cache.maximumAvailableStorageSpace = preTestCacheData.MaximumCacheSize;
|
||||
//cache.expirationDelay = preTestCacheData.ExpirationDelay;
|
||||
Caching.currentCacheForWriting = cache;
|
||||
|
||||
handle.Release();
|
||||
#else
|
||||
yield return null;
|
||||
Assert.Ignore();
|
||||
#endif
|
||||
}
|
||||
|
||||
class FakeInitializationObject : IInitializableObject
|
||||
{
|
||||
internal string m_Id;
|
||||
internal string m_Data;
|
||||
|
||||
public bool Initialize(string id, string data)
|
||||
{
|
||||
m_Id = id;
|
||||
m_Data = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public AsyncOperationHandle<bool> InitializeAsync(ResourceManager rm, string id, string data)
|
||||
{
|
||||
FakeAsyncOp op = new FakeAsyncOp();
|
||||
return rm.StartOperation(op, default);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeAsyncOp : AsyncOperationBase<bool>
|
||||
{
|
||||
protected override void Execute()
|
||||
{
|
||||
Complete(true, true, "");
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class InitializationObjects_FastMode : InitializationObjectsAsyncTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class InitializationObjects_VirtualMode : InitializationObjectsAsyncTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class InitializationObjects_PackedPlaymodeMode : InitializationObjectsAsyncTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class InitializationObjects_PackedMode : InitializationObjectsAsyncTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce10b9a173f68e7439b96557cb1bc223
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
using System.Collections;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.U2D;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets.Tests;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
namespace LegacyResourcesTests
|
||||
{
|
||||
abstract class LegacyResourceTests : AddressablesTestFixture
|
||||
{
|
||||
private const string kSpriteResourceName = "testSprite";
|
||||
private const string kSpriteAtlasResourceName = "testAtlas";
|
||||
private const string kObjectResourceName = "subfolder/testObject";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string rootFolder)
|
||||
{
|
||||
var group = settings.CreateGroup("Legacy", true, false, false, null, typeof(PlayerDataGroupSchema));
|
||||
var schema = group.GetSchema<PlayerDataGroupSchema>();
|
||||
schema.IncludeResourcesFolders = true;
|
||||
schema.IncludeBuildSettingsScenes = false;
|
||||
var resourceEntry = settings.CreateOrMoveEntry(AddressableAssetEntry.ResourcesName, group);
|
||||
resourceEntry.IsInResources = true;
|
||||
|
||||
string resourceDirectory = Path.Combine(rootFolder, "Resources");
|
||||
Directory.CreateDirectory(resourceDirectory + "/subfolder");
|
||||
|
||||
var spritePath = Path.Combine(resourceDirectory, kSpriteResourceName + ".png");
|
||||
CreateSpriteOnPath(spritePath);
|
||||
string spriteGuid = AssetDatabase.AssetPathToGUID(spritePath);
|
||||
SessionState.SetString("spriteGuid", spriteGuid);
|
||||
|
||||
CreateScriptableObjectOnPath(Path.Combine(resourceDirectory, kObjectResourceName + ".asset"));
|
||||
var atlasPath = Path.Combine(resourceDirectory, kSpriteAtlasResourceName + ".spriteatlas");
|
||||
CreateSpriteAtlas(atlasPath, new string[] {spritePath});
|
||||
}
|
||||
|
||||
void CreateSpriteOnPath(string spritePath)
|
||||
{
|
||||
CreateTextureOnPath(spritePath);
|
||||
var importer = AssetImporter.GetAtPath(spritePath) as TextureImporter;
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Single;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
void CreateTextureOnPath(string spritePath)
|
||||
{
|
||||
var texture = new Texture2D(32, 32);
|
||||
var data = ImageConversion.EncodeToPNG(texture);
|
||||
Object.DestroyImmediate(texture);
|
||||
File.WriteAllBytes(spritePath, data);
|
||||
AssetDatabase.ImportAsset(spritePath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
void CreateScriptableObjectOnPath(string path)
|
||||
{
|
||||
AssetDatabase.CreateAsset(TestObject.Create("test"), path);
|
||||
}
|
||||
|
||||
void CreateSpriteAtlas(string path, string[] spriteAssetPaths)
|
||||
{
|
||||
var sa = new SpriteAtlas();
|
||||
AssetDatabase.CreateAsset(sa, path);
|
||||
foreach (string spritePath in spriteAssetPaths)
|
||||
{
|
||||
sa.Add(new UnityEngine.Object[]
|
||||
{
|
||||
AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(spritePath)
|
||||
});
|
||||
}
|
||||
|
||||
SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] {sa}, EditorUserBuildSettings.activeBuildTarget, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanLoadFromResources_TextureSprite()
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<Sprite>(kSpriteResourceName);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.IsNotNull(op.Result);
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanLoadFromResources_ByGuid()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string resourceDirectory = Path.Combine(GetGeneratedAssetsPath(), "Resources");
|
||||
Directory.CreateDirectory(resourceDirectory + "/subfolder");
|
||||
string spriteGuid = AssetDatabase.AssetPathToGUID(Path.Combine(resourceDirectory, kSpriteResourceName + ".png"));
|
||||
Assert.IsFalse(string.IsNullOrEmpty(spriteGuid));
|
||||
var op = m_Addressables.LoadAssetAsync<Sprite>(spriteGuid);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.IsNotNull(op.Result);
|
||||
m_Addressables.Release(op);
|
||||
#else
|
||||
UnityEngine.Debug.Log($"Skipping test {nameof(CanLoadFromResources_ByGuid)} due to running outside of Editor.");
|
||||
yield break;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenLoadingSpecificTypes_ObjectOfSpecifiedTypeIsReturned()
|
||||
{
|
||||
AsyncOperationHandle spriteOp = m_Addressables.LoadAssetAsync<Sprite>(kSpriteResourceName);
|
||||
AsyncOperationHandle texOp = m_Addressables.LoadAssetAsync<Texture>(kSpriteResourceName);
|
||||
yield return spriteOp;
|
||||
yield return texOp;
|
||||
Assert.AreEqual(typeof(Sprite), spriteOp.Result.GetType());
|
||||
Assert.AreEqual(typeof(Texture2D), texOp.Result.GetType());
|
||||
m_Addressables.Release(spriteOp);
|
||||
m_Addressables.Release(texOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanLoadFromResources_ObjectWithPath()
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<TestObject>(kObjectResourceName);
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.IsNotNull(op.Result);
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanLoadFromResources_AtlasedSprite()
|
||||
{
|
||||
var op = m_Addressables.LoadAssetAsync<Sprite>(kSpriteAtlasResourceName + "[" + kSpriteResourceName + "]");
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.IsNotNull(op.Result.GetType());
|
||||
m_Addressables.Release(op);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class LegacyResourceTests_FastMode : LegacyResourceTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class LegacyResourceTests_VirtualMode : LegacyResourceTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class LegacyResourceTests_PackedPlaymodeMode : LegacyResourceTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class LegacyResourceTests_PackedMode : LegacyResourceTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a752b6e9dc874574babc9f4b5c08d5aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace AddressableAssetsIntegrationTests
|
||||
{
|
||||
internal class ManualPercentCompleteOperation : AsyncOperationBase<GameObject>
|
||||
{
|
||||
public ManualPercentCompleteOperation(float percentComplete)
|
||||
{
|
||||
m_PercentComplete = percentComplete;
|
||||
m_DownloadStatus = new DownloadStatus();
|
||||
}
|
||||
|
||||
public ManualPercentCompleteOperation(DownloadStatus status)
|
||||
{
|
||||
m_DownloadStatus = status;
|
||||
m_PercentComplete = 0f;
|
||||
}
|
||||
|
||||
public ManualPercentCompleteOperation(float percentComplete, DownloadStatus status)
|
||||
{
|
||||
m_DownloadStatus = status;
|
||||
m_PercentComplete = percentComplete;
|
||||
}
|
||||
|
||||
public float m_PercentComplete;
|
||||
public DownloadStatus m_DownloadStatus;
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
Complete(new GameObject(), true, "");
|
||||
}
|
||||
|
||||
protected override float Progress => m_PercentComplete;
|
||||
|
||||
internal override DownloadStatus GetDownloadStatus(HashSet<object> visited)
|
||||
{
|
||||
return m_DownloadStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a6212fd4877a4704aa905b317e16bac8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AddressableAssetsIntegrationTests
|
||||
{
|
||||
public class ObjectReferenceMonoBehaviour : MonoBehaviour
|
||||
{
|
||||
public UnityEngine.Object m_ObjectReference;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c250a53221434148be3ac31d903d8c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c2eb630b3a204847b868607a539fb4c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 962906719cf3dae4f8b815dcc25b22b5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,377 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine.AddressableAssets.Initialization;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
|
||||
namespace UnityEngine.AddressableAssets.ResourceProviders.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ContentCatalogProviderTests : AddressablesTestFixture
|
||||
{
|
||||
const string k_LocationName = "TestLocation";
|
||||
const string k_LocationId = "TestLocationID";
|
||||
const string k_CacheLocationId = "CacheLocationID";
|
||||
const string k_RemoteLocationId = "RemoteLocationID";
|
||||
private const string k_TempAssetFolder = "Assets/TempFolder";
|
||||
private const string k_TempBuildFolder = "TempBuildFolder";
|
||||
private readonly string m_RuntimeCatalogFilename;
|
||||
|
||||
public ContentCatalogProviderTests()
|
||||
{
|
||||
m_RuntimeCatalogFilename = "catalog" + m_UniqueTestName + ".bundle";
|
||||
}
|
||||
|
||||
ResourceLocationBase m_SimpleLocation = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
protected override TestBuildScriptMode BuildScriptMode => TestBuildScriptMode.Packed;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
settings.BundleLocalCatalog = true;
|
||||
settings.DefaultGroup.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.AppendHash;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfLocalCatalogsOnly_ReturnsMainId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"hash", string.Empty}, true);
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfNoDependencies_ReturnsMainId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(m_SimpleLocation, null);
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfTooFewDependencies_ReturnsMainId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(m_SimpleLocation, new List<object> {1});
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfTooManyDependencies_ReturnsMainId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(m_SimpleLocation, new List<object> {1, 2, 3});
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfOfflineAndNoCache_ReturnsMainId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(m_SimpleLocation, new List<object> {string.Empty, string.Empty});
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfOfflineAndHasCache_ReturnsCacheId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {string.Empty, "hash"});
|
||||
|
||||
Assert.AreEqual(k_CacheLocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfOnlineMatchesCache_ReturnsCacheId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"hash", "hash"});
|
||||
|
||||
Assert.AreEqual(k_CacheLocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfDisableContentCatalogUpdateTrue_ForcesLocalId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"hash", ""}, true);
|
||||
|
||||
Assert.AreEqual(k_LocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfDisableContentCatalogUpdateTrue_ForcesCachedIdWhenLocalHashExists()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"hash", "local"}, true);
|
||||
Assert.AreEqual(k_CacheLocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_SetsLocalHash_WhenDisableContentCatalogIsTrue_AndNoLocalHashExists()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(contentCatalogOp.m_LocalHashValue));
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"hash", ""}, true);
|
||||
Assert.IsFalse(string.IsNullOrEmpty(contentCatalogOp.m_LocalHashValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DetermineIdToLoad_IfOnlineMismatchesCache_ReturnsRemoteId()
|
||||
{
|
||||
var contentCatalogOp = new ContentCatalogProvider.InternalOp();
|
||||
|
||||
IResourceLocation[] dependencies = new IResourceLocation[(int) ContentCatalogProvider.DependencyHashIndex.Count];
|
||||
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Remote] = new ResourceLocationBase(string.Empty, k_RemoteLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
dependencies[(int) ContentCatalogProvider.DependencyHashIndex.Cache] = new ResourceLocationBase(string.Empty, k_CacheLocationId, typeof(ContentCatalogProvider).FullName, typeof(object));
|
||||
|
||||
var location = new ResourceLocationBase(k_LocationName, k_LocationId, typeof(ContentCatalogProvider).FullName, typeof(object), dependencies);
|
||||
|
||||
|
||||
var loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"newHash", "hash"});
|
||||
Assert.AreEqual(k_RemoteLocationId, loadedId);
|
||||
|
||||
loadedId = contentCatalogOp.DetermineIdToLoad(location, new List<object> {"newHash", string.Empty});
|
||||
Assert.AreEqual(k_RemoteLocationId, loadedId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(null, typeof(ArgumentNullException))]
|
||||
[TestCase("invalid", typeof(ArgumentException))]
|
||||
[TestCase("file.txt", typeof(ArgumentException))]
|
||||
public void BundledCatalog_LoadCatalogFromBundle_InvalidBundlePath_ShouldThrow(string path, Type exceptionType)
|
||||
{
|
||||
Assert.Throws(exceptionType, () => new ContentCatalogProvider.InternalOp.BundledCatalog(path));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[Ignore("https://jira.unity3d.com/browse/ADDR-1451")]
|
||||
public IEnumerator BundledCatalog_LoadCatalogFromBundle_InvalidBundleFileFormat_ShouldFail()
|
||||
{
|
||||
var bundleFilePath = Path.Combine(k_TempBuildFolder, "catalog.bundle");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(bundleFilePath));
|
||||
|
||||
var bytes = new byte[] {1, 2, 3, 4, 5, 6};
|
||||
File.WriteAllBytes(bundleFilePath, bytes);
|
||||
|
||||
LogAssert.Expect(LogType.Error, new Regex("Failed to read data for the AssetBundle", RegexOptions.IgnoreCase));
|
||||
|
||||
LogAssert.Expect(LogType.Error, new Regex("Unable to load dependent " +
|
||||
$"bundle from location :", RegexOptions.IgnoreCase));
|
||||
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.IsFalse(bundledCatalog.OpIsSuccess);
|
||||
|
||||
if (Directory.Exists(k_TempBuildFolder))
|
||||
Directory.Delete(k_TempBuildFolder, true);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BundledCatalog_WhenCatalogIsLocal_LoadCatalogFromBundle_ShouldLoadCatalogAndUnloadResources()
|
||||
{
|
||||
var bundleFilePath = Path.Combine(Addressables.RuntimePath, m_RuntimeCatalogFilename);
|
||||
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
bundledCatalog.OnLoaded += catalogData =>
|
||||
{
|
||||
Assert.NotNull(catalogData);
|
||||
Assert.AreEqual(ResourceManagerRuntimeData.kCatalogAddress, catalogData.ProviderId);
|
||||
};
|
||||
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.IsTrue(bundledCatalog.OpIsSuccess);
|
||||
Assert.Null(bundledCatalog.m_CatalogAssetBundle);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.Android})]
|
||||
public IEnumerator BundledCatalog_WhenCatalogIsRemote_LoadCatalogFromBundle_ShouldLoadCatalogAndUnloadResources()
|
||||
{
|
||||
string localBundleFilePath = Path.Combine(Addressables.RuntimePath, m_RuntimeCatalogFilename);
|
||||
string bundleFilePath = "file:///" + Path.GetFullPath(localBundleFilePath);
|
||||
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
bundledCatalog.OnLoaded += catalogData =>
|
||||
{
|
||||
Assert.NotNull(catalogData);
|
||||
Assert.AreEqual(ResourceManagerRuntimeData.kCatalogAddress, catalogData.ProviderId);
|
||||
};
|
||||
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.IsTrue(bundledCatalog.OpIsSuccess);
|
||||
Assert.Null(bundledCatalog.m_CatalogAssetBundle);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BundledCatalog_WhenRemoteCatalogDoesNotExist_LoadCatalogFromBundle_LogsErrorAndOpFails()
|
||||
{
|
||||
string bundleFilePath = "file:///doesnotexist.bundle";
|
||||
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
|
||||
LogAssert.Expect(LogType.Error, $"Unable to load dependent bundle from location : {bundleFilePath}");
|
||||
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.IsFalse(bundledCatalog.OpIsSuccess);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BundledCatalog_LoadCatalogFromBundle_WhenCalledMultipleTimes_OpNotCompleted_FirstShouldSucceedAndOthersShouldFail()
|
||||
{
|
||||
var bundleFilePath = Path.Combine(Addressables.RuntimePath, m_RuntimeCatalogFilename);
|
||||
|
||||
var timesCalled = 0;
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.OnLoaded += catalogData =>
|
||||
{
|
||||
Assert.NotNull(catalogData);
|
||||
Assert.AreEqual(ResourceManagerRuntimeData.kCatalogAddress, catalogData.ProviderId);
|
||||
timesCalled++;
|
||||
};
|
||||
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
LogAssert.Expect(LogType.Error, new Regex("progress", RegexOptions.IgnoreCase));
|
||||
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.AreEqual(1, timesCalled);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BundledCatalog_LoadCatalogFromBundle_WhenCalledMultipleTimes_OpCompleted_AllShouldSucceed()
|
||||
{
|
||||
var bundleFilePath = Path.Combine(Addressables.RuntimePath, m_RuntimeCatalogFilename);
|
||||
|
||||
var timesCalled = 0;
|
||||
var bundledCatalog = new ContentCatalogProvider.InternalOp.BundledCatalog(bundleFilePath);
|
||||
bundledCatalog.OnLoaded += catalogData =>
|
||||
{
|
||||
Assert.NotNull(catalogData);
|
||||
Assert.AreEqual(ResourceManagerRuntimeData.kCatalogAddress, catalogData.ProviderId);
|
||||
timesCalled++;
|
||||
};
|
||||
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
bundledCatalog.LoadCatalogFromBundleAsync();
|
||||
yield return new WaitWhile(() => bundledCatalog.OpInProgress);
|
||||
|
||||
Assert.AreEqual(2, timesCalled);
|
||||
Assert.IsTrue(bundledCatalog.OpIsSuccess);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentCatalogProvider_InternalOp_LoadCatalog_InvalidId_Throws()
|
||||
{
|
||||
Assert.Throws<NullReferenceException>(() => new ContentCatalogProvider.InternalOp().LoadCatalog("fakeId", false));
|
||||
}
|
||||
|
||||
#if ENABLE_BINARY_CATALOG
|
||||
[TestCase("http://127.0.0.1/catalog.bin", false)]
|
||||
#else
|
||||
[TestCase("http://127.0.0.1/catalog.json", false)]
|
||||
#endif
|
||||
[TestCase("http://127.0.0.1/catalog.bundle", true)]
|
||||
public void BundledCatalog_WhenRequestingRemoteCatalog_CanLoadCatalogFromBundle_ReturnsExpectedResult(string internalId, bool result)
|
||||
{
|
||||
var loc = new ResourceLocationBase(internalId, internalId, typeof(ContentCatalogProvider).FullName, typeof(IResourceLocator));
|
||||
ProviderOperation<Object> op = new ProviderOperation<Object>();
|
||||
op.Init(m_Addressables.ResourceManager, null, loc, new AsyncOperationHandle<IList<AsyncOperationHandle>>());
|
||||
ProvideHandle handle = new ProvideHandle(m_Addressables.ResourceManager, op);
|
||||
|
||||
bool loadCatalogFromLocalBundle = new ContentCatalogProvider.InternalOp().CanLoadCatalogFromBundle(internalId, handle.Location);
|
||||
Assert.AreEqual(result, loadCatalogFromLocalBundle);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BundledCatalog_WhenRequestingLocalCatalog_CanLoadCatalogFromBundle_ReturnsTrue()
|
||||
{
|
||||
string internalId = Path.Combine(Addressables.RuntimePath, m_RuntimeCatalogFilename);
|
||||
var loc = new ResourceLocationBase(internalId, internalId, typeof(ContentCatalogProvider).FullName, typeof(IResourceLocator));
|
||||
ProviderOperation<Object> op = new ProviderOperation<Object>();
|
||||
op.Init(m_Addressables.ResourceManager, null, loc, new AsyncOperationHandle<IList<AsyncOperationHandle>>());
|
||||
ProvideHandle handle = new ProvideHandle(m_Addressables.ResourceManager, op);
|
||||
|
||||
bool loadCatalogFromLocalBundle = new ContentCatalogProvider.InternalOp().CanLoadCatalogFromBundle(internalId, handle.Location);
|
||||
Assert.IsTrue(loadCatalogFromLocalBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 832363b0cc1d7e44dbd8750e91343bd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
|
||||
namespace UnityEngine.AddressableAssets.ResourceProviders.Tests
|
||||
{
|
||||
public class TextDataProviderStub : TextDataProvider
|
||||
{
|
||||
TextDataProvider m_TextDataProvider;
|
||||
string m_FakeRemoteFolder;
|
||||
|
||||
public TextDataProviderStub(string fakeRemoteFolder, TextDataProvider textDataProvider)
|
||||
{
|
||||
m_TextDataProvider = textDataProvider;
|
||||
m_FakeRemoteFolder = fakeRemoteFolder;
|
||||
}
|
||||
|
||||
public override string ProviderId => m_TextDataProvider.ProviderId;
|
||||
|
||||
public override void Provide(ProvideHandle provideHandle)
|
||||
{
|
||||
new InternalOpStub(m_FakeRemoteFolder).Start(provideHandle, m_TextDataProvider);
|
||||
}
|
||||
|
||||
internal class InternalOpStub : TextDataProvider.InternalOp
|
||||
{
|
||||
string m_FakeRemoteFolder;
|
||||
static readonly Regex k_Pattern = new Regex(@"http://[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}");
|
||||
|
||||
public InternalOpStub(string fakeRemoteFolder)
|
||||
{
|
||||
m_FakeRemoteFolder = fakeRemoteFolder;
|
||||
}
|
||||
|
||||
protected override void SendWebRequest(string path)
|
||||
{
|
||||
string pathWithFakeRemoteFolder = k_Pattern.Replace(ResourceManagerConfig.StripQueryParameters(path), m_FakeRemoteFolder);
|
||||
|
||||
string fileText = null;
|
||||
Exception ex = null;
|
||||
if (File.Exists(pathWithFakeRemoteFolder))
|
||||
fileText = File.ReadAllText(pathWithFakeRemoteFolder);
|
||||
else
|
||||
ex = new Exception($"{nameof(TextDataProvider)} unable to load from url {path}");
|
||||
|
||||
CompleteOperation(fileText, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonAssetProviderStub : TextDataProviderStub
|
||||
{
|
||||
public JsonAssetProviderStub(string fakeRemoteFolder, JsonAssetProvider jsonAssetProvider)
|
||||
: base(fakeRemoteFolder, jsonAssetProvider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86d78906b9304e148389fa0f7e3ae6a4
|
||||
timeCreated: 1618259584
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
public class RuntimePlatformMappingServiceTests
|
||||
{
|
||||
[TestCase(RuntimePlatform.XboxOne, AddressablesPlatform.XboxOne)]
|
||||
[TestCase(RuntimePlatform.Switch, AddressablesPlatform.Switch)]
|
||||
[TestCase(RuntimePlatform.PS4, AddressablesPlatform.PS4)]
|
||||
[TestCase(RuntimePlatform.IPhonePlayer, AddressablesPlatform.iOS)]
|
||||
[TestCase(RuntimePlatform.Android, AddressablesPlatform.Android)]
|
||||
[TestCase(RuntimePlatform.WebGLPlayer, AddressablesPlatform.WebGL)]
|
||||
[TestCase(RuntimePlatform.WindowsPlayer, AddressablesPlatform.Windows)]
|
||||
[TestCase(RuntimePlatform.OSXPlayer, AddressablesPlatform.OSX)]
|
||||
[TestCase(RuntimePlatform.LinuxPlayer, AddressablesPlatform.Linux)]
|
||||
[TestCase(RuntimePlatform.WSAPlayerARM, AddressablesPlatform.WindowsUniversal)]
|
||||
[TestCase(RuntimePlatform.WSAPlayerX64, AddressablesPlatform.WindowsUniversal)]
|
||||
[TestCase(RuntimePlatform.WSAPlayerX86, AddressablesPlatform.WindowsUniversal)]
|
||||
public void RuntimePlatformMappingService_EqualsDesiredAddressablesPlatform(RuntimePlatform platform, AddressablesPlatform desiredPlatform)
|
||||
{
|
||||
Assert.AreEqual(PlatformMappingService.GetAddressablesPlatformInternal(platform), desiredPlatform);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ea2465c600278f4db3fdb6b76ee06a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,608 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace SceneTests
|
||||
{
|
||||
abstract class SceneTests : AddressablesTestFixture
|
||||
{
|
||||
int m_StartingSceneCount;
|
||||
const int numScenes = 2;
|
||||
protected List<String> sceneKeys;
|
||||
const string prefabKey = "prefabKey";
|
||||
internal const string kEmbeddedSceneName = "embeddedassetscene";
|
||||
|
||||
protected internal string GetPrefabKey()
|
||||
{
|
||||
return prefabKey;
|
||||
}
|
||||
|
||||
public SceneTests()
|
||||
{
|
||||
sceneKeys = new List<string>();
|
||||
for (int i = 0; i < numScenes; i++)
|
||||
{
|
||||
sceneKeys.Add("SceneTests_Scene" + i);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
AddressableAssetGroup group = settings.CreateGroup("SceneGroup", true, false, false, null, typeof(BundledAssetGroupSchema));
|
||||
group.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
// Create prefab
|
||||
string prefabPath = CreateAssetPath(tempAssetFolder, prefabKey, ".prefab");
|
||||
string prefabGuid = CreatePrefab(prefabPath);
|
||||
AddressableAssetEntry prefabEntry = settings.CreateOrMoveEntry(prefabGuid, group, false, false);
|
||||
prefabEntry.address = Path.GetFileNameWithoutExtension(prefabEntry.AssetPath);
|
||||
|
||||
// Create scenes
|
||||
for (int i = 0; i < numScenes; i++)
|
||||
{
|
||||
string scenePath = CreateAssetPath(tempAssetFolder, sceneKeys[i], ".unity");
|
||||
string sceneGuid = CreateScene(scenePath);
|
||||
AddressableAssetEntry sceneEntry = settings.CreateOrMoveEntry(sceneGuid, group, false, false);
|
||||
sceneEntry.address = Path.GetFileNameWithoutExtension(sceneEntry.AssetPath);
|
||||
}
|
||||
|
||||
{
|
||||
string scenePath = CreateAssetPath(tempAssetFolder, kEmbeddedSceneName, ".unity");
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Additive);
|
||||
new GameObject("EmbededMeshGameObject").AddComponent<MeshFilter>().mesh = new Mesh();
|
||||
EditorSceneManager.SaveScene(scene, scenePath);
|
||||
string sceneGuid = AssetDatabase.AssetPathToGUID(scene.path);
|
||||
AddressableAssetEntry sceneEntry = settings.CreateOrMoveEntry(sceneGuid, group, false, false);
|
||||
sceneEntry.address = Path.GetFileNameWithoutExtension(sceneEntry.AssetPath);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_StartingSceneCount = m_Addressables.SceneOperationCount;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Assert.AreEqual(m_StartingSceneCount, m_Addressables.SceneOperationCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CanLoadMultipleScenesAdditively()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
|
||||
var op1 = m_Addressables.LoadSceneAsync(sceneKeys[1], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op1;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op1.Status);
|
||||
Assert.AreEqual(sceneKeys[1], SceneManager.GetSceneByName(sceneKeys[1]).name);
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
yield return UnloadSceneFromHandler(op1, m_Addressables);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator AddressablesImpl_LoadSceneAsync_FailsLoadNonexistent()
|
||||
{
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
var op = m_Addressables.LoadSceneAsync("testkey", new LoadSceneParameters(LoadSceneMode.Single));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.IsTrue(op.OperationException.Message.Contains("InvalidKey"));
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadSceneAsync_Fails_When_DepsFail()
|
||||
{
|
||||
var ifm = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
var loc = new ResourceLocationBase("scene", "asdf", typeof(SceneProvider).FullName, typeof(SceneInstance),
|
||||
new ResourceLocationBase("invalid", "nobundle", typeof(AssetBundleProvider).FullName, typeof(AssetBundleResource)));
|
||||
var op = m_Addressables.LoadSceneAsync(loc);
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, op.Status);
|
||||
Assert.IsTrue(op.OperationException.Message.Contains("GroupOperation"));
|
||||
LogAssert.ignoreFailingMessages = ifm;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator PercentComplete_NeverHasDecreasedValue_WhenLoadingScene()
|
||||
{
|
||||
//Setup
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
|
||||
//Test
|
||||
float lastPercentComplete = 0f;
|
||||
while (!op.IsDone)
|
||||
{
|
||||
Assert.IsFalse(lastPercentComplete > op.PercentComplete);
|
||||
lastPercentComplete = op.PercentComplete;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Assert.True(op.PercentComplete == 1 && op.IsDone);
|
||||
yield return op;
|
||||
|
||||
//Cleanup
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSceneUnloaded_InstanitatedObjectsInThatSceneAreReleased()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
SceneManager.SetActiveScene(op.Result.Scene);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetActiveScene().name);
|
||||
|
||||
var instOp = m_Addressables.InstantiateAsync(prefabKey);
|
||||
yield return instOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, instOp.Status);
|
||||
Assert.AreEqual(sceneKeys[0], instOp.Result.scene.name);
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
Assert.IsFalse(instOp.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSceneUnloadedWithSceneManager_InstanitatedObjectsInThatSceneAreReleased()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
SceneManager.SetActiveScene(op.Result.Scene);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetActiveScene().name);
|
||||
|
||||
var instOp = m_Addressables.InstantiateAsync(prefabKey);
|
||||
yield return instOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, instOp.Status);
|
||||
Assert.AreEqual(sceneKeys[0], instOp.Result.scene.name);
|
||||
|
||||
var unloadOp = SceneManager.UnloadSceneAsync(op.Result.Scene);
|
||||
yield return unloadOp;
|
||||
Assert.IsTrue(unloadOp.isDone);
|
||||
Assert.IsNull(SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
Assert.IsFalse(instOp.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSceneUnloaded_InstantiatedObjectsInOtherScenesAreNotReleased()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
|
||||
var activeScene = m_Addressables.LoadSceneAsync(sceneKeys[1], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return activeScene;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, activeScene.Status);
|
||||
Assert.AreEqual(sceneKeys[1], SceneManager.GetSceneByName(sceneKeys[1]).name);
|
||||
SceneManager.SetActiveScene(activeScene.Result.Scene);
|
||||
Assert.AreEqual(sceneKeys[1], SceneManager.GetActiveScene().name);
|
||||
|
||||
Assert.IsNull(GameObject.Find(prefabKey));
|
||||
var instOp = m_Addressables.InstantiateAsync(prefabKey);
|
||||
yield return instOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, instOp.Status);
|
||||
Assert.AreEqual(sceneKeys[1], instOp.Result.scene.name);
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
Assert.NotNull(GameObject.Find(instOp.Result.name));
|
||||
|
||||
yield return UnloadSceneFromHandler(activeScene, m_Addressables);
|
||||
Assert.IsFalse(instOp.IsValid());
|
||||
}
|
||||
|
||||
/* Regression test for https://jira.unity3d.com/browse/ADDR-1032
|
||||
*
|
||||
* Bug occurs when an instantiation happens after a previously completed instantiation.
|
||||
* The InstanceOperation is recycled from the previous instantiation, but its m_scene field is not cleaned.
|
||||
*
|
||||
* Test ensures that when instantiating a prefab and the InstanceOperation is recycled from a previous instantiation,
|
||||
* the m_Scene (field in InstanceOperation) should be null until the InstanceOperation is completed.
|
||||
*/
|
||||
[UnityTest]
|
||||
public IEnumerator WhenInstantiatingPrefab_AndOperationIsRecycled_SceneIsNullUntilCompletion()
|
||||
{
|
||||
// Previous instantiation
|
||||
var instOp = m_Addressables.InstantiateAsync(prefabKey);
|
||||
var internalInstanceOp1 = instOp.m_InternalOp;
|
||||
yield return instOp;
|
||||
instOp.Release();
|
||||
|
||||
// InstanceOperation we want to test
|
||||
var instOp2 = m_Addressables.InstantiateAsync(prefabKey);
|
||||
var internalInstanceOp2 = (ResourceManager.InstanceOperation)instOp2.m_InternalOp;
|
||||
|
||||
// Test
|
||||
Assert.False(internalInstanceOp2.IsDone, "InstanceOperation2 is not yet completed.");
|
||||
Assert.AreEqual(internalInstanceOp1, internalInstanceOp2, "The operation was not recycled");
|
||||
Assert.True(string.IsNullOrEmpty(internalInstanceOp2.InstanceScene().name), "Scene was not cleared from InstanceOperation");
|
||||
|
||||
// Cleanup
|
||||
yield return internalInstanceOp2;
|
||||
yield return instOp2;
|
||||
instOp2.Release();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ActivateSceneAsync_ReturnsOperation()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
var activateScene = op.Result.ActivateAsync();
|
||||
yield return activateScene;
|
||||
|
||||
Assert.AreEqual(op.Result.m_Operation, activateScene);
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_LoadSceneHandle_MatchesTrackedHandle()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(1, m_Addressables.m_SceneInstances.Count);
|
||||
Assert.IsTrue(m_Addressables.m_SceneInstances.Contains(op));
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_LoadSceneWithChainHandle_MatchesTrackedHandle()
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = m_Addressables.LoadSceneWithChain(impl.InitializeAsync(), sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(1, m_Addressables.m_SceneInstances.Count);
|
||||
Assert.IsTrue(m_Addressables.m_SceneInstances.Contains(op));
|
||||
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
impl.ResourceManager.Dispose();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_UnloadScene_RemovesTrackedInstanceOp()
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = m_Addressables.LoadSceneWithChain(impl.InitializeAsync(), sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(1, m_Addressables.m_SceneInstances.Count);
|
||||
yield return UnloadSceneFromHandler(op, m_Addressables);
|
||||
|
||||
Assert.AreEqual(0, m_Addressables.m_SceneInstances.Count);
|
||||
impl.ResourceManager.Dispose();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_UnloadSceneAsync_CanUnloadBaseHandle()
|
||||
{
|
||||
AddressablesImpl impl = new AddressablesImpl(new DefaultAllocationStrategy());
|
||||
var op = m_Addressables.LoadSceneWithChain(impl.InitializeAsync(), sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(1, m_Addressables.m_SceneInstances.Count);
|
||||
bool autoReleaseHandle = false;
|
||||
op = impl.UnloadSceneAsync((AsyncOperationHandle)op, UnloadSceneOptions.None, autoReleaseHandle);
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
op.Release();
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(0, m_Addressables.m_SceneInstances.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_UnloadSceneAsync_CanUnloadFromSceneInstance()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
Assert.AreEqual(1, m_Addressables.m_SceneInstances.Count);
|
||||
var sceneInst = op.m_InternalOp.Result;
|
||||
yield return m_Addressables.UnloadSceneAsync(sceneInst);
|
||||
|
||||
Assert.AreEqual(0, m_Addressables.m_SceneInstances.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_UnloadSceneAsync_UnloadSceneDecreaseRefOnlyOnce()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
|
||||
Addressables.ResourceManager.Acquire(op);
|
||||
yield return UnloadSceneFromHandlerRefCountCheck(op, m_Addressables);
|
||||
|
||||
// Cleanup
|
||||
Addressables.Release(op);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_Release_ReleaseToZeroRefCountUnloadsScene()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
|
||||
m_Addressables.Release(op);
|
||||
yield return null;
|
||||
|
||||
Assert.IsFalse(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_Release_ReleaseToRefCountZeroWhileLoadingUnloadsAfterLoadCompletes()
|
||||
{
|
||||
// Setup
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
|
||||
// Test
|
||||
op.Completed += s => Assert.IsTrue(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
m_Addressables.Release(op);
|
||||
yield return op;
|
||||
Assert.IsFalse(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsFalse(op.IsValid());
|
||||
|
||||
// Cleanup
|
||||
yield return op;
|
||||
}
|
||||
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_SceneOp_UpdateReceiverDoesNotRemainPastCompletion()
|
||||
{
|
||||
int startingReceiversCount = m_Addressables.ResourceManager.m_UpdateReceivers.Count + m_Addressables.ResourceManager.m_UpdateCallbacks.Count;
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
|
||||
try
|
||||
{
|
||||
op.m_InternalOp.Executed += () =>
|
||||
{
|
||||
if (op.m_InternalOp.HasExecuted && !op.m_InternalOp.IsDone)
|
||||
{
|
||||
Assert.AreEqual(startingReceiversCount + 1, m_Addressables.ResourceManager.m_UpdateReceivers.Count + m_Addressables.ResourceManager.m_UpdateCallbacks.Count,
|
||||
$"Expected {startingReceiversCount + 1} update receivers but was actually {m_Addressables.ResourceManager.m_UpdateReceivers.Count + m_Addressables.ResourceManager.m_UpdateCallbacks.Count}");
|
||||
}
|
||||
};
|
||||
|
||||
yield return op;
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
Assert.AreEqual(startingReceiversCount, m_Addressables.ResourceManager.m_UpdateReceivers.Count + m_Addressables.ResourceManager.m_UpdateCallbacks.Count);
|
||||
|
||||
m_Addressables.Release(op);
|
||||
|
||||
Assert.IsFalse(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsFalse(op.IsValid());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_Release_ReleaseNotRefCountZeroWhileLoadingDoesntUnloadAfterLoadCompletes()
|
||||
{
|
||||
// Setup
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
Addressables.ResourceManager.Acquire(op);
|
||||
|
||||
// Test
|
||||
op.Completed += s => Assert.IsTrue(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Addressables.Release(op);
|
||||
yield return op;
|
||||
Assert.IsTrue(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsTrue(op.IsValid());
|
||||
|
||||
// Cleanup
|
||||
yield return op;
|
||||
Assert.IsTrue(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsTrue(op.IsValid());
|
||||
m_Addressables.Release(op);
|
||||
|
||||
yield return op;
|
||||
Assert.IsFalse(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsFalse(op.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_Release_ReleaseNotToZeroRefCountDoesNotUnloadScene()
|
||||
{
|
||||
var op = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, op.Status);
|
||||
Assert.AreEqual(sceneKeys[0], SceneManager.GetSceneByName(sceneKeys[0]).name);
|
||||
Addressables.ResourceManager.Acquire(op);
|
||||
|
||||
m_Addressables.Release(op);
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(SceneManager.GetSceneByName(sceneKeys[0]).isLoaded);
|
||||
Assert.IsTrue(op.IsValid());
|
||||
|
||||
// Cleanup
|
||||
m_Addressables.Release(op);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetDownloadSize_DoesNotThrowInvalidKeyException_ForScene()
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
var dOp = m_Addressables.GetDownloadSizeAsync((object)sceneKeys[0]);
|
||||
yield return dOp;
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, dOp.Status);
|
||||
#else
|
||||
Assert.Ignore();
|
||||
yield break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class SceneTests_FastMode : SceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
}
|
||||
|
||||
class SceneTests_VirtualMode : SceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class SceneTests_PackedPlaymodeMode : SceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnloadScene_ChainsBehindLoadOp_IfLoadOpIsRunning_TypedHandle()
|
||||
{
|
||||
//Setup
|
||||
AsyncOperationHandle<SceneInstance> handle = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
|
||||
//Test
|
||||
var unloadHandle = m_Addressables.UnloadSceneAsync(handle);
|
||||
yield return unloadHandle;
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(typeof(ChainOperation<SceneInstance, SceneInstance>), unloadHandle.m_InternalOp.GetType(),
|
||||
"Unload a scene while a Load is in progress should have resulted in the unload being chained behind the load op, but wasn't");
|
||||
Addressables.Release(unloadHandle);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnloadScene_ChainsBehindLoadOp_IfLoadOpIsRunning_TypelessHandle()
|
||||
{
|
||||
//Setup
|
||||
AsyncOperationHandle handle = m_Addressables.LoadSceneAsync(sceneKeys[0], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
|
||||
//Test
|
||||
var unloadHandle = m_Addressables.UnloadSceneAsync(handle);
|
||||
yield return unloadHandle;
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(typeof(ChainOperationTypelessDepedency<SceneInstance>), unloadHandle.m_InternalOp.GetType(),
|
||||
"Unload a scene while a Load is in progress should have resulted in the unload being chained behind the load op, but wasn't");
|
||||
Addressables.Release(unloadHandle);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SceneTests_UnloadSceneAsync_UnloadSceneAfterAcquireAndDoNotDestroyOnLoadDoesNotUnloadDependenciesUntilSecondRelease()
|
||||
{
|
||||
// Setup scene
|
||||
int bundleCountBeforeTest = AssetBundle.GetAllLoadedAssetBundles().Count();
|
||||
var activeScene = m_Addressables.LoadSceneAsync(sceneKeys[1], new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return activeScene;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, activeScene.Status);
|
||||
Addressables.ResourceManager.Acquire(activeScene);
|
||||
Assert.AreEqual(activeScene.ReferenceCount, 2);
|
||||
SceneManager.SetActiveScene(activeScene.Result.Scene);
|
||||
Assert.AreEqual(sceneKeys[1], SceneManager.GetActiveScene().name);
|
||||
|
||||
// Setup obj
|
||||
Assert.IsNull(GameObject.Find(GetPrefabKey()));
|
||||
var instOp = m_Addressables.InstantiateAsync(GetPrefabKey());
|
||||
yield return instOp;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, instOp.Status);
|
||||
Assert.AreEqual(sceneKeys[1], instOp.Result.scene.name);
|
||||
UnityEngine.Object.DontDestroyOnLoad(instOp.Result);
|
||||
int bundleCountAfterInstantiate = AssetBundle.GetAllLoadedAssetBundles().Count();
|
||||
Assert.Greater(bundleCountAfterInstantiate, bundleCountBeforeTest);
|
||||
|
||||
// Test
|
||||
yield return UnloadSceneFromHandlerRefCountCheck(activeScene, m_Addressables);
|
||||
|
||||
Assert.NotNull(GameObject.Find(instOp.Result.name));
|
||||
Assert.IsFalse(activeScene.Result.Scene.isLoaded);
|
||||
int bundleCountAfterUnload = AssetBundle.GetAllLoadedAssetBundles().Count();
|
||||
Assert.AreEqual(bundleCountAfterInstantiate, bundleCountAfterUnload);
|
||||
|
||||
Addressables.Release(activeScene);
|
||||
yield return activeScene;
|
||||
|
||||
// Cleanup
|
||||
Assert.IsFalse(activeScene.IsValid());
|
||||
Addressables.Release(instOp);
|
||||
AssetBundleProvider.WaitForAllUnloadingBundlesToComplete();
|
||||
int bundleCountEndTest = AssetBundle.GetAllLoadedAssetBundles().Count();
|
||||
Assert.AreEqual(bundleCountBeforeTest, bundleCountEndTest);
|
||||
Assert.IsFalse(instOp.IsValid());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenUnloadScene_UnloadEmbeddedAssetsFlagWorks([Values(false, true)] bool unloadEmbeddedAssets)
|
||||
{
|
||||
// Create scene with embedded asset. Let's use Scriptable Object for ease of use
|
||||
var op = m_Addressables.LoadSceneAsync(kEmbeddedSceneName, new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
yield return op;
|
||||
|
||||
// find the ScriptableObject. Get reference to it
|
||||
Mesh mesh = GameObject.Find("EmbededMeshGameObject").GetComponent<MeshFilter>().mesh;
|
||||
|
||||
|
||||
UnloadSceneOptions options = unloadEmbeddedAssets ? UnloadSceneOptions.UnloadAllEmbeddedSceneObjects : UnloadSceneOptions.None;
|
||||
var unloadOp = m_Addressables.UnloadSceneAsync(op, options, false);
|
||||
yield return unloadOp;
|
||||
|
||||
Assert.AreEqual(mesh == null, unloadEmbeddedAssets);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//[Bug: https://jira.unity3d.com/browse/ADDR-1215]
|
||||
//[UnityPlatform(exclude = new[] { RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor })]
|
||||
//class SceneTests_PackedMode : SceneTests { protected override TestBuildScriptMode BuildScriptMode { get { return TestBuildScriptMode.Packed; } } }
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9847c86f230bc2e4d8f60483d345704c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,703 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AddressableTests.SyncAddressables
|
||||
{
|
||||
public abstract class SyncAddressableTests : AddressablesTestFixture
|
||||
{
|
||||
protected string m_PrefabKey = "syncprefabkey";
|
||||
protected string m_PrefabKey2 = "syncprefabkey2";
|
||||
protected string m_PrefabKey3 = "syncprefabkey3";
|
||||
protected string m_InvalidKey = "notarealkey";
|
||||
protected string m_SceneKey = "syncscenekey";
|
||||
protected string m_ResourcePrefabKey = "resourceprefabkey";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private AddressableAssetSettings m_settingsInstance;
|
||||
protected AddressableAssetSettings m_Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_settingsInstance == null)
|
||||
m_settingsInstance = AssetDatabase.LoadAssetAtPath<AddressableAssetSettings>(Path.Combine(GetGeneratedAssetsPath(), "Settings", "AddressableAssetSettings.Tests.asset"));
|
||||
return m_settingsInstance;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal override void Setup(AddressableAssetSettings settings, string tempAssetFolder)
|
||||
{
|
||||
AddressableAssetGroup syncGroup = settings.CreateGroup("SyncAddressables", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
syncGroup.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
AddressableAssetGroup syncGroup2 = settings.CreateGroup("SyncAddressables2", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
syncGroup2.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
|
||||
//Create prefab
|
||||
string guid = CreatePrefab(tempAssetFolder + "/synctest.prefab");
|
||||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, syncGroup);
|
||||
entry.address = m_PrefabKey;
|
||||
|
||||
string path = Path.Combine($"{GetGeneratedAssetsPath()}", "Resources");
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
string resourceGuid = CreatePrefab(Path.Combine(path, "synctest.prefab"));
|
||||
AddressableAssetEntry resourceEntry = settings.CreateOrMoveEntry(resourceGuid, syncGroup);
|
||||
resourceEntry.address = m_ResourcePrefabKey;
|
||||
|
||||
//Create prefab
|
||||
string guid2 = CreatePrefab(tempAssetFolder + "/synctest2.prefab");
|
||||
AddressableAssetEntry entry2 = settings.CreateOrMoveEntry(guid2, syncGroup2);
|
||||
entry2.address = m_PrefabKey2;
|
||||
|
||||
//Create Scenes
|
||||
string sceneGuid = CreateScene($"{tempAssetFolder}/SyncTestScene.unity");
|
||||
AddressableAssetEntry sceneEntry = settings.CreateOrMoveEntry(sceneGuid, syncGroup);
|
||||
sceneEntry.address = m_SceneKey;
|
||||
|
||||
#if ENABLE_ASYNC_ASSETBUNDLE_UWR
|
||||
AddressableAssetGroup syncGroup3 = settings.CreateGroup("SyncAddressables3", false, false, true,
|
||||
new List<AddressableAssetGroupSchema>(), typeof(BundledAssetGroupSchema));
|
||||
syncGroup3.GetSchema<BundledAssetGroupSchema>().BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.OnlyHash;
|
||||
syncGroup3.GetSchema<BundledAssetGroupSchema>().UseUnityWebRequestForLocalBundles = true;
|
||||
|
||||
//Create prefab
|
||||
string guid3 = CreatePrefab(tempAssetFolder + "/synctest3.prefab");
|
||||
AddressableAssetEntry entry3 = settings.CreateOrMoveEntry(guid3, syncGroup3);
|
||||
entry3.address = m_PrefabKey3;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected void ReleaseOp(AsyncOperationHandle handle)
|
||||
{
|
||||
if (handle.IsValid())
|
||||
handle.Release();
|
||||
Assert.IsFalse(handle.IsValid());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoad_CompletesWithValidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoad_CompletesWithValidKeyWhenLoadedFromResources()
|
||||
{
|
||||
//string path = Path.Combine($"{GetGeneratedAssetsPath()}", "Resources");
|
||||
|
||||
IResourceLocation loc = new ResourceLocationBase(m_ResourcePrefabKey, "synctest", typeof(LegacyResourcesProvider).FullName, typeof(GameObject));
|
||||
if (!m_Addressables.ResourceManager.ResourceProviders.Any(rp => rp.GetType() == typeof(LegacyResourcesProvider)))
|
||||
m_Addressables.ResourceManager.ResourceProviders.Add(new LegacyResourcesProvider());
|
||||
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(loc);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoadAssets_CompletesWithValidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadAssetsAsync<GameObject>(new List<string>() {m_PrefabKey, m_SceneKey}, null, Addressables.MergeMode.Union, false);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void SyncAddressables_DoesntHang_WhenCallingMultiple_BackToBack()
|
||||
{
|
||||
var pf1 = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey).WaitForCompletion();
|
||||
var pf2 = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey2).WaitForCompletion();
|
||||
|
||||
Assert.IsNotNull(pf1);
|
||||
Assert.IsNotNull(pf2);
|
||||
|
||||
m_Addressables.ReleaseInstance(pf1);
|
||||
m_Addressables.ReleaseInstance(pf2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void ProviderOperation_WaitForCompletion_AfterOpComplete_DoesntHang()
|
||||
{
|
||||
ProviderOperation<GameObject> providerOp = new ProviderOperation<GameObject>();
|
||||
providerOp.Init(m_Addressables.ResourceManager, new BundledAssetProvider(),
|
||||
new ResourceLocationBase(m_PrefabKey, m_PrefabKey, typeof(BundledAssetProvider).FullName, typeof(GameObject)),
|
||||
new AsyncOperationHandle<IList<AsyncOperationHandle>>());
|
||||
providerOp.HasExecuted = true;
|
||||
providerOp.ProviderCompleted(default(GameObject), true, null);
|
||||
|
||||
providerOp.WaitForCompletion();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoadAssets_CompletesWithInvalidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadAssetsAsync<GameObject>(new List<string>() {m_PrefabKey, m_SceneKey, "bad key"}, null, Addressables.MergeMode.Union, false);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoad_CompletesWithInvalidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_InvalidKey);
|
||||
Assert.IsNull(loadOp.WaitForCompletion());
|
||||
LogAssert.Expect(LogType.Error, new Regex("InvalidKeyException*"));
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, loadOp.Status);
|
||||
Assert.IsNull(loadOp.Result);
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CheckForCatalogUpdates_CompletesSynchronously()
|
||||
{
|
||||
var checkForUpdates = m_Addressables.CheckForCatalogUpdates(false);
|
||||
Assert.IsNotNull(checkForUpdates.WaitForCompletion());
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, checkForUpdates.Status);
|
||||
Assert.IsTrue(checkForUpdates.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(checkForUpdates);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CheckForCatalogUpdates_CompletesSynchronously_WhenAutoReleaseHandle()
|
||||
{
|
||||
var checkForUpdates = m_Addressables.CheckForCatalogUpdates();
|
||||
checkForUpdates.WaitForCompletion();
|
||||
Assert.IsFalse(checkForUpdates.IsValid());
|
||||
Assert.IsTrue(checkForUpdates.IsDone);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateCatalogs_CompletesSynchronously()
|
||||
{
|
||||
var updateCatalogs = m_Addressables.UpdateCatalogs(null, false);
|
||||
Assert.IsNull(updateCatalogs.WaitForCompletion());
|
||||
LogAssert.Expect(LogType.Error, new Regex("Content update not available*"));
|
||||
LogAssert.Expect(LogType.Error, new Regex(".*ChainOperation.*"));
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, updateCatalogs.Status);
|
||||
Assert.IsTrue(updateCatalogs.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(updateCatalogs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDownloadSizeAsync_CompletesSynchronously()
|
||||
{
|
||||
var getDownloadSize = m_Addressables.GetDownloadSizeAsync((object)m_PrefabKey);
|
||||
Assert.IsNotNull(getDownloadSize.WaitForCompletion());
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, getDownloadSize.Status);
|
||||
Assert.IsTrue(getDownloadSize.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(getDownloadSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadDependencies_CompletesSynchronously()
|
||||
{
|
||||
var downloadDependencies = m_Addressables.DownloadDependenciesAsync((object)m_PrefabKey);
|
||||
var result = downloadDependencies.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, downloadDependencies.Status);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(downloadDependencies.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(downloadDependencies);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearDependencyCache_CompletesSynchronously()
|
||||
{
|
||||
var clearCache = m_Addressables.ClearDependencyCacheAsync((object)m_PrefabKey, false);
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, clearCache.Status);
|
||||
Assert.IsTrue(clearCache.WaitForCompletion());
|
||||
Assert.IsTrue(clearCache.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(clearCache);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstantiateSync_CompletesSuccessfully_WithValidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.InstantiateAsync(m_PrefabKey);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstantiateMultipleObjectsSync_CompletesSuccessfully_WithValidKey()
|
||||
{
|
||||
var loadOp1 = m_Addressables.InstantiateAsync(m_PrefabKey);
|
||||
var result1 = loadOp1.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp1.Status);
|
||||
Assert.IsNotNull(result1);
|
||||
Assert.IsNotNull(loadOp1.Result);
|
||||
Assert.AreEqual(loadOp1.Result, result1);
|
||||
|
||||
var loadOp2 = m_Addressables.InstantiateAsync(m_PrefabKey);
|
||||
var result2 = loadOp2.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp2.Status);
|
||||
Assert.IsNotNull(result2);
|
||||
Assert.IsNotNull(loadOp2.Result);
|
||||
Assert.AreEqual(loadOp2.Result, result2);
|
||||
|
||||
Assert.AreNotEqual(result1, result2);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp1);
|
||||
ReleaseOp(loadOp2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstantiateSync_CompletesSuccessfully_WithInvalidKey()
|
||||
{
|
||||
var loadOp = m_Addressables.InstantiateAsync(m_InvalidKey);
|
||||
LogAssert.Expect(LogType.Error, new Regex("InvalidKeyException*"));
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, loadOp.Status);
|
||||
Assert.IsNull(loadOp.WaitForCompletion());
|
||||
Assert.IsNull(loadOp.Result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestingResourceLocation_CompletesSynchronously()
|
||||
{
|
||||
var requestOp = m_Addressables.LoadResourceLocationsAsync(m_PrefabKey);
|
||||
var result = requestOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, requestOp.Status);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNotNull(requestOp.Result);
|
||||
Assert.AreEqual(requestOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(requestOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestingResourceLocations_CompletesSynchronously()
|
||||
{
|
||||
var requestOp = m_Addressables.LoadResourceLocationsAsync(new List<string>() {m_PrefabKey, m_SceneKey}, Addressables.MergeMode.Union);
|
||||
var result = requestOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, requestOp.Status);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNotNull(requestOp.Result);
|
||||
Assert.AreEqual(requestOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(requestOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadContentCatalogSynchronously_SuccessfullyCompletes_WithValidPath()
|
||||
{
|
||||
string catalogPath = m_RuntimeSettingsPath.Replace("settings", "catalog");
|
||||
|
||||
//There's no catalog created for fast mode. Creating one at this point had issues on CI
|
||||
if (catalogPath.StartsWith("GUID:"))
|
||||
Assert.Ignore();
|
||||
|
||||
var loadCatalogOp = m_Addressables.LoadContentCatalogAsync(catalogPath, false);
|
||||
var result = loadCatalogOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadCatalogOp.Status);
|
||||
Assert.IsNotNull(loadCatalogOp.Result);
|
||||
Assert.AreEqual(loadCatalogOp.Result, result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadCatalogOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadContentCatalogSynchronously_SuccessfullyCompletes_WithInvalidPath()
|
||||
{
|
||||
//Removing need to check for each individual error message since it's brittle and not the purpose of this test
|
||||
bool savedLogAssertState = LogAssert.ignoreFailingMessages;
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
|
||||
var loadCatalogOp = m_Addressables.LoadContentCatalogAsync("not a real path.json", false);
|
||||
|
||||
var result = loadCatalogOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Failed, loadCatalogOp.Status);
|
||||
Assert.IsNull(result);
|
||||
Assert.IsNull(loadCatalogOp.Result);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(loadCatalogOp);
|
||||
LogAssert.ignoreFailingMessages = savedLogAssertState;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstanceOperation_WithFailedBundleLoad_CompletesSync()
|
||||
{
|
||||
var depOp = m_Addressables.LoadAssetAsync<GameObject>(m_InvalidKey);
|
||||
LogAssert.Expect(LogType.Error, new Regex("InvalidKeyException*"));
|
||||
|
||||
var instanceOperation = new ResourceManager.InstanceOperation();
|
||||
instanceOperation.Init(m_Addressables.ResourceManager, new InstanceProvider(), new InstantiationParameters(), depOp);
|
||||
//Since we're calling the operation directly we need to simulate the full workflow of the additional ref count during load
|
||||
instanceOperation.IncrementReferenceCount();
|
||||
|
||||
instanceOperation.WaitForCompletion();
|
||||
LogAssert.Expect(LogType.Error, new Regex("InvalidKeyException*"));
|
||||
|
||||
Assert.IsTrue(instanceOperation.IsDone);
|
||||
m_Addressables.Release(depOp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstantiateSync_InvalidKeyExceptionCorrectlyThrown()
|
||||
{
|
||||
var prevHandler = ResourceManager.ExceptionHandler;
|
||||
ResourceManager.ExceptionHandler = (handle, exception) =>
|
||||
{
|
||||
Assert.AreEqual(typeof(InvalidKeyException), exception.GetType(),
|
||||
"Exception thrown is not of the correct type.");
|
||||
};
|
||||
var depOp = m_Addressables.LoadAssetAsync<GameObject>(m_InvalidKey);
|
||||
m_Addressables.Release(depOp);
|
||||
ResourceManager.ExceptionHandler = prevHandler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InstanceOperation_WithSuccessfulBundleLoad_CompletesSync()
|
||||
{
|
||||
var depOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey);
|
||||
var instanceOperation = new ResourceManager.InstanceOperation();
|
||||
instanceOperation.Init(m_Addressables.ResourceManager, new InstanceProvider(), new InstantiationParameters(), depOp);
|
||||
//Since we're calling the operation directly we need to simulate the full workflow of the additional ref count during load
|
||||
instanceOperation.IncrementReferenceCount();
|
||||
|
||||
instanceOperation.WaitForCompletion();
|
||||
|
||||
Assert.IsTrue(instanceOperation.IsDone);
|
||||
m_Addressables.Release(depOp);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void CleanBundleCache_CompletesSynchronously(bool forceSingleThreading)
|
||||
{
|
||||
#if ENABLE_CACHING
|
||||
if (BuildScriptMode == TestBuildScriptMode.Fast || BuildScriptMode == TestBuildScriptMode.Virtual)
|
||||
Assert.Ignore("Bundle caching does not occur when using this playmode.");
|
||||
|
||||
var cleanOp = m_Addressables.CleanBundleCache(null, forceSingleThreading);
|
||||
cleanOp.WaitForCompletion();
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, cleanOp.Status);
|
||||
Assert.IsTrue(cleanOp.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(cleanOp);
|
||||
#else
|
||||
Assert.Ignore("Caching not enabled.");
|
||||
#endif
|
||||
}
|
||||
|
||||
class FailedAssetBundleResource : IAssetBundleResource
|
||||
{
|
||||
public AssetBundle GetAssetBundle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This class is made because of, and should be refactored away when resolved, bug: https://jira.unity3d.com/browse/ADDR-1215
|
||||
public abstract class SyncAddressablesWithSceneTests : SyncAddressableTests
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator LoadingScene_Synchronously_ActivateOnLoadDisabled_Completes()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadSceneAsync(m_SceneKey, new LoadSceneParameters(LoadSceneMode.Additive), false);
|
||||
bool callbackCompleted = false;
|
||||
loadOp.Completed += handle => callbackCompleted = true;
|
||||
var result = loadOp.WaitForCompletion();
|
||||
|
||||
Assert.IsTrue(callbackCompleted, "When activateOnLoad is disabled, scene load operation expected to complete in WaitForCompletion");
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(loadOp.IsDone);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
Assert.IsTrue(Mathf.Approximately(result.m_Operation.progress, 0.9f), "SceneLoading WaitForCompletion expected to end on 0.9 activation");
|
||||
|
||||
// complete the activation step
|
||||
yield return result.ActivateAsync();
|
||||
yield return loadOp;
|
||||
|
||||
//Cleanup
|
||||
var unloadHandle = m_Addressables.UnloadSceneAsync(loadOp);
|
||||
yield return unloadHandle;
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadingScene_Synchronously_ActivateOnLoad_CompletesAsynchronously()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadSceneAsync(m_SceneKey, new LoadSceneParameters(LoadSceneMode.Additive), true);
|
||||
bool callbackCompleted = false;
|
||||
loadOp.Completed += handle => callbackCompleted = true;
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(AsyncOperationStatus.None, loadOp.Status);
|
||||
Assert.IsFalse(loadOp.IsDone);
|
||||
Assert.IsFalse(callbackCompleted, "When activateOnLoad is enabled, scene load operation expected to complete after asynchronous activation");
|
||||
Assert.IsTrue(Mathf.Approximately(result.m_Operation.progress, 0.9f), "SceneLoading WaitForCompletion expected to end on 0.9 activation");
|
||||
|
||||
// complete the activation step
|
||||
yield return loadOp;
|
||||
Assert.IsTrue(callbackCompleted, "When activateOnLoad is enabled, scene load operation expected to complete after asynchronous activation");
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.IsTrue(result.m_Operation.isDone);
|
||||
Assert.AreEqual(loadOp.Result.Scene, result.Scene);
|
||||
|
||||
//Cleanup
|
||||
var unloadHandle = m_Addressables.UnloadSceneAsync(loadOp);
|
||||
yield return unloadHandle;
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnloadingScene_Synchronously_WhenAutoReleasingHandle_LogsWarning()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadSceneAsync(m_SceneKey, new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
loadOp.WaitForCompletion();
|
||||
yield return loadOp;
|
||||
|
||||
var unloadOp = m_Addressables.UnloadSceneAsync(loadOp);
|
||||
LogAssert.Expect(LogType.Warning, "Cannot unload a Scene with WaitForCompletion. Scenes must be unloaded asynchronously.");
|
||||
unloadOp.WaitForCompletion();
|
||||
yield return unloadOp;
|
||||
|
||||
Assert.IsFalse(unloadOp.IsValid());
|
||||
Assert.IsTrue(unloadOp.IsDone);
|
||||
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnloadingScene_Synchronously_LogsWarning()
|
||||
{
|
||||
var loadOp = m_Addressables.LoadSceneAsync(m_SceneKey, new LoadSceneParameters(LoadSceneMode.Additive));
|
||||
loadOp.WaitForCompletion();
|
||||
yield return loadOp;
|
||||
|
||||
var unloadOp = m_Addressables.UnloadSceneAsync(loadOp, UnloadSceneOptions.None, false);
|
||||
LogAssert.Expect(LogType.Warning, "Cannot unload a Scene with WaitForCompletion. Scenes must be unloaded asynchronously.");
|
||||
unloadOp.WaitForCompletion();
|
||||
yield return unloadOp;
|
||||
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, unloadOp.Status);
|
||||
Assert.IsTrue(unloadOp.IsValid());
|
||||
Assert.IsTrue(unloadOp.IsDone);
|
||||
|
||||
//Cleanup
|
||||
ReleaseOp(unloadOp);
|
||||
ReleaseOp(loadOp);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
class SyncAddressableTests_FastMode : SyncAddressablesWithSceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Fast; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Timeout(3000)]
|
||||
public void FastModeInitializeOperation_CompletesSync()
|
||||
{
|
||||
FastModeInitializationOperation fmio = new FastModeInitializationOperation(m_Addressables, m_Settings);
|
||||
fmio.WaitForCompletion();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadDependencies_CompletesSynchronously_WhenAutoReleased()
|
||||
{
|
||||
var downloadDependencies = m_Addressables.DownloadDependenciesAsync((object)m_PrefabKey, true);
|
||||
downloadDependencies.WaitForCompletion();
|
||||
Assert.IsTrue(downloadDependencies.IsDone);
|
||||
}
|
||||
}
|
||||
|
||||
class SyncAddressableTests_VirtualMode : SyncAddressablesWithSceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Virtual; }
|
||||
}
|
||||
}
|
||||
|
||||
class SyncAddressableTests_PackedPlaymodeMode : SyncAddressablesWithSceneTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.PackedPlaymode; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadDependencies_CompletesSynchronously_WhenAutoReleased()
|
||||
{
|
||||
var downloadDependencies = m_Addressables.DownloadDependenciesAsync((object)m_PrefabKey, true);
|
||||
downloadDependencies.WaitForCompletion();
|
||||
Assert.IsTrue(downloadDependencies.IsDone);
|
||||
}
|
||||
|
||||
#if ENABLE_CACHING && ENABLE_ASYNC_ASSETBUNDLE_UWR
|
||||
[Test]
|
||||
public void SyncAddressableLoad_CachedBundle_WithAutoLoadEnabled_Completes()
|
||||
{
|
||||
// Cache the bundle
|
||||
Caching.ClearCache();
|
||||
var initloadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
initloadOp.WaitForCompletion();
|
||||
ReleaseOp(initloadOp);
|
||||
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
ReleaseOp(loadOp);
|
||||
Caching.ClearCache();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoad_NotCachedBundle_WithAutoLoadEnabled_Completes()
|
||||
{
|
||||
Caching.ClearCache();
|
||||
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
ReleaseOp(loadOp);
|
||||
Caching.ClearCache();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor})]
|
||||
class SyncAddressableTests_PackedMode : SyncAddressableTests
|
||||
{
|
||||
protected override TestBuildScriptMode BuildScriptMode
|
||||
{
|
||||
get { return TestBuildScriptMode.Packed; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DownloadDependencies_CompletesSynchronously_WhenAutoReleased()
|
||||
{
|
||||
var downloadDependencies = m_Addressables.DownloadDependenciesAsync((object)m_PrefabKey, true);
|
||||
downloadDependencies.WaitForCompletion();
|
||||
Assert.IsTrue(downloadDependencies.IsDone);
|
||||
}
|
||||
|
||||
#if ENABLE_CACHING && ENABLE_ASYNC_ASSETBUNDLE_UWR
|
||||
[Test]
|
||||
public void SyncAddressableLoad_CachedBundle_WithAutoLoadEnabled_Completes()
|
||||
{
|
||||
// Cache the bundle
|
||||
Caching.ClearCache();
|
||||
var initloadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
initloadOp.WaitForCompletion();
|
||||
ReleaseOp(initloadOp);
|
||||
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
ReleaseOp(loadOp);
|
||||
Caching.ClearCache();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncAddressableLoad_NotCachedBundle_WithAutoLoadEnabled_Completes()
|
||||
{
|
||||
Caching.ClearCache();
|
||||
|
||||
var loadOp = m_Addressables.LoadAssetAsync<GameObject>(m_PrefabKey3);
|
||||
var result = loadOp.WaitForCompletion();
|
||||
Assert.AreEqual(AsyncOperationStatus.Succeeded, loadOp.Status);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsNotNull(loadOp.Result);
|
||||
Assert.AreEqual(loadOp.Result, result);
|
||||
|
||||
ReleaseOp(loadOp);
|
||||
Caching.ClearCache();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 04051f360312e3547be05554223ba464
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class TestBehaviourWithReference : MonoBehaviour
|
||||
{
|
||||
public Object Reference;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3534c90cd89bf7342937035fa421fd9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.AddressableAssets.Tests
|
||||
{
|
||||
[CreateAssetMenu(order = 0, fileName = "to", menuName = "Test/TestObject")]
|
||||
public class TestObject : ScriptableObject
|
||||
{
|
||||
static public TestObject Create(string name)
|
||||
{
|
||||
var obj = CreateInstance<TestObject>();
|
||||
obj.name = name;
|
||||
return obj;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static public TestObject Create(string name, string assetPath)
|
||||
{
|
||||
var obj = CreateInstance<TestObject>();
|
||||
obj.name = name;
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
AssetDatabase.CreateAsset(obj, assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a92af236ef5230b4eae4fcfbb2b3d41a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.AddressableAssets.Tests
|
||||
{
|
||||
public class TestObject2 : ScriptableObject
|
||||
{
|
||||
static public TestObject2 Create(string name)
|
||||
{
|
||||
var so = CreateInstance<TestObject2>();
|
||||
so.name = name;
|
||||
return so;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61985980b88404b40abb13be18b78b3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.AddressableAssets.Tests
|
||||
{
|
||||
[CreateAssetMenu(order = 0, fileName = "towsf", menuName = "Test/TestObjectWithSerializableField")]
|
||||
public class TestObjectWithSerializableField : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
private SerializableClass ByValueClass;
|
||||
|
||||
static public TestObjectWithSerializableField Create(string name)
|
||||
{
|
||||
var obj = CreateInstance<TestObjectWithSerializableField>();
|
||||
obj.name = name;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SerializableClass
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4383287c19544f4ebf11f0d92af3653
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System.Reflection;
|
||||
|
||||
namespace AddressableTests
|
||||
{
|
||||
static class TestReflectionHelpers
|
||||
{
|
||||
public static void SetResritctMainThreadFileIO(bool errorOnMainThreadFileIO)
|
||||
{
|
||||
System.Type t = System.Type.GetType("UnityEngine.IO.File, UnityEngine.CoreModule");
|
||||
if (t != null)
|
||||
{
|
||||
System.Reflection.PropertyInfo pInfo = t.GetProperty("MainThreadIORestrictionMode", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
if (pInfo != null)
|
||||
pInfo.SetValue(null, errorOnMainThreadFileIO ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue