initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -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
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 03115f3e85a5cee4ba080db3d02670e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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());
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cfcdca687c6d4574928e2741e1fb9287
timeCreated: 1597077093

View file

@ -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();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f0645bd0f9b0ea46a9bec32c403ab9e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf5e6ef0e57ead045be2e03ae1ec38b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 488e0dbf9a6f5ac48bbe7875855651f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 58d7919bd300ea94c8bc969913548cd8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyCompany("Unity Technologies")]
[assembly: InternalsVisibleTo("Unity.Addressables.Samples.Tests")]

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 738ea664e66824aa885346392956abc2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c9765ad9de06ee4193e087e7732d756
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07426e5d16eb07442847b80692e452c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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;
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfa3710e9aeaad547bae8719bd664926
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f4d1d59e25085e489592b2342c86673
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e59bf5e81ff06ac4ca62188908370bbb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 541f73e53f31a9c45aada1a7441da18a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc13c309185f5ef4cb30649341ab86fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5676580c9e682d4da654a6c5440b917
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfc18942d8f87f147a241b9de540a2a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa28bcae85fa11447917912c39d705c7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6faf7d815764fef408b2e42c8982f2d0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6c1d0b0ab4d44f42a99963de99d60ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 441d6ab2de7dd3948b7b50882e4370e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ce10b9a173f68e7439b96557cb1bc223
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a752b6e9dc874574babc9f4b5c08d5aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6212fd4877a4704aa905b317e16bac8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AddressableAssetsIntegrationTests
{
public class ObjectReferenceMonoBehaviour : MonoBehaviour
{
public UnityEngine.Object m_ObjectReference;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c250a53221434148be3ac31d903d8c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0c2eb630b3a204847b868607a539fb4c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6a7f04e028569f74e86bd76972ff7b2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68204acf7cb1bb74091cd6779c3da569
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f6ca99e013fe6c49bb6b98f8ec1897b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b42ee6f5a38f94b4baafd3c426bee7f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d07c590681843734482b565ad928be3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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));
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1fd8a0466f984a08874b05c3243189f6
timeCreated: 1620745004

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de4318cbbab37fa40bc08ac8c2f51a9b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6d71bdd364b36340962d0eb7f11980c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6e1ac52851690b48bdf019059b98207
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
using System;
namespace UnityEngine.ResourceManagement.Tests
{
public class ResourceManagerPackedModeTests
{
//TODO: implement tests that create bundles
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf2de0e8cc0a18b4d8887aad8e168377
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aaa68dbe5d4e2b24281d446a29c84c78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89f8257facdc8e04fbf8eefd512ee6a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c30a288c553aa7488774857f37eee83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3e098a01716164d41a666ccd8d2c1cf5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df92c48909f708647b98ae363e7618d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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"
]
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b1d1d33334b51724b9bc4457a3ebd9ee
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e17c64e4d2cf1742879de399aad96bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 962906719cf3dae4f8b815dcc25b22b5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 832363b0cc1d7e44dbd8750e91343bd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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)
{
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 86d78906b9304e148389fa0f7e3ae6a4
timeCreated: 1618259584

View file

@ -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);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ea2465c600278f4db3fdb6b76ee06a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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; } } }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9847c86f230bc2e4d8f60483d345704c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04051f360312e3547be05554223ba464
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestBehaviourWithReference : MonoBehaviour
{
public Object Reference;
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3534c90cd89bf7342937035fa421fd9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a92af236ef5230b4eae4fcfbb2b3d41a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61985980b88404b40abb13be18b78b3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4383287c19544f4ebf11f0d92af3653
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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