1041 lines
49 KiB
C#
1041 lines
49 KiB
C#
using System.Collections;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using BumpCombat.Core;
|
|
using BumpCombat.Progression;
|
|
using BumpCombat.UI;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.InputSystem.LowLevel;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.TestTools;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
|
|
namespace BumpCombat.PlayModeTests
|
|
{
|
|
public sealed class MissionAchievementPanelPlayModeTests
|
|
{
|
|
private Keyboard virtualKeyboard;
|
|
private bool virtualKeyboardInputActive;
|
|
private InputSettings.BackgroundBehavior previousBackgroundBehavior;
|
|
private InputSettings.EditorInputBehaviorInPlayMode previousEditorInputBehavior;
|
|
private bool previousRunInBackground;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
ArtifactRewardController.GrantCatalogForTests = true;
|
|
RunManager.ForceProductionModeForTests = true;
|
|
Time.timeScale = 1f;
|
|
}
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
EndVirtualKeyboardInput();
|
|
ArtifactRewardController.GrantCatalogForTests = false;
|
|
RunManager.ForceProductionModeForTests = false;
|
|
Time.timeScale = 1f;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator TabPanel_ShowsAllMissionsAndAchievementsAndClosesWithTabOrEscape()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
Assert.That(runManager, Is.Not.Null);
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(tracker, Is.Not.Null);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(panel.PageCount, Is.EqualTo(2));
|
|
SetPrivateField(runManager, "selectedRunMode", RunMode.Production);
|
|
SetPrivateField(runManager, "hasSelectedRunMode", true);
|
|
SetPrivateField(runManager, "guardUnlocked", false);
|
|
SetPrivateField(runManager, "artifactChargeUnlocked", false);
|
|
Assert.That(panel.transform.Find("Mission List Hint").gameObject.activeSelf,
|
|
Is.True);
|
|
Text missionHint = panel.transform.Find("Mission List Hint")
|
|
.GetComponent<Text>();
|
|
RectTransform missionHintRect = missionHint.rectTransform;
|
|
Assert.That(missionHint.supportRichText, Is.True);
|
|
Assert.That(missionHint.resizeTextForBestFit, Is.False);
|
|
Assert.That(missionHint.alignment, Is.EqualTo(TextAnchor.MiddleLeft));
|
|
Assert.That(missionHint.text, Does.Contain("<size=36>"));
|
|
Assert.That(missionHint.text, Does.Contain("<size=24>(미션 / 업적)</size>"));
|
|
Assert.That(missionHintRect.anchorMin, Is.EqualTo(new Vector2(0f, 1f)));
|
|
Assert.That(missionHintRect.anchorMax, Is.EqualTo(new Vector2(0f, 1f)));
|
|
Assert.That(missionHintRect.pivot, Is.EqualTo(new Vector2(0f, 1f)));
|
|
Assert.That(missionHintRect.anchoredPosition,
|
|
Is.EqualTo(new Vector2(24f, -250f)));
|
|
Assert.That(missionHintRect.sizeDelta,
|
|
Is.EqualTo(new Vector2(220f, 110f)));
|
|
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
Assert.That(runManager.IsSelectionOpen, Is.True);
|
|
Assert.That(Time.timeScale, Is.Zero);
|
|
Assert.That(panel.VisibleMissionRowCount, Is.EqualTo(6));
|
|
Assert.That(panel.transform.Find("Mission List Dim")
|
|
.GetComponent<Image>().raycastTarget, Is.True);
|
|
|
|
Transform firstRow = panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Page/Mission Row 1");
|
|
Text firstMission = firstRow.Find("Mission Title")
|
|
.GetComponent<Text>();
|
|
Assert.That(firstMission.text, Is.EqualTo("첫 소탕"));
|
|
Assert.That(firstRow.Find("Mission Condition").GetComponent<Text>().text,
|
|
Does.Contain("일반 적 100마리 처치"));
|
|
Assert.That(firstRow.Find("Mission Condition").GetComponent<Text>().text,
|
|
Does.Contain("소환수 제외"));
|
|
Assert.That(firstRow.Find("Mission Progress").GetComponent<Text>().text,
|
|
Is.EqualTo("0/100"));
|
|
Assert.That(firstRow.Find("Mission Reward").GetComponent<Text>().text,
|
|
Is.EqualTo("+10 XP"));
|
|
Assert.That(firstRow.Find("Mission Status Badge").gameObject.activeSelf,
|
|
Is.False, "Uncompleted missions do not repeat a '진행 중' badge.");
|
|
|
|
yield return PressAndRelease(keyboard, Key.PageDown);
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1));
|
|
Assert.That(panel.VisibleMissionRowCount, Is.EqualTo(5));
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Mission Page Number").GetComponent<Text>().text,
|
|
Is.EqualTo("2/2"));
|
|
Transform finalRow = panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Page/Mission Row 5");
|
|
Text finalMission = finalRow.Find("Mission Title")
|
|
.GetComponent<Text>();
|
|
Assert.That(finalMission.text, Does.Contain("파죽지세"));
|
|
Assert.That(finalRow.Find("Mission Condition").GetComponent<Text>().text,
|
|
Does.Contain("소환수 제외"));
|
|
Transform lockedRow = panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Page/Mission Row 2");
|
|
Text lockedMission = lockedRow.Find("Mission Title")
|
|
.GetComponent<Text>();
|
|
Assert.That(lockedMission.text, Does.Contain("정확한 방어"));
|
|
Assert.That(lockedRow.Find("Mission Status Badge/Label")
|
|
.GetComponent<Text>().text, Is.EqualTo("해금 대기"));
|
|
Assert.That(lockedRow.Find("Mission Progress").GetComponent<Text>().text,
|
|
Is.EqualTo("0/3"));
|
|
Assert.That(lockedRow.Find("Mission Reward").GetComponent<Text>().text,
|
|
Is.EqualTo("+15 XP"));
|
|
|
|
yield return PressAndRelease(keyboard, Key.PageUp);
|
|
Assert.That(panel.CurrentPageIndex, Is.Zero);
|
|
panel.transform.Find("Mission and Achievement List/Next Mission Page")
|
|
.GetComponent<Button>().onClick.Invoke();
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1),
|
|
"The visible page button should navigate to the next mission page.");
|
|
|
|
panel.transform.Find("Mission and Achievement List/Achievement Tab")
|
|
.GetComponent<Button>().onClick.Invoke();
|
|
Assert.That(panel.ShowingAchievements, Is.True);
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1),
|
|
"Switching tabs should preserve the selected mission page.");
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Achievement List Page/Achievement Preparation Message")
|
|
.GetComponent<Text>().text, Does.Contain("업적 준비 중"));
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Achievement List Page/Lifetime Mission Records")
|
|
.GetComponent<Text>().text, Does.Contain("누적 미션 완료"));
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Achievement List Page/Lifetime Mission Records")
|
|
.GetComponent<Text>().text, Does.Not.Contain("스킨"));
|
|
|
|
Transform missionTab = panel.transform.Find(
|
|
"Mission and Achievement List/Mission Tab");
|
|
Transform achievementTab = panel.transform.Find(
|
|
"Mission and Achievement List/Achievement Tab");
|
|
Assert.That(missionTab.Find("Label").GetComponent<Text>().text,
|
|
Is.EqualTo("미션 [1]"));
|
|
Assert.That(achievementTab.Find("Label").GetComponent<Text>().text,
|
|
Is.EqualTo("업적 [2]"));
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Help")
|
|
.GetComponent<Text>().text, Does.Contain("← / → 탭"));
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Help")
|
|
.GetComponent<Text>().text, Does.Contain("↑ / ↓ 페이지"));
|
|
yield return PressAndRelease(keyboard, Key.LeftArrow);
|
|
Assert.That(panel.ShowingAchievements, Is.False,
|
|
"Left arrow should select the mission tab.");
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1));
|
|
yield return PressAndRelease(keyboard, Key.RightArrow);
|
|
Assert.That(panel.ShowingAchievements, Is.True,
|
|
"Right arrow should select the achievement tab.");
|
|
yield return PressAndRelease(keyboard, Key.LeftArrow);
|
|
Assert.That(panel.ShowingAchievements, Is.False,
|
|
"The mission list should be reachable again from achievements.");
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1));
|
|
|
|
yield return PressAndRelease(keyboard, Key.Digit1);
|
|
Assert.That(panel.ShowingAchievements, Is.False);
|
|
yield return PressEscapeAndAssertPauseIsSuppressedThisFrame(
|
|
keyboard,
|
|
panel,
|
|
runManager);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
Assert.That(panel.transform.Find("Mission List Hint").gameObject.activeSelf,
|
|
Is.True);
|
|
yield return null;
|
|
Assert.That(runManager.TryOpenPause(), Is.True);
|
|
Assert.That(runManager.ClosePause(), Is.True);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator MissionCompletionToast_QueuesAndFreezesDuringMenus()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
RunMenuController menu = Object.FindAnyObjectByType<RunMenuController>();
|
|
Assert.That(runManager, Is.Not.Null);
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(tracker, Is.Not.Null);
|
|
Assert.That(menu, Is.Not.Null);
|
|
SetPrivateField(runManager, "selectedRunMode", RunMode.Production);
|
|
SetPrivateField(runManager, "hasSelectedRunMode", true);
|
|
|
|
GameObject toast = GetPrivateField<GameObject>(panel, "completionToast");
|
|
Assert.That(toast, Is.Not.Null);
|
|
Assert.That(toast.activeSelf, Is.False);
|
|
Assert.That(toast.GetComponent<Image>().raycastTarget, Is.False);
|
|
CanvasGroup canvasGroup = toast.GetComponent<CanvasGroup>();
|
|
Assert.That(canvasGroup.blocksRaycasts, Is.False);
|
|
Assert.That(canvasGroup.interactable, Is.False);
|
|
foreach (Graphic graphic in toast.GetComponentsInChildren<Graphic>(true))
|
|
{
|
|
Assert.That(graphic.raycastTarget, Is.False);
|
|
}
|
|
|
|
CompleteMissionForToast(tracker, panel, 0);
|
|
CompleteMissionForToast(tracker, panel, 1);
|
|
CompleteMissionForToast(tracker, panel, 0);
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.EqualTo(2),
|
|
"A repeated completion notification must not add another queue item.");
|
|
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
Assert.That(runManager.TryOpenSelection(menu), Is.True);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.False,
|
|
"Queued notices stay hidden during another selection screen.");
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.EqualTo(2));
|
|
Assert.That(runManager.CloseSelection(menu), Is.True);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.True);
|
|
Assert.That(GetPrivateField<Text>(panel, "completionToastMissionText").text,
|
|
Is.EqualTo("첫 소탕"));
|
|
Assert.That(GetPrivateField<Text>(panel, "completionToastRewardText").text,
|
|
Is.EqualTo("+10 XP"));
|
|
float initialRemaining =
|
|
GetPrivateField<float>(panel, "activeCompletionNoticeRemaining");
|
|
Assert.That(initialRemaining, Is.GreaterThan(2.5f));
|
|
Assert.That(initialRemaining, Is.LessThanOrEqualTo(3f));
|
|
|
|
yield return new WaitForSeconds(0.2f);
|
|
float remainingAfterVisibleTime =
|
|
GetPrivateField<float>(panel, "activeCompletionNoticeRemaining");
|
|
Assert.That(remainingAfterVisibleTime, Is.LessThan(initialRemaining));
|
|
|
|
Assert.That(runManager.TryOpenPause(), Is.True);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.False,
|
|
"The toast must hide as soon as pause opens.");
|
|
float remainingAtPause =
|
|
GetPrivateField<float>(panel, "activeCompletionNoticeRemaining");
|
|
yield return new WaitForSecondsRealtime(0.2f);
|
|
Assert.That(GetPrivateField<float>(panel, "activeCompletionNoticeRemaining"),
|
|
Is.EqualTo(remainingAtPause).Within(0.001f),
|
|
"Paused real time must not consume the toast duration.");
|
|
Assert.That(runManager.ClosePause(), Is.True);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.True);
|
|
|
|
float remainingAtPanelOpen =
|
|
GetPrivateField<float>(panel, "activeCompletionNoticeRemaining");
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
Assert.That(toast.activeSelf, Is.False,
|
|
"The toast must hide under the mission panel.");
|
|
Assert.That(GetPrivateField<float>(panel, "activeCompletionNoticeRemaining"),
|
|
Is.EqualTo(remainingAtPanelOpen).Within(0.05f));
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.True,
|
|
"The active toast should resume after the panel closes.");
|
|
|
|
SetPrivateField(panel, "activeCompletionNoticeRemaining", 0f);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.False,
|
|
"The first toast should end when its three gameplay seconds expire.");
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.True);
|
|
Assert.That(GetPrivateField<Text>(panel, "completionToastMissionText").text,
|
|
Is.EqualTo("성장의 발판"),
|
|
"The next queued completion should appear after the first one ends.");
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.Zero);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator OtherModalTitlePauseAndGameOver_DoNotLeaveMissionPanelOpen()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
RunMenuController menu = Object.FindAnyObjectByType<RunMenuController>();
|
|
Assert.That(runManager, Is.Not.Null);
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(menu, Is.Not.Null);
|
|
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
Assert.That(runManager.TryOpenSelection(menu), Is.True);
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsSelectionOpen, Is.True,
|
|
"The mission panel must not take another screen's selection lock.");
|
|
Assert.That(runManager.CloseSelection(menu), Is.True);
|
|
|
|
Assert.That(runManager.TryOpenPause(), Is.True);
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsPaused, Is.True);
|
|
Assert.That(runManager.ClosePause(), Is.True);
|
|
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
CompleteMissionForToast(tracker, panel, 0);
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.EqualTo(1));
|
|
runManager.EndRun();
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
Assert.That(runManager.IsGameOver, Is.True);
|
|
Assert.That(GetPrivateField<GameObject>(panel, "completionToast").activeSelf,
|
|
Is.False);
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.Zero,
|
|
"Game over must clear the active toast and pending queue.");
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator TitleScreen_DoesNotOpenTheMissionPanel()
|
|
{
|
|
ArtifactRewardController.GrantCatalogForTests = false;
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMenuController menu = Object.FindAnyObjectByType<RunMenuController>();
|
|
Assert.That(runManager, Is.Not.Null);
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(menu, Is.Not.Null);
|
|
Assert.That(runManager.IsTitleScreen, Is.True);
|
|
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsTitleScreen, Is.True);
|
|
|
|
yield return PressAndRelease(keyboard, Key.DownArrow);
|
|
yield return PressAndRelease(keyboard, Key.DownArrow);
|
|
Assert.That(
|
|
EventSystem.current.currentSelectedGameObject
|
|
.GetComponentInChildren<Text>().text,
|
|
Is.EqualTo("업적"));
|
|
yield return PressAndRelease(keyboard, Key.Enter);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
Assert.That(panel.ShowingAchievements, Is.True);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False,
|
|
"Title records do not acquire the gameplay selection lock.");
|
|
Assert.That(runManager.IsTitleScreen, Is.True);
|
|
Assert.That(Time.timeScale, Is.Zero);
|
|
|
|
Transform achievementPanel = panel.transform.Find(
|
|
"Mission and Achievement List");
|
|
Assert.That(achievementPanel.Find("Mission Tab").gameObject.activeSelf,
|
|
Is.False,
|
|
"Title records do not expose current-run missions.");
|
|
Assert.That(achievementPanel.Find("Mission List Page").gameObject.activeSelf,
|
|
Is.False);
|
|
Assert.That(achievementPanel.Find("Achievement List Page").gameObject.activeSelf,
|
|
Is.True);
|
|
Text records = achievementPanel.Find(
|
|
"Achievement List Page/Lifetime Mission Records").GetComponent<Text>();
|
|
Assert.That(records.text, Does.Contain("누적 미션 완료"));
|
|
Assert.That(achievementPanel.Find("Mission List Title")
|
|
.GetComponent<Text>().text, Is.EqualTo("업적"));
|
|
|
|
yield return PressAndRelease(keyboard, Key.Digit1);
|
|
Assert.That(panel.ShowingAchievements, Is.True,
|
|
"Keyboard tab changes cannot switch title records to missions.");
|
|
yield return PressAndRelease(keyboard, Key.Escape);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(menu.IsVisible, Is.True);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
Assert.That(runManager.IsTitleScreen, Is.True);
|
|
Assert.That(Time.timeScale, Is.Zero);
|
|
Assert.That(menu.transform.Find("Run Menu/Button 1/Label")
|
|
.GetComponent<Text>().text, Is.EqualTo("게임시작"));
|
|
|
|
menu.transform.Find("Run Menu/Button 3").GetComponent<Button>()
|
|
.onClick.Invoke();
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
panel.enabled = false;
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(menu.IsVisible, Is.True,
|
|
"Disabling the title records panel returns to the title menu.");
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
panel.enabled = true;
|
|
yield return null;
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(menu.IsVisible, Is.True);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator AchievementRecords_ExplainUnavailableOrUnpersistedProfileState()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(tracker, Is.Not.Null);
|
|
|
|
UserProfileStore store = tracker.ProfileStore;
|
|
SetPrivateField(store, "<LoadIssue>k__BackingField", "save-failed");
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Button achievementTab = panel.transform.Find(
|
|
"Mission and Achievement List/Achievement Tab").GetComponent<Button>();
|
|
achievementTab.onClick.Invoke();
|
|
Text records = panel.transform.Find(
|
|
"Mission and Achievement List/Achievement List Page/Lifetime Mission Records")
|
|
.GetComponent<Text>();
|
|
Assert.That(records.text, Does.Contain("누적 미션 완료"));
|
|
Assert.That(records.text, Does.Contain("영구 저장 실패"));
|
|
Assert.That(records.text, Does.Not.Contain("save-failed"));
|
|
|
|
SetPrivateField(store, "<CanSave>k__BackingField", false);
|
|
SetPrivateField(store, "<LoadIssue>k__BackingField", "newer-schema");
|
|
achievementTab.onClick.Invoke();
|
|
Assert.That(records.text, Does.Contain("프로필 버전이 높아"));
|
|
Assert.That(records.text, Does.Not.Contain("누적 미션 완료"));
|
|
Assert.That(records.text, Does.Not.Contain("newer-schema"));
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator DisableAndReenable_ReleasesOnlyItsOwnSelectionLock()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
CompleteMissionForToast(tracker, panel, 0);
|
|
CompleteMissionForToast(tracker, panel, 1);
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.EqualTo(2));
|
|
GameObject toast = GetPrivateField<GameObject>(panel, "completionToast");
|
|
panel.enabled = false;
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
Assert.That(RunManager.GameplayInputEnabled, Is.True);
|
|
Assert.That(toast.activeSelf, Is.False);
|
|
Assert.That(GetQueuedCompletionNoticeCount(panel), Is.Zero,
|
|
"Disabling the panel must clear active and queued notices.");
|
|
|
|
panel.enabled = true;
|
|
yield return null;
|
|
Assert.That(panel.IsOpen, Is.False,
|
|
"Reenabling the component must not reopen a previously held modal.");
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
Assert.That(runManager.IsSelectionOpen, Is.True);
|
|
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
CompleteMissionForToast(tracker, panel, 2);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.True);
|
|
Object.Destroy(panel);
|
|
yield return null;
|
|
Assert.That(toast.activeSelf, Is.False,
|
|
"Destroying the component must hide its toast child.");
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator LayoutAt720pAnd1080p_StaysInsideCanvasAndCapturesScreenshots()
|
|
{
|
|
yield return LoadSceneAndWait();
|
|
RunManager runManager = Object.FindAnyObjectByType<RunManager>();
|
|
MissionAchievementPanel panel =
|
|
Object.FindAnyObjectByType<MissionAchievementPanel>();
|
|
RunMissionTracker tracker =
|
|
Object.FindAnyObjectByType<RunMissionTracker>();
|
|
Assert.That(runManager, Is.Not.Null);
|
|
Assert.That(panel, Is.Not.Null);
|
|
Assert.That(tracker, Is.Not.Null);
|
|
SetPrivateField(runManager, "selectedRunMode", RunMode.Production);
|
|
SetPrivateField(runManager, "hasSelectedRunMode", true);
|
|
SetPrivateField(runManager, "guardUnlocked", false);
|
|
SetPrivateField(runManager, "artifactChargeUnlocked", false);
|
|
|
|
int[] progressValues = GetPrivateField<int[]>(tracker, "progress");
|
|
bool[] completedValues = GetPrivateField<bool[]>(tracker, "completed");
|
|
progressValues[0] = 37;
|
|
progressValues[2] = 60;
|
|
completedValues[2] = true;
|
|
|
|
Keyboard keyboard = BeginVirtualKeyboardInput();
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.True);
|
|
InvokePrivateMethod(panel, "RefreshView");
|
|
|
|
Canvas canvas = Object.FindAnyObjectByType<Canvas>();
|
|
CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();
|
|
Assert.That(scaler.referenceResolution,
|
|
Is.EqualTo(new Vector2(1920f, 1080f)));
|
|
RectTransform panelRect = panel.transform.Find(
|
|
"Mission and Achievement List").GetComponent<RectTransform>();
|
|
Assert.That(panelRect.sizeDelta,
|
|
Is.EqualTo(new Vector2(1360f, 880f)));
|
|
Assert.That(panelRect.rect.width * (720f / 1080f),
|
|
Is.LessThan(1280f));
|
|
Assert.That(panelRect.rect.height * (720f / 1080f),
|
|
Is.LessThan(720f));
|
|
|
|
Transform page1 = panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Page");
|
|
Transform partialRow = page1.Find("Mission Row 1");
|
|
Transform completedRow = page1.Find("Mission Row 3");
|
|
Assert.That(partialRow.Find("Mission Progress").GetComponent<Text>().text,
|
|
Is.EqualTo("37/100"));
|
|
Assert.That(partialRow.Find("Mission Status Badge").gameObject.activeSelf,
|
|
Is.False);
|
|
Assert.That(completedRow.Find("Mission Status Badge/Label")
|
|
.GetComponent<Text>().text, Is.EqualTo("완료"));
|
|
Assert.That(completedRow.Find("Mission Progress").GetComponent<Text>().text,
|
|
Is.EqualTo("60/60"));
|
|
|
|
Text title = page1.Find("Mission Row 1/Mission Title").GetComponent<Text>();
|
|
Text condition = page1.Find("Mission Row 1/Mission Condition")
|
|
.GetComponent<Text>();
|
|
Text progressText = page1.Find("Mission Row 1/Mission Progress")
|
|
.GetComponent<Text>();
|
|
Text reward = page1.Find("Mission Row 1/Mission Reward").GetComponent<Text>();
|
|
Assert.That(title.fontSize * 720f / scaler.referenceResolution.y,
|
|
Is.GreaterThanOrEqualTo(21f));
|
|
Assert.That(progressText.fontSize * 720f / scaler.referenceResolution.y,
|
|
Is.GreaterThanOrEqualTo(21f));
|
|
Assert.That(condition.fontSize * 720f / scaler.referenceResolution.y,
|
|
Is.GreaterThanOrEqualTo(17f));
|
|
Assert.That(reward.fontSize * 720f / scaler.referenceResolution.y,
|
|
Is.GreaterThanOrEqualTo(17f));
|
|
Assert.That(title.resizeTextForBestFit, Is.False);
|
|
Assert.That(condition.resizeTextForBestFit, Is.False);
|
|
|
|
Button missionTab = panel.transform.Find(
|
|
"Mission and Achievement List/Mission Tab").GetComponent<Button>();
|
|
Image missionTabImage = missionTab.targetGraphic as Image;
|
|
Color selectedMissionColor = missionTabImage.color;
|
|
Assert.That(missionTab.transition, Is.EqualTo(Selectable.Transition.None));
|
|
Assert.That(missionTabImage.sprite, Is.Null);
|
|
Assert.That(missionTab.GetComponent<Outline>(), Is.Not.Null);
|
|
Assert.That(selectedMissionColor.r, Is.GreaterThan(0.85f));
|
|
Assert.That(selectedMissionColor.g, Is.GreaterThan(0.65f));
|
|
Assert.That(selectedMissionColor.b, Is.LessThan(0.5f));
|
|
missionTab.OnPointerEnter(new PointerEventData(EventSystem.current));
|
|
Assert.That(missionTabImage.color, Is.EqualTo(selectedMissionColor),
|
|
"Pointer hover must preserve the selected tab fill.");
|
|
|
|
string captureDirectory = Path.GetFullPath(Path.Combine(
|
|
Application.dataPath,
|
|
"..",
|
|
"..",
|
|
"output",
|
|
"mission-readability-v2",
|
|
"captures"));
|
|
Directory.CreateDirectory(captureDirectory);
|
|
string toastCaptureDirectory = Path.GetFullPath(Path.Combine(
|
|
Application.dataPath,
|
|
"..",
|
|
"..",
|
|
"output",
|
|
"mission-tab-hint-v1",
|
|
"captures"));
|
|
Directory.CreateDirectory(toastCaptureDirectory);
|
|
RectTransform finalMissionRow = page1.Find("Mission Row 6")
|
|
.GetComponent<RectTransform>();
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
finalMissionRow,
|
|
captureDirectory,
|
|
"page1");
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
finalMissionRow,
|
|
toastCaptureDirectory,
|
|
"mission-page1");
|
|
|
|
yield return PressAndRelease(keyboard, Key.PageDown);
|
|
Assert.That(panel.CurrentPageIndex, Is.EqualTo(1));
|
|
Transform page2 = panel.transform.Find(
|
|
"Mission and Achievement List/Mission List Page");
|
|
Assert.That(page2.Find("Mission Row 2/Mission Status Badge/Label")
|
|
.GetComponent<Text>().text, Is.EqualTo("해금 대기"));
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
page2.Find("Mission Row 5").GetComponent<RectTransform>(),
|
|
captureDirectory,
|
|
"page2");
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
page2.Find("Mission Row 5").GetComponent<RectTransform>(),
|
|
toastCaptureDirectory,
|
|
"mission-page2");
|
|
|
|
Button achievementTab = panel.transform.Find(
|
|
"Mission and Achievement List/Achievement Tab").GetComponent<Button>();
|
|
Assert.That(achievementTab.transition,
|
|
Is.EqualTo(Selectable.Transition.None));
|
|
achievementTab.onClick.Invoke();
|
|
Assert.That(panel.ShowingAchievements, Is.True);
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Mission Progress Header").gameObject.activeSelf,
|
|
Is.False);
|
|
Assert.That(panel.transform.Find(
|
|
"Mission and Achievement List/Mission Reward Header").gameObject.activeSelf,
|
|
Is.False);
|
|
Color selectedAchievementColor =
|
|
(achievementTab.targetGraphic as Image).color;
|
|
Assert.That(selectedAchievementColor.r, Is.GreaterThan(0.85f));
|
|
Assert.That(achievementTab.GetComponentInChildren<Text>().color.r,
|
|
Is.LessThan(0.3f));
|
|
achievementTab.OnPointerEnter(new PointerEventData(EventSystem.current));
|
|
Assert.That((achievementTab.targetGraphic as Image).color,
|
|
Is.EqualTo(selectedAchievementColor),
|
|
"Pointer hover must preserve the selected tab fill.");
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
page2.Find("Mission Row 5").GetComponent<RectTransform>(),
|
|
captureDirectory,
|
|
"achievements");
|
|
CaptureBothResolutions(
|
|
canvas,
|
|
panelRect,
|
|
page2.Find("Mission Row 5").GetComponent<RectTransform>(),
|
|
toastCaptureDirectory,
|
|
"achievements");
|
|
|
|
yield return PressAndRelease(keyboard, Key.Tab);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
completedValues[2] = false;
|
|
CompleteMissionForToast(tracker, panel, 0);
|
|
yield return null;
|
|
GameObject completionToast = GetPrivateField<GameObject>(
|
|
panel,
|
|
"completionToast");
|
|
Assert.That(completionToast.activeSelf, Is.True);
|
|
Assert.That(panel.transform.Find("Mission List Hint").gameObject.activeSelf,
|
|
Is.True,
|
|
"The left-side TAB hint should be visible in gameplay captures.");
|
|
RectTransform toastRect = completionToast.GetComponent<RectTransform>();
|
|
Assert.That(toastRect.anchorMin, Is.EqualTo(new Vector2(1f, 0f)));
|
|
Assert.That(toastRect.anchorMax, Is.EqualTo(new Vector2(1f, 0f)));
|
|
Assert.That(toastRect.pivot, Is.EqualTo(new Vector2(1f, 0f)));
|
|
CaptureCompletionToastBothResolutions(
|
|
canvas,
|
|
toastRect,
|
|
toastCaptureDirectory);
|
|
}
|
|
|
|
private Keyboard BeginVirtualKeyboardInput()
|
|
{
|
|
Assert.That(virtualKeyboardInputActive, Is.False);
|
|
previousBackgroundBehavior = InputSystem.settings.backgroundBehavior;
|
|
previousEditorInputBehavior =
|
|
InputSystem.settings.editorInputBehaviorInPlayMode;
|
|
previousRunInBackground = Application.runInBackground;
|
|
InputSystem.settings.backgroundBehavior =
|
|
InputSettings.BackgroundBehavior.IgnoreFocus;
|
|
InputSystem.settings.editorInputBehaviorInPlayMode =
|
|
InputSettings.EditorInputBehaviorInPlayMode
|
|
.AllDeviceInputAlwaysGoesToGameView;
|
|
Application.runInBackground = true;
|
|
virtualKeyboard = InputSystem.AddDevice<Keyboard>();
|
|
virtualKeyboard.MakeCurrent();
|
|
virtualKeyboardInputActive = true;
|
|
return virtualKeyboard;
|
|
}
|
|
|
|
private void EndVirtualKeyboardInput()
|
|
{
|
|
if (!virtualKeyboardInputActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (virtualKeyboard != null && virtualKeyboard.added)
|
|
{
|
|
InputSystem.RemoveDevice(virtualKeyboard);
|
|
}
|
|
InputSystem.settings.backgroundBehavior = previousBackgroundBehavior;
|
|
InputSystem.settings.editorInputBehaviorInPlayMode =
|
|
previousEditorInputBehavior;
|
|
Application.runInBackground = previousRunInBackground;
|
|
virtualKeyboard = null;
|
|
virtualKeyboardInputActive = false;
|
|
}
|
|
|
|
private static IEnumerator PressAndRelease(Keyboard keyboard, Key key)
|
|
{
|
|
InputSystem.QueueStateEvent(keyboard, new KeyboardState(key));
|
|
yield return null;
|
|
Assert.That(keyboard[key].isPressed, Is.True);
|
|
InputSystem.QueueStateEvent(keyboard, new KeyboardState());
|
|
yield return null;
|
|
Assert.That(keyboard[key].isPressed, Is.False);
|
|
}
|
|
|
|
private static IEnumerator PressEscapeAndAssertPauseIsSuppressedThisFrame(
|
|
Keyboard keyboard,
|
|
MissionAchievementPanel panel,
|
|
RunManager runManager)
|
|
{
|
|
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.Escape));
|
|
yield return null;
|
|
Assert.That(keyboard.escapeKey.isPressed, Is.True);
|
|
Assert.That(panel.IsOpen, Is.False);
|
|
Assert.That(runManager.IsSelectionOpen, Is.False);
|
|
Assert.That(runManager.IsPaused, Is.False,
|
|
"Escape closes the list without opening pause.");
|
|
Assert.That(runManager.TryOpenPause(), Is.False,
|
|
"Pause is suppressed for the frame that closes the list.");
|
|
|
|
InputSystem.QueueStateEvent(keyboard, new KeyboardState());
|
|
yield return null;
|
|
Assert.That(keyboard.escapeKey.isPressed, Is.False);
|
|
}
|
|
|
|
private static void CaptureAtResolution(
|
|
Canvas canvas,
|
|
RectTransform panelRect,
|
|
RectTransform finalMissionRow,
|
|
int width,
|
|
int height,
|
|
string outputPath)
|
|
{
|
|
Camera worldCamera = Camera.main;
|
|
Assert.That(worldCamera, Is.Not.Null);
|
|
RenderTexture worldTarget = new(
|
|
width,
|
|
height,
|
|
24,
|
|
RenderTextureFormat.ARGB32);
|
|
RenderTexture uiTarget = new(
|
|
width,
|
|
height,
|
|
24,
|
|
RenderTextureFormat.ARGB32);
|
|
GameObject uiCameraObject = new("Mission Panel Capture Camera");
|
|
Camera uiCamera = uiCameraObject.AddComponent<Camera>();
|
|
Texture2D screenshot = null;
|
|
Texture2D uiScreenshot = null;
|
|
RenderTexture previousActive = RenderTexture.active;
|
|
RenderTexture previousWorldTarget = worldCamera.targetTexture;
|
|
float previousWorldAspect = worldCamera.aspect;
|
|
int previousWorldMask = worldCamera.cullingMask;
|
|
RenderTexture previousUiTarget = uiCamera.targetTexture;
|
|
float previousUiAspect = uiCamera.aspect;
|
|
RenderMode previousRenderMode = canvas.renderMode;
|
|
Camera previousCanvasCamera = canvas.worldCamera;
|
|
float previousCanvasPlaneDistance = canvas.planeDistance;
|
|
float previousCanvasScaleFactor = canvas.scaleFactor;
|
|
CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();
|
|
bool previousScalerEnabled = scaler != null && scaler.enabled;
|
|
Transform[] canvasChildren = canvas.GetComponentsInChildren<Transform>(true);
|
|
int[] previousLayers = new int[canvasChildren.Length];
|
|
for (int i = 0; i < canvasChildren.Length; i++)
|
|
{
|
|
previousLayers[i] = canvasChildren[i].gameObject.layer;
|
|
}
|
|
|
|
try
|
|
{
|
|
worldTarget.Create();
|
|
uiTarget.Create();
|
|
worldCamera.targetTexture = worldTarget;
|
|
worldCamera.aspect = (float)width / height;
|
|
worldCamera.cullingMask &= ~(1 << 5);
|
|
|
|
uiCamera.enabled = false;
|
|
uiCamera.transform.SetPositionAndRotation(
|
|
worldCamera.transform.position,
|
|
worldCamera.transform.rotation);
|
|
uiCamera.orthographic = worldCamera.orthographic;
|
|
uiCamera.orthographicSize = worldCamera.orthographicSize;
|
|
uiCamera.aspect = (float)width / height;
|
|
uiCamera.clearFlags = CameraClearFlags.SolidColor;
|
|
uiCamera.backgroundColor = Color.clear;
|
|
uiCamera.cullingMask = 1 << 5;
|
|
uiCamera.targetTexture = uiTarget;
|
|
|
|
for (int i = 0; i < canvasChildren.Length; i++)
|
|
{
|
|
canvasChildren[i].gameObject.layer = 5;
|
|
}
|
|
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
|
canvas.worldCamera = uiCamera;
|
|
canvas.planeDistance = 1f;
|
|
if (scaler != null)
|
|
{
|
|
scaler.enabled = false;
|
|
}
|
|
canvas.scaleFactor = width / 1920f;
|
|
foreach (Graphic graphic in canvas.GetComponentsInChildren<Graphic>(true))
|
|
{
|
|
graphic.SetAllDirty();
|
|
}
|
|
|
|
Canvas.ForceUpdateCanvases();
|
|
AssertRectInsideRenderTarget(
|
|
panelRect,
|
|
canvas.GetComponent<RectTransform>(),
|
|
uiCamera,
|
|
width,
|
|
height);
|
|
AssertRectInsideRenderTarget(
|
|
finalMissionRow,
|
|
canvas.GetComponent<RectTransform>(),
|
|
uiCamera,
|
|
width,
|
|
height);
|
|
|
|
worldCamera.Render();
|
|
uiCamera.Render();
|
|
|
|
RenderTexture.active = worldTarget;
|
|
screenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
|
|
screenshot.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
|
|
screenshot.Apply();
|
|
RenderTexture.active = uiTarget;
|
|
uiScreenshot = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
|
uiScreenshot.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
|
|
uiScreenshot.Apply();
|
|
|
|
Color32[] worldPixels = screenshot.GetPixels32();
|
|
Color32[] uiPixels = uiScreenshot.GetPixels32();
|
|
for (int i = 0; i < worldPixels.Length; i++)
|
|
{
|
|
float alpha = uiPixels[i].a / 255f;
|
|
worldPixels[i] = new Color32(
|
|
(byte)Mathf.Min(255, uiPixels[i].r + worldPixels[i].r * (1f - alpha)),
|
|
(byte)Mathf.Min(255, uiPixels[i].g + worldPixels[i].g * (1f - alpha)),
|
|
(byte)Mathf.Min(255, uiPixels[i].b + worldPixels[i].b * (1f - alpha)),
|
|
255);
|
|
}
|
|
screenshot.SetPixels32(worldPixels);
|
|
screenshot.Apply();
|
|
byte[] imageBytes = screenshot.EncodeToPNG();
|
|
Assert.That(imageBytes.Length, Is.GreaterThan(5000),
|
|
"The captured Unity-rendered panel should contain visible UI content.");
|
|
File.WriteAllBytes(outputPath, imageBytes);
|
|
}
|
|
finally
|
|
{
|
|
RenderTexture.active = previousActive;
|
|
worldCamera.targetTexture = previousWorldTarget;
|
|
worldCamera.aspect = previousWorldAspect;
|
|
worldCamera.cullingMask = previousWorldMask;
|
|
uiCamera.targetTexture = previousUiTarget;
|
|
uiCamera.aspect = previousUiAspect;
|
|
for (int i = 0; i < canvasChildren.Length; i++)
|
|
{
|
|
if (canvasChildren[i] != null)
|
|
{
|
|
canvasChildren[i].gameObject.layer = previousLayers[i];
|
|
}
|
|
}
|
|
canvas.renderMode = previousRenderMode;
|
|
canvas.worldCamera = previousCanvasCamera;
|
|
canvas.planeDistance = previousCanvasPlaneDistance;
|
|
canvas.scaleFactor = previousCanvasScaleFactor;
|
|
if (scaler != null)
|
|
{
|
|
scaler.enabled = previousScalerEnabled;
|
|
}
|
|
Canvas.ForceUpdateCanvases();
|
|
if (screenshot != null)
|
|
{
|
|
Object.DestroyImmediate(screenshot);
|
|
}
|
|
if (uiScreenshot != null)
|
|
{
|
|
Object.DestroyImmediate(uiScreenshot);
|
|
}
|
|
Object.DestroyImmediate(uiCameraObject);
|
|
worldTarget.Release();
|
|
uiTarget.Release();
|
|
Object.DestroyImmediate(worldTarget);
|
|
Object.DestroyImmediate(uiTarget);
|
|
}
|
|
}
|
|
|
|
private static void CaptureBothResolutions(
|
|
Canvas canvas,
|
|
RectTransform panelRect,
|
|
RectTransform finalMissionRow,
|
|
string captureDirectory,
|
|
string viewName)
|
|
{
|
|
CaptureAtResolution(
|
|
canvas,
|
|
panelRect,
|
|
finalMissionRow,
|
|
1280,
|
|
720,
|
|
Path.Combine(captureDirectory, $"{viewName}-720p.png"));
|
|
CaptureAtResolution(
|
|
canvas,
|
|
panelRect,
|
|
finalMissionRow,
|
|
1920,
|
|
1080,
|
|
Path.Combine(captureDirectory, $"{viewName}-1080p.png"));
|
|
}
|
|
|
|
private static void CaptureCompletionToastBothResolutions(
|
|
Canvas canvas,
|
|
RectTransform toastRect,
|
|
string captureDirectory)
|
|
{
|
|
CaptureAtResolution(
|
|
canvas,
|
|
toastRect,
|
|
toastRect,
|
|
1280,
|
|
720,
|
|
Path.Combine(captureDirectory, "mission-toast-720p.png"));
|
|
CaptureAtResolution(
|
|
canvas,
|
|
toastRect,
|
|
toastRect,
|
|
1920,
|
|
1080,
|
|
Path.Combine(captureDirectory, "mission-toast-1080p.png"));
|
|
}
|
|
|
|
private static void AssertRectInsideRenderTarget(
|
|
RectTransform rect,
|
|
RectTransform canvas,
|
|
Camera camera,
|
|
int width,
|
|
int height)
|
|
{
|
|
Vector3[] corners = new Vector3[4];
|
|
rect.GetWorldCorners(corners);
|
|
for (int i = 0; i < corners.Length; i++)
|
|
{
|
|
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(
|
|
camera,
|
|
corners[i]);
|
|
Assert.That(screenPoint.x, Is.GreaterThanOrEqualTo(-0.5f));
|
|
Assert.That(screenPoint.x, Is.LessThanOrEqualTo(width + 0.5f));
|
|
Assert.That(screenPoint.y, Is.GreaterThanOrEqualTo(-0.5f));
|
|
Assert.That(screenPoint.y, Is.LessThanOrEqualTo(height + 0.5f));
|
|
}
|
|
|
|
Assert.That(rect.rect.width, Is.LessThanOrEqualTo(canvas.rect.width));
|
|
Assert.That(rect.rect.height, Is.LessThanOrEqualTo(canvas.rect.height));
|
|
}
|
|
|
|
private static void SetPrivateField<T>(
|
|
object target,
|
|
string fieldName,
|
|
T value)
|
|
{
|
|
FieldInfo field = target.GetType().GetField(
|
|
fieldName,
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(field, Is.Not.Null, $"Missing field: {fieldName}");
|
|
field.SetValue(target, value);
|
|
}
|
|
|
|
private static T GetPrivateField<T>(object target, string fieldName)
|
|
{
|
|
FieldInfo field = target.GetType().GetField(
|
|
fieldName,
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(field, Is.Not.Null, $"Missing field: {fieldName}");
|
|
return (T)field.GetValue(target);
|
|
}
|
|
|
|
private static int GetQueuedCompletionNoticeCount(
|
|
MissionAchievementPanel panel)
|
|
{
|
|
object queue = GetPrivateField<object>(
|
|
panel,
|
|
"pendingCompletionNotices");
|
|
PropertyInfo countProperty = queue.GetType().GetProperty("Count");
|
|
Assert.That(countProperty, Is.Not.Null);
|
|
return (int)countProperty.GetValue(queue);
|
|
}
|
|
|
|
private static void CompleteMissionForToast(
|
|
RunMissionTracker tracker,
|
|
MissionAchievementPanel panel,
|
|
int missionIndex)
|
|
{
|
|
int[] progress = GetPrivateField<int[]>(tracker, "progress");
|
|
bool[] completed = GetPrivateField<bool[]>(tracker, "completed");
|
|
progress[missionIndex] = RunMissionTracker.GetDefinition(missionIndex).Target;
|
|
completed[missionIndex] = true;
|
|
InvokePrivateMethod(panel, "HandleProgressChanged");
|
|
}
|
|
|
|
private static void InvokePrivateMethod(object target, string methodName)
|
|
{
|
|
MethodInfo method = target.GetType().GetMethod(
|
|
methodName,
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(method, Is.Not.Null, $"Missing method: {methodName}");
|
|
method.Invoke(target, null);
|
|
}
|
|
|
|
private static IEnumerator LoadSceneAndWait()
|
|
{
|
|
AsyncOperation load = SceneManager.LoadSceneAsync("CombatPrototype");
|
|
while (!load.isDone)
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
yield return null;
|
|
yield return null;
|
|
}
|
|
}
|
|
}
|