197 lines
8.4 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|