Danro-Jump/Assets/Tests/EditMode/Editor/ServiceSettingsSceneInjectorTests.cs
Danil Iarosh c1b72854f4 Implement prize QR and service UI polish
Подробные изменения:

- Добавлена система призовых уровней и выдачи призов с QR-контуром Telegram, шаблоном сообщения и генерацией QR без внешних библиотек.

- Доработаны сервисные настройки: действия кнопок, модальные окна, ввод с джойстика/клавиатуры, статистика, настройки призов и маршрутизация QR.

- Переработаны gameplay HUD и overlay-панели на UI Toolkit со спрайтовыми плашками, DEV BUILD-статистикой, экраном продолжения и экраном результата приза.

- Исправлены сценарии смерти, GameOver, продолжения игры, начисления очков за высоту и перехода в главное меню.

- Перенесены UI-шаблоны из Resources в Assets/UI, подключена Addressables-загрузка шаблонов настроек и standalone-стили для MainMenuModals.

- Добавлены EditMode/PlayMode тесты для призов, QR, arcade input, UI-модалок, scene flow, HUD и gameplay-сессии.

- Обновлены сцены, настройки Addressables, service settings database, документация и дорожная карта.

Проверки:

- Targeted EditMode QR/UI/settings: 23/23 passed

- Targeted UI templates/EditMode: 17/17 passed

- MainMenuUxmlTests: 3/3 passed

- Full EditMode: 129/129 passed

- PlayMode: 6/6 passed

- Runtime Addressables template load check: loaded=5

- Unity Console после финального refresh: 0 errors
2026-06-12 16:43:28 +03:00

146 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using DanroJump.SceneFlow;
using DanroJump.Settings;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Zenject;
namespace DanroJump.Tests.EditMode
{
public sealed class ServiceSettingsSceneInjectorTests
{
private readonly List<GameObject> createdObjects = new();
[TearDown]
public void TearDown()
{
foreach (var createdObject in createdObjects)
{
if (createdObject != null)
{
UnityEngine.Object.DestroyImmediate(createdObject);
}
}
createdObjects.Clear();
}
[Test]
public void Initialize_InjectsActionsAlreadyPresentInLoadedScene()
{
var gameObject = CreateGameObject("Service Settings Actions");
var actions = gameObject.AddComponent<ServiceSettingsActions>();
var sceneFlow = new RecordingSceneFlowService();
var container = new DiContainer();
container.Bind<IServiceSettingsService>().FromInstance(new NoopServiceSettingsService()).AsSingle();
container.Bind<ISceneFlowService>().FromInstance(sceneFlow).AsSingle();
var injector = new ServiceSettingsSceneInjector(container, true);
injector.Initialize();
actions.LoadScene("Game");
actions.LoadMainMenu();
injector.Dispose();
Assert.That(sceneFlow.LoadedScene, Is.EqualTo("Game"));
Assert.That(sceneFlow.OpenMainMenuCount, Is.EqualTo(1));
}
[Test]
public void Initialize_DoesNothingWhenSceneActionInjectionIsDisabled()
{
var gameObject = CreateGameObject("Disabled Service Settings Actions");
var actions = gameObject.AddComponent<ServiceSettingsActions>();
var sceneFlow = new RecordingSceneFlowService();
var container = new DiContainer();
container.Bind<IServiceSettingsService>().FromInstance(new NoopServiceSettingsService()).AsSingle();
container.Bind<ISceneFlowService>().FromInstance(sceneFlow).AsSingle();
var injector = new ServiceSettingsSceneInjector(container, false);
injector.Initialize();
LogAssert.Expect(LogType.Warning, "ServiceSettingsActions requires ISceneFlowService from DI.");
actions.LoadMainMenu();
injector.Dispose();
Assert.That(sceneFlow.OpenMainMenuCount, Is.EqualTo(0));
}
private GameObject CreateGameObject(string name)
{
var gameObject = new GameObject(name);
createdObjects.Add(gameObject);
return gameObject;
}
private sealed class RecordingSceneFlowService : ISceneFlowService
{
public string LoadedScene { get; private set; }
public int OpenMainMenuCount { get; private set; }
public void LoadScene(string sceneName)
{
LoadedScene = sceneName;
}
public void OpenMainMenu()
{
OpenMainMenuCount++;
}
public void StartGameplay(string sceneName)
{
LoadedScene = sceneName;
}
public void OpenSettingsScene(string sceneName)
{
LoadedScene = sceneName;
}
public void ReturnToMainMenuAfterGameOver(TimeSpan delay)
{
OpenMainMenu();
}
public void CancelGameOverReturn()
{
}
public bool SceneExists(string sceneName)
{
return !string.IsNullOrWhiteSpace(sceneName);
}
}
private sealed class NoopServiceSettingsService : IServiceSettingsService
{
public ServiceSettingsDatabase Database => null;
public event Action SettingsLoaded;
public event Action SettingsSaved;
public event Action<string, ServiceSettingValue> SettingChanged;
public void Load() => SettingsLoaded?.Invoke();
public void Save() => SettingsSaved?.Invoke();
public void ReloadExternalChanges() { }
public void ApplyAll() { }
public void ResetAllToDefaults() { }
public void ResetGroupToDefaults(string groupName) { }
public bool Set(string key, ServiceSettingValue value) { SettingChanged?.Invoke(key, value); return true; }
public bool SetExternal(string key, ServiceSettingValue value) => Set(key, value);
public bool SetBool(string key, bool value) => Set(key, ServiceSettingValue.Bool(value));
public bool SetInt(string key, int value) => Set(key, ServiceSettingValue.Int(value));
public bool SetFloat(string key, float value) => Set(key, ServiceSettingValue.Float(value));
public bool SetString(string key, string value) => Set(key, ServiceSettingValue.String(value));
public bool SetOptionIndex(string key, int optionIndex) => Set(key, ServiceSettingValue.Option(optionIndex));
public bool TryGetDefinition(string key, out ServiceSettingDefinition definition) { definition = null; return false; }
public IReadOnlyDictionary<string, ServiceSettingValue> Snapshot() => new Dictionary<string, ServiceSettingValue>();
public ServiceSettingValue Get(string key) => default;
public bool GetBool(string key) => false;
public int GetInt(string key) => 0;
public float GetFloat(string key) => 0f;
public string GetString(string key) => string.Empty;
public int GetOptionIndex(string key) => 0;
}
}
}