VanguardReMaster/client/Assets/Vanguard/Tests/Editor/ClientSmokeTests.cs

343 lines
14 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.Api.Contracts;
using Vanguard.App;
using Vanguard.Auth;
using Vanguard.Board3D;
using Vanguard.Meta;
using Vanguard.Shared.Protocol;
using Vanguard.State;
using Vanguard.UI;
using BattleView = Vanguard.UI.BattleView;
namespace Vanguard.Tests
{
public sealed class ClientSmokeTests
{
[Test]
public void Client_Views_Build()
{
var config = new AppConfig();
config.Load();
var tokens = new TokenStore();
var api = new ApiClient(config, tokens);
var player = new PlayerState();
var auth = new AuthService(api, tokens, player);
var meta = new MetaService(api, player);
var canvas = UiKit.CreateCanvas("Test Canvas");
var login = new LoginView(canvas.transform, config, auth, () => { });
login.Show("smoke");
var lobby = new MetaView(
canvas.transform, auth, player, () => { },
() => { }, () => { }, () => { }, () => { }, () => { });
var onboarding = new OnboardingView(
canvas.transform, auth, meta, () => { }, () => { });
var decks = new DeckBuilderView(
canvas.transform, meta, auth, () => { }, _ => { }, _ => { });
var queue = new QueueView(
canvas.transform, meta, auth, () => { }, _ => { });
var store = new StoreView(
canvas.transform, meta, auth, player, () => { });
var history = new HistoryView(
canvas.transform, meta, auth, () => { });
var battle = new BattleView(
canvas.transform, meta, () => { });
Assert.IsNotNull(GameObject.Find("LoginScreen"));
Assert.IsTrue(Exists("MetaScreen"));
Assert.IsTrue(Exists("OnboardingScreen"));
Assert.IsTrue(Exists("DeckBuilderScreen"));
Assert.IsTrue(Exists("StoreScreen"));
Assert.IsTrue(Exists("HistoryScreen"));
Assert.IsTrue(Exists("ReplayScreen"));
Assert.IsTrue(Exists("QueueScreen"));
Assert.IsTrue(Exists("BattleScreen"));
Assert.IsNotNull(
Resources.Load<Texture2D>("CardArt/td01_005"),
"TD01 card art is not imported");
var standardBack = Resources.Load<Texture2D>("CardArt/vanguard_back");
Assert.IsNotNull(standardBack, "Standard Vanguard card back is not imported");
Assert.AreEqual(standardBack, CardArt.Back.texture);
var artGo = new GameObject("ArtProbe", typeof(RectTransform), typeof(Image));
var artImage = artGo.GetComponent<Image>();
CardImageService.Apply(artImage, "td01_005", null);
Assert.IsNotNull(artImage.sprite, "CardImageService did not load real card art");
Object.DestroyImmediate(artGo);
// После смены сцены старые views не должны реагировать на PlayerState.
lobby.Dispose();
store.Dispose();
player.Apply(new MeResponse
{
UserName = "after-dispose",
Gold = 10,
Dust = 2,
Tokens = 1,
});
Cleanup();
}
[Test]
public void Localization_Translates_Static_And_Dynamic_Strings()
{
Loc.SetLanguage(UiLanguage.Ru);
Assert.AreEqual("Коллекция", Loc.Translate("Коллекция"));
Loc.SetLanguage(UiLanguage.En);
Assert.AreEqual("Collection", Loc.Translate("Коллекция"));
Assert.AreEqual("Grade: all", Loc.Translate("Ранг: все"));
Assert.AreEqual("Cards in collection: 12", Loc.Translate("Карт в коллекции: 12"));
Assert.AreEqual("Victory!", Loc.Translate("Победа!"));
Assert.AreEqual("Sentinel: yes · Boost: no", Loc.Translate("Sentinel: да · Boost: нет"));
Loc.SetLanguage(UiLanguage.Ru);
var go = new GameObject("LocalizedLabel", typeof(RectTransform), typeof(Text));
var label = go.GetComponent<Text>();
var localized = go.AddComponent<LocalizedText>();
localized.Initialize("Коллекция");
Assert.AreEqual("Коллекция", label.text);
Loc.SetLanguage(UiLanguage.En);
Assert.AreEqual("Collection", label.text);
label.text = "Магазин";
localized.ApplyNow();
Assert.AreEqual("Store", label.text);
Loc.SetLanguage(UiLanguage.Ru);
Assert.AreEqual("Магазин", label.text);
Object.DestroyImmediate(go);
}
[Test]
public void Battle_Layout_Fits_Reference_Resolution()
{
var config = new AppConfig();
config.Load();
var tokens = new TokenStore();
var api = new ApiClient(config, tokens);
var player = new PlayerState();
var auth = new AuthService(api, tokens, player);
var meta = new MetaService(api, player);
var canvas = UiKit.CreateCanvas("Layout Test Canvas");
try
{
var battle = new BattleView(canvas.transform, meta, () => { });
var screen = Resources.FindObjectsOfTypeAll<GameObject>()
.First(go => go.name == "BattleScreen");
screen.SetActive(true);
var self = ReferenceRect(FindRect("ZoneBlocksSelf"));
var opponent = ReferenceRect(FindRect("ZoneBlocksOpponent"));
var phase = ReferenceRect(FindRect("PhasePanel"));
var stats = ReferenceRect(FindRect("CombatStats"));
AssertWithinScreen(self, "self zones");
AssertWithinScreen(opponent, "opponent zones");
AssertWithinScreen(phase, "phase panel");
AssertWithinScreen(stats, "combat stats");
Assert.IsFalse(self.Overlaps(opponent));
Assert.IsFalse(self.Overlaps(phase));
Assert.IsFalse(opponent.Overlaps(phase));
Assert.IsFalse(opponent.Overlaps(stats));
Assert.IsFalse(phase.Overlaps(stats));
}
finally
{
Object.DestroyImmediate(canvas.gameObject);
Cleanup();
}
}
private static RectTransform FindRect(string name) =>
Resources.FindObjectsOfTypeAll<GameObject>()
.Where(go => go.scene.IsValid() && go.name == name)
.Select(go => go.GetComponent<RectTransform>())
.First(rect => rect != null);
private static Rect ReferenceRect(RectTransform rect)
{
var size = rect.sizeDelta;
var anchor = new Vector2(
Mathf.Lerp(0f, 1920f, rect.anchorMin.x),
Mathf.Lerp(0f, 1080f, rect.anchorMin.y));
return new Rect(
anchor + rect.anchoredPosition - Vector2.Scale(size, rect.pivot),
size);
}
private static void AssertWithinScreen(Rect rect, string name)
{
Assert.GreaterOrEqual(rect.xMin, 0f, name + " left");
Assert.GreaterOrEqual(rect.yMin, 0f, name + " bottom");
Assert.LessOrEqual(rect.xMax, 1920f, name + " right");
Assert.LessOrEqual(rect.yMax, 1080f, name + " top");
}
[Test]
public void Battle_Renders_3D_Damage_And_Rested_Cards()
{
var config = new AppConfig();
config.Load();
var tokens = new TokenStore();
var api = new ApiClient(config, tokens);
var player = new PlayerState();
var auth = new AuthService(api, tokens, player);
var meta = new MetaService(api, player);
var canvas = UiKit.CreateCanvas("Test Canvas");
var battle = new BattleView(canvas.transform, meta, () => { });
var screen = Resources.FindObjectsOfTypeAll<GameObject>()
.First(go => go.name == "BattleScreen");
screen.SetActive(true);
CardView Card(string id, int instance, bool rested = false) => new CardView
{
PrintingId = id,
InstanceId = instance,
Rested = rested,
FaceUp = true,
Power = 8000,
BasePower = 8000,
Critical = 1,
BaseCritical = 1,
};
var self = new PlayerView
{
Index = 0,
Name = "Me",
Vanguard = Card("BT01/001EN", 1),
RearGuards = new CardView?[5],
Hand = new List<CardView> { Card("BT01/042EN", 2) },
Soul = new List<CardView> { Card("BT01/003EN", 3) },
FaceDownDamage = 2,
FaceUpDamage = new List<CardView> { Card("BT01/056EN", 4) },
DeckCount = 40,
Drop = new List<CardView>(),
};
self.RearGuards[3] = Card("BT01/042EN", 5, rested: true);
var opponent = new PlayerView
{
Index = 1,
Name = "Opponent",
Vanguard = Card("BT01/001EN", 6),
RearGuards = new CardView?[5],
Hand = new List<CardView>(),
Soul = new List<CardView>(),
FaceDownDamage = 1,
FaceUpDamage = new List<CardView>(),
DeckCount = 40,
Drop = new List<CardView>(),
};
var match = new MatchView
{
MatchId = "render-test",
You = 0,
ActivePlayer = 0,
Phase = GamePhase.Main,
Players = new List<PlayerView> { self, opponent },
Battle = new Vanguard.Shared.Protocol.BattleView
{
GuardCards = new List<CardView> { Card("BT01/011EN", 7) },
},
Clock = new ClockView(),
LegalIntents = new List<IntentPayload>(),
};
Resources.FindObjectsOfTypeAll<GameBoard3D>()
.FirstOrDefault()
?.SetVisible(true);
typeof(BattleView)
.GetField("_view", BindingFlags.Instance | BindingFlags.NonPublic)!
.SetValue(battle, match);
typeof(BattleView)
.GetMethod("Render", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(battle, null);
Assert.IsTrue(Exists("GameBoard3D"));
var cards = Resources.FindObjectsOfTypeAll<Card3D>()
.Where(card => card.gameObject.activeInHierarchy)
.ToList();
Assert.GreaterOrEqual(cards.Count, 3);
var rested = cards.FirstOrDefault(card =>
card.Ref.Zone == BoardZone.RearGuard
&& card.Ref.Player == 0
&& card.Ref.Slot == 3);
Assert.IsNotNull(rested, "Rested rear-guard was not rendered in 3D");
Assert.IsTrue(rested.IsRested);
Assert.AreEqual(90f, Mathf.Abs(Mathf.DeltaAngle(rested.TargetYaw, 0f)), 0.1f);
var damage = cards.Where(card =>
card.Ref.Zone == BoardZone.Damage
&& card.Ref.Player == 0).ToList();
Assert.AreEqual(3, damage.Count);
Assert.IsFalse(damage.Single(card => card.Ref.Index == 2).IsFaceUp);
Assert.AreEqual(
-90f,
Mathf.DeltaAngle(0f, damage.Single(card => card.Ref.Index == 0).TargetYaw),
0.1f,
"Damage cards must be turned counter-clockwise");
Assert.IsTrue(cards.Any(card =>
card.Ref.Zone == BoardZone.Guardian
&& card.Ref.InstanceId == 7));
var selfZoneRoot = Resources.FindObjectsOfTypeAll<GameObject>()
.FirstOrDefault(go => go.name == "ZoneBlocksSelf");
var opponentZoneRoot = Resources.FindObjectsOfTypeAll<GameObject>()
.FirstOrDefault(go => go.name == "ZoneBlocksOpponent");
Assert.IsNotNull(selfZoneRoot);
Assert.IsNotNull(opponentZoneRoot);
var selfLabels = selfZoneRoot.GetComponentsInChildren<Text>();
var opponentLabels = opponentZoneRoot.GetComponentsInChildren<Text>();
Assert.IsTrue(selfLabels.Any(text => text.text.Contains("Рука 1")));
Assert.IsTrue(selfLabels.Any(text => text.text.Contains("Душа 1")));
Assert.IsTrue(opponentLabels.Any(text => text.text.Contains("Рука 0")));
Cleanup();
}
private static bool Exists(string name) =>
Resources.FindObjectsOfTypeAll<GameObject>().Any(go => go.name == name);
private static void Cleanup()
{
foreach (var board in Resources.FindObjectsOfTypeAll<GameBoard3D>())
{
if (board != null)
Object.DestroyImmediate(board.gameObject);
}
var canvas = GameObject.Find("Test Canvas");
if (canvas != null)
Object.DestroyImmediate(canvas);
var eventSystem = Object.FindAnyObjectByType<EventSystem>();
if (eventSystem != null)
Object.DestroyImmediate(eventSystem.gameObject);
}
}
}