Files
MagnetismHeroes/Assets/MagnetismHeroes/Tests/EditMode/ContentSessionTests.cs
T

112 lines
7.8 KiB
C#

using System;
using System.Linq;
using MagnetismHeroes.Core;
using MagnetismHeroes.UnityRuntime.StageAssets;
using NUnit.Framework;
using UnityEditor;
namespace MagnetismHeroes.Tests
{
public sealed class ContentSessionTests
{
private sealed class Store : IProgressStore
{
public ProgressSave Saved = new ProgressSave();
public bool TryLoad(out ProgressSave save, out string error) { save = Saved; error = null; return true; }
public bool TrySave(ProgressSave save, out string error) { Saved = save; error = null; return true; }
}
private static StageDefinition[] Definitions() => Enumerable.Range(1,30).Select(id =>
AssetDatabase.LoadAssetAtPath<StageAsset>($"Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage{id:D2}.asset").ToDefinition()).ToArray();
private static void Apply(GameSession session, BoardHint hint)
{
Assert.That(hint, Is.Not.Null);
RuleResult result;
switch (hint.Kind)
{
case HintKind.Collect: result = session.MoveGroup(hint.FirstGroupId, new Position3(.1f,0,0)); break;
case HintKind.Count: result = session.Count(hint.BallIds[0]); break;
case HintKind.Merge: result = session.MoveAndMerge(hint.FirstGroupId, new Position3(.1f,0,0), hint.SecondGroupId); break;
default: result = session.SplitAndMove(hint.FirstGroupId, hint.BallIds, "hint-split-" + Guid.NewGuid().ToString("N"), new Position3(1,0,0)); break;
}
Assert.That(result.Accepted, Is.True, result.Reason.ToString());
}
[Test] public void FreshSaveSolvesAllThirtyThroughActualCoreCallsUnlocksNextAndNeverThirtyOne()
{
var definitions = Definitions(); var store = new Store(); var session = new GameSession(definitions, store);
Assert.That(Enumerable.Range(1,30).Where(session.IsUnlocked), Is.EqualTo(new[] {1}));
for (int id = 1; id <= 30; id++)
{
if (id == 1) Assert.That(session.StartStage(id), Is.True);
else Assert.That(session.StartNextStage(), Is.True);
Assert.That(session.Board.StageId, Is.EqualTo(id));
for (int step = 0; session.Screen == SessionScreen.Puzzle && step < 40; step++)
{
var before = UnityEngine.JsonUtility.ToJson(store.Saved); var ids = session.Board.Balls.Select(ball => ball.id).ToArray();
var hint = session.Hint;
Assert.That(UnityEngine.JsonUtility.ToJson(store.Saved), Is.EqualTo(before), "Help is read-only.");
Apply(session, hint); Assert.That(session.Board.Balls.Select(ball => ball.id), Is.EqualTo(ids));
}
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay), $"Stage {id}");
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,id)));
Assert.That(session.HasNextStage, Is.EqualTo(id < 30));
Assert.That(store.Saved.latestFreePlay.sourceStageId, Is.EqualTo(id));
session = new GameSession(definitions, store); Assert.That(session.ContinueFreePlay(), Is.True);
}
Assert.That(session.IsUnlocked(31), Is.False); Assert.That(session.StartNextStage(), Is.False); Assert.That(session.StartStage(31), Is.False);
Assert.That(session.StartStage(6), Is.True); session.MoveGroup(session.Board.Groups[0].id, new Position3(.2f,0,0)); session.ShowHome();
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,30))); Assert.That(session.IsUnlocked(30), Is.True);
Assert.That(session.StartStage(6), Is.True); Assert.That(session.Board.Balls[0].position.x, Is.EqualTo(definitions[5].BallPositions[0].x+.2f));
}
[Test] public void NextPrefersSavedPuzzleAndHelpRecoversFromAlternativeDisconnectedPartitions()
{
var definitions = Definitions(); var store = new Store { Saved = new ProgressSave { completedStageIds = Enumerable.Range(1,29).ToArray() } };
var session = new GameSession(definitions,store); Assert.That(session.StartStage(30), Is.True);
var group = session.Board.Groups[0]; session.SplitAndMove(group.id,new[] {group.ballIds[0],group.ballIds[2]},"alternative",new Position3(0,2,0));
session.CommitCamera(new CameraState { distance=12 }); session.ShowHome();
Assert.That(session.StartStage(29), Is.True);
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
Assert.That(session.StartNextStage(), Is.True); Assert.That(session.Camera.distance, Is.EqualTo(12));
Assert.That(session.Board.Groups.Any(value=>value.id=="alternative"), Is.True);
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay));
Assert.That(session.Board.Groups.Select(value=>value.ballIds.Length).OrderBy(size=>size), Is.EqualTo(new[] {5,5}));
}
[Test] public void AllIntegerPartitionsHaveLiveHintsThatReachEachCompositionTarget()
{
foreach (var definition in Definitions().Where(stage=>stage.Kind==StageKind.Composition))
foreach (var sizes in Partitions(definition.Total,1))
{
var board = new BoardRules(new StageDefinition(definition.Id,StageKind.Composition,sizes,definition.TargetGroups.ToArray()));
for (int i=0; !board.IsSolved && i<20; i++)
{
var hint=BoardHint.Find(board,definition); Assert.That(hint, Is.Not.Null);
var result=hint.Kind==HintKind.Merge ? board.TryMerge(hint.FirstGroupId,hint.SecondGroupId)
: board.TrySplit(hint.FirstGroupId,hint.BallIds,"split-"+i);
Assert.That(result.Accepted, Is.True);
}
Assert.That(board.IsSolved, Is.True, $"{definition.Id}: {string.Join(",",sizes)}");
}
}
private static System.Collections.Generic.IEnumerable<int[]> Partitions(int total,int minimum)
{
if (total==0) { yield return Array.Empty<int>(); yield break; }
for (int first=minimum; first<=total; first++)
foreach (var rest in Partitions(total-first,first)) yield return new[] {first}.Concat(rest).ToArray();
}
[Test] public void CountingHelpRejoinsCollectedSplitBeforeFindingOtherFriendsThenCountsOnlyUncountedId()
{
var definition=new StageDefinition(4,StageKind.Counting,new[] {1,1,1,1},new[] {4}); var board=new BoardRules(definition);
board.TryMerge(board.Groups[0].id,board.Groups[1].id); var collected=board.Groups.First(group=>group.ballIds.Length==2);
board.TrySplit(collected.id,new[] {collected.ballIds[0]},"resplit");
var hint=BoardHint.Find(board,definition); Assert.That(hint.Kind, Is.EqualTo(HintKind.Merge));
Assert.That(hint.BallIds.All(board.CollectedBallIds.Contains), Is.True); board.TryMerge(hint.FirstGroupId,hint.SecondGroupId);
Assert.That(BoardHint.Find(board,definition).Kind, Is.EqualTo(HintKind.Collect));
foreach (var group in board.Groups) board.TryMoveGroup(group.id,new Position3(.1f,0,0));
while (board.Groups.Length>1) board.TryMerge(board.Groups[0].id,board.Groups[1].id);
board.TryCount(board.Balls[0].id); hint=BoardHint.Find(board,definition);
Assert.That(hint.Kind, Is.EqualTo(HintKind.Count)); Assert.That(board.CountedBallIds, Does.Not.Contain(hint.BallIds[0]));
Assert.That(board.TryCount(hint.BallIds[0]).Accepted, Is.True);
}
}
}