Files
aibis-dream/Assets/Tests/FrameAnimation/EditMode/FrameClipStandaloneImportTests.cs
T

197 lines
8.4 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Text;
using AibisDream.FrameAnimation.Editor;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
namespace AibisDream.FrameAnimation.Tests.EditMode
{
public sealed class FrameClipStandaloneImportTests
{
private const string Root = "Assets/Tests/FrameAnimation/GeneratedStandaloneClipTests";
private const string TexturePath = Root + "/Atlas.png";
private const string JsonPath = Root + "/Atlas.json";
private const string ClipPath = Root + "/Standalone.asset";
[SetUp]
public void SetUp()
{
AssetDatabase.DeleteAsset(Root);
EnsureFolder(Root);
}
[TearDown]
public void TearDown()
{
AssetDatabase.DeleteAsset(Root);
AssetDatabase.Refresh();
}
[Test]
public void Preview_UsesOnlyFirstTagAndRespectsDirection()
{
var clip = CreateSourceClip(string.Empty, JsonWithTags("reverse"));
var preview = FrameClipImportService.Preview(clip);
Assert.That(preview.HasErrors, Is.False, JoinIssues(preview));
Assert.That(preview.SourceTagName, Is.EqualTo("First"));
CollectionAssert.AreEqual(new[] { 1, 0 }, preview.SourceIndices);
Assert.That(preview.SpriteDiffs.Count(diff => diff.Kind == FrameAnimationSpriteChangeKind.Added),
Is.EqualTo(2));
}
[Test]
public void Preview_WithoutTagsUsesAllFrames()
{
var clip = CreateSourceClip("Existing", JsonWithoutTags());
var preview = FrameClipImportService.Preview(clip);
Assert.That(preview.HasErrors, Is.False, JoinIssues(preview));
Assert.That(preview.SourceTagName, Is.Empty);
CollectionAssert.AreEqual(new[] { 0, 1 }, preview.SourceIndices);
}
[Test]
public void Apply_InitializesEmptyIdAndRefreshPreservesExistingId()
{
var clip = CreateSourceClip(string.Empty, JsonWithTags("forward"));
var first = FrameClipImportService.Preview(clip);
Assert.That(FrameClipImportService.Apply(first, true, out var error), Is.True, error);
Assert.That(clip.Id, Is.EqualTo("First"));
Assert.That(clip.DisplayName, Is.EqualTo("First"));
Assert.That(clip.FrameCount, Is.EqualTo(2));
Assert.That(clip.StandaloneImportSource.LastImportedTagName, Is.EqualTo("First"));
var serialized = new SerializedObject(clip);
serialized.FindProperty("id").stringValue = "CustomId";
serialized.ApplyModifiedPropertiesWithoutUndo();
WriteJson(JsonWithTags("reverse"));
var second = FrameClipImportService.Preview(clip);
Assert.That(FrameClipImportService.Apply(second, true, out error), Is.True, error);
Assert.That(clip.Id, Is.EqualTo("CustomId"));
CollectionAssert.AreEqual(new[] { 1, 0 }, clip.Frames.Select(frame => frame.SourceIndex));
}
[Test]
public void Detach_PreservesFramesAndAllowsGraphReference()
{
var clip = CreateSourceClip("External", JsonWithoutTags());
var preview = FrameClipImportService.Preview(clip);
Assert.That(FrameClipImportService.Apply(preview, true, out var error), Is.True, error);
var frames = clip.Frames.ToArray();
var graph = ScriptableObject.CreateInstance<FrameAnimationGraph>();
graph.Configure("Graph", "Graph", Array.Empty<FrameClip>(), Array.Empty<AnimationNode>(),
Array.Empty<AnimationEdge>(), Array.Empty<AnimationFlow>(), clip.Id);
AssetDatabase.CreateAsset(graph, Root + "/Graph.asset");
Assert.That(FrameAnimationAssetOperations.AddExistingManualClip(graph, clip, out error), Is.True, error);
Assert.That(FrameAnimationGraphValidator.Validate(graph).HasErrors, Is.False);
FrameClipImportService.DetachSource(clip);
Assert.That(clip.HasStandaloneImportSource, Is.False);
CollectionAssert.AreEqual(frames, clip.Frames);
}
[Test]
public void Preview_RejectsSecondWritableStandaloneOwnerForSameTexture()
{
CreateTexture();
WriteJson(JsonWithoutTags());
var first = CreateLinkedClipAt(ClipPath, "FirstOwner");
var second = CreateLinkedClipAt(Root + "/Second.asset", "SecondOwner");
var preview = FrameClipImportService.Preview(second);
Assert.That(first.StandaloneImportSource.Texture, Is.SameAs(second.StandaloneImportSource.Texture));
Assert.That(preview.HasErrors, Is.True);
Assert.That(preview.Issues.Any(issue =>
issue.Code == FrameAnimationImportIssueCode.TextureOwnershipConflict), Is.True);
}
private static FrameClip CreateSourceClip(string id, string json)
{
CreateTexture();
WriteJson(json);
return CreateLinkedClipAt(ClipPath, id);
}
private static FrameClip CreateLinkedClipAt(string path, string id)
{
var clip = ScriptableObject.CreateInstance<FrameClip>();
clip.Configure(id, string.Empty, Array.Empty<FrameAnimationFrame>());
AssetDatabase.CreateAsset(clip, path);
Assert.That(FrameClipImportService.EnableSource(clip, out var error), Is.True, error);
var serialized = new SerializedObject(clip);
var source = serialized.FindProperty("standaloneImportSource");
source.FindPropertyRelative("texture").objectReferenceValue =
AssetDatabase.LoadAssetAtPath<Texture2D>(TexturePath);
source.FindPropertyRelative("asepriteJson").objectReferenceValue =
AssetDatabase.LoadAssetAtPath<TextAsset>(JsonPath);
source.FindPropertyRelative("manageSpriteSlicing").boolValue = true;
serialized.ApplyModifiedPropertiesWithoutUndo();
AssetDatabase.SaveAssets();
return clip;
}
private static void CreateTexture()
{
var texture = new Texture2D(4, 2, TextureFormat.RGBA32, false);
texture.SetPixels(Enumerable.Range(0, 8).Select(index => index < 4 ? Color.red : Color.green).ToArray());
texture.Apply();
File.WriteAllBytes(TexturePath, texture.EncodeToPNG());
UnityEngine.Object.DestroyImmediate(texture);
AssetDatabase.ImportAsset(TexturePath, ImportAssetOptions.ForceSynchronousImport);
}
private static void WriteJson(string json)
{
File.WriteAllText(JsonPath, json, new UTF8Encoding(false));
AssetDatabase.ImportAsset(JsonPath, ImportAssetOptions.ForceSynchronousImport);
}
private static string JsonWithTags(string direction)
{
return Json("[{\"name\":\"First\",\"from\":0,\"to\":1,\"direction\":\"" + direction +
"\"},{\"name\":\"Ignored\",\"from\":1,\"to\":1,\"direction\":\"invalid\"}]");
}
private static string JsonWithoutTags()
{
return Json("[]");
}
private static string Json(string tags)
{
return "{" +
"\"frames\":{" +
"\"FrameA\":{\"frame\":{\"x\":0,\"y\":0,\"w\":2,\"h\":2},\"rotated\":false,\"trimmed\":false,\"duration\":100,\"spriteSourceSize\":{\"x\":0,\"y\":0,\"w\":2,\"h\":2},\"sourceSize\":{\"w\":2,\"h\":2}}," +
"\"FrameB\":{\"frame\":{\"x\":2,\"y\":0,\"w\":2,\"h\":2},\"rotated\":false,\"trimmed\":false,\"duration\":200,\"spriteSourceSize\":{\"x\":0,\"y\":0,\"w\":2,\"h\":2},\"sourceSize\":{\"w\":2,\"h\":2}}}," +
"\"meta\":{\"image\":\"Atlas.png\",\"size\":{\"w\":4,\"h\":2},\"frameTags\":" + tags + "}}";
}
private static string JoinIssues(FrameClipImportPreview preview)
{
return string.Join("\n", preview.Issues.Select(issue => issue.Message));
}
private static void EnsureFolder(string path)
{
var segments = path.Split('/');
var current = segments[0];
for (var index = 1; index < segments.Length; index++)
{
var next = current + "/" + segments[index];
if (!AssetDatabase.IsValidFolder(next)) AssetDatabase.CreateFolder(current, segments[index]);
current = next;
}
}
}
}