Files
aibis-dream/Assets/Editor/Huoshan/LogReleasePresentationTests.cs
T
2026-07-28 21:34:42 +08:00

217 lines
8.6 KiB
C#

using System;
using System.Collections;
using System.Reflection;
using AibisDream.MiniGame.Language;
using NUnit.Framework;
using UnityEngine;
namespace AibisDream.EditorTests.Huoshan
{
public sealed class LogReleasePresentationTests
{
[Test]
public void LineClip_RejectsOutsideSegment()
{
Bounds bounds = new Bounds(Vector3.zero, new Vector3(2f, 2f, 0f));
bool visible = ConnectionRenderer.TryClipLineToBounds(
new Vector3(-3f, 2f),
new Vector3(3f, 2f),
bounds,
out _,
out _);
Assert.That(visible, Is.False);
}
[TestCase(-0.5f, 0f, 0.5f, 0f, -0.5f, 0f, 0.5f, 0f)]
[TestCase(-2f, 0f, 2f, 0f, -1f, 0f, 1f, 0f)]
[TestCase(0f, -2f, 0f, 0.5f, 0f, -1f, 0f, 0.5f)]
[TestCase(-2f, -2f, 2f, 2f, -1f, -1f, 1f, 1f)]
public void LineClip_ReturnsExpectedInteriorSegment(
float ax,
float ay,
float bx,
float by,
float expectedAx,
float expectedAy,
float expectedBx,
float expectedBy)
{
Bounds bounds = new Bounds(Vector3.zero, new Vector3(2f, 2f, 0f));
bool visible = ConnectionRenderer.TryClipLineToBounds(
new Vector3(ax, ay),
new Vector3(bx, by),
bounds,
out Vector3 clippedA,
out Vector3 clippedB);
Assert.That(visible, Is.True);
Assert.That(clippedA.x, Is.EqualTo(expectedAx).Within(0.0001f));
Assert.That(clippedA.y, Is.EqualTo(expectedAy).Within(0.0001f));
Assert.That(clippedB.x, Is.EqualTo(expectedBx).Within(0.0001f));
Assert.That(clippedB.y, Is.EqualTo(expectedBy).Within(0.0001f));
}
[TestCase(CompletionPhase.None, false)]
[TestCase(CompletionPhase.Completed, false)]
[TestCase(CompletionPhase.Focusing, true)]
[TestCase(CompletionPhase.FocusHolding, true)]
[TestCase(CompletionPhase.Finished, true)]
public void ConnectionClipping_OnlyStartsAfterOutput(
CompletionPhase phase,
bool expected)
{
Assert.That(LanguageParticleManager.ShouldClipConnections(phase), Is.EqualTo(expected));
}
[Test]
public void LieEdgePosition_LandsOnScreenPerimeterAndStaysInside()
{
Bounds bounds = new Bounds(Vector3.zero, new Vector3(6f, 4f, 0f));
const float inset = 0.1f;
for (int i = 0; i < 8; i++)
{
Vector3 position = LanguageParticleManager.CalculateScreenEdgePosition(
bounds,
i,
8,
inset);
Assert.That(position.x, Is.InRange(bounds.min.x, bounds.max.x));
Assert.That(position.y, Is.InRange(bounds.min.y, bounds.max.y));
bool touchesVerticalEdge =
Mathf.Abs(Mathf.Abs(position.x) - (bounds.extents.x - inset)) < 0.0001f;
bool touchesHorizontalEdge =
Mathf.Abs(Mathf.Abs(position.y) - (bounds.extents.y - inset)) < 0.0001f;
Assert.That(touchesVerticalEdge || touchesHorizontalEdge, Is.True);
}
}
[TestCase(6, 0.70f)]
[TestCase(6, 0.90f)]
[TestCase(6, 1.10f)]
public void ResolveTiming_LastCharacterCompletesWithinPreset(int characterCount, float totalDuration)
{
LanguageParticleManager.CalculateResolveTiming(
characterCount,
totalDuration,
3.5f,
0.4f,
out float characterDuration,
out float stagger);
float lastCompletion = characterDuration + stagger * (characterCount - 1);
Assert.That(lastCompletion, Is.LessThanOrEqualTo(totalDuration + 0.0001f));
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()
{
GameObject rectObject = new GameObject("ScreenRect", typeof(RectTransform));
GameObject textObject = new GameObject("TextTransform");
try
{
RectTransform rect = rectObject.GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(4f, 2f);
rect.position = new Vector3(2f, -1f, 0f);
rect.rotation = Quaternion.Euler(0f, 0f, 17f);
rect.localScale = new Vector3(1.2f, 0.8f, 1f);
textObject.transform.position = new Vector3(-0.5f, 0.75f, 0f);
textObject.transform.rotation = Quaternion.Euler(0f, 0f, -11f);
textObject.transform.localScale = new Vector3(1.4f, 0.65f, 1f);
Vector4 actual = TMPRectClipper.CalculateLocalClipRect(textObject.transform, rect);
Vector3[] corners = new Vector3[4];
rect.GetWorldCorners(corners);
Vector3 first = textObject.transform.InverseTransformPoint(corners[0]);
float minX = first.x;
float minY = first.y;
float maxX = first.x;
float maxY = first.y;
for (int i = 1; i < corners.Length; i++)
{
Vector3 local = textObject.transform.InverseTransformPoint(corners[i]);
minX = Mathf.Min(minX, local.x);
minY = Mathf.Min(minY, local.y);
maxX = Mathf.Max(maxX, local.x);
maxY = Mathf.Max(maxY, local.y);
}
Assert.That(actual.x, Is.EqualTo(minX).Within(0.0001f));
Assert.That(actual.y, Is.EqualTo(minY).Within(0.0001f));
Assert.That(actual.z, Is.EqualTo(maxX).Within(0.0001f));
Assert.That(actual.w, Is.EqualTo(maxY).Within(0.0001f));
}
finally
{
UnityEngine.Object.DestroyImmediate(rectObject);
UnityEngine.Object.DestroyImmediate(textObject);
}
}
[TestCase(null, null)]
[TestCase("", null)]
[TestCase(" | ", null)]
[TestCase("没问题|冇", "没问题冇")]
[TestCase("没 问 题", "没问题")]
public void SlotMachinePool_StripsSeparatorsAndWhitespace(string input, string expected)
{
Assert.That(LanguageParticleManager.SanitizeSlotMachinePool(input), Is.EqualTo(expected));
}
[Test]
public void ActorPhraseList_PreservesWordsAndDropsEmptyEntries()
{
string[] phrases = LogReleasePresentationController.ParseActorPhrases(
" 没问题 | | 冇问题|帽问题 ");
Assert.That(phrases, Is.EqualTo(new[] { "没问题", "冇问题", "帽问题" }));
}
[Test]
public void ActorFlash_OutsideMemoryState_CompletesImmediatelyWithoutStateChange()
{
GameObject host = new GameObject("PresentationHost");
try
{
var controller = host.AddComponent<LogReleasePresentationController>();
IEnumerator routine = controller.FlashActorLie("没问题", 0.6f);
Assert.That(routine.MoveNext(), Is.False);
Assert.That(
controller.State,
Is.EqualTo(LogReleasePresentationController.PresentationState.Idle));
}
finally
{
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));
}
}
}