Skip to content

Instantly share code, notes, and snippets.

@SolidAlloy
Last active March 6, 2024 03:42
Show Gist options
  • Save SolidAlloy/3027f88e69b63700b9ae530360cfd0eb to your computer and use it in GitHub Desktop.
Save SolidAlloy/3027f88e69b63700b9ae530360cfd0eb to your computer and use it in GitHub Desktop.
AssetDatabase unit tests that show the implications of Refresh() and SaveAssets()
using System;
using System.IO;
using JetBrains.Annotations;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
/// <summary>
/// Unit tests that show how AssetDatabase operates.
/// </summary>
public class AssetDatabaseTests
{
private const string TestingFolder = "Assets/Testing";
private const string ExpectedFieldValue = "changed";
[OneTimeSetUp]
public void BeforeAllTests()
{
var parts = TestingFolder.Split(new[] { '/' }, 2);
AssetDatabase.CreateFolder(parts[0], parts[1]);
}
[OneTimeTearDown]
public void AfterAllTests()
{
AssetDatabase.DeleteAsset(TestingFolder);
}
[Test]
public void Does_not_register_a_manually_created_file_without_refresh()
{
string assetPath = CreateFileManually();
string actualGUID = AssetDatabase.AssetPathToGUID(assetPath);
Assert.IsTrue(string.IsNullOrEmpty(actualGUID));
}
[Test]
public void Registers_file_without_refresh_after_CreateAsset()
{
string assetPath = CreateFileThroughAssetDatabase();
string actualGUID = AssetDatabase.AssetPathToGUID(assetPath);
Assert.IsFalse(string.IsNullOrEmpty(actualGUID));
}
[Test]
public void Cannot_obtain_object_from_manually_created_asset_without_refresh()
{
string assetPath = CreateFileManually();
var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath);
Assert.IsNull(asset);
}
[Test]
public void Can_obtain_object_from_asset_created_using_CreateAsset_without_refresh()
{
string assetPath = CreateFileThroughAssetDatabase();
var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath);
Assert.IsNotNull(asset);
}
[Test]
public void Can_obtain_object_from_manually_created_asset_after_refresh()
{
string assetPath = CreateFileManually();
AssetDatabase.Refresh();
var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath);
Assert.IsNotNull(asset);
}
// BE AWARE !!!
// A GUID of a previously created asset is not removed from AssetDatabase until an Editor restart,
// no matter in what way you delete the asset.
[Test]
public void Does_not_remove_guid_from_database_after_asset_is_loaded()
{
string assetPath = CreateFileManually();
AssetDatabase.Refresh();
// Try everything to make AssetDatabase notice that both asset and the loaded Object are removed.
EditorUtility.UnloadUnusedAssetsImmediate();
AssetDatabase.DeleteAsset(assetPath);
AssetDatabase.Refresh();
string actualGUID = AssetDatabase.AssetPathToGUID(assetPath);
// The asset GUID is not empty.
Assert.IsFalse(string.IsNullOrEmpty(actualGUID));
// And the path can still be obtained.
string actualAssetPath = AssetDatabase.GUIDToAssetPath(actualGUID);
Assert.AreEqual(assetPath, actualAssetPath);
// However, no assets can be loaded from it.
var assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
Assert.That(assets.Length.Equals(0));
}
[Test]
public void Does_not_write_object_changes_to_disk_automatically()
{
(string assetPath, _) = SetScriptableObjectFieldToExpectedValue();
AssertThatChangesAreNotSaved(assetPath);
}
[Test]
public void Does_not_write_object_changes_to_disk_after_SaveAssets()
{
(string assetPath, _) = SetScriptableObjectFieldToExpectedValue();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
AssertThatChangesAreNotSaved(assetPath);
}
[Test]
public void Does_not_write_object_changes_to_disk_after_SetDirty()
{
(string assetPath, var scriptableObject) = SetScriptableObjectFieldToExpectedValue();
EditorUtility.SetDirty(scriptableObject);
AssertThatChangesAreNotSaved(assetPath);
}
[Test]
public void Writes_object_changes_to_disk_after_SetDirty_and_SaveAssets()
{
(string assetPath, var scriptableObject) = SetScriptableObjectFieldToExpectedValue();
EditorUtility.SetDirty(scriptableObject);
AssetDatabase.SaveAssets();
string fileContent = File.ReadAllText(assetPath);
Assert.IsTrue(fileContent.Contains(ExpectedFieldValue));
}
private static string CreateFileManually()
{
string assetPath = GetUniqueTextFilePath();
File.WriteAllText(assetPath, "test");
return assetPath;
}
private static string CreateFileThroughAssetDatabase()
{
string assetPath = GetUniqueTextFilePath();
TextAsset asset = new TextAsset("test");
AssetDatabase.CreateAsset(asset, assetPath);
return assetPath;
}
private static string GetUniqueTextFilePath()
{
return $"{TestingFolder}/test{Guid.NewGuid().ToString()}.txt";
}
private static (string assetPath, Object obj) SetScriptableObjectFieldToExpectedValue()
{
(string assetPath, var testSO) = CreateTestSOAsset();
testSO.StringField = ExpectedFieldValue;
return (assetPath, testSO);
}
private static void AssertThatChangesAreNotSaved(string assetPath)
{
string fileContent = File.ReadAllText(assetPath);
Assert.IsFalse(fileContent.Contains(ExpectedFieldValue));
}
private static (string assetPath, TestScriptableObject obj) CreateTestSOAsset()
{
var testSO = ScriptableObject.CreateInstance<TestScriptableObject>();
string assetPath = GetUniqueScriptableObjectPath();
AssetDatabase.CreateAsset(testSO, assetPath);
return (assetPath, testSO);
}
private static string GetUniqueScriptableObjectPath()
{
return $"{TestingFolder}/testSO{Guid.NewGuid().ToString()}.asset";
}
private class TestScriptableObject : ScriptableObject
{
[UsedImplicitly]
public string StringField;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment