Skip to content

Commit

Permalink
Merge pull request #2122 from andy840119/separate-the-lyric-caret-sta…
Browse files Browse the repository at this point in the history
…te-test-case

Rewrite the LyricCaretStateTest
  • Loading branch information
andy840119 committed Sep 15, 2023
2 parents 96696c6 + a41d8af commit 7aca426
Show file tree
Hide file tree
Showing 7 changed files with 1,032 additions and 446 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
// Copyright (c) andy840119 <andy840119@gmail.com>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Rulesets.Karaoke.Beatmaps;
using osu.Game.Rulesets.Karaoke.Configuration;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics.CaretPosition;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics.CaretPosition.Algorithms;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics.States;
using osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics.States.Modes;
using osu.Game.Screens.Edit;
using osu.Game.Tests.Visual;

namespace osu.Game.Rulesets.Karaoke.Tests.Screens.Edit.Beatmap.Lyrics.States;

[HeadlessTest]
public abstract partial class BaseLyricCaretStateTest : OsuTestScene
{
private TestLyricEditorState state = null!;
private EditorBeatmap editorBeatmap = null!;

private LyricCaretState lyricCaretState = null!;

protected ILyricCaretState LyricCaretState => lyricCaretState;

[BackgroundDependencyLoader]
private void load()
{
var beatmap = new KaraokeBeatmap
{
BeatmapInfo =
{
Ruleset = new KaraokeRuleset().RulesetInfo,
},
};

Dependencies.Cache(editorBeatmap = new EditorBeatmap(beatmap));
Dependencies.Cache(new EditorClock());
Dependencies.CacheAs<ILyricEditorState>(state = new TestLyricEditorState());
Dependencies.CacheAs<ITextingModeState>(new TextingModeState());
Dependencies.CacheAs<IEditRubyModeState>(new EditRubyModeState());
Dependencies.CacheAs<ITimeTagModeState>(new TimeTagModeState());
Dependencies.Cache(new KaraokeRulesetLyricEditorConfigManager());

var lyricsProvider = new LyricsProvider();
Dependencies.CacheAs<ILyricsProvider>(lyricsProvider);

Children = new Drawable[]
{
state,
lyricsProvider,
lyricCaretState = new LyricCaretState(),
};
}

[SetUp]
public void Setup()
{
AddStep("Set-up.", () =>
{
state.SwitchMode(LyricEditorMode.View);
});
}

#region Test utility

public void PrepareLyrics(IEnumerable<string> lyricTexts)
{
AddStep("Prepare lyrics", () =>
{
var lyrics = lyricTexts.Select((x, i) => new Lyric { Text = x, Order = i });
editorBeatmap.Clear();
editorBeatmap.AddRange(lyrics);
});
}

protected void ChangeMode(TestCaretType type)
{
AddStep("Switch to edit mode", () =>
{
switch (type)
{
case TestCaretType.ViewOnly:
state.SwitchMode(LyricEditorMode.View);
return;
case TestCaretType.CaretEnable:
state.SwitchMode(LyricEditorMode.Reference);
break;
case TestCaretType.CaretWithIndex:
state.SwitchMode(LyricEditorMode.Texting);
state.SwitchEditStep(TextingEditStep.Split);
break;
case TestCaretType.CaretDraggable:
state.SwitchMode(LyricEditorMode.Texting);
state.SwitchEditStep(TextingEditStep.Typing);
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
});
}

protected Lyric GetLyric(int index)
{
var hitObjects = editorBeatmap.HitObjects[index];

if (hitObjects is not Lyric lyric)
throw new InvalidCastException();

return lyric;
}

public void PrepareHoverCaretPosition(Func<ICaretPosition?> getPosition)
{
AddStep("Set hover caret position", () =>
{
if (LyricCaretState.BindableHoverCaretPosition is not Bindable<ICaretPosition?> bindable)
throw new InvalidOperationException();
bindable.Value = getPosition();
});
}

public void PrepareCaretPosition(Func<ICaretPosition?> getPosition)
{
AddStep("Set caret position", () =>
{
if (LyricCaretState.BindableCaretPosition is not Bindable<ICaretPosition?> bindable)
throw new InvalidOperationException();
bindable.Value = getPosition();
});
}

public void PrepareRangeCaretPosition(Func<RangeCaretPosition?> getPosition)
{
AddStep("Set caret position", () =>
{
if (LyricCaretState.BindableRangeCaretPosition is not Bindable<RangeCaretPosition?> bindable)
throw new InvalidOperationException();
bindable.Value = getPosition();
});
}

protected void AssertHoverCaretPosition(Func<ICaretPosition?> getPosition)
{
AddAssert("Assert hover caret position", () => EqualityComparer<ICaretPosition?>.Default.Equals(getPosition(), LyricCaretState.HoverCaretPosition));
}

protected void AssertCaretPosition(Func<ICaretPosition?> getPosition)
{
AddAssert("Assert caret position", () => EqualityComparer<ICaretPosition?>.Default.Equals(getPosition(), LyricCaretState.CaretPosition));
}

protected void AssertDraggableCaretPosition(Func<RangeCaretPosition?> getPosition)
{
AddAssert("Assert range caret position", () => EqualityComparer<RangeCaretPosition?>.Default.Equals(getPosition(), LyricCaretState.RangeCaretPosition));
}

#endregion

private partial class TestLyricEditorState : Component, ILyricEditorState
{
private readonly Bindable<LyricEditorMode> bindableMode = new();

private readonly Bindable<EditorModeWithEditStep> bindableModeWithEditStep = new();

public IBindable<LyricEditorMode> BindableMode => bindableMode;

public IBindable<EditorModeWithEditStep> BindableModeWithEditStep => bindableModeWithEditStep;

public LyricEditorMode Mode => bindableMode.Value;

[Resolved]
private ITextingModeState textingModeState { get; set; } = null!;

public void SwitchMode(LyricEditorMode mode)
{
bindableMode.Value = mode;

bindableMode.BindValueChanged((_) =>
{
updateModeWithEditStep();
}, true);
textingModeState.BindableEditStep.BindValueChanged(e =>
{
updateModeWithEditStep();
});
}

private void updateModeWithEditStep()
{
bindableModeWithEditStep.Value = new EditorModeWithEditStep
{
Mode = bindableMode.Value,
EditStep = getTheEditStep(bindableMode.Value),
Default = false,
};

Enum? getTheEditStep(LyricEditorMode mode) =>
mode switch
{
LyricEditorMode.View => null,
LyricEditorMode.Texting => textingModeState.EditStep,
LyricEditorMode.Reference => null,
LyricEditorMode.Language => throw new NotSupportedException(),
LyricEditorMode.EditRuby => throw new NotSupportedException(),
LyricEditorMode.EditRomaji => throw new NotSupportedException(),
LyricEditorMode.EditTimeTag => throw new NotSupportedException(),
LyricEditorMode.EditNote => throw new NotSupportedException(),
LyricEditorMode.Singer => throw new NotSupportedException(),
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null),
};
}

public void SwitchEditStep<TEditStep>(TEditStep editStep) where TEditStep : Enum
{
if (editStep is not TextingEditStep textingEditStep)
throw new NotSupportedException();

textingModeState.ChangeEditStep(textingEditStep);
}

public void NavigateToFix(LyricEditorMode mode)
=> throw new NotSupportedException();
}
}

/// <summary>
/// The main goal of the test case is testing the behavior if using different <see cref="ICaretPositionAlgorithm"/>
/// Not test all the <see cref="ICaretPositionAlgorithm"/>
/// So we choose the some representative <see cref="ICaretPositionAlgorithm"/>.
/// </summary>
public enum TestCaretType
{
ViewOnly,

CaretEnable,

CaretWithIndex,

CaretDraggable,
}
Loading

0 comments on commit 7aca426

Please sign in to comment.