Files
aibis-dream/Assets/Tests/FrameAnimation/PlayMode/FrameAnimationPlayerTests.cs
T

219 lines
7.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace AibisDream.FrameAnimation.Tests.PlayMode
{
/// <summary>
/// 帧动画组件的最小运行时集成测试。
/// 时间推进细节由 EditMode 的 PlaybackSession 契约覆盖。
/// </summary>
public sealed class FrameAnimationPlayerTests
{
private readonly List<UnityEngine.Object> createdObjects =
new List<UnityEngine.Object>();
[TearDown]
public void TearDown()
{
for (var index = createdObjects.Count - 1; index >= 0; index--)
{
if (createdObjects[index] != null)
UnityEngine.Object.DestroyImmediate(createdObjects[index]);
}
createdObjects.Clear();
}
[Test]
public void GraphPlayer_RendersAndAppliesTerminalBehavior()
{
var first = CreateSprite(Color.red);
var second = CreateSprite(Color.blue);
var clip = CreateClip(
"Clip",
FrameClipEndBehavior.Clear,
first,
second);
var graph = CreateGraph(clip);
var gameObject = Track(new GameObject("Graph Player"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.Play(clip.Id);
Assert.That(renderer.sprite, Is.SameAs(first));
player.EvaluateForTests(0.2d);
Assert.That(handle.Result.Reason,
Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(renderer.sprite, Is.Null);
Assert.That(renderer.enabled, Is.True);
}
[Test]
public void StandalonePlayer_PlaysConfiguredClipWithoutGraph()
{
var first = CreateSprite(Color.magenta);
var second = CreateSprite(Color.cyan);
var clip = CreateClip(
"Standalone",
FrameClipEndBehavior.HoldLastFrame,
first,
second);
var gameObject = Track(new GameObject("Standalone Player"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameClipPlayer>();
player.ConfigureForAuthoring(clip, false, 1f);
var handle = player.Play();
Assert.That(player.CurrentClip, Is.SameAs(clip));
player.EvaluateForTests(0.2d);
Assert.That(handle.Result.Reason,
Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(renderer.sprite, Is.SameAs(second));
}
[Test]
public void PlayRequest_FailureKeepsActiveAndSuccessReplacesIt()
{
var first = CreateClip(
"First",
FrameClipEndBehavior.Loop,
CreateSprite(Color.white));
var second = CreateClip(
"Second",
FrameClipEndBehavior.Loop,
CreateSprite(Color.black));
var graph = CreateGraph(first, second);
var gameObject = Track(new GameObject("Request Arbitration"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var active = player.Play(first.Id);
var failed = player.Play("Missing");
Assert.That(failed.Result.Error.Code,
Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
Assert.That(active.IsCompleted, Is.False);
Assert.That(player.CurrentPlayableId, Is.EqualTo(first.Id));
var replacement = player.Play(second.Id);
Assert.That(active.Result.Reason,
Is.EqualTo(FrameAnimationCompletionReason.Replaced));
Assert.That(replacement.IsCompleted, Is.False);
Assert.That(player.CurrentPlayableId, Is.EqualTo(second.Id));
}
[Test]
public void RestoreTerminalState_RebuildsSavedVisualState()
{
var terminalSprite = CreateSprite(Color.green);
var hold = CreateClip(
"Hold",
FrameClipEndBehavior.HoldLastFrame,
CreateSprite(Color.red),
terminalSprite);
var hidden = CreateClip(
"Hidden",
FrameClipEndBehavior.HideTarget,
CreateSprite(Color.blue));
var graph = CreateGraph(hold, hidden);
var gameObject = Track(new GameObject("Restore Terminal State"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var holdResult = player.RestoreTerminalState(hold.Id);
Assert.That(holdResult.Result.Reason,
Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(renderer.sprite, Is.SameAs(terminalSprite));
Assert.That(renderer.enabled, Is.True);
player.RestoreTerminalState(hidden.Id);
Assert.That(renderer.enabled, Is.False);
}
[UnityTest]
public IEnumerator Disable_SettlesActiveRequestAsStopped()
{
var clip = CreateClip(
"Loop",
FrameClipEndBehavior.Loop,
CreateSprite(Color.white));
var gameObject = Track(new GameObject("Disable Player"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(CreateGraph(clip), false, 1f);
var handle = player.Play(clip.Id);
player.enabled = false;
yield return null;
Assert.That(handle.Result.Reason,
Is.EqualTo(FrameAnimationCompletionReason.Stopped));
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Stopped));
}
private FrameClip CreateClip(
string id,
FrameClipEndBehavior endBehavior,
params Sprite[] sprites)
{
var clip = Track(ScriptableObject.CreateInstance<FrameClip>());
var frames = new List<FrameAnimationFrame>();
for (var index = 0; index < sprites.Length; index++)
{
frames.Add(new FrameAnimationFrame(
sprites[index],
100,
$"frame_{index}",
index));
}
clip.Configure(id, id, frames, 1f, endBehavior);
return clip;
}
private FrameAnimationGraph CreateGraph(params FrameClip[] clips)
{
var graph = Track(ScriptableObject.CreateInstance<FrameAnimationGraph>());
graph.Configure(
"Graph",
"Graph",
clips,
Array.Empty<AnimationNode>(),
Array.Empty<AnimationEdge>(),
Array.Empty<AnimationFlow>(),
clips[0].Id);
return graph;
}
private Sprite CreateSprite(Color color)
{
var texture = Track(new Texture2D(2, 2));
texture.SetPixels(new[] { color, color, color, color });
texture.Apply();
return Track(Sprite.Create(
texture,
new Rect(0, 0, 2, 2),
new Vector2(0.5f, 0.5f)));
}
private T Track<T>(T value) where T : UnityEngine.Object
{
createdObjects.Add(value);
return value;
}
}
}