chore: UnityTest清理

This commit is contained in:
2026-07-31 18:22:08 +08:00
parent 0749df3eb2
commit 01cc5036d3
15 changed files with 178 additions and 670 deletions
@@ -70,12 +70,6 @@ namespace AibisDream.DeveloperMode.Editor
}
}
[Test]
public void EditorBuildEnablesDeveloperMode()
{
Assert.That(DeveloperModeGate.IsEnabled, Is.True);
}
[Test]
public void PrefabIsConfiguredAndPersistenceReferencesIt()
{
@@ -87,7 +81,6 @@ namespace AibisDream.DeveloperMode.Editor
var panel = prefab.GetComponent<DeveloperModePanel>();
Assert.That(panel, Is.Not.Null);
Assert.That(panel.IsConfigured, Is.True);
Assert.That(prefab.GetComponent<RectTransform>().sizeDelta, Is.EqualTo(new Vector2(840f, 760f)));
Assert.That(AssetDatabase.GetDependencies(scenePath), Does.Contain(prefabPath));
}
@@ -14,12 +14,9 @@ namespace AibisDream.SystemEditor.Tests
"Assets/Prefabs/FixSystemPrefabs/FrameAnimationActor.prefab";
[Test]
public void ActorType_AppendsFrameAnimationWithoutChangingExistingValues()
public void ActorType_IncludesFrameAnimationMember()
{
Assert.That((int)ActorType.Sprite, Is.EqualTo(0));
Assert.That((int)ActorType.Anima, Is.EqualTo(1));
Assert.That((int)ActorType.AnimaEx, Is.EqualTo(2));
Assert.That((int)ActorType.FrameAnimation, Is.EqualTo(3));
Assert.That(System.Enum.IsDefined(typeof(ActorType), ActorType.FrameAnimation), Is.True);
Assert.That(
System.Enum.TryParse("FrameAnimation", out ActorType parsed),
Is.True);
@@ -86,8 +86,9 @@ namespace AibisDream.EditorTests.Huoshan
yield return null;
LocalizationSettings.SelectedLocale = previous;
Assert.That(chineseTask.Result, Is.EqualTo("我就是个笑话"));
Assert.That(englishTask.Result, Is.EqualTo("I am nothing but a joke"));
Assert.That(chineseTask.Result, Is.Not.Empty);
Assert.That(englishTask.Result, Is.Not.Empty);
Assert.That(chineseTask.Result, Is.Not.EqualTo(englishTask.Result));
}
[UnityTest]
@@ -133,12 +134,13 @@ namespace AibisDream.EditorTests.Huoshan
AssetDatabase.LoadAssetAtPath<ExpressionContentCatalog>(CatalogPath);
Assert.That(catalog, Is.Not.Null);
Assert.That(catalog.GetValidationErrors(), Is.Empty);
Assert.That(catalog.Rounds.Select(round => round.Id),
Is.EqualTo(new[] { "log1", "log2", "log3" }));
Assert.That(catalog.Rounds, Is.Not.Empty);
Assert.That(catalog.TryGetRound("log1", out ExpressionRoundDefinition log1), Is.True);
Assert.That(log1.NonTargetParticleCount, Is.EqualTo(16));
Assert.That(catalog.TryGetRound("LOG1", out _), Is.False);
string firstRoundId = catalog.Rounds[0].Id;
Assert.That(catalog.TryGetRound(firstRoundId, out _), Is.True);
Assert.That(
catalog.TryGetRound(firstRoundId.ToUpperInvariant(), out _),
Is.False);
Assert.That(catalog.TryGetRound("missing", out _), Is.False);
}
@@ -353,17 +355,14 @@ namespace AibisDream.EditorTests.Huoshan
}
[Test]
public void WordProfile_ScalesConfiguredNonTargetCounts()
public void WordProfile_ScalesNonTargetCountByConfiguredScale()
{
ExpressionParticleLanguageProfile profile =
AssetDatabase.LoadAssetAtPath<ExpressionParticleLanguageProfile>(
ParticleProfilePath);
ExpressionParticleLocaleSettings english =
profile.Resolve(new LocaleIdentifier("en"));
var settings = ExpressionParticleLocaleSettings.CreateFallback();
SetPrivateField(settings, "nonTargetCountScale", 0.625f);
Assert.That(english.ScaleNonTargetCount(16), Is.EqualTo(10));
Assert.That(english.ScaleNonTargetCount(28), Is.EqualTo(18));
Assert.That(english.ScaleNonTargetCount(38), Is.EqualTo(25));
Assert.That(settings.ScaleNonTargetCount(16), Is.EqualTo(10));
Assert.That(settings.ScaleNonTargetCount(-1), Is.EqualTo(-1));
Assert.That(settings.ScaleNonTargetCount(0), Is.EqualTo(0));
}
[Test]
@@ -403,6 +402,10 @@ namespace AibisDream.EditorTests.Huoshan
Bounds bounds = particle.GetVisualWorldBounds();
Assert.That(bounds.size.x, Is.GreaterThan(0f));
Assert.That(
particle.DistanceToVisualBounds(
new Vector2(bounds.min.x, bounds.center.y)),
Is.EqualTo(0f).Within(0.0001f));
Assert.That(
particle.DistanceToVisualBounds(
new Vector2(bounds.max.x, bounds.center.y)),
@@ -414,52 +417,6 @@ namespace AibisDream.EditorTests.Huoshan
}
}
[Test]
public void Params_ContainsEnglishWordPoolAndPendingPoolsForOtherLocales()
{
StringTableCollection collection =
LocalizationEditorSettings.GetStringTableCollection(ConstRef.ParamsTable);
Assert.That(collection, Is.Not.Null);
string key =
LocalizationKit.GetL10NParamKey(ConstRef.ExpressParticlePoolParam);
Assert.That(collection.SharedData.GetEntry(key), Is.Not.Null);
string[] localeCodes = { "zh-Hans", "en", "ja-JP", "es", "ru", "pt-BR" };
foreach (string localeCode in localeCodes)
{
StringTable table =
collection.GetTable(new LocaleIdentifier(localeCode)) as StringTable;
Assert.That(table, Is.Not.Null, localeCode);
Assert.That(table.GetEntry(key), Is.Not.Null, localeCode);
}
StringTable chinese =
collection.GetTable(new LocaleIdentifier("zh-Hans")) as StringTable;
Assert.That(
ExpressionTextTokenizer.GetVisibleElements(
chinese.GetEntry(key).LocalizedValue),
Is.Not.Empty);
StringTable english =
collection.GetTable(new LocaleIdentifier("en")) as StringTable;
Assert.That(
LanguageYarnCommand.TryParseExpressionPool(
english.GetEntry(key).LocalizedValue,
ExpressionParticleUnitMode.Word,
out List<string> englishPool),
Is.True);
Assert.That(englishPool, Does.Contain("truth"));
Assert.That(englishPool, Does.Contain("believe"));
foreach (string localeCode in localeCodes.Skip(2))
{
StringTable table =
collection.GetTable(new LocaleIdentifier(localeCode)) as StringTable;
Assert.That(table.GetEntry(key).LocalizedValue, Is.Empty, localeCode);
}
}
[Test]
public void TextParticle_UsesConfiguredRoleAndOverridePoolsWithoutFirstFrameFallback()
{
@@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Reflection;
using AibisDream.MiniGame.Language;
using NUnit.Framework;
using UnityEngine;
@@ -105,22 +104,6 @@ namespace AibisDream.EditorTests.Huoshan
Assert.That(lastCompletion, Is.EqualTo(totalDuration).Within(0.0001f));
}
[TestCase("LightPreset", 0.10f)]
[TestCase("MediumPreset", 0.20f)]
[TestCase("HeavyPreset", 0.35f)]
public void PresentationPreset_UsesApprovedValues(
string presetFieldName,
float baseDistortion)
{
const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
FieldInfo presetField = typeof(LogReleasePresentationController).GetField(presetFieldName, flags);
Assert.That(presetField, Is.Not.Null);
object preset = presetField.GetValue(null);
Type presetType = preset.GetType();
AssertPresetField(presetType, preset, "BaseDistortion", baseDistortion);
}
[Test]
public void TmpClipRect_ConvertsWorldCornersIntoTextLocalSpace()
{
@@ -205,12 +188,5 @@ namespace AibisDream.EditorTests.Huoshan
UnityEngine.Object.DestroyImmediate(host);
}
}
private static void AssertPresetField(Type presetType, object preset, string name, float expected)
{
FieldInfo field = presetType.GetField(name, BindingFlags.Instance | BindingFlags.Public);
Assert.That(field, Is.Not.Null);
Assert.That((float)field.GetValue(preset), Is.EqualTo(expected).Within(0.0001f));
}
}
}
@@ -1,44 +0,0 @@
using AibisDream.Utility;
using NUnit.Framework;
using Yarn.Unity;
namespace AibisDream.SystemEditor.Tests
{
public sealed class OptionPromptMetadataTests
{
[Test]
public void IsOptionPromptLine_WithExactMetadata_ReturnsTrue()
{
var line = new LocalizedLine
{
Metadata = new[] { "line:0123456", YarnUtil.OptionPrompt }
};
Assert.That(line.IsOptionPromptLine(), Is.True);
}
[TestCase("option_prompts")]
[TestCase("dream_option_prompt")]
[TestCase("OPTION_PROMPT")]
public void IsOptionPromptLine_WithSimilarMetadata_ReturnsFalse(string metadata)
{
var line = new LocalizedLine
{
Metadata = new[] { metadata }
};
Assert.That(line.IsOptionPromptLine(), Is.False);
}
[Test]
public void IsOptionPromptLine_WithoutMetadata_ReturnsFalse()
{
var line = new LocalizedLine
{
Metadata = null
};
Assert.That(line.IsOptionPromptLine(), Is.False);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d5e819fca9154e979c37ac490184620b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -10,7 +10,7 @@ using Yarn.Unity;
namespace AibisDream.SystemEditor.Tests
{
public sealed class AutoNextMetadataTests
public sealed class YarnLineMetadataTests
{
[Test]
public void AutoNextWithoutParameter_UsesExistingFixedDelay()
@@ -81,7 +81,7 @@ namespace AibisDream.SystemEditor.Tests
[TestCase("auto_next_extra:4.5")]
[TestCase("AUTO_NEXT")]
[TestCase("AUTO_NEXT:4.5")]
public void SimilarMetadata_IsNotRecognized(string metadata)
public void SimilarAutoNextMetadata_IsNotRecognized(string metadata)
{
var line = CreateLine(metadata);
@@ -90,7 +90,7 @@ namespace AibisDream.SystemEditor.Tests
}
[Test]
public void ParameterizedTag_TakesPrecedenceOverPlainTag()
public void ParameterizedAutoNextTag_TakesPrecedenceOverPlainTag()
{
var lineInfo = LineInfo.Generate(CreateLine("auto_next", "auto_next:2.5"));
@@ -100,7 +100,7 @@ namespace AibisDream.SystemEditor.Tests
}
[Test]
public void MultipleParameterizedTags_UseFirstAndWarn()
public void MultipleParameterizedAutoNextTags_UseFirstAndWarn()
{
LogAssert.Expect(LogType.Warning, new Regex("存在多个 auto_next 参数标签"));
@@ -110,11 +110,46 @@ namespace AibisDream.SystemEditor.Tests
Assert.That(lineInfo.CalcAutoNextDelayTime(), Is.EqualTo(2500));
}
[Test]
public void IsOptionPromptLine_WithExactMetadata_ReturnsTrue()
{
var line = new LocalizedLine
{
Metadata = new[] { "line:0123456", YarnUtil.OptionPrompt }
};
Assert.That(line.IsOptionPromptLine(), Is.True);
}
[TestCase("option_prompts")]
[TestCase("dream_option_prompt")]
[TestCase("OPTION_PROMPT")]
public void IsOptionPromptLine_WithSimilarMetadata_ReturnsFalse(string metadata)
{
var line = new LocalizedLine
{
Metadata = new[] { metadata }
};
Assert.That(line.IsOptionPromptLine(), Is.False);
}
[Test]
public void IsOptionPromptLine_WithoutMetadata_ReturnsFalse()
{
var line = new LocalizedLine
{
Metadata = null
};
Assert.That(line.IsOptionPromptLine(), Is.False);
}
private static LocalizedLine CreateLine(params string[] metadata)
{
return new LocalizedLine
{
TextID = "line:auto-next-test",
TextID = "line:yarn-metadata-test",
Metadata = metadata,
Text = new MarkupParseResult("Test line", new List<MarkupAttribute>())
};
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d476e493adf4855468ce46409dae6661
guid: a9b456d04f99d9849a0200e688ddfb39
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -223,6 +223,24 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
Assert.That(handle.WaitAsync().Result.RequestId, Is.EqualTo(42));
}
[Test]
public void SessionSnapshotAndSeek_UseTheRuntimeEvaluator()
{
var clip = CreateClip("Clip", FrameClipEndBehavior.HoldLastFrame, 2f, 100, 200, 300);
var graph = CreateGraph("Graph", new[] { clip }, Array.Empty<AnimationNode>(),
Array.Empty<AnimationEdge>(), Array.Empty<AnimationFlow>(), clip.Id);
Assert.That(FrameAnimationResolver.TryResolve(graph, clip.Id, default, out var plan, out _), Is.True);
var session = new FrameAnimationPlaybackSession(plan);
session.Start(_ => { });
session.Seek(0.075d, _ => { });
Assert.That(session.Snapshot.StepIndex, Is.EqualTo(0));
Assert.That(session.Snapshot.FrameIndex, Is.EqualTo(1));
Assert.That(session.Snapshot.FrameElapsedSeconds, Is.EqualTo(0.05d).Within(0.000001d));
Assert.That(session.Snapshot.StepSpeed, Is.EqualTo(2f));
}
private FrameClip CreateClip(
string id,
FrameClipEndBehavior endBehavior,
@@ -178,13 +178,15 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
}
[Test]
public void FlowFocusPolicy_ExitsOnlyWhenSelectionLeavesFocusedFlowContext()
public void FlowFocusPolicy_ExitsForOutOfContextSelectionAndExpandsWithTopology()
{
var entry = AddNode("entry");
var reachable = AddNode("reachable");
var inside = AddNode("inside");
var outside = AddNode("outside");
var edge = new AnimationEdge(entry.InternalId, reachable.InternalId, "focused-edge");
graph.AddEdge(edge);
graph.AddEdge(new AnimationEdge(reachable.InternalId, inside.InternalId));
var flow = new AnimationFlow("FocusFlow", "Focus Flow", entry.InternalId);
graph.AddFlow(flow);
@@ -198,26 +200,6 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
graph, flow.Id, Select(FrameAnimationEditorSelectionKind.Node, outside)), Is.True);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelection(
graph, flow.Id, Select(FrameAnimationEditorSelectionKind.Graph, graph)), Is.True);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelection(
graph, flow.Id, Select(FrameAnimationEditorSelectionKind.Clip, clip)), Is.True);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelection(
graph, flow.Id, Select(FrameAnimationEditorSelectionKind.Source, null)), Is.True);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelection(
graph, flow.Id, Select(FrameAnimationEditorSelectionKind.Flow, flow)), Is.False);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelection(
graph, flow.Id, default), Is.False);
}
[Test]
public void FlowFocusPolicy_MixedSelectionExits_AndTopologyExpansionBecomesReachable()
{
var entry = AddNode("entry");
var inside = AddNode("inside");
var outside = AddNode("outside");
graph.AddEdge(new AnimationEdge(entry.InternalId, inside.InternalId));
var flow = new AnimationFlow("FocusFlow", "Focus Flow", entry.InternalId);
graph.AddFlow(flow);
Assert.That(FrameAnimationFlowFocusPolicy.ShouldExitForSelectionSet(graph, flow.Id, new[]
{
Select(FrameAnimationEditorSelectionKind.Node, entry),
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Linq;
using System.Text;
@@ -53,20 +53,15 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
objectDocument.Frames.Select(frame => frame.FrameName),
arrayDocument.Frames.Select(frame => frame.FrameName));
CollectionAssert.AreEqual(new[] { "待机", "眨眼" }, objectDocument.Tags.Select(tag => tag.Name));
}
[Test]
public void Parser_TrimsTagNameWhitespace()
{
var json = "{" +
"\"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}}}," +
"\"meta\":{\"image\":\"Atlas.png\",\"size\":{\"w\":2,\"h\":2},\"frameTags\":[" +
"{\"name\":\" 待机 \",\"from\":0,\"to\":0,\"direction\":\"forward\"}]}}";
Assert.That(AsepriteJsonParser.TryParse(json, "source", out var document, out var issue),
Is.True, issue?.Message);
Assert.That(document.Tags.Single().Name, Is.EqualTo("待机"));
var trimJson = "{" +
"\"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}}}," +
"\"meta\":{\"image\":\"Atlas.png\",\"size\":{\"w\":2,\"h\":2},\"frameTags\":[" +
"{\"name\":\" 待机 \",\"from\":0,\"to\":0,\"direction\":\"forward\"}]}}";
Assert.That(AsepriteJsonParser.TryParse(trimJson, "source", out var trimDocument, out var trimIssue),
Is.True, trimIssue?.Message);
Assert.That(trimDocument.Tags.Single().Name, Is.EqualTo("待机"));
}
[Test]
@@ -237,11 +232,12 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
}
[Test]
public void ReadOnlyPreview_MatchesExistingSpritesWithoutChangingImporter()
public void ReadOnlyPreview_PreservesImporterAndMapsSharedSprites()
{
var writableGraph = CreateWritableGraph(ObjectJson());
var writablePreview = FrameAnimationImportService.PreviewAll(writableGraph);
Assert.That(FrameAnimationImportService.Apply(writablePreview, true, out var applyError), Is.True, applyError);
Assert.That(FrameAnimationImportService.Apply(writablePreview, true, out var objectApplyError),
Is.True, objectApplyError);
var importer = (TextureImporter)AssetImporter.GetAtPath(TexturePath);
var before = EditorJsonUtility.ToJson(importer);
@@ -254,44 +250,35 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
AssetDatabase.CreateAsset(readOnlyGraph, TestRoot + "/ReadOnlyGraph.asset");
AssetDatabase.SaveAssets();
var preview = FrameAnimationImportService.PreviewAll(readOnlyGraph);
Assert.That(preview.HasErrors, Is.False, JoinIssues(preview));
Assert.That(preview.HasSpriteChanges, Is.False);
var objectPreview = FrameAnimationImportService.PreviewAll(readOnlyGraph);
Assert.That(objectPreview.HasErrors, Is.False, JoinIssues(objectPreview));
Assert.That(objectPreview.HasSpriteChanges, Is.False);
Assert.That(EditorJsonUtility.ToJson(importer), Is.EqualTo(before));
}
[Test]
public void ReadOnlyRefresh_MapsSharedSourceFramesToOneExistingSprite()
{
var writableGraph = CreateWritableGraph(SharedRectJson());
var writablePreview = FrameAnimationImportService.PreviewAll(writableGraph);
Assert.That(FrameAnimationImportService.Apply(writablePreview, true, out var applyError),
Is.True, applyError);
var importer = (TextureImporter)AssetImporter.GetAtPath(TexturePath);
var before = EditorJsonUtility.ToJson(importer);
var sharedWritableGraph = CreateWritableGraph(SharedRectJson(), TestRoot + "/SharedImportGraph.asset");
var sharedPreview = FrameAnimationImportService.PreviewAll(sharedWritableGraph);
Assert.That(FrameAnimationImportService.Apply(sharedPreview, true, out var sharedApplyError),
Is.True, sharedApplyError);
before = EditorJsonUtility.ToJson(importer);
var readOnlyGraph = ScriptableObject.CreateInstance<FrameAnimationGraph>();
readOnlyGraph.Configure("ReadOnlyShared", "Read Only Shared", Array.Empty<FrameClip>(),
var readOnlySharedGraph = ScriptableObject.CreateInstance<FrameAnimationGraph>();
readOnlySharedGraph.Configure("ReadOnlyShared", "Read Only Shared", Array.Empty<FrameClip>(),
Array.Empty<AnimationNode>(), Array.Empty<AnimationEdge>(), Array.Empty<AnimationFlow>(), string.Empty);
readOnlyGraph.AddImportSource(new FrameAnimationImportSource(
readOnlySharedGraph.AddImportSource(new FrameAnimationImportSource(
"Read Only Shared", AssetDatabase.LoadAssetAtPath<Texture2D>(TexturePath),
AssetDatabase.LoadAssetAtPath<TextAsset>(JsonPath), new Vector2(0.5f, 0.5f), false));
AssetDatabase.CreateAsset(readOnlyGraph, TestRoot + "/ReadOnlySharedGraph.asset");
AssetDatabase.CreateAsset(readOnlySharedGraph, TestRoot + "/ReadOnlySharedGraph.asset");
AssetDatabase.SaveAssets();
var preview = FrameAnimationImportService.PreviewAll(readOnlyGraph);
Assert.That(preview.HasErrors, Is.False, JoinIssues(preview));
Assert.That(preview.HasSpriteChanges, Is.False);
Assert.That(preview.Sources.Single().SpritePlan.ReadOnlySpritesBySourceIndex[0],
Is.SameAs(preview.Sources.Single().SpritePlan.ReadOnlySpritesBySourceIndex[1]));
Assert.That(FrameAnimationImportService.Apply(preview, false, out var error), Is.True, error);
var clip = readOnlyGraph.Clips.Single(item => item.ImportInfo.SourceTagName == "Shared");
var sharedReadOnlyPreview = FrameAnimationImportService.PreviewAll(readOnlySharedGraph);
Assert.That(sharedReadOnlyPreview.HasErrors, Is.False, JoinIssues(sharedReadOnlyPreview));
Assert.That(sharedReadOnlyPreview.HasSpriteChanges, Is.False);
Assert.That(sharedReadOnlyPreview.Sources.Single().SpritePlan.ReadOnlySpritesBySourceIndex[0],
Is.SameAs(sharedReadOnlyPreview.Sources.Single().SpritePlan.ReadOnlySpritesBySourceIndex[1]));
Assert.That(FrameAnimationImportService.Apply(sharedReadOnlyPreview, false, out var error), Is.True, error);
var clip = readOnlySharedGraph.Clips.Single(item => item.ImportInfo.SourceTagName == "Shared");
Assert.That(clip.Frames[0].Sprite, Is.SameAs(clip.Frames[1].Sprite));
Assert.That(EditorJsonUtility.ToJson(importer), Is.EqualTo(before));
var secondPreview = FrameAnimationImportService.PreviewAll(readOnlyGraph);
Assert.That(secondPreview.Sources.Single().ClipDiffs.All(diff =>
diff.Kind == FrameAnimationImportChangeKind.Unchanged), Is.True);
}
[Test]
@@ -337,7 +324,7 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
Assert.That(graph.Clips, Is.Empty);
}
private FrameAnimationGraph CreateWritableGraph(string json)
private FrameAnimationGraph CreateWritableGraph(string json, string graphAssetPath = null)
{
CreateTexture();
WriteJson(json);
@@ -350,7 +337,7 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
AssetDatabase.LoadAssetAtPath<TextAsset>(JsonPath),
new Vector2(0.5f, 0.5f),
true));
AssetDatabase.CreateAsset(graph, GraphPath);
AssetDatabase.CreateAsset(graph, graphAssetPath ?? GraphPath);
AssetDatabase.SaveAssets();
return graph;
}
@@ -5,7 +5,6 @@ using System.Reflection;
using AibisDream.FrameAnimation.Editor;
using NUnit.Framework;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
@@ -25,24 +24,6 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
objects.Clear();
}
[Test]
public void SessionSnapshotAndSeek_UseTheRuntimeEvaluator()
{
var clip = Clip("Clip", 2f, FrameClipEndBehavior.HoldLastFrame, 100, 200, 300);
var graph = Graph(new[] { clip }, Array.Empty<AnimationNode>(), Array.Empty<AnimationEdge>(),
Array.Empty<AnimationFlow>());
Assert.That(FrameAnimationResolver.TryResolve(graph, clip.Id, default, out var plan, out _), Is.True);
var session = new FrameAnimationPlaybackSession(plan);
session.Start(_ => { });
session.Seek(0.075d, _ => { });
Assert.That(session.Snapshot.StepIndex, Is.EqualTo(0));
Assert.That(session.Snapshot.FrameIndex, Is.EqualTo(1));
Assert.That(session.Snapshot.FrameElapsedSeconds, Is.EqualTo(0.05d).Within(0.000001d));
Assert.That(session.Snapshot.StepSpeed, Is.EqualTo(2f));
}
[Test]
public void NodeResolver_AppliesNodeOverridesWithoutChangingClip()
{
@@ -194,34 +175,7 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
}
[Test]
public void GraphView_FocusedFlowUsesItsColorAndShowAllKeepsNeutralEdges()
{
var clip = Clip("Clip", 1f, FrameClipEndBehavior.HoldLastFrame, 100);
var first = new AnimationNode(clip.Id, internalId: "first");
var second = new AnimationNode(clip.Id, internalId: "second");
var edge = new AnimationEdge(first.InternalId, second.InternalId, internalId: "edge");
var flow = new AnimationFlow("Flow", "Flow", first.InternalId);
var graph = Graph(new[] { clip }, new[] { first, second }, new[] { edge }, new[] { flow });
var stored = new Color(0.12f, 0.72f, 0.38f, 0.15f);
graph.EditorData.GetOrCreateFlowData(flow.Id, stored);
var palette = FrameAnimationFlowColorUtility.CreatePalette(stored);
var view = new FrameAnimationGraphView();
view.Bind(graph, Array.Empty<FrameAnimationEditorIssue>(), string.Empty);
var edgeView = view.Query<FrameAnimationEdgeView>().First();
Assert.That(edgeView.edgeControl.inputColor.r, Is.EqualTo(119f / 255f).Within(0.001f));
Assert.That(view.Query<Label>(className: "fa-flow-badge").ToList().Count, Is.EqualTo(2));
view.SetFocusedFlow(flow.Id);
Assert.That(edgeView.edgeControl.inputColor.r, Is.EqualTo(palette.Stroke.r).Within(0.003f));
Assert.That(edgeView.edgeControl.inputColor.g, Is.EqualTo(palette.Stroke.g).Within(0.003f));
Assert.That(view.Query<FrameAnimationClipNodeView>(className: "fa-node--focused").ToList().Count,
Is.EqualTo(2));
}
[Test]
public void GraphView_SharedPathSwitchesToNewFocusedFlowColor()
public void GraphView_FocusFlowColorSwitchAndValidationOverride()
{
var clip = Clip("Clip", 1f, FrameClipEndBehavior.HoldLastFrame, 100);
var first = new AnimationNode(clip.Id, internalId: "first");
@@ -239,29 +193,16 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
view.SetFocusedFlow(blueFlow.Id);
var blue = edgeView.edgeControl.inputColor;
Assert.That(red.r, Is.GreaterThan(red.b));
Assert.That(blue.b, Is.GreaterThan(blue.r));
}
Assert.That(view.Query<FrameAnimationClipNodeView>(className: "fa-node--focused").ToList().Count,
Is.EqualTo(2));
[Test]
public void GraphView_EdgeValidationColorOverridesFlowAndPreviewColor()
{
var clip = Clip("Clip", 1f, FrameClipEndBehavior.HoldLastFrame, 100);
var first = new AnimationNode(clip.Id, internalId: "first");
var second = new AnimationNode(clip.Id, internalId: "second");
var edge = new AnimationEdge(first.InternalId, second.InternalId, internalId: "edge");
var flow = new AnimationFlow("Flow", "Flow", first.InternalId);
var graph = Graph(new[] { clip }, new[] { first, second }, new[] { edge }, new[] { flow });
graph.EditorData.GetOrCreateFlowData(flow.Id, Color.green);
var issue = new FrameAnimationEditorIssue(FrameAnimationValidationSeverity.Error, "BrokenEdge",
new FrameAnimationEditorSelection(FrameAnimationEditorSelectionKind.Edge, edge), "Broken", string.Empty);
var view = new FrameAnimationGraphView();
view.Bind(graph, new[] { issue }, flow.Id);
var edgeView = view.Query<FrameAnimationEdgeView>().First();
view.Bind(graph, new[] { issue }, redFlow.Id);
edgeView = view.Query<FrameAnimationEdgeView>().First();
edgeView.SetPreviewState(FrameAnimationFlowElementState.Current);
Assert.That(edgeView.edgeControl.inputColor.r, Is.EqualTo(223f / 255f).Within(0.003f));
Assert.That(edgeView.edgeControl.inputColor.g, Is.EqualTo(106f / 255f).Within(0.003f));
}
@@ -296,76 +237,20 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
typeof(FrameAnimationGraphEditorWindow).GetMethod("CreateGUI",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window, null);
Assert.That(window.rootVisualElement.Q<VisualElement>("fa-workbench"), Is.Not.Null);
Assert.That(window.rootVisualElement.Query<FrameAnimationPreviewElement>().ToList().Count,
Is.GreaterThanOrEqualTo(1));
Assert.That(window.rootVisualElement.Query<Slider>().ToList().Count,
Is.GreaterThanOrEqualTo(2));
Assert.That(window.rootVisualElement.Q<Button>("graph-properties-button"), Is.Not.Null);
Assert.That(window.rootVisualElement.Q<Button>("graph-breadcrumb-button"), Is.Not.Null);
Assert.That(window.rootVisualElement.Q<VisualElement>("canvas-toolbar").Query<Slider>().ToList(),
Is.Empty);
Assert.That(window.rootVisualElement.Query<IMGUIContainer>().ToList(), Is.Empty);
Assert.That(window.rootVisualElement.Q<VisualElement>("fa-workbench"), Is.Not.Null);
var clipsTab = window.rootVisualElement.Q<Button>("resource-tab-clips");
typeof(FrameAnimationGraphEditorWindow).GetMethod("SetResourceTab",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window,
new[] { clipsTab.userData, (object)false });
Assert.That(clipsTab.ClassListContains("fa-tab--active"), Is.True);
var importDiffTab = window.rootVisualElement.Q<Button>("bottom-tab-import-diff");
typeof(FrameAnimationGraphEditorWindow).GetMethod("SetBottomTab",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window,
new[] { importDiffTab.userData });
Assert.That(importDiffTab.ClassListContains("fa-tab--active"), Is.True);
var transport = window.rootVisualElement.Q<Toolbar>("preview-transport");
Assert.That(transport, Is.Not.Null);
Assert.That(transport.Q<Button>("preview-restart"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-previous-frame"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-play-pause"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-next-frame"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-stop"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-stop").Q<Image>().image, Is.Not.Null);
Assert.That(transport.Q<Slider>("preview-timeline"), Is.Not.Null);
Assert.That(transport.Q<Label>("preview-time"), Is.Not.Null);
Assert.That(transport.Q<Button>("preview-play-pause").enabledSelf, Is.False);
var flowsTab = window.rootVisualElement.Q<Button>("resource-tab-flows");
typeof(FrameAnimationGraphEditorWindow).GetMethod("SetResourceTab",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window,
new[] { flowsTab.userData, (object)true });
Assert.That(flowsTab.ClassListContains("fa-tab--active"), Is.True);
Assert.That(window.rootVisualElement.Q<Button>("resource-tab-clips")
.ClassListContains("fa-tab--active"), Is.False);
var validationTab = window.rootVisualElement.Q<Button>("bottom-tab-validation");
typeof(FrameAnimationGraphEditorWindow).GetMethod("SetBottomTab",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window,
new[] { validationTab.userData });
Assert.That(validationTab.ClassListContains("fa-tab--active"), Is.True);
Assert.That(window.rootVisualElement.Q<Button>("bottom-tab-import-diff")
.ClassListContains("fa-tab--active"), Is.False);
var clip = sample.Clips.First(item => item != null);
var setSelection = typeof(FrameAnimationGraphEditorWindow).GetMethod("SetSelection",
BindingFlags.Instance | BindingFlags.NonPublic);
var clip = sample.Clips.First(item => item != null);
setSelection?.Invoke(window, new object[]
{
new FrameAnimationEditorSelection(FrameAnimationEditorSelectionKind.Clip, clip),
false
});
AssertSelectionPreview(window, "Clip Preview");
var playButton = transport.Q<Button>("preview-play-pause");
Assert.That(playButton.enabledSelf, Is.True);
Assert.That(playButton.text, Is.Empty);
Assert.That(playButton.tooltip, Is.EqualTo("Play"));
Assert.That(playButton.Q<Image>(), Is.Not.Null);
Assert.That(playButton.Q<Image>().image, Is.Not.Null);
typeof(FrameAnimationGraphEditorWindow).GetMethod("PreviewPlayPause",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window, null);
Assert.That(playButton.text, Is.Empty);
Assert.That(playButton.tooltip, Is.EqualTo("Pause"));
Assert.That(playButton.Q<Image>().image, Is.Not.Null);
var node = sample.Nodes.First(item => item != null);
setSelection?.Invoke(window, new object[]
@@ -382,13 +267,6 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
false
});
AssertSelectionPreview(window, "Flow Preview");
typeof(FrameAnimationGraphEditorWindow).GetMethod("SelectGraphProperties",
BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(window, null);
var selected = (FrameAnimationEditorSelection)typeof(FrameAnimationGraphEditorWindow)
.GetField("selection", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(window);
Assert.That(selected.Kind, Is.EqualTo(FrameAnimationEditorSelectionKind.Graph));
Assert.That(selected.Value, Is.SameAs(sample));
}
finally
{
@@ -88,44 +88,6 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
Assert.That(player.CurrentClip, Is.SameAs(temporary));
}
[Test]
public void FrameClipPlayer_RestoreTerminalStateAppliesLastFrame()
{
var first = CreateSprite(Color.red);
var last = CreateSprite(Color.green);
var clip = CreateClip("RestoreStandalone", FrameClipEndBehavior.HoldLastFrame, first, last);
var gameObject = Track(new GameObject("Restore Standalone"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameClipPlayer>();
player.ConfigureForAuthoring(clip, false, 1f);
var handle = player.RestoreTerminalState();
Assert.That(handle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(renderer.sprite, Is.SameAs(last));
}
[Test]
public void FrameClipPlayer_ImageLoopWaitsForFirstPassAndKeepsPlaying()
{
var first = CreateSprite(Color.yellow);
var second = CreateSprite(Color.black);
var clip = CreateClip("StandaloneLoop", FrameClipEndBehavior.Loop, first, second);
var gameObject = Track(new GameObject("Standalone Image", typeof(RectTransform), typeof(CanvasRenderer)));
var image = gameObject.AddComponent<Image>();
var player = gameObject.AddComponent<FrameClipPlayer>();
player.ConfigureForAuthoring(clip, false, 1f);
var handle = player.Play();
var wait = player.WaitForFirstPass(handle);
player.EvaluateForTests(0.2d);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.IsCompleted, Is.False);
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Playing));
Assert.That(image.sprite, Is.SameAs(first));
}
[Test]
public void GraphAndClipPlayersOnSameObjectReturnConflict()
{
@@ -175,10 +137,20 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
player.ConfigureForAuthoring(graph, false, 1f);
var active = player.Play(clip.Id);
var failed = player.Play("Missing");
var failedPlay = player.Play("Missing");
var failedRestore = player.RestoreTerminalState("Missing");
var failedHandle = player.Play("Missing");
var failedWait = player.WaitForFirstPass(failedHandle);
Assert.That(failed.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Failed));
Assert.That(failed.Result.Error.Code, Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
Assert.That(failedPlay.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Failed));
Assert.That(
failedPlay.Result.Error.Code,
Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
Assert.That(failedRestore.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Failed));
Assert.That(
failedRestore.Result.Error.Code,
Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
Assert.That(failedWait.keepWaiting, Is.False);
Assert.That(active.IsCompleted, Is.False);
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Playing));
Assert.That(player.CurrentPlayableId, Is.EqualTo(clip.Id));
@@ -221,12 +193,20 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
var gameObject = Track(new GameObject("Wait Direct Loop"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
player.ConfigureForAuthoring(graph, false, 0f);
var handle = player.Play(clip.Id);
var wait = player.WaitForFirstPass(handle);
player.EvaluateForTests(1d);
Assert.That(wait.keepWaiting, Is.True);
player.SetSpeed(1f);
player.Pause();
player.EvaluateForTests(1d);
Assert.That(wait.keepWaiting, Is.True);
player.Resume();
player.EvaluateForTests(0.1d);
Assert.That(wait.keepWaiting, Is.True);
@@ -277,7 +257,7 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
Assert.That(player.CurrentClipId, Is.EqualTo(loopClip.Id));
Assert.That(wait.keepWaiting, Is.True);
player.EvaluateForTests(0.2d);
player.EvaluateForTests(1.35d);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.IsCompleted, Is.False);
@@ -286,148 +266,6 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
Assert.That(renderer.sprite, Is.SameAs(loopFirst));
}
[Test]
public void WaitForFirstPass_LargeDeltaCrossesIntroAndTerminalLoopCycle()
{
var introClip = CreateClip(
"Intro",
FrameClipEndBehavior.HoldLastFrame,
CreateSprite(Color.red));
var loopClip = CreateClip(
"Loop",
FrameClipEndBehavior.Loop,
CreateSprite(Color.green),
CreateSprite(Color.blue));
var introNode = new AnimationNode(introClip.Id);
var loopNode = new AnimationNode(loopClip.Id);
var graph = Track(ScriptableObject.CreateInstance<FrameAnimationGraph>());
graph.Configure(
"Graph",
"Graph",
new[] { introClip, loopClip },
new[] { introNode, loopNode },
new[] { new AnimationEdge(introNode.InternalId, loopNode.InternalId) },
new[] { new AnimationFlow("Flow", "Flow", introNode.InternalId) },
"Flow");
var gameObject = Track(new GameObject("Wait Large Delta"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.Play("Flow");
var wait = player.WaitForFirstPass(handle);
player.EvaluateForTests(1.35d);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.IsCompleted, Is.False);
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Playing));
}
[Test]
public void WaitForFirstPass_NonLoopMirrorsNaturalCompletion()
{
var clip = CreateClip(
"Once",
FrameClipEndBehavior.HoldLastFrame,
CreateSprite(Color.red),
CreateSprite(Color.blue));
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Wait Once"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.Play(clip.Id);
var wait = player.WaitForFirstPass(handle);
player.EvaluateForTests(0.2d);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Stopped));
}
[Test]
public void WaitForFirstPass_ReleasesWhenRequestIsReplacedOrStopped()
{
var first = CreateClip("First", FrameClipEndBehavior.Loop, CreateSprite(Color.red));
var second = CreateClip("Second", FrameClipEndBehavior.Loop, CreateSprite(Color.blue));
var graph = Track(ScriptableObject.CreateInstance<FrameAnimationGraph>());
graph.Configure(
"Graph",
"Graph",
new[] { first, second },
Array.Empty<AnimationNode>(),
Array.Empty<AnimationEdge>(),
Array.Empty<AnimationFlow>(),
first.Id);
var gameObject = Track(new GameObject("Wait Termination"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var replacedHandle = player.Play(first.Id);
var replacedWait = player.WaitForFirstPass(replacedHandle);
var stoppedHandle = player.Play(second.Id);
var stoppedWait = player.WaitForFirstPass(stoppedHandle);
Assert.That(replacedWait.keepWaiting, Is.False);
Assert.That(replacedHandle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Replaced));
Assert.That(stoppedWait.keepWaiting, Is.True);
player.Stop();
Assert.That(stoppedWait.keepWaiting, Is.False);
Assert.That(stoppedHandle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Stopped));
}
[Test]
public void WaitForFirstPass_PauseAndZeroSpeedDoNotReleaseEarly()
{
var clip = CreateClip(
"Loop",
FrameClipEndBehavior.Loop,
CreateSprite(Color.red),
CreateSprite(Color.blue));
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Wait Paused"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 0f);
var handle = player.Play(clip.Id);
var wait = player.WaitForFirstPass(handle);
player.EvaluateForTests(1d);
Assert.That(wait.keepWaiting, Is.True);
player.SetSpeed(1f);
player.Pause();
player.EvaluateForTests(1d);
Assert.That(wait.keepWaiting, Is.True);
player.Resume();
player.EvaluateForTests(0.2d);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.IsCompleted, Is.False);
}
[Test]
public void WaitForFirstPass_FailedRequestDoesNotWait()
{
var clip = CreateClip("Loop", FrameClipEndBehavior.Loop, CreateSprite(Color.white));
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Wait Failed"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.Play("Missing");
var wait = player.WaitForFirstPass(handle);
Assert.That(wait.keepWaiting, Is.False);
Assert.That(handle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Failed));
Assert.That(handle.Result.Error.Code, Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
}
[Test]
public void FailedTargetProbeDoesNotDiscardCurrentTargetOrRequest()
{
@@ -550,29 +388,15 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
}
[Test]
public void RestoreTerminalState_HoldLastFrameAppliesLastFrameImmediately()
{
var first = CreateSprite(Color.red);
var last = CreateSprite(Color.blue);
var clip = CreateClip("Terminal", FrameClipEndBehavior.HoldLastFrame, first, last);
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Restore Terminal"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.RestoreTerminalState(clip.Id);
Assert.That(handle.IsCompleted, Is.True);
Assert.That(handle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Stopped));
Assert.That(renderer.sprite, Is.SameAs(last));
Assert.That(renderer.enabled, Is.True);
}
[Test]
public void RestoreTerminalState_AppliesClearAndHideTargetEndBehaviors()
public void RestoreTerminalState_AppliesTargetEndBehaviors()
{
var holdFirst = CreateSprite(Color.red);
var holdLast = CreateSprite(Color.blue);
var holdClip = CreateClip(
"Hold",
FrameClipEndBehavior.HoldLastFrame,
holdFirst,
holdLast);
var clearClip = CreateClip(
"Clear",
FrameClipEndBehavior.Clear,
@@ -581,69 +405,47 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
"Hide",
FrameClipEndBehavior.HideTarget,
CreateSprite(Color.blue));
var loopFirst = CreateSprite(Color.green);
var loopSecond = CreateSprite(Color.yellow);
var loopClip = CreateClip(
"Loop",
FrameClipEndBehavior.Loop,
loopFirst,
loopSecond);
var graph = Track(ScriptableObject.CreateInstance<FrameAnimationGraph>());
graph.Configure(
"Graph",
"Graph",
new[] { clearClip, hideClip },
new[] { holdClip, clearClip, hideClip, loopClip },
Array.Empty<AnimationNode>(),
Array.Empty<AnimationEdge>(),
Array.Empty<AnimationFlow>(),
clearClip.Id);
holdClip.Id);
var gameObject = Track(new GameObject("Restore End Behaviors"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var holdHandle = player.RestoreTerminalState(holdClip.Id);
Assert.That(holdHandle.IsCompleted, Is.True);
Assert.That(holdHandle.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Completed));
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Stopped));
Assert.That(renderer.sprite, Is.SameAs(holdLast));
Assert.That(renderer.enabled, Is.True);
player.RestoreTerminalState(clearClip.Id);
Assert.That(renderer.sprite, Is.Null);
Assert.That(renderer.enabled, Is.True);
player.RestoreTerminalState(hideClip.Id);
Assert.That(renderer.enabled, Is.False);
}
renderer.enabled = true;
[Test]
public void RestoreTerminalState_LoopRestartsFromFirstFrameWithoutCompleting()
{
var first = CreateSprite(Color.red);
var second = CreateSprite(Color.blue);
var clip = CreateClip("Loop", FrameClipEndBehavior.Loop, first, second);
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Restore Loop"));
var renderer = gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var handle = player.RestoreTerminalState(clip.Id);
Assert.That(handle.IsCompleted, Is.False);
var loopHandle = player.RestoreTerminalState(loopClip.Id);
Assert.That(loopHandle.IsCompleted, Is.False);
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Playing));
Assert.That(player.CurrentFrameIndex, Is.EqualTo(0));
Assert.That(renderer.sprite, Is.SameAs(first));
}
[Test]
public void FailedTerminalRestoreDoesNotReplaceActiveRequest()
{
var clip = CreateClip("Loop", FrameClipEndBehavior.Loop, CreateSprite(Color.white));
var graph = CreateDirectGraph(clip);
var gameObject = Track(new GameObject("Failed Restore"));
gameObject.AddComponent<SpriteRenderer>();
var player = gameObject.AddComponent<FrameAnimationPlayer>();
player.ConfigureForAuthoring(graph, false, 1f);
var active = player.Play(clip.Id);
var failed = player.RestoreTerminalState("Missing");
Assert.That(failed.IsCompleted, Is.True);
Assert.That(failed.Result.Reason, Is.EqualTo(FrameAnimationCompletionReason.Failed));
Assert.That(
failed.Result.Error.Code,
Is.EqualTo(FrameAnimationPlaybackErrorCode.PlayableNotFound));
Assert.That(active.IsCompleted, Is.False);
Assert.That(player.State, Is.EqualTo(FrameAnimationPlaybackState.Playing));
Assert.That(player.CurrentPlayableId, Is.EqualTo(clip.Id));
Assert.That(renderer.sprite, Is.SameAs(loopFirst));
}
[Test]
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e93af359c134479a88d141136397693e
guid: 6ab7be47fb2561242a443b00c0089c26
AssemblyDefinitionImporter:
externalObjects: {}
userData:
@@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using UnityEngine;
@@ -12,65 +11,6 @@ namespace AibisDream.Huoshan.Tests.PlayMode
{
private const string RuntimeAssemblyName = "Assembly-CSharp";
[Test]
public void WordMode_TokenizesWholeWordsAtRuntime()
{
Type tokenizerType = RequireRuntimeType(
"AibisDream.MiniGame.Language.ExpressionTextTokenizer");
Type modeType = RequireRuntimeType(
"AibisDream.MiniGame.Language.ExpressionParticleUnitMode");
object wordMode = Enum.Parse(modeType, "Word");
MethodInfo tokenize = tokenizerType.GetMethod(
"TokenizeText",
BindingFlags.Public | BindingFlags.Static);
Assert.That(tokenize, Is.Not.Null);
IEnumerable result = (IEnumerable)tokenize.Invoke(
null,
new[] { "I am not self-doubt", wordMode });
string[] units = result.Cast<object>()
.Select(value => value.ToString())
.ToArray();
Assert.That(
units,
Is.EqualTo(new[] { "I", "am", "not", "self-doubt" }));
}
[UnityTest]
public IEnumerator WordParticle_BoundsIncludesBothPointerEdges()
{
GameObject gameObject = new GameObject("WordParticlePlayModeTest");
try
{
Component particle = gameObject.AddComponent(
RequireRuntimeType(
"AibisDream.MiniGame.Language.CandidateParticle"));
Invoke(particle, "ForceSetUnitText", "self-doubt");
yield return null;
Bounds bounds = (Bounds)Invoke(particle, "GetVisualWorldBounds");
Assert.That(bounds.size.x, Is.GreaterThan(0f));
float leftDistance = (float)Invoke(
particle,
"DistanceToVisualBounds",
new Vector2(bounds.min.x, bounds.center.y));
float rightDistance = (float)Invoke(
particle,
"DistanceToVisualBounds",
new Vector2(bounds.max.x, bounds.center.y));
Assert.That(leftDistance, Is.EqualTo(0f).Within(0.0001f));
Assert.That(rightDistance, Is.EqualTo(0f).Within(0.0001f));
}
finally
{
UnityEngine.Object.Destroy(gameObject);
}
yield return null;
}
[UnityTest]
public IEnumerator LongWords_ConnectThroughVisualEdgeDistance()
{
@@ -86,10 +26,8 @@ namespace AibisDream.Huoshan.Tests.PlayMode
Invoke(second, "ForceSetUnitText", "characteristically");
yield return null;
Bounds firstBounds =
(Bounds)Invoke(first, "GetVisualWorldBounds");
Bounds secondBounds =
(Bounds)Invoke(second, "GetVisualWorldBounds");
Bounds firstBounds = (Bounds)Invoke(first, "GetVisualWorldBounds");
Bounds secondBounds = (Bounds)Invoke(second, "GetVisualWorldBounds");
secondObject.transform.position = new Vector3(
firstBounds.extents.x + secondBounds.extents.x + 0.1f,
0f,