using System; using System.Collections.Generic; using System.IO; using AddressableAssetsIntegrationTests; using NUnit.Framework; using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; using UnityEditor.AddressableAssets.Build.Layout; using UnityEditor.Animations; using UnityEngine; namespace UnityEditor.AddressableAssets.Tests.Diagnostics { public class BuildLayoutTests { private BuildLayout.ExplicitAsset CreateExplicitAssetWithParentBundle(BuildLayout.Bundle parent, ulong filesize = 1) { BuildLayout.ExplicitAsset asset = new BuildLayout.ExplicitAsset(); asset.Bundle = parent; asset.SerializedSize = filesize; return asset; } private BuildLayout.Bundle CreateBundleWithFileSize(ulong filesize, string name = "default") { var bundle = new BuildLayout.Bundle(); bundle.Name = name; bundle.FileSize = (ulong) filesize; return bundle; } private BuildLayout.Bundle CreateBundleWithFileSize(int assetCount, string name = "default") { var bundle = new BuildLayout.Bundle(); bundle.AssetCount = assetCount; bundle.Name = name; bundle.FileSize = (ulong) assetCount; return bundle; } [Test] public void BuildLayoutBundle_CalculateEfficiency_CorrectlyWorksInSimpleCase() { BuildLayout.Bundle parent = CreateBundleWithFileSize(5); BuildLayout.Bundle child = CreateBundleWithFileSize(10); BuildLayout.ExplicitAsset parentAsset = CreateExplicitAssetWithParentBundle(parent); BuildLayout.ExplicitAsset childAsset = CreateExplicitAssetWithParentBundle(child); child.DependentBundles.Add(parent); parent.UpdateBundleDependency(parentAsset, childAsset); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(parent); float expectedEfficiency = .10f; Assert.AreEqual(expectedEfficiency, parent.BundleDependencies[0].ExpandedEfficiency); } [Test] public void BuildLayoutBundle_CalculateEfficiency_MultipleAssetDependencyCaseStillCreatesCorrectEfficiency() { BuildLayout.Bundle parent = CreateBundleWithFileSize(5); BuildLayout.Bundle child = CreateBundleWithFileSize(10); BuildLayout.ExplicitAsset parentAsset = CreateExplicitAssetWithParentBundle(parent); for (int i = 0; i < 10; i++) { var asset = CreateExplicitAssetWithParentBundle(child); parent.UpdateBundleDependency(parentAsset, asset); } parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(parent); float expectedEfficiency = 1f; Assert.AreEqual(expectedEfficiency, parent.BundleDependencies[0].ExpandedEfficiency); } [Test] [TestCase(5, 10, 1, 5)] [TestCase(6, 12, 2, 7)] [TestCase(20, 43, 7, 15)] [TestCase(27, 68, 25, 60)] public void BuildLayoutBundle_CalculateEfficiency_ThreeLayeredTreeGeneratesCorrectEfficiencyAtAllLevels( int parentAssetCount, int childAssetCount, int parentDependencyCount, int childDependencyCount) { BuildLayout.Bundle grandparent = CreateBundleWithFileSize(1); BuildLayout.Bundle parent = CreateBundleWithFileSize(parentAssetCount); BuildLayout.Bundle child = CreateBundleWithFileSize(childAssetCount); BuildLayout.ExplicitAsset grandparentAsset = CreateExplicitAssetWithParentBundle(grandparent); List parentAssets = new List(); for (int i = 0; i < parentDependencyCount; i++) { var parentAsset = CreateExplicitAssetWithParentBundle(parent); grandparent.UpdateBundleDependency(grandparentAsset, parentAsset); parentAssets.Add(parentAsset); } for (int i = 0; i < childDependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(child); parent.UpdateBundleDependency(parentAssets[0], childAsset); } grandparent.SerializeBundleToBundleDependency(); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(grandparent); float expectedGrandparentEfficiency = (float) parentDependencyCount / parentAssetCount; float expectedGrandparentExpandedEfficiency = (float) (childDependencyCount + parentDependencyCount) / (childAssetCount + parentAssetCount); float expectedParentEfficiency = (float) childDependencyCount / childAssetCount; Assert.AreEqual(expectedGrandparentEfficiency, grandparent.BundleDependencies[0].Efficiency, "Grandparent Efficiency not calculated correctly - this should not be affected by the children of parent."); Assert.AreEqual(expectedGrandparentExpandedEfficiency, grandparent.BundleDependencies[0].ExpandedEfficiency, "Grandparent ExpandedEfficiency not calculated correctly - this should take into account the total Efficiency of both the direct children Dependency Links as well as all BundleDependencies below the child."); Assert.AreEqual(expectedParentEfficiency, parent.BundleDependencies[0].ExpandedEfficiency, "Parent ExpandedEfficiency not calculated correctly - this should take into account the Efficiency of the direct child only."); } [Test] public void BuildLayoutBundle_CalculateEfficiency_AssetDependenciesAreNotDoubleCounted() { var parentBundle = CreateBundleWithFileSize(1); var childBundle = CreateBundleWithFileSize(1); var parentAsset = CreateExplicitAssetWithParentBundle(parentBundle); var childAsset = CreateExplicitAssetWithParentBundle(childBundle); parentBundle.UpdateBundleDependency(parentAsset, childAsset); parentBundle.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(parentBundle); Assert.AreEqual(1f, parentBundle.BundleDependencies[0].ExpandedEfficiency, "ExpandedEfficiency not correctly calculated"); Assert.AreEqual(1f, parentBundle.BundleDependencies[0].Efficiency, "Efficiency not correctly calculated"); } [Test] [TestCase(3, 3, 1, 1 )] [TestCase(50, 5, 5, 2)] [TestCase(100, 100, 1, 50)] public void BuildLayoutBundle_CalculateEfficiency_MultiProngedShortTreeGeneratesCorrectEfficiency( int child1AssetCount, int child2AssetCount, int child1DependencyCount, int child2DependencyCount) { BuildLayout.Bundle parentBundle = CreateBundleWithFileSize(2); BuildLayout.Bundle childBundle1 = CreateBundleWithFileSize(child1AssetCount); BuildLayout.Bundle childBundle2 = CreateBundleWithFileSize(child2AssetCount); var parentAsset1 = CreateExplicitAssetWithParentBundle(parentBundle); var parentAsset2 = CreateExplicitAssetWithParentBundle(parentBundle); for (int i = 0; i < child1DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(childBundle1); parentBundle.UpdateBundleDependency(parentAsset1, childAsset); } for (int i = 0; i < child2DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(childBundle2); parentBundle.UpdateBundleDependency(parentAsset2, childAsset); } parentBundle.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(parentBundle); float expectedChild1Efficiency = (float) child1DependencyCount / child1AssetCount; float expectedChild2Efficiency = (float) child2DependencyCount / child2AssetCount; Assert.AreEqual(expectedChild1Efficiency, parentBundle.BundleDependencies[0].ExpandedEfficiency); Assert.AreEqual(expectedChild2Efficiency, parentBundle.BundleDependencies[1].ExpandedEfficiency); } [Test] public void BuildLayoutBundle_CalculateEfficiency_DoesNotDoubleCountDependencies() { BuildLayout.Bundle parent = CreateBundleWithFileSize(2); BuildLayout.Bundle child = CreateBundleWithFileSize(2); BuildLayout.ExplicitAsset parentAsset1 = CreateExplicitAssetWithParentBundle(parent); BuildLayout.ExplicitAsset parentAsset2 = CreateExplicitAssetWithParentBundle(parent); BuildLayout.ExplicitAsset childAsset1 = CreateExplicitAssetWithParentBundle(child); parent.UpdateBundleDependency(parentAsset1, childAsset1); parent.UpdateBundleDependency(parentAsset2, childAsset1); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(parent); float expectedEfficiency = .5f; Assert.AreEqual(expectedEfficiency, parent.BundleDependencies[0].ExpandedEfficiency, "If multiple assets in a parent bundle depend on a single asset in the child, this reliance should not be double counted."); Assert.AreEqual(expectedEfficiency, parent.BundleDependencies[0].Efficiency, "If multiple assets in a parent bundle depend on a single asset in the child, this reliance should not be double counted."); } [Test] [TestCase(2, 1, 1, 1, 1)] [TestCase(2, 5, 5, 2, 3)] [TestCase(10, 3,3, 3,3)] [TestCase(30, 30, 30, 20, 20)] [TestCase(50, 50, 50, 50, 50)] public void BuildLayoutBundle_CalculateEfficiency_HigherLevelTreesCorrectlyPromulgateLowerLevelEfficiency( int parentAssetCount, int child1AssetCount, int child2AssetCount, int child1DependencyCount, int child2DependencyCount) { BuildLayout.Bundle grandparent = CreateBundleWithFileSize(1); BuildLayout.Bundle parent = CreateBundleWithFileSize(parentAssetCount); BuildLayout.Bundle childBundle1 = CreateBundleWithFileSize(child1AssetCount); BuildLayout.Bundle childBundle2 = CreateBundleWithFileSize(child2AssetCount); BuildLayout.ExplicitAsset grandparentAsset = CreateExplicitAssetWithParentBundle(grandparent); BuildLayout.ExplicitAsset parentAsset = CreateExplicitAssetWithParentBundle(parent); grandparent.UpdateBundleDependency(grandparentAsset, parentAsset); for (int i = 0; i < child1DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(childBundle1); parent.UpdateBundleDependency(parentAsset, childAsset); } for (int i = 0; i < child2DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(childBundle2); parent.UpdateBundleDependency(parentAsset, childAsset); } grandparent.SerializeBundleToBundleDependency(); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(grandparent); float expectedGrandparentToParentEfficiency = (float) 1 / parentAssetCount; float expectedGrandparentToParentExpandedEfficiency = (float) (1 + child1DependencyCount + child2DependencyCount) / (parentAssetCount + child1AssetCount + child2AssetCount); float expectedParentToChild1Efficiency = (float) child1DependencyCount / child1AssetCount; float expectedParentToChild2Efficiency = (float) child2DependencyCount / child2AssetCount; Assert.AreEqual(expectedGrandparentToParentEfficiency, grandparent.BundleDependencies[0].Efficiency); Assert.AreEqual(expectedGrandparentToParentExpandedEfficiency, grandparent.BundleDependencies[0].ExpandedEfficiency); Assert.AreEqual(expectedParentToChild1Efficiency, parent.BundleDependencies[0].Efficiency); Assert.AreEqual(expectedParentToChild2Efficiency, parent.BundleDependencies[1].Efficiency); } [Test] [TestCase(5, 10, 10, 3, 5)] [TestCase(7, 20, 15, 5, 8)] [TestCase(11, 35, 40, 15, 20)] public void BuildLayoutBundle_CalculateEfficiency_CacheCorrectlyAvoidsDoubleComputation( int parentAssetCount, int child1AssetCount, int child2AssetCount, int child1DependencyCount, int child2DependencyCount) { BuildLayout.Bundle grandparent1 = CreateBundleWithFileSize(1); BuildLayout.Bundle grandparent2 = CreateBundleWithFileSize(1); BuildLayout.Bundle parent = CreateBundleWithFileSize(parentAssetCount); BuildLayout.Bundle child1 = CreateBundleWithFileSize(child1AssetCount); BuildLayout.Bundle child2 = CreateBundleWithFileSize(child2AssetCount); BuildLayout.ExplicitAsset grandparent1Asset = CreateExplicitAssetWithParentBundle(grandparent1); BuildLayout.ExplicitAsset grandparent2Asset = CreateExplicitAssetWithParentBundle(grandparent2); BuildLayout.ExplicitAsset parentAsset = CreateExplicitAssetWithParentBundle(parent); grandparent1.UpdateBundleDependency(grandparent1Asset, parentAsset); grandparent2.UpdateBundleDependency(grandparent2Asset, parentAsset); for (int i = 0; i < child1DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(child1); parent.UpdateBundleDependency(parentAsset, childAsset); } for (int i = 0; i < child2DependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(child2); parent.UpdateBundleDependency(parentAsset, childAsset); } Dictionary bdCache = new Dictionary(); grandparent1.SerializeBundleToBundleDependency(); grandparent2.SerializeBundleToBundleDependency(); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(grandparent1, bdCache); var ef1 = new BuildLayout.Bundle.EfficiencyInfo { totalAssetFileSize = (ulong) child1AssetCount, referencedAssetFileSize = (ulong) child1DependencyCount }; var ef2 = new BuildLayout.Bundle.EfficiencyInfo { totalAssetFileSize = (ulong) child2AssetCount, referencedAssetFileSize = (ulong) child2DependencyCount }; float bd1Efficiency = (float) child1DependencyCount / child1AssetCount; float bd2Efficiency = (float) child2DependencyCount / child2AssetCount; float gp1Efficiency = (float) (1 + child1DependencyCount + child2DependencyCount) / (parentAssetCount + child1AssetCount + child2AssetCount); Assert.IsTrue(bdCache.ContainsKey(parent.BundleDependencies[0]), "BundleDependencyCache not properly populated"); Assert.AreEqual(bdCache[parent.BundleDependencies[0]], ef1); Assert.AreEqual(parent.BundleDependencies[0].ExpandedEfficiency, bd1Efficiency); Assert.IsTrue(bdCache.ContainsKey(parent.BundleDependencies[1]), "BundleDependencyCache not properly populated"); Assert.AreEqual(bdCache[parent.BundleDependencies[1]], ef2); Assert.AreEqual(parent.BundleDependencies[1].ExpandedEfficiency, bd2Efficiency); Assert.AreEqual(grandparent1.BundleDependencies[0].ExpandedEfficiency, gp1Efficiency); // Create a new asset that is not cached - we do this to ensure that cached values are used and that we're not recalculating Efficiency // This will never happen in normal execution - this is just a workaround to make sure the cache is working properly. var uncachedAsset = CreateExplicitAssetWithParentBundle(child1); parent.UpdateBundleDependency(parentAsset, uncachedAsset); BuildLayoutGenerationTask.CalculateEfficiency(grandparent2, bdCache); Assert.IsTrue(bdCache.ContainsKey(parent.BundleDependencies[0]), "Key should not be removed"); Assert.AreEqual(bdCache[parent.BundleDependencies[0]], ef1, "Efficiency should not change since cached value should be used"); Assert.AreEqual(parent.BundleDependencies[0].ExpandedEfficiency, bd1Efficiency, "Efficiency should not change since cached value should be used."); Assert.AreEqual(grandparent2.BundleDependencies[0].ExpandedEfficiency, gp1Efficiency, "Efficiency of grandparent2 should be equal to grandparent1, since cache was used."); //Calculation without cache should be incorrect BuildLayoutGenerationTask.CalculateEfficiency(grandparent2); Assert.AreNotEqual(parent.BundleDependencies[0].ExpandedEfficiency, bd1Efficiency, "Efficiency should change since cached value is not used"); Assert.AreNotEqual(grandparent2.BundleDependencies[0].ExpandedEfficiency, gp1Efficiency, "Efficiency of grandparent2 should not be equal to grandparent1 since cache isnt used"); } [Test] [TestCase(5, 5, 5, 3, 2, 3, 4)] [TestCase(50, 2, 10, 10, 1, 2, 4)] [TestCase(1, 1, 1, 1, 1, 1, 1)] [TestCase(100, 100, 100, 20, 30, 40, 40)] public void BuildLayoutBundle_CalculateEfficiency_NonTreeStructureProperlyHandled( int bundleBAssetCount, int bundleCAssetCount, int bundleDAssetCount, int bundleBDependencyCount, int bundleBToBundleCDependencyCount, int bundleCDependencyCount, int bundleDDependencyCount) { BuildLayout.Bundle bundleA = CreateBundleWithFileSize(1); BuildLayout.Bundle bundleB = CreateBundleWithFileSize(bundleBAssetCount); BuildLayout.Bundle bundleC = CreateBundleWithFileSize(bundleCAssetCount); BuildLayout.Bundle bundleD = CreateBundleWithFileSize(bundleDAssetCount); var assetA = CreateExplicitAssetWithParentBundle(bundleA); var assetB = CreateExplicitAssetWithParentBundle(bundleB); var assetC = CreateExplicitAssetWithParentBundle(bundleC); bundleA.UpdateBundleDependency(assetA, assetB); for (int i = 0; i < bundleBDependencyCount - 1; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleB); bundleA.UpdateBundleDependency(assetA, childAsset); } bundleA.UpdateBundleDependency(assetA, assetC); for (int i = 0; (i < bundleCDependencyCount - 1) || (i < bundleBToBundleCDependencyCount); i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleC); if (i < bundleCDependencyCount - 1) bundleA.UpdateBundleDependency(assetA, childAsset); if (i < bundleBToBundleCDependencyCount) bundleB.UpdateBundleDependency(assetB, childAsset); } for (int i = 0; i < bundleDDependencyCount; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleD); bundleC.UpdateBundleDependency(assetC, childAsset); } bundleA.SerializeBundleToBundleDependency(); bundleB.SerializeBundleToBundleDependency(); bundleC.SerializeBundleToBundleDependency(); bundleD.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(bundleA); var cToDExpandedEfficiency = (float)bundleDDependencyCount / bundleDAssetCount; var BToCExpandedEfficiency = (float)(bundleDDependencyCount + bundleBToBundleCDependencyCount) / (bundleCAssetCount + bundleDAssetCount); var AToBExpandedEfficiency = (float) (bundleBDependencyCount + bundleDDependencyCount + bundleBToBundleCDependencyCount) / (bundleBAssetCount + bundleCAssetCount + bundleDAssetCount); Assert.AreEqual(bundleC.BundleDependencies[0].ExpandedEfficiency, cToDExpandedEfficiency); Assert.AreEqual(bundleB.BundleDependencies[0].ExpandedEfficiency, BToCExpandedEfficiency); Assert.AreEqual(bundleA.BundleDependencies[0].ExpandedEfficiency, AToBExpandedEfficiency); } [Test] [TestCase(20, 20, 20, 5, 5, 5, 5)] [TestCase(50, 30, 10, 15, 10, 8, 7)] [TestCase(100, 75, 35, 35, 7, 30, 25)] public void BuildLayoutBundle_CalculateEfficiency_HandlesCycleWithLeadInByCuttingOffLastNodeConnections( int bundleBAssetCount, int bundleCAssetCount, int bundleDAssetCount, int bundleAToBDependencyCount, int bundleBToCDependencyCount, int bundleCToDDependencyCount, int bundleDToBDependencyCount) { BuildLayout.Bundle bundleA = CreateBundleWithFileSize(1); BuildLayout.Bundle bundleB = CreateBundleWithFileSize(bundleBAssetCount, "B"); BuildLayout.Bundle bundleC = CreateBundleWithFileSize(bundleCAssetCount, "C"); BuildLayout.Bundle bundleD = CreateBundleWithFileSize(bundleDAssetCount, "D"); var assetA = CreateExplicitAssetWithParentBundle(bundleA); var assetB = CreateExplicitAssetWithParentBundle(bundleB); var assetC = CreateExplicitAssetWithParentBundle(bundleC); var assetD = CreateExplicitAssetWithParentBundle(bundleD); bundleA.UpdateBundleDependency(assetA, assetB); bundleB.UpdateBundleDependency(assetB, assetC); bundleC.UpdateBundleDependency(assetC, assetD); bundleD.UpdateBundleDependency(assetD, assetB); for (int i = 0; i < bundleAToBDependencyCount - 1; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleB); bundleA.UpdateBundleDependency(assetA, childAsset); } for (int i = 0; i < bundleBToCDependencyCount - 1; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleC); bundleB.UpdateBundleDependency(assetB, childAsset); } for (int i = 0; i < bundleCToDDependencyCount - 1; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleD); bundleC.UpdateBundleDependency(assetC, childAsset); } for (int i = 0; i < bundleDToBDependencyCount - 1; i++) { var childAsset = CreateExplicitAssetWithParentBundle(bundleB); bundleD.UpdateBundleDependency(assetD, childAsset); } bundleA.SerializeBundleToBundleDependency(); bundleB.SerializeBundleToBundleDependency(); bundleC.SerializeBundleToBundleDependency(); bundleD.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(bundleA); float bundleDToBExpandedEfficiency = (float) bundleDToBDependencyCount / bundleBAssetCount; float bundleCToDExpandedEfficiency = (float) (bundleCToDDependencyCount + bundleDToBDependencyCount) / (bundleDAssetCount + bundleBAssetCount); float bundleBToCExpandedEfficiency = (float) (bundleBToCDependencyCount + bundleCToDDependencyCount + bundleDToBDependencyCount) / (bundleCAssetCount + bundleDAssetCount + bundleBAssetCount); float bundleAToBExpandedEfficiency = (float) (bundleAToBDependencyCount + bundleBToCDependencyCount + bundleCToDDependencyCount + bundleDToBDependencyCount) / (bundleBAssetCount + bundleCAssetCount + bundleDAssetCount + bundleBAssetCount); Assert.AreEqual(bundleAToBExpandedEfficiency, bundleA.BundleDependencies[0].ExpandedEfficiency); Assert.AreEqual(bundleBToCExpandedEfficiency, bundleB.BundleDependencies[0].ExpandedEfficiency); Assert.AreEqual(bundleCToDExpandedEfficiency, bundleC.BundleDependencies[0].ExpandedEfficiency); Assert.AreEqual(bundleDToBExpandedEfficiency, bundleD.BundleDependencies[0].ExpandedEfficiency); } BuildLayout CreateTestLayout(DateTime buildDate, string error = null) { BuildLayout layout = new BuildLayout(); layout.BuildTarget = BuildTarget.Android; layout.BuildResultHash = "testHash123"; layout.BuildType = BuildType.UpdateBuild; layout.BuildStart = buildDate; layout.Duration = 10; layout.BuildError = error; layout.BuildScript = "DefaultBuildScript"; BuildLayout.Bundle bundle = CreateBundleWithFileSize(2); bundle.Files = new List(); BuildLayout.File file = new BuildLayout.File(); bundle.Files.Add(file); file.Assets = new List(); file.Assets.Add(CreateExplicitAssetWithParentBundle(bundle)); file.Assets.Add(CreateExplicitAssetWithParentBundle(bundle)); BuildLayout.Group group = new BuildLayout.Group(); group.Bundles = new List(); group.Bundles.Add(bundle); layout.Groups = new List(); layout.Groups.Add(group); layout.DefaultGroup = group; return layout; } [Test] public void BuildLayoutBundle_SaveAndLoad_SavesCorrectlyToDisk() { DateTime time = DateTime.Now; BuildLayout layout = CreateTestLayout(time); string filePath = $"{Application.dataPath}/testLayout.json"; try { layout.WriteToFile(filePath, false); FileAssert.Exists(filePath, $"Failed to save build layout to {filePath}"); } finally { if (File.Exists(filePath)) File.Delete(filePath); } } [Test] [TestCase(50UL, 50UL, 20UL, 20UL, 10, 5)] [TestCase(30UL, 50UL, 10UL, 5UL, 3, 2)] [TestCase(1UL, 1UL, 1UL, 1UL, 1, 1)] [TestCase(30UL, 1UL, 30UL, 1UL, 1, 1)] [TestCase(5000UL, 5000UL, 500UL, 500UL, 30, 50)] public void BuildLayoutBundle_CalculateEfficiency_CorrectlyUsesFilesizeForEfficiency( ulong parentTotalFilesize, ulong childTotalFilesize, ulong parentDepFileSize, ulong childDepFilesize, int parentDependencyCount, int childDependencyCount) { BuildLayout.Bundle grandparent = CreateBundleWithFileSize(1); BuildLayout.Bundle parent = CreateBundleWithFileSize(parentTotalFilesize); BuildLayout.Bundle child = CreateBundleWithFileSize(childTotalFilesize); BuildLayout.ExplicitAsset grandparentAsset = CreateExplicitAssetWithParentBundle(grandparent); List parentAssets = new List(); ulong expectedParentDepFileSize = 0; for (int i = 0; i < parentDependencyCount; i++) { var curFileSize = (ulong)parentDependencyCount / parentDepFileSize; expectedParentDepFileSize += curFileSize; var parentAsset = CreateExplicitAssetWithParentBundle(parent, curFileSize); grandparent.UpdateBundleDependency(grandparentAsset, parentAsset); parentAssets.Add(parentAsset); } ulong expectedChildDepFileSize = 0; for (int i = 0; i < childDependencyCount; i++) { var curFileSize = (ulong)childDependencyCount / childDepFilesize; expectedChildDepFileSize += curFileSize; var childAsset = CreateExplicitAssetWithParentBundle(child, curFileSize); parent.UpdateBundleDependency(parentAssets[0], childAsset); } grandparent.SerializeBundleToBundleDependency(); parent.SerializeBundleToBundleDependency(); BuildLayoutGenerationTask.CalculateEfficiency(grandparent); float expectedGrandparentEfficiency = (float) expectedParentDepFileSize / parentTotalFilesize; float expectedGrandparentExpandedEfficiency = (float) (expectedParentDepFileSize + expectedChildDepFileSize) / (parentTotalFilesize + childTotalFilesize); float expectedParentEfficiency = (float) expectedChildDepFileSize / childTotalFilesize; Assert.AreEqual(expectedGrandparentEfficiency, grandparent.BundleDependencies[0].Efficiency, "Grandparent Efficiency not calculated correctly - this should not be affected by the children of parent."); Assert.AreEqual(expectedGrandparentExpandedEfficiency, grandparent.BundleDependencies[0].ExpandedEfficiency, "Grandparent ExpandedEfficiency not calculated correctly - this should take into account the total Efficiency of both the direct children Dependency Links as well as all BundleDependencies below the child."); Assert.AreEqual(expectedParentEfficiency, parent.BundleDependencies[0].ExpandedEfficiency, "Parent ExpandedEfficiency not calculated correctly - this should take into account the Efficiency of the direct child only."); } [Test] public void BuildLayoutBundle_SaveAndLoad_ReadsCorrectDataForHeader() { DateTime time = DateTime.Now; BuildLayout layout = CreateTestLayout(time, "testError123"); time = layout.BuildStart; // due to removing miliseconds in the layout string filePath = $"{Application.dataPath}/testLayout.json"; try { layout.WriteToFile(filePath, false); FileAssert.Exists(filePath, $"Failed to save build layout to {filePath}"); BuildLayout readLayout = BuildLayout.Open(filePath, false, false); Assert.AreEqual(DateTime.MinValue, readLayout.BuildStart, "StartDate was not expected to have read a valid date"); // test all header values to ensure the values are as expect (not the same as default values) readLayout.ReadHeader(); Assert.AreEqual(time, readLayout.Header.BuildStart, "Header Data written or Read incorrectly"); Assert.AreEqual(10, readLayout.Header.Duration, "Header Data written or Read incorrectly"); Assert.AreEqual("testError123", readLayout.Header.BuildError, "Header Data written or Read incorrectly"); Assert.AreEqual(BuildTarget.Android, readLayout.Header.BuildTarget, "Header Data written or Read incorrectly"); Assert.AreEqual(BuildType.UpdateBuild, readLayout.Header.BuildType, "Header Data written or Read incorrectly"); Assert.AreEqual("testHash123", readLayout.Header.BuildResultHash, "Header Data written or Read incorrectly"); // that the test groups have not been read Assert.AreEqual(0, readLayout.Groups.Count, "Expect to have not read any Groups yet with only Header read"); } finally { if (File.Exists(filePath)) File.Delete(filePath); } } [Test] public void BuildLayoutBundle_SaveAndLoad_ReadsCorrectDataForBody() { DateTime time = DateTime.Now; BuildLayout layout = CreateTestLayout(time); string filePath = $"{Application.dataPath}/testLayout.json"; try { layout.WriteToFile(filePath, false); FileAssert.Exists(filePath, $"Failed to save build layout to {filePath}"); BuildLayout readLayout = BuildLayout.Open(filePath, false, false); Assert.AreEqual(0, readLayout.Groups.Count, "Expect to have not read any Groups yet with no data yet read read"); readLayout.ReadHeader(); Assert.AreEqual(0, readLayout.Groups.Count, "Expect to have not read any Groups yet with only Header read"); readLayout.ReadFull(); Assert.AreEqual(1, readLayout.Groups.Count, "Expect to have 1 Groups after doing a full read read"); } finally { if (File.Exists(filePath)) File.Delete(filePath); } } [Test] [TestCase(typeof(GameObject), AssetType.GameObject)] [TestCase(typeof(SceneAsset), AssetType.Scene)] [TestCase(typeof(AnimatorController), AssetType.AnimationController)] [TestCase(typeof(TestObject), AssetType.ScriptableObject)] [TestCase(typeof(ObjectReferenceMonoBehaviour), AssetType.MonoBehaviour)] public void GetAssetType_ReturnsCorrect(System.Type typeIn, AssetType expectedType) { AssetType actual = BuildLayoutHelpers.GetAssetType(typeIn); Assert.AreEqual(expectedType, actual); } } }