291 lines
11 KiB
C#
291 lines
11 KiB
C#
|
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);
|
||
|
}
|
||
|
}
|