Files
aibis-dream/Assets/Editor/Tests/TypographyContractTests.cs
T

183 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.EditorTools;
using AibisDream.UI;
using NUnit.Framework;
using TMPro;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace AibisDream.SystemEditor.Tests
{
public sealed class TypographyContractTests
{
private const string ProfileFolder = "Assets/GameContent/Common/Typography/Profiles";
[TestCase(LocaleKind.Cn, TypographyProfileKind.ZhHans)]
[TestCase(LocaleKind.Ja, TypographyProfileKind.Japanese)]
[TestCase(LocaleKind.En, TypographyProfileKind.Latin)]
[TestCase(LocaleKind.Es, TypographyProfileKind.Latin)]
[TestCase(LocaleKind.PtBr, TypographyProfileKind.Latin)]
[TestCase(LocaleKind.Ru, TypographyProfileKind.Russian)]
public void LocaleMapping_UsesExpectedProfile(LocaleKind locale, TypographyProfileKind expected)
{
Assert.That(TypographyLocaleMapping.GetProfileKind(locale), Is.EqualTo(expected));
Assert.That(
TypographyLocaleMapping.GetProfileKey(locale),
Is.EqualTo($"Typography/Profile/{expected}"));
}
[Test]
public void Resolve_MissingRoleFallsBackToBody()
{
TMP_FontAsset font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(
"Assets/Font/Assets/ChillBitmap_16px SDF.asset");
var profile = ScriptableObject.CreateInstance<TypographyProfile>();
try
{
var body = new TypographyStyle(TypographyRole.Body, font);
profile.Configure(TypographyProfileKind.Latin, new[] { body });
Assert.That(profile.Resolve(TypographyRole.Dialogue), Is.SameAs(body));
}
finally
{
UnityEngine.Object.DestroyImmediate(profile);
}
}
[Test]
public void Binding_ReapplyUsesCapturedBaselineWithoutAccumulatingMetrics()
{
TMP_FontAsset font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(
"Assets/Font/Assets/ChillBitmap_16px SDF.asset");
var profile = ScriptableObject.CreateInstance<TypographyProfile>();
var go = new GameObject("TypographyMetricContract", typeof(RectTransform));
try
{
TextMeshProUGUI text = go.AddComponent<TextMeshProUGUI>();
text.fontSize = 40f;
text.lineSpacing = 3f;
text.characterSpacing = 2f;
LocalizedTypography binding = go.AddComponent<LocalizedTypography>();
profile.Configure(
TypographyProfileKind.Latin,
new[]
{
new TypographyStyle(
TypographyRole.Body,
font,
fontSizeMultiplier: 0.75f,
lineSpacingOffset: 1f,
characterSpacingOffset: 2f)
});
binding.ApplyProfile(profile);
binding.ApplyProfile(profile);
Assert.That(text.fontSize, Is.EqualTo(30f));
Assert.That(text.lineSpacing, Is.EqualTo(4f));
Assert.That(text.characterSpacing, Is.EqualTo(4f));
}
finally
{
UnityEngine.Object.DestroyImmediate(go);
UnityEngine.Object.DestroyImmediate(profile);
}
}
[Test]
public void FirstRoundProfiles_AreCompleteAndAddressableByConvention()
{
foreach (TypographyProfileKind kind in Enum.GetValues(typeof(TypographyProfileKind)))
{
TypographyProfile profile = AssetDatabase.LoadAssetAtPath<TypographyProfile>(
$"{ProfileFolder}/{kind}.asset");
Assert.That(profile, Is.Not.Null, kind.ToString());
Assert.That(profile.ProfileKind, Is.EqualTo(kind));
Assert.That(profile.GetValidationErrors(), Is.Empty, kind.ToString());
Assert.That(
Enum.GetValues(typeof(TypographyRole)).Cast<TypographyRole>()
.All(role => profile.Resolve(role) != null),
Is.True,
kind.ToString());
string guid = AssetDatabase.AssetPathToGUID($"{ProfileFolder}/{kind}.asset");
var entry = AddressableAssetSettingsDefaultObject.Settings.FindAssetEntry(guid);
Assert.That(entry, Is.Not.Null, kind.ToString());
Assert.That(entry.address, Is.EqualTo($"Typography/Profile/{kind}"));
}
}
[Test]
public void TerminalPrefabs_BindEveryTextExactlyOnce()
{
foreach (string path in TerminalTypographyMigration.PrefabPaths)
{
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
Assert.That(prefab, Is.Not.Null, path);
TMP_Text[] texts = prefab.GetComponentsInChildren<TMP_Text>(true);
Assert.That(texts, Is.Not.Empty, path);
foreach (TMP_Text text in texts)
{
LocalizedTypography[] bindings = text.GetComponents<LocalizedTypography>();
Assert.That(bindings, Has.Length.EqualTo(1), $"{path}: {text.name}");
Assert.That(bindings[0].Role, Is.EqualTo(TypographyRole.Terminal),
$"{path}: {text.name}");
}
}
}
[Test]
public void PersistenceTerminalComposition_InheritsTypographyBindings()
{
Scene scene = SceneManager.GetSceneByPath(TerminalTypographyMigration.PersistenceScenePath);
bool openedForTest = !scene.IsValid() || !scene.isLoaded;
if (openedForTest)
{
scene = EditorSceneManager.OpenScene(
TerminalTypographyMigration.PersistenceScenePath,
OpenSceneMode.Additive);
}
try
{
Component[] hosts = scene.GetRootGameObjects()
.SelectMany(root => root.GetComponentsInChildren<Component>(true))
.Where(component => component is TerminalPanel || component is InGameTerminalPanel)
.ToArray();
Assert.That(hosts, Has.Length.EqualTo(2));
var violations = new List<string>();
foreach (Component host in hosts)
{
foreach (TMP_Text text in host.GetComponentsInChildren<TMP_Text>(true))
{
LocalizedTypography[] bindings = text.GetComponents<LocalizedTypography>();
if (bindings.Length != 1)
{
violations.Add($"{host.name}: {text.name} has {bindings.Length} bindings");
continue;
}
if (bindings[0].Role != TypographyRole.Terminal)
violations.Add($"{host.name}: {text.name} uses {bindings[0].Role}");
}
}
Assert.That(violations, Is.Empty, string.Join("\n", violations));
}
finally
{
if (openedForTest)
EditorSceneManager.CloseScene(scene, true);
}
}
}
}