using System; using System.Collections.Generic; using System.IO; using System.Linq; using NUnit.Framework; using UnityEditor.AddressableAssets.Build; using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets.Settings.GroupSchemas; using UnityEngine; using static UnityEditor.AddressableAssets.Settings.AddressablesFileEnumeration; namespace UnityEditor.AddressableAssets.Tests { public class AddressableAssetFolderSubfolderTests : AddressableAssetTestBase { string m_TestFolderPath; string m_AddrParentFolderPath; string m_AddrChildSubfolderPath; string m_ParentObjPath; string m_AddrParentObjPath; string m_ChildObjPath; AddressableAssetGroup m_ParentGroup; AddressableAssetGroup m_ChildGroup; /* Creates the following folder structure * /AddrParentFolder/ * parentObj.prefab * addrParentObj.prefab * /AddrChildSubfolder/ * childObj.prefab */ protected override void OnInit() { // Create directories m_TestFolderPath = TestFolder; m_AddrParentFolderPath = m_TestFolderPath + "/AddrParentFolder"; m_AddrChildSubfolderPath = m_AddrParentFolderPath + "/AddrChildSubfolder"; string addrParentFolderGuid = AssetDatabase.CreateFolder(m_TestFolderPath, "AddrParentFolder"); string addrChildFolderGuid = AssetDatabase.CreateFolder(m_AddrParentFolderPath, "AddrChildSubfolder"); // Create prefabs GameObject parentObj = new GameObject("ParentObject"); GameObject addrParentObj = new GameObject("AddrParentObject"); GameObject childObj = new GameObject("ChildObject"); m_ParentObjPath = m_AddrParentFolderPath + "/parentObj.prefab"; m_AddrParentObjPath = m_AddrParentFolderPath + "/addrParentObj.prefab"; m_ChildObjPath = m_AddrChildSubfolderPath + "/childObj.prefab"; PrefabUtility.SaveAsPrefabAsset(parentObj, m_ParentObjPath); PrefabUtility.SaveAsPrefabAsset(addrParentObj, m_AddrParentObjPath); PrefabUtility.SaveAsPrefabAsset(childObj, m_ChildObjPath); // Create groups const string parentGroupName = "ParentGroup"; const string childGroupName = "ChildGroup"; m_ParentGroup = Settings.CreateGroup(parentGroupName, false, false, false, null, typeof(BundledAssetGroupSchema)); m_ChildGroup = Settings.CreateGroup(childGroupName, false, false, false, null, typeof(BundledAssetGroupSchema)); // Create entries Settings.CreateOrMoveEntry(addrParentFolderGuid, m_ParentGroup); Settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(m_AddrParentObjPath), m_ChildGroup); Settings.CreateOrMoveEntry(addrChildFolderGuid, m_ChildGroup); } protected override void OnCleanup() { Settings.RemoveGroup(m_ParentGroup); Settings.RemoveGroup(m_ChildGroup); AssetDatabase.DeleteAsset(m_TestFolderPath + "/"); AssetDatabase.Refresh(); } List GetValidAssetPaths(string path, AddressableAssetSettings settings) { List pathsWithCache; using (var cache = new AddressablesFileEnumerationCache(settings, true, null)) { pathsWithCache = EnumerateAddressableFolder(path, settings, true).ToList(); } List pathsWithoutCache = EnumerateAddressableFolder(path, settings, true).ToList(); // Compare the results of two different code paths: with cache and without cache Assert.AreEqual(pathsWithCache.Count, pathsWithoutCache.Count); for (int i = 0; i < pathsWithCache.Count; i++) { Assert.AreEqual(pathsWithCache[i], pathsWithoutCache[i]); } return pathsWithCache; } [Test] public void Build_WithAddrParentFolderAndAddrSubfolders_InSeparateGroups_Succeeds() { var context = new AddressablesDataBuilderInput(Settings); foreach (IDataBuilder db in Settings.DataBuilders) { if (db.CanBuildData()) db.BuildData(context); } } [Test] public void WhenSubfolderIsAddr_AddrParentFolder_DoesNotInclude_SubfolderContents() { List assetPaths = GetValidAssetPaths(m_AddrParentFolderPath, Settings); Assert.IsFalse(assetPaths.Contains(m_ChildObjPath)); } [Test] public void WhenAssetIsAddr_AssetIsNotIncludedInParentAddrFolder() { List assetPaths = GetValidAssetPaths(m_AddrParentFolderPath, Settings); Assert.IsFalse(assetPaths.Contains(m_AddrParentObjPath)); } [Test] public void EnumerateFiles_ReturnsFilesOnly() { List assetPaths = EnumerateAddressableFolder(m_AddrParentFolderPath, Settings, true); foreach (string path in assetPaths) { Assert.IsFalse(Directory.Exists(path)); } } [Test] public void WhenEmptyFolderIsAddr_EnumerateFiles_ReturnsNothing() { string path = m_TestFolderPath + "/AddrEmptyFolder"; string guid = AssetDatabase.CreateFolder(m_TestFolderPath, "AddrEmptyFolder"); Settings.CreateOrMoveEntry(guid, m_ParentGroup); List assetPaths = EnumerateAddressableFolder(path, Settings, true); Assert.AreEqual(0, assetPaths.Count); Settings.RemoveAssetEntry(guid); AssetDatabase.DeleteAsset(path); } [Test] public void WhenEnumerateFilesIsNonRecursive_ReturnTopLevelAssetsOnly() { string path = m_AddrParentFolderPath + "/ChildFolder"; string guid = AssetDatabase.CreateFolder(m_AddrParentFolderPath, "ChildFolder"); GameObject obj = new GameObject("TestObject"); string objPath = path + "/childObj.prefab"; PrefabUtility.SaveAsPrefabAsset(obj, objPath); List assetPaths = EnumerateAddressableFolder(m_AddrParentFolderPath, Settings, false); Assert.AreEqual(1, assetPaths.Count); Assert.AreEqual(m_ParentObjPath, assetPaths[0]); AssetDatabase.DeleteAsset(path); } [Test] public void WhenPathDoesNotExist_EnumerateFiles_ThrowsException() { string path = "PathDoesntExist"; Exception ex = Assert.Throws(() => { EnumerateAddressableFolder(path, Settings, false); }); Assert.AreEqual($"Path {path} cannot be enumerated because it does not exist", ex.Message); } [Test] public void WhenPathIsNotInTree_EnumerateFiles_ReturnsFiles() { string path = m_AddrParentFolderPath + "/ChildFolder"; string guid = AssetDatabase.CreateFolder(m_AddrParentFolderPath, "ChildFolder"); GameObject obj = new GameObject("TestObject"); string objPath = path + "/childObj.prefab"; PrefabUtility.SaveAsPrefabAsset(obj, objPath); List assetPaths = EnumerateAddressableFolder(path, Settings, true); Assert.AreEqual(1, assetPaths.Count); Assert.AreEqual(objPath, assetPaths[0]); AssetDatabase.DeleteAsset(path); } [Test] public void WhenFileIsNotInAssetDatabase_EnumerateFiles_DoesNotReturnPath() { string folderPath = m_TestFolderPath + "/TestFolder"; AssetDatabase.CreateFolder(m_TestFolderPath, "TestFolder"); string filePath = Path.Combine(folderPath, ".hiddenfile"); File.Create(filePath).Close(); List assetPaths = EnumerateAddressableFolder(folderPath, Settings, true); Assert.AreEqual(0, assetPaths.Count); File.Delete(filePath); AssetDatabase.DeleteAsset(folderPath); } [Test] public void WhenNoFolderIsAddressable_EnumerateFiles_ReturnsNothing() { string parentFolderGuid = AssetDatabase.AssetPathToGUID(m_AddrParentFolderPath); string childFolderGuid = AssetDatabase.AssetPathToGUID(m_AddrChildSubfolderPath); Settings.RemoveAssetEntry(parentFolderGuid); Settings.RemoveAssetEntry(childFolderGuid); using (var cache = new AddressablesFileEnumerationCache(Settings, true, null)) { List assetPaths = EnumerateAddressableFolder(m_TestFolderPath, Settings, false); Assert.AreEqual(0, assetPaths.Count); } Settings.CreateOrMoveEntry(parentFolderGuid, m_ParentGroup); Settings.CreateOrMoveEntry(childFolderGuid, m_ChildGroup); } [Test] public void WhenAFolderIsAddressable_FileEnumerationCache_CreatesFileTree() { using (var cache = new AddressablesFileEnumerationCache(Settings, false, null)) { Assert.IsTrue(m_PrecomputedTree != null); } } [Test] public void WhenNoFolderIsAddressable_FileEnumerationCache_DoesNotCreateFileTree() { string parentFolderGuid = AssetDatabase.AssetPathToGUID(m_AddrParentFolderPath); string childFolderGuid = AssetDatabase.AssetPathToGUID(m_AddrChildSubfolderPath); Settings.RemoveAssetEntry(parentFolderGuid); Settings.RemoveAssetEntry(childFolderGuid); using (var cache = new AddressablesFileEnumerationCache(Settings, true, null)) { Assert.IsTrue(m_PrecomputedTree == null); } Settings.CreateOrMoveEntry(parentFolderGuid, m_ParentGroup); Settings.CreateOrMoveEntry(childFolderGuid, m_ChildGroup); } [Test] public void WhenPrepopulateAssetsIsTrue_FileEnumerationCache_AddsAllAssetsToTree() { using (var cache = new AddressablesFileEnumerationCache(Settings, true, null)) { AddressableAssetTree.TreeNode node = m_PrecomputedTree.FindNode(m_ChildObjPath, false); Assert.IsTrue(node != null); } } [Test] public void WhenPrepopulateAssetsIsFalse_FileEnumerationCache_OnlyAddsAddressablesToTree() { using (var cache = new AddressablesFileEnumerationCache(Settings, false, null)) { AddressableAssetTree.TreeNode node = m_PrecomputedTree.FindNode(m_ChildObjPath, false); Assert.IsTrue(node == null); } } } }